490 lines
30 KiB
Markdown
490 lines
30 KiB
Markdown
# 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](tools/CONTRACT.md).
|
|
|
|
Den optionalen **MCP-Leseserver** installiert und betreibt
|
|
[INSTALL-MCP.md](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](https://github.com/BurntSushi/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:
|
|
|
|
```bash
|
|
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](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:
|
|
|
|
```bash
|
|
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.
|
|
|
|
```bash
|
|
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](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.
|
|
|
|
```bash
|
|
tools/wikitool version # was läuft hier, und woher kommt es
|
|
tools/wikitool version check # gibt es ein neueres Release?
|
|
```
|
|
|
|
`version check`, `version notes` und `dist upgrade --latest` sind die einzigen Befehle, die
|
|
ins Netz gehen, und alle drei 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; `dist upgrade` fragt den Feed nur, wenn `--latest` dasteht, und lädt dann auch das Release
|
|
herunter (siehe „Eine Instanz aktualisieren"). 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](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, und
|
|
wem die Instanz als Quelle vertraut - und zwei Sonderfälle, die die Instruktion nicht abdecken
|
|
kann, weil es sie dort noch nicht gibt.
|
|
|
|
**Das Release kommt mit einem Befehl.** `tools/wikitool dist upgrade --latest --expect <version>`
|
|
fragt den Release-Feed, lädt Tarball und `.sha256` in ein Arbeitsverzeichnis, prüft den Tarball
|
|
gegen die Summe und wendet ihn an; das Arbeitsverzeichnis verschwindet bei jedem Ausgang wieder,
|
|
auch bei `--dry-run`. `<version>` ist die, die `version notes` gedruckt hat: der Feed kennt nur
|
|
sein *neuestes* Release, und `--expect` verweigert den Lauf **vor** dem Download, wenn inzwischen
|
|
ein neueres erschienen ist, statt es ungelesen einzuspielen. Beides zusammen entscheidet vor dem
|
|
Download über „schon aktuell", Downgrade und Vor-Release (`-beta.N` braucht `--pre`); fehlt dem
|
|
Release der Tarball oder die Summe, bricht der Befehl vor dem ersten Download ab und nennt die
|
|
Release-Seite. Wer offline arbeitet oder einen Tarball vom Betreiber bekommen hat, gibt statt
|
|
`--latest` weiter die Datei an (`dist upgrade <tarball>`).
|
|
|
|
**Was die Prüfsumme leistet - und was nicht.** Die `.sha256` liegt beim selben Feed wie der
|
|
Tarball. Sie schützt vor einer beschädigten Übertragung, nicht vor einem Feed, der selbst
|
|
kompromittiert ist: die Echtheit eines Releases beruht auf dem Vertrauen in den Host, dessen
|
|
Feed die Instanz fragt (`update_url` im Stamp). Es gibt keinen https-Zwang; wer einen
|
|
`http://`-Feed konfiguriert, tut das bewusst. `$WIKITOOL_UPDATE_TOKEN` geht nur an Downloads
|
|
auf demselben Host wie der Feed.
|
|
|
|
**Beim ersten Sprung auf ein Release, das `--latest` kennt, gibt es die Option in der Instanz
|
|
noch nicht** - die Instruktion, die dort steht, gehört zum Release, das die Instanz verlässt.
|
|
Dann den Tarball einmal von Hand holen (Weg A oben), prüfen und `dist upgrade <tarball>` geben;
|
|
ab dem Release danach trägt die Instanz `--latest` selbst.
|
|
|
|
**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:
|
|
|
|
```bash
|
|
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](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.
|
|
Mit `<tarball-oder-verzeichnis>` lädt der Befehl selbst nichts herunter; die Datei muss vorher
|
|
aus Weg A geholt werden. Nur `--latest` lädt, und ein Tarball muss in beiden Fällen 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.md](tools/CONTRACT.md)s `dist upgrade`-Datensatz (oder direkt:
|
|
`tools/wikitool dist upgrade -h`).
|
|
|
|
## 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](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) |
|
|
| `WIKITOOL_TASKS_CONFIG` | Pfad zu einer Tracker-Konfiguration, die `task`, `review` und `doctor` statt `.wikitool-tasks.json` lesen - um einen Checkout der Reihe nach gegen mehrere Tracker laufen zu lassen | die `.wikitool-tasks.json` im Repo-Root. Nennt die Variable eine Datei, die es nicht gibt, ist das ein Fehler und nie „kein Tracker konfiguriert" |
|
|
| `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`):
|
|
|
|
```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](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:
|
|
|
|
```bash
|
|
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.
|
|
|
|
```json
|
|
{
|
|
"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>"
|
|
}
|
|
}
|
|
```
|
|
|
|
```json
|
|
"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:
|
|
|
|
```json
|
|
"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 `href`s 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
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
tools/wikitool docs verify
|
|
tools/wikitool instructions verify
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
- **`wikitool: venv not found`** - Schritt "Werkzeugumgebung anlegen" aus
|
|
[instructions/bootstrap.md](instructions/bootstrap.md) bzw.
|
|
[instructions/setup-instance.md](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](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.
|
|
- **Setup oder Update schlägt fehl und ich will es melden** - den Agenten
|
|
[instructions/bug-report.md](instructions/bug-report.md) ausführen lassen, oder direkt
|
|
`python3 tools/bugreport.py`. Das Skript braucht nur Python 3.8 oder neuer, läuft auch ohne
|
|
funktionierendes `wikitool` und schreibt ein Bündel nach `reports/bugreport-<Zeitstempel>/`
|
|
samt Zip. Geheimnisse werden entfernt, und aus allem, was das Skript selbst erzeugt, bleiben
|
|
Seitentitel draußen (`--titles` nimmt sie mit). Der Sitzungs-Trace ist standardmäßig dabei
|
|
(`--no-trace` lässt ihn weg) und kann wie Chronologie und Transkripte Seiteninhalt und Titel
|
|
enthalten; das Bündel enthält außerdem Maschinen-, Benutzer- und Pfadnamen. Es wird nirgends hochgeladen -
|
|
den Kanal wählst du selbst.
|
|
- **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.
|