Files
chemenu/INSTALL.md
T
torben 6d53c55d0d
CI / verify (push) Successful in 1m12s
Release / release (push) Successful in 39s
tasks: CalDAV provider (Nextcloud Tasks/iOS), review reports unknown values; bump stops pointing at release (#139)
Files changed:
- CHANGES.md
- INSTALL.md
- VERSION
- instructions/dev/version-parts.md
- instructions/gtd-weekly-review/SKILL.md
- tools/CONTRACT.md
- tools/chemenu/commands/doctor.py
- tools/chemenu/commands/version_cmd.py
- tools/chemenu/review.py
- tools/chemenu/tasks/__init__.py
- tools/chemenu/tasks/caldav.py
- tools/chemenu/tasks/config.py
- tools/chemenu/tests/test_caldav.py
- tools/chemenu/tests/test_doctor.py
- tools/chemenu/tests/test_review.py
- tools/requirements.txt
2026-09-25 20:43:53 +02:00

27 KiB

Installation

Dieses Dokument richtet sich an Menschen. Es gibt vier Wege: ein Release herunterladen (der normale Weg zu einer neuen Instanz), eine Distribution selbst exportieren, dieses Repo klonen (Testbett und Demo, samt Beispielkorpus), oder eine private Instanz mit diesem Repo als Upstream aufsetzen. Der agent-seitige Ablauf steckt in instructions/; hier stehen nur die menschlichen Teile - für die vollständige Kommandoreferenz siehe tools/CONTRACT.md.

Den optionalen MCP-Leseserver installiert und betreibt INSTALL-MCP.md: derselbe Korpus, lesend, für einen Konsumenten, der kein Terminal auf dieser Maschine ist.

Voraussetzungen

  • Python 3.11 oder neuer
  • git
  • ripgrep (rg) - wird von search und sources coverage gebraucht

Weg A: Release herunterladen

Der kürzeste Weg zu einer eigenen Instanz - kein Checkout dieses Repos nötig. Jedes Release trägt genau einen dist export-Baum plus eine Prüfsumme. Das Repo ist öffentlich, der Download braucht also weder Konto noch Token:

BASE=https://gitea.nehmer.net/torben/chemenu/releases/download/v<version>
curl -LO $BASE/chemenu-stack-<version>.tar.gz
curl -LO $BASE/chemenu-stack-<version>.tar.gz.sha256
sha256sum -c chemenu-stack-<version>.tar.gz.sha256
tar xzf chemenu-stack-<version>.tar.gz
cd chemenu-stack-<version>

Die Prüfsumme ist nicht Zierde: Sie ist das Einzige, was einen unterbrochenen Download von einem vollständigen unterscheidet, und sha256sum -c muss OK sagen, bevor irgendetwas entpackt wird.

Danach weiter mit Schritt 2 aus Weg B: den Agenten instructions/setup-instance.md ausführen lassen. Der entpackte Baum ist bereits eine Distribution - Schritt 1 (dist export) entfällt.

Die Liste der Releases: https://gitea.nehmer.net/torben/chemenu/releases.

Weg B: Neue, leere Instanz selbst exportieren

Dasselbe Ergebnis aus einem Checkout dieses Repos - für einen Stand, der noch kein Release hat. Zwei Schritte, von denen nur der erste rein menschlich ist:

  1. Zielverzeichnis wählen und die Distribution dorthin exportieren, aus einem Checkout dieses Repos:

    tools/wikitool dist export /pfad/zur/neuen/instanz
    

    Das Ziel muss leer sein oder noch nicht existieren. dist export kopiert die Maschinerie (Werkzeuge, Typen, Instruktionen, die Collection-Contracts) ohne Wiki-Inhalt, ohne Git-Historie und ohne instructions/dev/ (Stack-Entwicklung selbst, inkl. der vendorten commonplace/-Wissensbasis) - dauerhaft, ohne Restore-Weg.

  2. Den Agenten dort arbeiten lassen. Öffne das Zielverzeichnis in deinem Agent-Harness (Claude Code, GitHub Copilot, Codex CLI, Mistral Vibe) und lass es instructions/setup-instance.md ausführen. Diese Anweisung fragt dich dabei explizit nach:

    • Autor-Identität (Name + E-Mail für git config) - wird nie geraten oder aus einem anderen Repo übernommen, und ist zugleich der Autorname jeder künftig angelegten Wiki-Seite ($WIKI_AUTHOR überschreibt dies bei Bedarf).
    • Remote (optional) - eine URL, wenn du das Repo auf einen Server pushen willst; sonst bleibt die Instanz lokal, und jedes publish läuft mit --no-push.
    • Autorenkonventionen - Sprache, Abschnittsnamen, Namensformen, Ton, Beziehungslabels und Hedging-Regel stehen in kb/CONVENTIONS.md, dazu je Collection die Regeln in kb/<name>/COLLECTION.md. Die Distribution bringt davon nur die .template-Dateien mit: das sind Entscheidungen dieser Instanz, keine Eigenschaft des Musters, und nichts davon liegt unter tools/ oder types/. Fertige Profile - darunter ein vollständiges deutsches - hält instructions/kb-profiles.md bereit; es ist eine Palette, kein Enum. Sag die Sprache vor dem ersten Ingest - danach ist ein Wechsel der Abschnittsnamen eine Migration jeder bereits angelegten Seite.
    • Anwendungsgebiet - woraus dieses Wiki seine Quellen zieht. Daraus schlägt der Agent eine source_type-Liste vor (bei einem Verein etwa Satzung, Protokoll, Spielbericht statt Transkript, Analyse, Artikel) und setzt sie in types/source.schema.yaml und types/source.md ein. Das ist ein Startpunkt, keine Festlegung: zu diesem Zeitpunkt hat die Instanz null Quellen, die Taxonomie ist also geraten, bevor jemand Material gesehen hat. Sie wird später an echtem Bestand korrigiert - instructions/evolve-subtypes.md beschreibt, wie ein Wert dazukommt und wie das Auffangfach unclassified wieder leer wird. Nicht zur Wahl stehen fidelity und authority: die beiden sind Stack-Vokabular und in jeder Domäne dieselben.
    • Personalization - wer diese Instanz bedient (USER.md) und wie sie klingt (SOUL.md). Die Distribution bringt nur USER.md.template und SOUL.md.template mit: persönlicher Inhalt gehört nicht in jede exportierte Kopie, aber beide Dateien werden in jeder Session gelesen, sind also Betriebsvoraussetzung. Der Agent interviewt dich entlang der Template-Abschnitte und schreibt deine Antworten wörtlich mit - inklusive der beiden Fragen, die er nicht raten darf: der Persona-Name und die Themen, die bewusst draußen bleiben.

    Danach ist die Instanz initialisiert, verifiziert und committet.

    Was von der Sprachwahl unberührt bleibt: die Trennung zwischen Prosa und Identifiern. Seitentitel, Wikilink-Ziele, Zitat-IDs, Schema-Werte, Tags, Befehle und Pfade folgen keiner KB-Sprache, sondern dem etablierten Namen der Sache - Act Runner heißt in jeder Instanz Act Runner.

Weg C: Dieses Repo klonen

Für die Arbeit am Stack selbst, oder um sich den mitgelieferten Korpus als begehbares Beispiel anzusehen. Was hier liegt, ist ein Testbett und eine Demo, keine produktive Wissensbasis: rund 170 Seiten, die den Stack selbst dokumentieren - Gates, Lint, Versionierung, Suche, das Wiki-Muster. Wer eigenes Wissen sammeln will, nimmt Weg A oder B und fängt mit einem leeren kb/ an.

git clone https://gitea.nehmer.net/torben/chemenu.git
cd chemenu

Danach den Agenten instructions/bootstrap.md ausführen lassen (Werkzeugumgebung + Skills publizieren). Git-Repo, Autor-Identität und Inhalt existieren hier bereits.

Ein Clone, der älter ist als die Personalization-Dateien, hat kein USER.md/SOUL.md - doctor meldet dafür personalization: FAIL. Das ist einmalig nachzuholen: nur Schritt 6 (Personalization) aus instructions/setup-instance.md, nicht der ganze Ablauf. bootstrap.md verweist an derselben Stelle darauf.

ENVIRONMENT.md fehlt nach einem Clone immer - die Datei ist gitignored, weil sie einen Checkout beschreibt und nicht das Repo. Sie ist optional; wer sie anlegt, spart jeder folgenden Session die Fragen nach Harness, MCP-Servern und Remote. Vorlage: ENVIRONMENT.md.template, Ablauf: Schritt 5 in instructions/bootstrap.md.

Weg D: Private Instanz mit diesem Repo als Upstream

Die Kombination aus A und C: eine eigene, nicht öffentliche Instanz, die weiterhin Stack-Updates von hier zieht - per git merge statt per Tarball, also mit echtem Drei-Wege-Merge statt cp -r.

Das ist der Weg mit dem höchsten Einsatz, weil ein Checkout dann zwei Remotes hat und git beim Push nicht unterscheidet, welcher welcher ist. Ein falsches --remote legt privaten Inhalt auf ein öffentliches Repo, und ein Force-Push holt das nicht zurück - die Objekte bleiben per SHA abrufbar, bis auf dem Server die Reflogs verfallen.

Dagegen gibt es das Publish-Remote-Gate, und die Anleitung setzt es an die Stelle, an der es wirkt: vor dem ersten publish. Vollständiges Vorgehen: instructions/private-instance.md.

Version und Updates

Jede Instanz trägt die Version des Stacks (Werkzeuge, Typen, Instruktionen, Contracts) - nicht die ihres Inhalts. Sie steht in VERSION, und eine per Release oder dist export erzeugte Instanz trägt zusätzlich .wikitool-release.json mit Herkunft und Exportdatum.

tools/wikitool version         # was läuft hier, und woher kommt es
tools/wikitool version check   # gibt es ein neueres Release?

version check und version notes sind die einzigen Befehle, die ins Netz gehen, und beide fragen denselben Release-Feed der Ursprungs-Instanz ($WIKITOOL_UPDATE_URL überschreibt; sonst der Wert aus dem Stamp). version check ist dafür da; version notes greift nur dann darauf zurück, wenn die lokale CHANGES.md den Eintrag nicht hat - auf einer Instanz also immer, siehe unten - und sagt vorher auf stderr, welche URL es fragt. Ein nicht erreichbarer Feed wird als Fehler gemeldet - nie als „aktuell" und nie als „keine Notes".

Was die Versionsnummer aussagt: kompatibel ist, was in der linkesten von Null verschiedenen Stelle übereinstimmt. 0.1.3 → 0.1.4 ist ein sicheres Update, 0.1.3 → 0.2.0 nicht, und ab 1.0.0 liest sich dieselbe Regel als das gewohnte „MAJOR bricht". version check sagt das direkt (state: update vs. state: migration).

Was diese Stelle beantwortet, ist ob die neue Version ein Drop-in-Ersatz ist - ob sich die Maschinerie einfach darüberkopieren lässt und ob die alte danach noch zurückkann. Ob Inhalt migriert werden muss, ist eine zweite, unabhängige Frage. Ein MAJOR-Sprung kann eine leere Migrationskette haben und trotzdem Handarbeit verlangen: umbenannter Release-Feed, umbenanntes Artefakt, umbenannter Import- oder Kommandoname, geänderte Envvar - kb/ bleibt dabei unangetastet, das Update ist trotzdem keins zum Drüberkopieren. Der Abschnitt „Sonderfall: Update von 1.x auf 2.0.0" unten ist genau dieser Fall.

Deshalb stehen in den Release-Notes eines MAJOR zwei getrennte Zeilen, und beide sind vor dem Update zu lesen: Breaking Change: sagt, was aufhört zu funktionieren und was diese Instanz dagegen tun muss; Migration: sagt, ob und wie der Korpus umgeschrieben wird (none required, wenn nicht). tools/wikitool version notes druckt beide Zeilen - im Ursprungs-Repo aus der dort gefüllten CHANGES.md, auf einer ausgelieferten Instanz aus dem Release-Feed, weil die Instanz die Datei nur als Stub bekommt und ein Update sie nie überschreibt. Der Befehl fragt dabei immer das neueste Release: solange VERSION noch die alte Fassung nennt, antwortet er also mit einer anderen Version als der eigenen und sagt das auf stderr dazu. Ist der Feed nicht erreichbar, nennt die Fehlermeldung die Release-Seite, die .wikitool-release.json als release_url führt; --offline verlangt diesen Weg von vornherein.

Eine Instanz aktualisieren

Zwei Wege, je nachdem, wie diese Instanz entstanden ist. Ein Clone mit gemeinsamer Git-History (upstream-Remote auf das Ursprungs-Repo, siehe instructions/private-instance.md) nimmt Stack-Updates per echtem Drei-Wege-Merge: tools/wikitool upstream merge. Alles Folgende gilt für eine Instanz aus einem Tarball, ohne gemeinsame History.

Das Anwenden eines Updates schreibt in eine Instanz, die bereits Inhalt hat. Der Inhalt hat dabei eine eigene Version: .wikitool-kb.json sagt, in welcher Form die Seiten vorliegen, unabhängig davon, welche Maschinerie danebensteht. Genau dieser Unterschied ist der Zustand, in dem sich jede Instanz mitten im Upgrade befindet.

Die Durchführung selbst steht in instructions/upgrade-instance.md - die Reihenfolge, was jeder Schritt entscheidet, wo die Agent-Sitzung neu gestartet werden muss, und die beiden Stellen, an denen heute Handarbeit nötig ist. Sie steht dort und nicht hier, weil sie von einer Agent-Sitzung ausgeführt wird; eine zweite Fassung derselben Schrittfolge an dieser Stelle wäre genau die Kopie, die irgendwann auseinanderläuft. Wer den Lauf selbst fahren will, liest dieselbe Datei.

Was dieses Dokument beiträgt, ist die Entscheidung davor - welches Release, ob überhaupt, woher der Tarball kommt (§ „Version und Updates" und Weg A oben) - und der eine Sonderfall, den die Instruktion nicht abdecken kann, weil es sie dort noch nicht gibt:

Beim ersten Sprung auf 4.5.0 oder höher gibt es dist upgrade in der Instanz noch nicht - es kam erst mit 4.5.0. Dann das Werkzeug aus dem entpackten neuen Tarball verwenden, gegen die alte Instanz gerichtet:

tar -xzf chemenu-stack-<version>.tar.gz
CHEMENU_ROOT="$PWD" chemenu-stack-<version>/tools/wikitool \
  dist upgrade chemenu-stack-<version>.tar.gz --dry-run

CHEMENU_ROOT sagt dem Paket, auf welchen Korpus es zeigen soll (siehe § Konfiguration); ohne die Variable würde es den entpackten Tarball selbst für die Instanz halten. Ab dem zweiten Upgrade trägt die Instanz Kommando und Instruktion selbst, und der normale Weg greift.

Was dist upgrade dabei genau tut, klassifiziert und verweigert, steht in tools/CONTRACT.md - einschließlich des vollständigen Fehlerkontrakts. Eine lokal veränderte Stack-Datei ist damit sichtbar, statt von Hand gegen die sha256-Summen im files-Block geprüft werden zu müssen - genau der Schritt, der vor 4.5.0 hier stand.

doctor warnt, solange kb_version hinter VERSION zurückliegt und noch Migrationen offen sind. Einer Instanz, die älter ist als .wikitool-kb.json, fehlt die Datei ganz - dann einmalig tools/wikitool migrate baseline <version> aufrufen; geraten wird nichts.

Fallstricke. Eine Instanz ohne lokale .wikitool-release.json (oder eine ohne files-Block, aus der Zeit vor 4.5.0) hat für dist upgrade keine Basis, gegen die es eine lokale Änderung erkennen könnte, und verweigert den Tausch - dafür gibt es heute keine Reparatur. Der Befehl lädt selbst nichts herunter: <tarball-oder-verzeichnis> muss vorher aus Weg A geholt werden, und ein Tarball muss genau ein Top-Level-Verzeichnis enthalten - die Form, in der .gitea/workflows/release.yml es baut.

Vor 4.5.0 stand hier ein rein manueller Ablauf (Maschinerie von Hand kopieren, kb/CONTRACT.md eingeschlossen, sha256-Vergleich von Hand). dist upgrade ersetzt genau diesen Teil; wer ihn dennoch von Hand nachvollziehen will oder muss (ein Werkzeug, das wikitool selbst nicht ausführen kann), findet die Dateiliste im files-Block der .wikitool-release.json und die Ausnahmen (kb/CONVENTIONS.md, kb/*/COLLECTION.md, .wikitool-kb.json) in tools/CONTRACT.mds dist upgrade-Zeile.

Konfiguration

Variable Zweck Fallback
WIKI_AUTHOR Override für den Autornamen neuer Source-Seiten git config user.name - fehlt beides, bricht new mit ERROR ab
WIKITOOL_SESSION_ID Scopt das Iteration-Budget-Gate auf eine Aufgabe statt auf ein Terminal Eine vom Harness selbst gesetzte Sitzungs-Variable, wo eine bekannt ist (z. B. CLAUDE_CODE_SESSION_ID), sonst die Parent-Process-ID (siehe instructions/session-setup.md)
WIKITOOL_UPDATE_URL Release-Feed, den version check abfragt Wert aus .wikitool-release.json, sonst der Feed der Ursprungs-Instanz
WIKITOOL_UPDATE_TOKEN Gitea-Token für den Release-Feed keiner - gegen torben/chemenu nicht nötig, nur für einen privaten Fork (siehe unten)
CHEMENU_ROOT Auf welchen Korpus das Paket zeigt - für einen Aufrufer, der nicht im Checkout selbst liegt der Checkout, in dem das Paket liegt (tools/wikitool verhält sich ohne die Variable unverändert)
WIKI_TRACE / WIKI_TRACE_DIR Telemetrie abschalten bzw. aus dem Arbeitsbaum heraus umlenken Hängt vom Installationsweg ab - siehe unten
WIKI_TRACE_MAX_SESSION_BYTES / WIKI_TRACE_KEEP_SESSIONS Byte-Deckel je Session-Trace bzw. wie viele Session-Verzeichnisse die Retention behält 5 MiB je Session, 250 Verzeichnisse

Gegen das Ursprungs-Repo braucht es kein Token. torben/chemenu ist öffentlich lesbar; version check und der Download in Weg A funktionieren ohne Konfiguration.

Telemetrie-Default hängt vom gewählten Weg ab, nicht von einem festen Schalter. Weg A und Weg B erzeugen eine .wikitool-release.json (Weg A trägt sie schon im Release, Weg B schreibt sie beim Export) - daran erkennt chemenu.telemetry.policy, dass niemand Telemetrie bestellt hat, und der Default steht auf aus. Weg C (dieses Repo geklont) trägt keine solche Datei - hier sind die Traces das Messinstrument, mit dem der Stack sich selbst bewertet, und der Default steht auf an. Weg D erbt den Default von der Distribution, aus der die private Instanz entstand, also ebenfalls aus.

Wer den Default umdrehen will, legt .wikitool-telemetry.json im Repo-Root an (pro Checkout, gitignored, kein .template - genau wie .wikitool-remotes.json):

{ "enabled": true, "max_session_bytes": 5242880, "keep_sessions": 250 }

Alle drei Schlüssel sind optional. WIKI_TRACE überschreibt enabled weiterhin in beide Richtungen und schlägt diese Datei. wikitool doctor meldet den aktuellen Zustand (an/aus, warum, und die Menge gegen beide Deckel); mehr dazu in EVALS.md § "Whether it runs at all".

Für einen privaten Fork schon. Wer den Stack in ein eigenes, nicht öffentliches Repo legt und WIKITOOL_UPDATE_URL auf dessen Feed zeigen lässt, stößt auf eine Eigenheit, die man kennen sollte: Gitea antwortet anonymen Aufrufern für ein unsichtbares Repo mit demselben 404 wie für ein gar nicht existierendes. Ein fehlendes Release und ein fehlender Zugriff sehen dann identisch aus - „kein Update gefunden" wäre in dem Fall schlicht gelogen. Dagegen hilft ein Gitea-Token mit Lesezugriff:

export WIKITOOL_UPDATE_TOKEN="<gitea-token>"
tools/wikitool version check

Aufgaben-Tracker anbinden - optional. Der Wochenrückblick (tools/wikitool review, Skill gtd-weekly-review) gleicht die Projektseiten unter kb/gtd/ gegen einen Aufgaben-Tracker ab. Welcher das ist, steht in .wikitool-tasks.json im Repo-Root - der dritten Datei dieser Art neben .wikitool-telemetry.json und .wikitool-remotes.json: pro Checkout, ohne .template, und gitignored, sobald ein Token darin liegt. Fehlt sie, ist schlicht kein Tracker konfiguriert; das ist ein gültiger Endzustand, kein Fehler. Kaputt ist sie dagegen ein FAIL - eine unlesbare Konfiguration darf nicht als „kein Tracker" durchgehen.

{
  "schema": 1,
  "provider": "superproductivity",
  "thresholds": {
    "stalled_waiting_days": 14,
    "unpaged_project_weeks": 3,
    "someday_stale_months": 5
  },
  "superproductivity": {
    "access": "api",
    "api_base_url": "http://127.0.0.1:3876",
    "api_token": "<token aus den SP-Einstellungen>"
  }
}
  "superproductivity": {
    "access": "snapshot",
    "backups_dir": "~/.config/superProductivity/backups"
  }

provider wählt den Adapter - ausgeliefert werden superproductivity und caldav. Der thresholds-Block trägt die drei Schwellwerte des Rückblicks (Konfiguration, nicht Schema): ab wann ein Waiting-For überfällig ist, ab welchem Alter ein Tracker-Projekt ohne kb/-Seite gemeldet wird, und ab wann ein Someday-Eintrag als verstaubt gilt. Ein Wert, den der Provider gar nicht liefern kann - ein Waiting-Posten ohne Wiedervorlagedatum, ein Tracker-Projekt ohne bestimmbares Anlagedatum - wird vom Rückblick nicht still übersprungen, sondern als eigene Fundstelle gemeldet (waiting_no_follow_up/project_age_unknown).

Der gleichnamige Provider-Block trägt dessen Verbindungsangaben, und bei Super Productivity entscheidet access verpflichtend und ohne Rückfall, welcher von zwei sich ausschließenden Wegen das ist: eine headless bediente Instanz setzt access: "snapshot" und liest ausschließlich den jüngsten Backup-Schnappschuss unter backups_dir (läuft auch ohne laufende App, aber rein lesend - der Tracker ist von dort aus nicht schreibbar); eine Desktop-Instanz setzt access: "api" und spricht ausschließlich die lokale REST-API an, die nur antwortet, solange die App läuft, dafür aber auch den aktuellen Zustand liefert und den Schreibpfad trägt. Der Block nennt nur die Felder seines eigenen Wegs - ein backups_dir neben access: "api" oder ein api_token neben access: "snapshot" wird beim Lesen der Konfiguration abgelehnt, nicht ignoriert. api_token ist bei access: "api" Pflicht, da jeder Endpunkt außer GET /health Authorization: Bearer <token> verlangt.

tools/wikitool new project legt einen gleichnamigen Tracker-Eintrag nur auf einer access: "api"-Instanz an (und auch dort nicht automatisch - siehe die Kommandotabelle). Auf einer access: "snapshot"-Instanz verweigert das Kommando vollständig, exit 1: der Tracker ist von dort aus nur lesbar. Dasselbe gilt für tools/wikitool task new, den zweiten Schreibweg: es legt einen einzelnen Posten im Tracker an - ohne kb/-Seite - und existiert ebenfalls nur auf einer access: "api"-Instanz. tools/wikitool task close --id ist der dritte und letzte Schreibweg - er markiert einen Posten erledigt, löscht ihn nie - und verweigert auf access: "snapshot" auf dieselbe Weise. tools/wikitool task list --project ist rein lesend und beantwortet daher auf beiden Zugriffsarten.

caldav ist der standardbasierte zweite Adapter (RFC 4791/5545), gegen Nextcloud Tasks verifiziert, mit iOS Erinnerungen als mobilem Client - gebaut nach dem Zuschnitt: auf dem Telefon wird abgehakt, gepflegt wird am Schreibtisch. Anders als bei Super Productivity gibt es nur einen Zugriffsweg - CalDAV ist immer ein Netzwerkzugriff, kein access-Feld nötig:

  "caldav": {
    "url": "https://<host>/remote.php/dav/calendars/<user>/",
    "username": "<login>",
    "app_password": "<Nextcloud-App-Passwort>",
    "inbox_list": "Inbox",
    "someday_list": "Someday",
    "exclude_lists": ["<vorhandene Liste, die kein Projekt ist>"]
  }

url zeigt auf das CalDAV-Calendar-Home-Set des Kontos; sie darf ein Alias sein (Nextcloud akzeptiert dort einen Kurznamen), da jede spätere Adresse ausschließlich aus den vom Server gelieferten hrefs stammt, nie aus dieser URL und einem Namen zusammengesetzt wird. username ist der Login-Name, der von der Benutzer-ID in der URL abweichen kann - ein Nextcloud-App-Passwort wird empfohlen, nicht das Kontopasswort. inbox_list/someday_list nennen die beiden festen Listen (je genau eine pro Instanz); exclude_lists nimmt vorhandene reine Aufgabenlisten heraus, die keine Projekte sind - eine Liste mit VEVENT-Anteil zählt ohnehin nie als Projekt.

Ein Projekt ist dort eine Liste, deren unterstützte Komponente ausschließlich VTODO ist; tools/wikitool new project legt sie automatisch per MKCALENDAR an - anders als bei Super Productivity ohne Rückfrage, weil CalDAV einen echten Anlage-Befehl für Listen kennt. Die Eindeutigkeitsprüfung läuft gegen jede Liste im Konto, auch gegen ausgeschlossene, Inbox, Someday und gemischte Kalender - kollidiert ein neuer Name mit einer davon, wird nichts angelegt und die Kollision genannt; die vorhandene Liste in Nextcloud umzubenennen bleibt Handarbeit. tools/wikitool task new/task close funktionieren auf einer caldav-Instanz uneingeschränkt - es gibt keinen reinen Lesemodus wie access: "snapshot". Beim Abhaken ändert task close ausschließlich STATUS, COMPLETED, PERCENT-COMPLETE, LAST-MODIFIED und DTSTAMP an der bestehenden .ics-Ressource; jede andere Eigenschaft - auch eine unbekannte X--Eigenschaft oder ein Alarm

  • bleibt unverändert erhalten, und eine seit dem Lesen veränderte Ressource (ETag-Konflikt) schreibt nichts und bricht mit exit 1 ab. Gelöscht wird nie etwas.

Listen abgeschlossener Projekte bleiben nach dem Archivieren bestehen - der Adapter löscht nie eine Liste; das übernimmt der Betreiber von Hand in Nextcloud, sobald gewünscht.

Verifikation

tools/wikitool doctor

Prüft in einem Aufruf: Abhängigkeiten, Autor-Auflösung, Git-Identität/Branch/Remote, publizierte Skills, Struktur (Collection-Contracts, generierte Dateien), Personalization (USER.md/SOUL.md vorhanden und ausgefüllt), die optionale Umgebungsnotiz (ENVIRONMENT.md), den Aufgaben-Tracker (.wikitool-tasks.json - fehlt sie, ist das OK; ist ein Provider konfiguriert, zusätzlich ob sein Lesepfad bereitsteht und seine API gerade antwortet, beides nie ein FAIL) und die Session-ID. OK/WARN sind unbedenklich (ein fehlender Remote z. B. ist ein gültiger Endzustand); nur ein FAIL bricht mit exit 1 ab, und jede Zeile nennt ihr eigenes Fix-Kommando.

Danach zusätzlich:

tools/wikitool docs verify
tools/wikitool instructions verify

Troubleshooting

  • wikitool: venv not found - Schritt "Werkzeugumgebung anlegen" aus instructions/bootstrap.md bzw. instructions/setup-instance.md wurde noch nicht ausgeführt.
  • Der Agent bietet keine Skills an (wiki-ingest, wiki-query, ...) - .agents/skills/ und .claude/skills/ sind generiert und nicht committet. tools/wikitool instructions sync ausführen, dann die Agent-Session neu starten (Harnesses lesen Skills nur beim Start).
  • doctor meldet personalization: FAIL - USER.md/SOUL.md fehlen, oder sie tragen noch die Sentinel-Zeile aus dem Template (ein umbenanntes Template ist kein ausgefülltes). Den Personalization-Schritt (6) aus instructions/setup-instance.md ausführen lassen; bei einer Instanz nach Weg C ist das der einzige nachzuholende Schritt.
  • doctor meldet environment: WARN - ENVIRONMENT.md existiert, trägt aber noch die Sentinel-Zeile aus dem Template. Ausfüllen (Vorlage: ENVIRONMENT.md.template) und die Zeile entfernen, oder die Datei löschen - sie ist optional, und absent ist ein gültiger Endzustand.
  • new bricht mit "No author configured" ab - weder $WIKI_AUTHOR noch git config user.name sind gesetzt. git config user.name "<Name>" ausführen, oder WIKI_AUTHOR exportieren.
  • publish endet mit Exit-Code 42 (Mass-Update-Gate) - erwartetes Verhalten bei ≥10 gezählten Dateien (z. B. beim allerersten Commit einer neuen Instanz). Das ist kein Fehler, sondern die Aufforderung, die Ausgabe einem Menschen zu zeigen: sie enthält die vollständige Dateiliste und die exakte --confirm <token>-Zeile, die nach Freigabe veröffentlicht. Details: instructions/gates.md.
  • publish endet mit Exit-Code 42 (Publish-Remote-Gate) - dieser Checkout hat eine .wikitool-remotes.json, und das angesteuerte Remote steht nicht darin. Ebenfalls kein Fehler: Die Ausgabe nennt die Push-URL, an die geschrieben würde, und die erlaubten. Anders als beim Mass-Update-Gate gibt es hier keinen Token und keine Flagge - stimmt das Ziel wirklich, trägt der Mensch dessen URL selbst in die Datei ein. Ein Agent, der die Datei anfasst, um an der Verweigerung vorbeizukommen, öffnet ein Gate aus eigenem Antrieb.
  • Ich will am Tool-Stack selbst weiterarbeiten (nicht nur Wiki-Inhalt betreiben) - eine neue Instanz hat dafür keinen Weg: dist export lässt instructions/dev/ (Stack-Entwicklung, inkl. der vendorten commonplace/-Wissensbasis) bewusst und dauerhaft weg, ohne Restore-Mechanismus. Für Stack-Entwicklung im Ursprungs-Repo arbeiten (oder eine neue Dev-Instanz daraus exportieren) statt in dieser Instanz nachzurüsten.