Ein zweiter Provider für die Aufgaben-Schicht, damit die private Instanz nicht an Super Productivity (SP) gebunden ist: CalDAV-Aufgaben (VTODO), Zielserver Nextcloud, mit der iOS-App Erinnerungen als mobilem Client.
Stand (2026-09-25): umgesetzt und veröffentlicht in Commit 6d53c55 als Kandidat 7.1.0-beta.2. Ein Release gibt es noch nicht; wann der Kandidat ausgeliefert wird, entscheidet der Betreiber. Das Protokoll (tasks/protocol.py) ist unverändert geblieben. Außerhalb des Adapters hat sich nur D3 in review.py geändert.
Die Begründung der Zwei-Schichten-Konstruktion steht in docs/knowledge-and-commitment.md, die verbindlichen Zeilen zu review, new project, task new, task list/task close und doctor stehen in tools/CONTRACT.md. Die sechs Regeln für einen zweiten Adapter stehen in #128.
Zuschnitt: was iOS tun soll und was nicht
Betreiber, 2026-09-23: Auf dem iPhone wird abgehakt, nicht gearbeitet. Gepflegt wird am Schreibtisch, in der Nextcloud-Tasks-Web-App oder mit wikitool task new. Die iOS-Schwächen bei CalDAV-Listen betreffen nur das Pflegen, nicht das Abhaken: keine Tags oder Kategorien, keine Unteraufgaben, keine Markierungen, nur ein Datum. Eine eigene Nextcloud-App wird nicht gebraucht, denn Nextcloud (Sabre/DAV) und iOS erhalten fremde Eigenschaften.
Warum CalDAV und nicht Deck
Recherchiert am 2026-09-22.
Deck kennt „erledigt“ doppelt, als Stack „Done“ und als done-Flag.
PUT auf eine Karte ersetzt die Karte vollständig.
startdate ist unsicher.
Deck synchronisiert nicht mit iOS.
CalDAV ist ein Standard (RFC 4791/5545). Der Provider heißt deshalb caldav und nicht nextcloud.
Testlauf 2026-09-25 (Nextcloud und iOS Erinnerungen, echtes Konto)
Aktion auf iOS
Was iOS geschrieben hat
Folge
Liste sichtbar?
ja
create_project per MKCALENDAR kommt bis aufs iPhone
Abhaken
STATUS:COMPLETED, COMPLETED, PERCENT-COMPLETE:100; DTSTART entfernt; CATEGORIES und X--Eigenschaften bleiben erhalten
close_item setzt dieselben Felder, lässt DTSTART aber stehen
Umbenennen
nur SUMMARY
unkritisch
Datum setzen
DTSTART und DUE auf das neue Datum
Das iOS-Datum wird zur Wiedervorlage (follow_up_at = DTSTART). Eine in Nextcloud gesetzte Fälligkeit geht dabei verloren
Neuer Posten auf iOS
CREATED, STATUS:NEEDS-ACTION, UID in Großbuchstaben
Der Ersatzwert „ältestes CREATED“ funktioniert
Siri in die Inbox
nicht getestet; der Betreiber nimmt an, dass es funktioniert
nachrangig
Weitere Befunde:
Kein Kalender liefert DAV:creationdate. Das begründet D3.
Die konfigurierte URL darf ein Alias sein, denn die Antworten tragen die kanonische Benutzer-ID.
Bestehende Listen im Konto werden ignoriert (D5).
Umgesetzte Abbildung
Protokoll
CalDAV
Projekt
Collection, deren supported-calendar-component-set genau VTODO ist; displayname = Projektname. Inbox, Someday und exclude_lists sind ausgenommen
Inbox, Someday
je eine reine VTODO-Liste, Name aus der Konfiguration
offener Posten
STATUS ist weder COMPLETED noch CANCELLED
WAITING
CATEGORIES enthält waiting (ohne Rücksicht auf Groß-/Kleinschreibung)
follow_up_at
DTSTART, nieDUE
ProjectSummary.created
ältestes CREATED der Posten; None bei einer leeren Liste
create_project
MKCALENDAR unter einem UUID-Pfad, automatisch, kein Exit 42. Vorher wird der Name gegen alle Listen des Kontos geprüft
create_item
PUT einer neuen .ics mit If-None-Match: *; notes wird zu DESCRIPTION
close_item
GET, dann nur die fünf Felder ändern, dann PUT mit If-Match. Bei 412 bricht es mit Exit 1 ab, ohne Retry
source()
kind: "api", immer live
Adressen
nur aus den hrefs, die der Server liefert, aufgelöst gegen die Anfrage-URL
Konfiguration: url, username (Login-Name), app_password, inbox_list, someday_list, optional exclude_lists. Die Form steht in INSTALL.md § Konfiguration.
Entschieden (Betreiber, 2026-09-25)
D1: Aufwandsschätzung wurde nach #141 ausgelagert.
D2: Die private Instanz stellt vollständig um.torben/nathan wechselt von SP auf caldav, denn es gilt ein Tracker je Instanz (#119 D15). Offene SP-Posten zieht der Betreiber von Hand um; es gibt keine Migration zwischen Providern. Die Umstellung selbst ist Betreiberarbeit in der privaten Instanz und nicht Teil dieses Issues.
D3: Fehlende Daten werden gemeldet, nicht still übersprungen. Umgesetzt als eigene Fundstellen waiting_no_follow_up (unter Prüfung 2) und project_age_unknown (unter Prüfung 3), für jeden Provider. Es sind keine zusätzlichen Einträge in ALL_CHECKS; die Zählung „5 Prüfungen liefen“ bleibt. Der Skill gtd-weekly-review hat für beide eine Tabellenzeile bekommen.
D4: icalendar steht in tools/requirements.txt, als >=6.0. Versionsteil: minor, nach instructions/dev/version-parts.md. Das Modul wird nur geladen, wenn caldav konfiguriert ist. Eine bestehende Instanz ohne CalDAV läuft deshalb ohne erneutes pip install weiter, der Wechsel ist in beide Richtungen drop-in.
D5: Vorhandene Listen werden ignoriert. Kollidiert ein neuer Projektname mit einer solchen Liste, verweigert create_project und nennt die Liste. Umbenennen bleibt Handarbeit in Nextcloud.
D6: Eine Liste je Projekt (Variante A) plus Inbox und Someday. B (RELATED-TO-Hierarchie) und C (Titelpräfix, verletzt #119 D4) sind verworfen. Der Adapter löscht nie; Listen abgeschlossener Projekte löscht der Betreiber von Hand.
Akzeptanzkriterien
caldav erfüllt TaskReader/TaskWriter vollständig, ohne dass tasks/protocol.py sich ändert.
review, new project, task new, task list und task close laufen über das generische Dispatch gegen caldav, ohne Wortänderung in einem Skill; test_task_tracker_skills_name_no_provider ist grün. Die neue Zeile im Skill gtd-weekly-review betrifft D3 und nennt keinen Provider.
D3 ist als eigene Fundstellen umgesetzt; Text- und --json-Ausgabe stimmen überein. Getestet für SP und caldav.
close_item ändert nur die fünf Felder. X-APPLE-SORT-ORDER, VALARM und DTSTART bleiben unverändert erhalten, getestet gegen eine Fixture in iOS-Form.
Ein ETag-Konflikt (412) schreibt nichts und führt zu Exit 1.
Der Adapter sendet kein DELETE.
Jede Adresse stammt aus einem href des Servers. Getestet mit einer Fixture, deren hrefs eine andere Benutzer-ID tragen als die konfigurierte URL.
D5: Die Kollisionsprüfung läuft gegen jede Liste des Kontos, und die Meldung nennt die kollidierende Liste.
Eine unbekannte Antwortform scheitert laut: kein Multistatus, falscher Status, nicht parsebares VTODO.
exclude_lists, Inbox, Someday und Listen mit VEVENT-Anteil sind keine Projekte. Von anderen geteilte Listen werden nicht eigens erkannt. Sie zählen nur dann nicht als Projekt, wenn sie gemischt sind oder in exclude_lists stehen. Eine geteilte reine VTODO-Liste gehört in exclude_lists.
KNOWN_PROVIDERS, build_reader und build_writer kennen caldav. Ein unvollständiger oder überzähliger Konfigurationsblock scheitert beim Lesen.
icalendar steht in requirements.txt; der Versionsteil ist begründet (D4).
Alle Tests laufen gegen lokale http.server-Stubs; es wird kein erreichbarer CalDAV-Server gebraucht.
doctor meldet Provider, Erreichbarkeit und Authentifizierung. Ein FAIL gibt es nur bei kaputter Konfiguration.
Es liegt kein Zugangsdatum im Repo. INSTALL.md nennt die Form des Konfigurationsblocks, das App-Passwort, den Unterschied zwischen Login-Name und Benutzer-ID und das Löschen alter Listen von Hand.
docs verify, instructions verify und pytest sind grün: 1487 Tests, zusätzlich gegen eine leere Maschine (env -i). Die CI-Läufe 360/361 zu 6d53c55 sind im Schlusskommentar genannt.
Nebenbefund in derselben Session
Die Session hat zwischenzeitlich eigenmächtig version release ausgeführt. Der Grund war der Hinweis in der Ausgabe von version bump. Das wurde vor dem Publish zurückgenommen. Mit demselben Commit ist der Hinweis aus der Ausgabe von version bump entfernt, und instructions/dev/version-parts.md Schritt 7 sagt jetzt ausdrücklich: Ein Kandidat wird nur fixiert, wenn der Betreiber das verlangt.
Abhängigkeiten
#128 (Azure DevOps) liest sich jetzt gegen zwei Präzedenzfälle und erbt D3.
#131 (Lesen über MCP): Ein immer erreichbarer Server macht die Verteilung von Snapshots überflüssig. Er vergrößert aber die Sprengweite des Tokens auf den ganzen Aufgabenbestand.
Ein zweiter Provider für die Aufgaben-Schicht, damit die private Instanz nicht an Super Productivity (SP) gebunden ist: **CalDAV-Aufgaben (VTODO), Zielserver Nextcloud**, mit der iOS-App *Erinnerungen* als mobilem Client.
**Stand (2026-09-25): umgesetzt und veröffentlicht** in Commit `6d53c55` als Kandidat `7.1.0-beta.2`. Ein Release gibt es noch nicht; wann der Kandidat ausgeliefert wird, entscheidet der Betreiber. Das Protokoll (`tasks/protocol.py`) ist unverändert geblieben. Außerhalb des Adapters hat sich nur D3 in `review.py` geändert.
Die Begründung der Zwei-Schichten-Konstruktion steht in `docs/knowledge-and-commitment.md`, die verbindlichen Zeilen zu `review`, `new project`, `task new`, `task list`/`task close` und `doctor` stehen in `tools/CONTRACT.md`. Die sechs Regeln für einen zweiten Adapter stehen in #128.
## Zuschnitt: was iOS tun soll und was nicht
Betreiber, 2026-09-23: **Auf dem iPhone wird abgehakt, nicht gearbeitet.** Gepflegt wird am Schreibtisch, in der Nextcloud-Tasks-Web-App oder mit `wikitool task new`. Die iOS-Schwächen bei CalDAV-Listen betreffen nur das Pflegen, nicht das Abhaken: keine Tags oder Kategorien, keine Unteraufgaben, keine Markierungen, nur *ein* Datum. Eine eigene Nextcloud-App wird nicht gebraucht, denn Nextcloud (Sabre/DAV) und iOS erhalten fremde Eigenschaften.
## Warum CalDAV und nicht Deck
Recherchiert am 2026-09-22.
- Deck kennt „erledigt“ doppelt, als Stack „Done“ und als `done`-Flag.
- `PUT` auf eine Karte ersetzt die Karte vollständig.
- `startdate` ist unsicher.
- Deck synchronisiert nicht mit iOS.
CalDAV ist ein Standard (RFC 4791/5545). Der Provider heißt deshalb `caldav` und nicht `nextcloud`.
## Testlauf 2026-09-25 (Nextcloud und iOS Erinnerungen, echtes Konto)
| Aktion auf iOS | Was iOS geschrieben hat | Folge |
|---|---|---|
| Liste sichtbar? | ja | `create_project` per `MKCALENDAR` kommt bis aufs iPhone |
| Abhaken | `STATUS:COMPLETED`, `COMPLETED`, `PERCENT-COMPLETE:100`; **`DTSTART` entfernt**; `CATEGORIES` und `X-`-Eigenschaften bleiben erhalten | `close_item` setzt dieselben Felder, lässt `DTSTART` aber stehen |
| Umbenennen | nur `SUMMARY` | unkritisch |
| Datum setzen | **`DTSTART` und `DUE`** auf das neue Datum | Das iOS-Datum wird zur Wiedervorlage (`follow_up_at` = `DTSTART`). Eine in Nextcloud gesetzte Fälligkeit geht dabei verloren |
| Neuer Posten auf iOS | `CREATED`, `STATUS:NEEDS-ACTION`, UID in Großbuchstaben | Der Ersatzwert „ältestes `CREATED`“ funktioniert |
| Siri in die Inbox | nicht getestet; der Betreiber nimmt an, dass es funktioniert | nachrangig |
Weitere Befunde:
- Kein Kalender liefert `DAV:creationdate`. Das begründet D3.
- Die konfigurierte URL darf ein Alias sein, denn die Antworten tragen die kanonische Benutzer-ID.
- Bestehende Listen im Konto werden ignoriert (D5).
## Umgesetzte Abbildung
| Protokoll | CalDAV |
|---|---|
| Projekt | Collection, deren `supported-calendar-component-set` genau VTODO ist; `displayname` = Projektname. Inbox, Someday und `exclude_lists` sind ausgenommen |
| Inbox, Someday | je eine reine VTODO-Liste, Name aus der Konfiguration |
| offener Posten | `STATUS` ist weder `COMPLETED` noch `CANCELLED` |
| `WAITING` | `CATEGORIES` enthält `waiting` (ohne Rücksicht auf Groß-/Kleinschreibung) |
| `follow_up_at` | `DTSTART`, **nie** `DUE` |
| `ProjectSummary.created` | ältestes `CREATED` der Posten; `None` bei einer leeren Liste |
| `create_project` | `MKCALENDAR` unter einem UUID-Pfad, automatisch, **kein Exit 42**. Vorher wird der Name gegen **alle** Listen des Kontos geprüft |
| `create_item` | `PUT` einer neuen `.ics` mit `If-None-Match: *`; `notes` wird zu `DESCRIPTION` |
| `close_item` | `GET`, dann nur die fünf Felder ändern, dann `PUT` mit `If-Match`. Bei 412 bricht es mit Exit 1 ab, ohne Retry |
| `source()` | `kind: "api"`, immer live |
| Adressen | nur aus den `href`s, die der Server liefert, aufgelöst gegen die Anfrage-URL |
Konfiguration: `url`, `username` (Login-Name), `app_password`, `inbox_list`, `someday_list`, optional `exclude_lists`. Die Form steht in `INSTALL.md` § Konfiguration.
## Entschieden (Betreiber, 2026-09-25)
- **D1: Aufwandsschätzung wurde nach #141 ausgelagert.**
- **D2: Die private Instanz stellt vollständig um.** `torben/nathan` wechselt von SP auf `caldav`, denn es gilt ein Tracker je Instanz (#119 D15). Offene SP-Posten zieht der Betreiber von Hand um; es gibt keine Migration zwischen Providern. *Die Umstellung selbst ist Betreiberarbeit in der privaten Instanz und nicht Teil dieses Issues.*
- **D3: Fehlende Daten werden gemeldet, nicht still übersprungen.** Umgesetzt als eigene Fundstellen `waiting_no_follow_up` (unter Prüfung 2) und `project_age_unknown` (unter Prüfung 3), für jeden Provider. Es sind keine zusätzlichen Einträge in `ALL_CHECKS`; die Zählung „5 Prüfungen liefen“ bleibt. Der Skill `gtd-weekly-review` hat für beide eine Tabellenzeile bekommen.
- **D4: `icalendar` steht in `tools/requirements.txt`**, als `>=6.0`. **Versionsteil: minor**, nach `instructions/dev/version-parts.md`. Das Modul wird nur geladen, wenn `caldav` konfiguriert ist. Eine bestehende Instanz ohne CalDAV läuft deshalb ohne erneutes `pip install` weiter, der Wechsel ist in beide Richtungen drop-in.
- **D5: Vorhandene Listen werden ignoriert.** Kollidiert ein neuer Projektname mit einer solchen Liste, verweigert `create_project` und nennt die Liste. Umbenennen bleibt Handarbeit in Nextcloud.
- **D6: Eine Liste je Projekt (Variante A)** plus Inbox und Someday. B (`RELATED-TO`-Hierarchie) und C (Titelpräfix, verletzt #119 D4) sind verworfen. Der Adapter löscht nie; Listen abgeschlossener Projekte löscht der Betreiber von Hand.
## Akzeptanzkriterien
- [x] `caldav` erfüllt `TaskReader`/`TaskWriter` vollständig, **ohne dass `tasks/protocol.py` sich ändert**.
- [x] `review`, `new project`, `task new`, `task list` und `task close` laufen über das generische Dispatch gegen `caldav`, ohne Wortänderung in einem Skill; `test_task_tracker_skills_name_no_provider` ist grün. Die neue Zeile im Skill `gtd-weekly-review` betrifft D3 und nennt keinen Provider.
- [x] D3 ist als eigene Fundstellen umgesetzt; Text- und `--json`-Ausgabe stimmen überein. Getestet für SP und `caldav`.
- [x] `close_item` ändert nur die fünf Felder. `X-APPLE-SORT-ORDER`, `VALARM` und `DTSTART` bleiben unverändert erhalten, getestet gegen eine Fixture in iOS-Form.
- [x] Ein ETag-Konflikt (412) schreibt nichts und führt zu Exit 1.
- [x] Der Adapter sendet kein `DELETE`.
- [x] Jede Adresse stammt aus einem `href` des Servers. Getestet mit einer Fixture, deren `href`s eine andere Benutzer-ID tragen als die konfigurierte URL.
- [x] D5: Die Kollisionsprüfung läuft gegen jede Liste des Kontos, und die Meldung nennt die kollidierende Liste.
- [x] Eine unbekannte Antwortform scheitert laut: kein Multistatus, falscher Status, nicht parsebares VTODO.
- [x] `exclude_lists`, Inbox, Someday und Listen mit VEVENT-Anteil sind keine Projekte. *Von anderen geteilte Listen werden nicht eigens erkannt.* Sie zählen nur dann nicht als Projekt, wenn sie gemischt sind oder in `exclude_lists` stehen. Eine geteilte reine VTODO-Liste gehört in `exclude_lists`.
- [x] `KNOWN_PROVIDERS`, `build_reader` und `build_writer` kennen `caldav`. Ein unvollständiger oder überzähliger Konfigurationsblock scheitert beim Lesen.
- [x] `icalendar` steht in `requirements.txt`; der Versionsteil ist begründet (D4).
- [x] Alle Tests laufen gegen lokale `http.server`-Stubs; es wird kein erreichbarer CalDAV-Server gebraucht.
- [x] `doctor` meldet Provider, Erreichbarkeit und Authentifizierung. Ein `FAIL` gibt es nur bei kaputter Konfiguration.
- [x] Es liegt kein Zugangsdatum im Repo. `INSTALL.md` nennt die Form des Konfigurationsblocks, das App-Passwort, den Unterschied zwischen Login-Name und Benutzer-ID und das Löschen alter Listen von Hand.
- [x] `docs verify`, `instructions verify` und `pytest` sind grün: 1487 Tests, zusätzlich gegen eine leere Maschine (`env -i`). Die CI-Läufe 360/361 zu `6d53c55` sind im Schlusskommentar genannt.
## Nebenbefund in derselben Session
Die Session hat zwischenzeitlich eigenmächtig `version release` ausgeführt. Der Grund war der Hinweis in der Ausgabe von `version bump`. Das wurde vor dem Publish zurückgenommen. Mit demselben Commit ist der Hinweis aus der Ausgabe von `version bump` entfernt, und `instructions/dev/version-parts.md` Schritt 7 sagt jetzt ausdrücklich: Ein Kandidat wird nur fixiert, wenn der Betreiber das verlangt.
## Abhängigkeiten
- #128 (Azure DevOps) liest sich jetzt gegen zwei Präzedenzfälle und erbt D3.
- #141 übernimmt die Aufwandsschätzung.
- #131 (Lesen über MCP): Ein immer erreichbarer Server macht die Verteilung von Snapshots überflüssig. Er vergrößert aber die Sprengweite des Tokens auf den ganzen Aufgabenbestand.
Changelog: Testlauf gegen echtes Nextcloud und iOS Erinnerungen (2026-09-25) eingearbeitet; vier von fünf „Vorher zu klären“-Punkten abgehakt, Siri bleibt offen und nicht blockierend.
Neu: Abschnitt „Testlauf“. iOS erhält CATEGORIES/X-/DESCRIPTION bei allen Aktionen. Abhaken schreibt dieselben drei Felder wie der geplante close_item, entfernt aber DTSTART. Ein auf iOS gesetztes Datum überschreibt DTSTARTundDUE.
Präzisiert:follow_up_at = DTSTART ist jetzt verifiziert statt vermutet; das iOS-Datum wird damit zur Wiedervorlage. Die Abbildungstabelle trägt eine iOS-Spalte mit den Befunden.
Neue Kriterien: Adressen nur aus Server-hrefs, weil die konfigurierte URL ein Alias sein darf. close_item erhält DTSTART und X-APPLE-SORT-ORDER. INSTALL.md nennt Login-Name gegenüber Benutzer-ID.
Neu offen: D5, bestehende Listen im Konto (zwei reine Aufgabenlisten, ein gemischter Standardkalender) und ob der Standardkalender als Inbox zulässig ist.
kein creationdate an Kalendern bestätigt D3.
**Changelog:** Testlauf gegen echtes Nextcloud und iOS Erinnerungen (2026-09-25) eingearbeitet; vier von fünf „Vorher zu klären“-Punkten abgehakt, Siri bleibt offen und nicht blockierend.
- **Neu:** Abschnitt „Testlauf“. iOS erhält `CATEGORIES`/`X-`/`DESCRIPTION` bei allen Aktionen. Abhaken schreibt dieselben drei Felder wie der geplante `close_item`, entfernt aber `DTSTART`. Ein auf iOS gesetztes Datum überschreibt `DTSTART` **und** `DUE`.
- **Präzisiert:** `follow_up_at` = `DTSTART` ist jetzt verifiziert statt vermutet; das iOS-Datum wird damit zur Wiedervorlage. Die Abbildungstabelle trägt eine iOS-Spalte mit den Befunden.
- **Neue Kriterien:** Adressen nur aus Server-`href`s, weil die konfigurierte URL ein Alias sein darf. `close_item` erhält `DTSTART` und `X-APPLE-SORT-ORDER`. `INSTALL.md` nennt Login-Name gegenüber Benutzer-ID.
- **Neu offen:** D5, bestehende Listen im Konto (zwei reine Aufgabenlisten, ein gemischter Standardkalender) und ob der Standardkalender als Inbox zulässig ist.
- `kein creationdate` an Kalendern bestätigt D3.
Changelog: Betreiberentscheidungen vom 2026-09-25 eingearbeitet.
Entschieden: D2 (torben/nathan stellt vollständig auf caldav um; kb/gtd/ dort noch leer, also nichts umzuziehen), D3 (fehlende Daten melden statt überspringen, jetzt mit eigenem Kriterium), D4 (icalendar), D5 (vorhandene Listen ignorieren, bei Konflikt in Nextcloud umbenennen). Siri gilt als funktionierend.
Neu: Abschnitt „Wie viele Listen entstehen“: eine je kb/gtd/-Projekt plus Inbox und Someday. Die Alternative „eine Liste, Projekt als Kategorie“ ist verworfen, weil iOS keine Kategorien kann.
Neues Kriterium aus D5:create_project prüft die Eindeutigkeit gegen alle Listen des Kontos, auch ausgeschlossene.
D1 neu gefasst: Betreiberwunsch „Schätzung übertragen, wenn der Adapter kann“; Vorschlag, das ohne Konsumenten in ein eigenes Issue auszugliedern.
Neu offen: D6, was mit Listen abgeschlossener Projekte geschieht.
**Changelog:** Betreiberentscheidungen vom 2026-09-25 eingearbeitet.
- **Entschieden:** D2 (`torben/nathan` stellt vollständig auf `caldav` um; `kb/gtd/` dort noch leer, also nichts umzuziehen), D3 (fehlende Daten melden statt überspringen, jetzt mit eigenem Kriterium), D4 (`icalendar`), D5 (vorhandene Listen ignorieren, bei Konflikt in Nextcloud umbenennen). Siri gilt als funktionierend.
- **Neu:** Abschnitt „Wie viele Listen entstehen“: eine je `kb/gtd/`-Projekt plus Inbox und Someday. Die Alternative „eine Liste, Projekt als Kategorie“ ist verworfen, weil iOS keine Kategorien kann.
- **Neues Kriterium aus D5:** `create_project` prüft die Eindeutigkeit gegen alle Listen des Kontos, auch ausgeschlossene.
- **D1 neu gefasst:** Betreiberwunsch „Schätzung übertragen, wenn der Adapter kann“; Vorschlag, das ohne Konsumenten in ein eigenes Issue auszugliedern.
- **Neu offen:** D6, was mit Listen abgeschlossener Projekte geschieht.
Changelog: D1 entschieden und nach #141 ausgegliedert. Das alte D6 (Listen abgeschlossener Projekte) geht im neuen D6 auf, der Listenstruktur, nach dem Einwand des Betreibers gegen viele Einzellisten.
Neu: D6 vergleicht A (Liste je Projekt), B (Liste je Verantwortungsbereich, Projekt als übergeordnete VTODO mit RELATED-TO) und C (Bereichslisten, Projekt als Titelpräfix). Echte Listenhierarchie gibt es nicht: RFC 4791 verbietet verschachtelte Kalender-Collections, Listengruppen in iOS gibt es nur für iCloud. C fällt heraus, weil sie #119 D4 verletzt.
Neu nicht getestet: RELATED-TO unter iOS-Bearbeitung; ob die intelligenten Listen von iOS CalDAV-Listen einschließen.
Präzisiert: Die Abbildungstabelle gilt für Variante A; welche Zeilen an D6 hängen, ist markiert. Das Akzeptanzkriterium zum Protokoll unterscheidet A und B.
Abschnitt „Wie viele Listen entstehen“ ist in D6 aufgegangen.
**Changelog:** D1 entschieden und nach #141 ausgegliedert. Das alte D6 (Listen abgeschlossener Projekte) geht im neuen D6 auf, der Listenstruktur, nach dem Einwand des Betreibers gegen viele Einzellisten.
- **Neu:** D6 vergleicht A (Liste je Projekt), B (Liste je Verantwortungsbereich, Projekt als übergeordnete VTODO mit `RELATED-TO`) und C (Bereichslisten, Projekt als Titelpräfix). Echte Listenhierarchie gibt es nicht: RFC 4791 verbietet verschachtelte Kalender-Collections, Listengruppen in iOS gibt es nur für iCloud. C fällt heraus, weil sie #119 D4 verletzt.
- **Neu nicht getestet:** RELATED-TO unter iOS-Bearbeitung; ob die intelligenten Listen von iOS CalDAV-Listen einschließen.
- **Präzisiert:** Die Abbildungstabelle gilt für Variante A; welche Zeilen an D6 hängen, ist markiert. Das Akzeptanzkriterium zum Protokoll unterscheidet A und B.
- Abschnitt „Wie viele Listen entstehen“ ist in D6 aufgegangen.
Changelog: D6 entschieden, Variante A (eine Liste je Projekt plus Inbox und Someday); B und C sind mit Begründung als verworfen festgehalten. Die Abbildungstabelle ist nicht mehr bedingt, das Protokoll bleibt unverändert. INSTALL.md nennt zusätzlich das Löschen der Listen abgeschlossener Projekte von Hand.
Labels:kind/decision → kind/build, weil keine Betreiberentscheidung mehr offen ist; size/L → size/M, weil keine Designfrage mehr vor dem ersten Commit steht und die Arbeit einem Adapter plus einer review.py-Änderung entspricht.
**Changelog:** D6 entschieden, Variante A (eine Liste je Projekt plus Inbox und Someday); B und C sind mit Begründung als verworfen festgehalten. Die Abbildungstabelle ist nicht mehr bedingt, das Protokoll bleibt unverändert. `INSTALL.md` nennt zusätzlich das Löschen der Listen abgeschlossener Projekte von Hand.
**Labels:** `kind/decision` → `kind/build`, weil keine Betreiberentscheidung mehr offen ist; `size/L` → `size/M`, weil keine Designfrage mehr vor dem ersten Commit steht und die Arbeit einem Adapter plus einer `review.py`-Änderung entspricht.
Changelog: Der Body steht jetzt auf dem Endstand. Umgesetzt und veröffentlicht in 6d53c55 als Kandidat 7.1.0-beta.2, ohne Release.
Alle Akzeptanzkriterien sind abgehakt. Das Kriterium zu geteilten Listen hat einen Vorbehalt: Eine von anderen geteilte, reine VTODO-Liste wird nicht selbst erkannt und muss in exclude_lists eingetragen werden.
D2 wird ausdrücklich als Betreiberarbeit in torben/nathan geführt, außerhalb dieses Issues. D4 (minor) ist begründet.
Neu im Body ist der Abschnitt „Nebenbefund“: version release wurde eigenmächtig ausgeführt und zurückgenommen. Der Hinweis in der Ausgabe von version bump ist entfernt, und version-parts.md Schritt 7 ist verschärft.
Verifiziert mit pytest (1487 Tests, lokal und gegen eine leere Maschine), docs verify und instructions verify. CI-Läufe 360 und 361 auf 6d53c55: beide success.
**Changelog:** Der Body steht jetzt auf dem Endstand. Umgesetzt und veröffentlicht in `6d53c55` als Kandidat `7.1.0-beta.2`, ohne Release.
- Alle Akzeptanzkriterien sind abgehakt. Das Kriterium zu geteilten Listen hat einen Vorbehalt: Eine von anderen geteilte, reine VTODO-Liste wird nicht selbst erkannt und muss in `exclude_lists` eingetragen werden.
- D2 wird ausdrücklich als Betreiberarbeit in `torben/nathan` geführt, außerhalb dieses Issues. D4 (minor) ist begründet.
- Neu im Body ist der Abschnitt „Nebenbefund“: `version release` wurde eigenmächtig ausgeführt und zurückgenommen. Der Hinweis in der Ausgabe von `version bump` ist entfernt, und `version-parts.md` Schritt 7 ist verschärft.
- Verifiziert mit `pytest` (1487 Tests, lokal und gegen eine leere Maschine), `docs verify` und `instructions verify`. CI-Läufe [360](https://gitea.nehmer.net/torben/chemenu/actions/runs/360) und [361](https://gitea.nehmer.net/torben/chemenu/actions/runs/361) auf `6d53c55`: beide `success`.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Ein zweiter Provider für die Aufgaben-Schicht, damit die private Instanz nicht an Super Productivity (SP) gebunden ist: CalDAV-Aufgaben (VTODO), Zielserver Nextcloud, mit der iOS-App Erinnerungen als mobilem Client.
Stand (2026-09-25): umgesetzt und veröffentlicht in Commit
6d53c55als Kandidat7.1.0-beta.2. Ein Release gibt es noch nicht; wann der Kandidat ausgeliefert wird, entscheidet der Betreiber. Das Protokoll (tasks/protocol.py) ist unverändert geblieben. Außerhalb des Adapters hat sich nur D3 inreview.pygeändert.Die Begründung der Zwei-Schichten-Konstruktion steht in
docs/knowledge-and-commitment.md, die verbindlichen Zeilen zureview,new project,task new,task list/task closeunddoctorstehen intools/CONTRACT.md. Die sechs Regeln für einen zweiten Adapter stehen in #128.Zuschnitt: was iOS tun soll und was nicht
Betreiber, 2026-09-23: Auf dem iPhone wird abgehakt, nicht gearbeitet. Gepflegt wird am Schreibtisch, in der Nextcloud-Tasks-Web-App oder mit
wikitool task new. Die iOS-Schwächen bei CalDAV-Listen betreffen nur das Pflegen, nicht das Abhaken: keine Tags oder Kategorien, keine Unteraufgaben, keine Markierungen, nur ein Datum. Eine eigene Nextcloud-App wird nicht gebraucht, denn Nextcloud (Sabre/DAV) und iOS erhalten fremde Eigenschaften.Warum CalDAV und nicht Deck
Recherchiert am 2026-09-22.
done-Flag.PUTauf eine Karte ersetzt die Karte vollständig.startdateist unsicher.CalDAV ist ein Standard (RFC 4791/5545). Der Provider heißt deshalb
caldavund nichtnextcloud.Testlauf 2026-09-25 (Nextcloud und iOS Erinnerungen, echtes Konto)
create_projectperMKCALENDARkommt bis aufs iPhoneSTATUS:COMPLETED,COMPLETED,PERCENT-COMPLETE:100;DTSTARTentfernt;CATEGORIESundX--Eigenschaften bleiben erhaltenclose_itemsetzt dieselben Felder, lässtDTSTARTaber stehenSUMMARYDTSTARTundDUEauf das neue Datumfollow_up_at=DTSTART). Eine in Nextcloud gesetzte Fälligkeit geht dabei verlorenCREATED,STATUS:NEEDS-ACTION, UID in GroßbuchstabenCREATED“ funktioniertWeitere Befunde:
DAV:creationdate. Das begründet D3.Umgesetzte Abbildung
supported-calendar-component-setgenau VTODO ist;displayname= Projektname. Inbox, Someday undexclude_listssind ausgenommenSTATUSist wederCOMPLETEDnochCANCELLEDWAITINGCATEGORIESenthältwaiting(ohne Rücksicht auf Groß-/Kleinschreibung)follow_up_atDTSTART, nieDUEProjectSummary.createdCREATEDder Posten;Nonebei einer leeren Listecreate_projectMKCALENDARunter einem UUID-Pfad, automatisch, kein Exit 42. Vorher wird der Name gegen alle Listen des Kontos geprüftcreate_itemPUTeiner neuen.icsmitIf-None-Match: *;noteswird zuDESCRIPTIONclose_itemGET, dann nur die fünf Felder ändern, dannPUTmitIf-Match. Bei 412 bricht es mit Exit 1 ab, ohne Retrysource()kind: "api", immer livehrefs, die der Server liefert, aufgelöst gegen die Anfrage-URLKonfiguration:
url,username(Login-Name),app_password,inbox_list,someday_list, optionalexclude_lists. Die Form steht inINSTALL.md§ Konfiguration.Entschieden (Betreiber, 2026-09-25)
torben/nathanwechselt von SP aufcaldav, denn es gilt ein Tracker je Instanz (#119 D15). Offene SP-Posten zieht der Betreiber von Hand um; es gibt keine Migration zwischen Providern. Die Umstellung selbst ist Betreiberarbeit in der privaten Instanz und nicht Teil dieses Issues.waiting_no_follow_up(unter Prüfung 2) undproject_age_unknown(unter Prüfung 3), für jeden Provider. Es sind keine zusätzlichen Einträge inALL_CHECKS; die Zählung „5 Prüfungen liefen“ bleibt. Der Skillgtd-weekly-reviewhat für beide eine Tabellenzeile bekommen.icalendarsteht intools/requirements.txt, als>=6.0. Versionsteil: minor, nachinstructions/dev/version-parts.md. Das Modul wird nur geladen, wenncaldavkonfiguriert ist. Eine bestehende Instanz ohne CalDAV läuft deshalb ohne erneutespip installweiter, der Wechsel ist in beide Richtungen drop-in.create_projectund nennt die Liste. Umbenennen bleibt Handarbeit in Nextcloud.RELATED-TO-Hierarchie) und C (Titelpräfix, verletzt #119 D4) sind verworfen. Der Adapter löscht nie; Listen abgeschlossener Projekte löscht der Betreiber von Hand.Akzeptanzkriterien
caldaverfülltTaskReader/TaskWritervollständig, ohne dasstasks/protocol.pysich ändert.review,new project,task new,task listundtask closelaufen über das generische Dispatch gegencaldav, ohne Wortänderung in einem Skill;test_task_tracker_skills_name_no_providerist grün. Die neue Zeile im Skillgtd-weekly-reviewbetrifft D3 und nennt keinen Provider.--json-Ausgabe stimmen überein. Getestet für SP undcaldav.close_itemändert nur die fünf Felder.X-APPLE-SORT-ORDER,VALARMundDTSTARTbleiben unverändert erhalten, getestet gegen eine Fixture in iOS-Form.DELETE.hrefdes Servers. Getestet mit einer Fixture, derenhrefs eine andere Benutzer-ID tragen als die konfigurierte URL.exclude_lists, Inbox, Someday und Listen mit VEVENT-Anteil sind keine Projekte. Von anderen geteilte Listen werden nicht eigens erkannt. Sie zählen nur dann nicht als Projekt, wenn sie gemischt sind oder inexclude_listsstehen. Eine geteilte reine VTODO-Liste gehört inexclude_lists.KNOWN_PROVIDERS,build_readerundbuild_writerkennencaldav. Ein unvollständiger oder überzähliger Konfigurationsblock scheitert beim Lesen.icalendarsteht inrequirements.txt; der Versionsteil ist begründet (D4).http.server-Stubs; es wird kein erreichbarer CalDAV-Server gebraucht.doctormeldet Provider, Erreichbarkeit und Authentifizierung. EinFAILgibt es nur bei kaputter Konfiguration.INSTALL.mdnennt die Form des Konfigurationsblocks, das App-Passwort, den Unterschied zwischen Login-Name und Benutzer-ID und das Löschen alter Listen von Hand.docs verify,instructions verifyundpytestsind grün: 1487 Tests, zusätzlich gegen eine leere Maschine (env -i). Die CI-Läufe 360/361 zu6d53c55sind im Schlusskommentar genannt.Nebenbefund in derselben Session
Die Session hat zwischenzeitlich eigenmächtig
version releaseausgeführt. Der Grund war der Hinweis in der Ausgabe vonversion bump. Das wurde vor dem Publish zurückgenommen. Mit demselben Commit ist der Hinweis aus der Ausgabe vonversion bumpentfernt, undinstructions/dev/version-parts.mdSchritt 7 sagt jetzt ausdrücklich: Ein Kandidat wird nur fixiert, wenn der Betreiber das verlangt.Abhängigkeiten
Changelog: Testlauf gegen echtes Nextcloud und iOS Erinnerungen (2026-09-25) eingearbeitet; vier von fünf „Vorher zu klären“-Punkten abgehakt, Siri bleibt offen und nicht blockierend.
CATEGORIES/X-/DESCRIPTIONbei allen Aktionen. Abhaken schreibt dieselben drei Felder wie der geplanteclose_item, entfernt aberDTSTART. Ein auf iOS gesetztes Datum überschreibtDTSTARTundDUE.follow_up_at=DTSTARTist jetzt verifiziert statt vermutet; das iOS-Datum wird damit zur Wiedervorlage. Die Abbildungstabelle trägt eine iOS-Spalte mit den Befunden.hrefs, weil die konfigurierte URL ein Alias sein darf.close_itemerhältDTSTARTundX-APPLE-SORT-ORDER.INSTALL.mdnennt Login-Name gegenüber Benutzer-ID.kein creationdatean Kalendern bestätigt D3.Changelog: Betreiberentscheidungen vom 2026-09-25 eingearbeitet.
torben/nathanstellt vollständig aufcaldavum;kb/gtd/dort noch leer, also nichts umzuziehen), D3 (fehlende Daten melden statt überspringen, jetzt mit eigenem Kriterium), D4 (icalendar), D5 (vorhandene Listen ignorieren, bei Konflikt in Nextcloud umbenennen). Siri gilt als funktionierend.kb/gtd/-Projekt plus Inbox und Someday. Die Alternative „eine Liste, Projekt als Kategorie“ ist verworfen, weil iOS keine Kategorien kann.create_projectprüft die Eindeutigkeit gegen alle Listen des Kontos, auch ausgeschlossene.Changelog: D1 entschieden und nach #141 ausgegliedert. Das alte D6 (Listen abgeschlossener Projekte) geht im neuen D6 auf, der Listenstruktur, nach dem Einwand des Betreibers gegen viele Einzellisten.
RELATED-TO) und C (Bereichslisten, Projekt als Titelpräfix). Echte Listenhierarchie gibt es nicht: RFC 4791 verbietet verschachtelte Kalender-Collections, Listengruppen in iOS gibt es nur für iCloud. C fällt heraus, weil sie #119 D4 verletzt.Changelog: D6 entschieden, Variante A (eine Liste je Projekt plus Inbox und Someday); B und C sind mit Begründung als verworfen festgehalten. Die Abbildungstabelle ist nicht mehr bedingt, das Protokoll bleibt unverändert.
INSTALL.mdnennt zusätzlich das Löschen der Listen abgeschlossener Projekte von Hand.Labels:
kind/decision→kind/build, weil keine Betreiberentscheidung mehr offen ist;size/L→size/M, weil keine Designfrage mehr vor dem ersten Commit steht und die Arbeit einem Adapter plus einerreview.py-Änderung entspricht.Changelog: Der Body steht jetzt auf dem Endstand. Umgesetzt und veröffentlicht in
6d53c55als Kandidat7.1.0-beta.2, ohne Release.exclude_listseingetragen werden.torben/nathangeführt, außerhalb dieses Issues. D4 (minor) ist begründet.version releasewurde eigenmächtig ausgeführt und zurückgenommen. Der Hinweis in der Ausgabe vonversion bumpist entfernt, undversion-parts.mdSchritt 7 ist verschärft.pytest(1487 Tests, lokal und gegen eine leere Maschine),docs verifyundinstructions verify. CI-Läufe 360 und 361 auf6d53c55: beidesuccess.