Files
chemenu/DEVELOPMENT.md
T
torbenandClaude Opus 5.5 d8224ee2ab
CI / verify (push) Successful in 5m15s
CI / pwsh (push) Successful in 2m2s
Release / release (push) Successful in 34s
feat: stack development in three phases - stack-dev (design), stack-build, stack-close, handed over through tracker states (#168)
stack-build and stack-close carry disable-model-invocation, so each phase change is
the operator's slash command; no skill offers a mid-session /model or /effort switch.
Mode rules and the phase table move to instructions/dev/stack-mode.md, publish and CI
waiting to instructions/dev/publish-and-ci.md, the ready definition to issue-tracking.md.

Files changed:
- AGENTS.md
- CHANGES.md
- DEVELOPMENT.md
- README.md
- VERSION
- docs/model-and-effort-selection.md
- instructions/CONTRACT.md
- instructions/dev/commonplace-kb.md
- instructions/dev/dev-setup.md
- instructions/dev/doc-pull-through.md
- instructions/dev/issue-tracking.md
- instructions/dev/publish-and-ci.md
- instructions/dev/stack-build/SKILL.md
- instructions/dev/stack-close/SKILL.md
- instructions/dev/stack-dev/SKILL.md
- instructions/dev/stack-mode.md
- instructions/dev/testing-conventions.md
- instructions/dev/version-parts.md
- tools/chemenu/commands/git_publish.py
- tools/chemenu/tests/test_git_publish.py
- tools/chemenu/tests/test_instructions_cmd.py

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
2026-10-02 20:33:07 +02:00

10 KiB
Raw Blame History

Entwicklung dieses Stacks

Dieses Dokument richtet sich an Menschen, die an tools/wikitool, dem Type-Schema oder der Instruction-/Skill-Schicht selbst arbeiten - nicht an den Konsumenten einer Instanz. Für die Gegenseite (eine Instanz installieren, aktualisieren, betreiben) siehe INSTALL.md.

Diese Datei wird nicht ausgeliefert. Sie ist das menschliche Gegenstück zu instructions/dev/, das tools/wikitool dist export vollständig ausschließt: eine ausgelieferte Instanz hat keinen Release-Workflow, keine CI und kein Issue-Board, also braucht sie auch keine Anleitung dafür. dist_cmd.ROOT_FILES listet sie deshalb bewusst nicht - der Grund steht dort als Kommentar, damit eine spätere Sitzung die vermeintliche Lücke nicht "repariert". Und weil sie nicht ausgeliefert wird, darf sie - anders als README.md, INSTALL.md oder EVALS.md, die instructions verify auf genau diesen Punkt prüft - nach instructions/dev/ verlinken.

Entwicklungsumgebung

Am Stack wird in einem Klon dieses Repos gearbeitet. Ein solcher Klon ist keine Instanz und wird nie eine. Instanzen entstehen ausschließlich aus Releases, siehe INSTALL.md.

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

Danach den Agenten instructions/bootstrap.md ausführen lassen: Preflight, dann tools/wikitool instructions sync. Die Agenten-Seite dazu - was hier anders ist als in einer Instanz und wie dist export als Testwerkzeug läuft - steht in instructions/dev/dev-setup.md.

Was ein Klon mitbringt und eine Instanz nicht:

  • Den Demo-Korpus. Rund 170 Seiten, die den Stack selbst dokumentieren: Gates, Lint, Versionierung, Suche, das Wiki-Muster. Er ist Testbett und begehbares Beispiel, keine produktive Wissensbasis. Was an ihm geändert werden darf, regelt instructions/dev/corpus-policy.md.
  • Eine Demo-Persona in USER.md/SOUL.md. doctor meldet beide als ausgefüllt. Sie beschreiben den Demo-Betrieb, nicht dich.
  • Telemetrie an. Ohne .wikitool-release.json ist der Klon die Messstation, mit der der Stack sich selbst bewertet (EVALS.md § „Whether it runs at all“).
  • instructions/dev/, commonplace/, .gitea/ und diese Datei. dist export liefert davon nichts aus.

ENVIRONMENT.md fehlt nach jedem Klon, weil die Datei gitignored ist: Sie beschreibt einen Checkout, nicht das Repo. Wer sie anlegt (Vorlage ENVIRONMENT.md.template, Schritt 5 in instructions/bootstrap.md), erspart jeder Stack-Sitzung die Fragen nach Harness, gitea-mcp und Remote.

dist export als Build- und Testwerkzeug

tools/wikitool dist export <leeres Verzeichnis> schreibt genau den Baum, den ein Release ausliefert: Maschinerie ohne Wiki-Inhalt, ohne Git-Historie, ohne instructions/dev/. Damit prüft man vor einem Release, was ausgeliefert würde (--dry-run listet es nur). Und man spielt den Installationsweg nach, ohne auf ein Release zu warten: Tarball daraus bauen wie .gitea/workflows/release.yml, dann das Preflight-Skript in einem leeren Verzeichnis mit --archive <tarball> starten. Der CI-Schritt „The distribution works as a fresh instance“ in .gitea/workflows/ci.yml macht genau das.

Für eine echte Instanz ist ein solcher Export kein Weg. Ihm fehlen die Release-Herkunft im Stamp, und dist upgrade --latest vergleicht später gegen einen Stand, den es nie als Release gab.

Ein Release-Feed in einem nicht öffentlichen Repo

Wer den Stack in einem eigenen, nicht öffentlichen Repo betreibt und Instanzen von dort aktualisiert, lässt WIKITOOL_UPDATE_URL auf dessen Feed zeigen. Dabei gibt es eine Eigenheit: 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 falsch. Dagegen hilft ein Gitea-Token mit Lesezugriff in WIKITOOL_UPDATE_TOKEN. Es geht nur an Downloads auf demselben Host wie der Feed.

Der Release-Ablauf

Zwischen zwei Releases führt der Stack einen laufenden Versionskandidaten statt einer neuen Nummer pro Bump. Das volle Modell - Zustandsort, Eskalationslogik, warum eine Nummer erst durch ein Release verbraucht wird - steht in instructions/dev/version-parts.md und docs/version-model.md. Hier nur der Ablauf, in der Reihenfolge, in der eine Sitzung ihn tatsächlich durchläuft:

  1. Bump eröffnet oder eskaliert den Kandidaten, gewichtet mit --impact.

    tools/wikitool version bump --minor --title "Was sich geändert hat" --impact medium
    

    Schreibt VERSION als X.Y.Z-beta.N und öffnet (oder aktualisiert) den passenden CHANGES.md-Eintrag. Mehrere Bumps für dieselbe Änderung sind normal - jeder aktualisiert denselben Eintrag, statt einen neuen zu eröffnen. --impact high|medium|low (Default medium) gruppiert den Eintrag; tools/wikitool version regrade korrigiert eine Note später, wenn der Gesamteindruck des Kandidaten den Blick auf einen früheren Bump ändert.

  2. Der Eintrag bekommt seine Prosa - zweigeteilt. bump schreibt nur das Skelett (Heading, Datum, Autor, die maschinenverwaltete, gruppierte Bump-Titel-Liste, ggf. Breaking-/Migration-Zeile). Darunter kommen zwei Autorenanteile: eine kurze Zusammenfassung (ein paar Sätze, worum es in diesem Release geht) direkt unter der Liste, und darunter je Bump ein eigener ### <Bump-Titel>-Changeset-Absatz. Details dazu in instructions/dev/version-parts.md § The candidate model.

  3. Verify laufen lassen, bevor irgendetwas gepublished wird:

    cd tools && .venv/bin/python -m pytest -q
    tools/wikitool docs verify
    tools/wikitool instructions verify
    
  4. version release fixiert den Kandidaten, sobald er ausgeliefert werden soll:

    tools/wikitool version release --title "Zusammenfassender Titel"
    

    Streicht den -beta.N-Suffix aus VERSION und schließt den Changelog-Eintrag. --title ist optional - ohne ihn bleibt der Titel des letzten Bumps stehen; mit ihm bekommt ein Kandidat, der mehrere Bump-Titel gesammelt hat, eine zusammenfassende Überschrift. Verweigert, wenn der Kandidat zwei oder mehr Bumps gesammelt hat und die Zusammenfassung aus Schritt 2 noch fehlt - ein Kandidat mit genau einem Bump ist davon ausgenommen. Committet und pusht nichts (Invariante 5 in AGENTS.md).

  5. Publish bewegt VERSION auf main.

    tools/wikitool publish --message "..."
    

    Das Mass-Update-Gate und das Publish-Remote-Gate gelten wie bei jedem anderen Publish - siehe instructions/gates.md.

  6. CI übernimmt den Rest. .gitea/workflows/release.yml reagiert auf jeden Push, der VERSION bewegt: Eine suffixbehaftete VERSION (ein Kandidat) lässt den Job sauber überspringen, bevor er die Releases-API überhaupt anfragt - Betas werden nie veröffentlicht. Eine suffixfreie VERSION baut die Distribution (dist export), erzeugt Tag und Release und lädt Tarball und Prüfsumme hoch, dazu die beiden Preflight-Skripte und die Anleitungen setup-instance.md und preflight.md, auf die der Installationssatz in INSTALL.md zeigt. CI setzt den Tag, nie eine Sitzung - das hält Invariante 5 intakt.

Die drei Verify-Befehle stehen oben in Schritt 3; was jeder von ihnen prüft, steht in tools/CONTRACT.md und wird dort von docs verify gegen die tatsächliche CLI gehalten. Hier steht es bewusst nicht noch einmal: eine zweite Beschreibung derselben Befehle ist genau die Kopie, die driftet (AGENTS.md Invariante 8), und dieses Dokument liegt außerhalb der Dateien, die der Kommando-Datensatz-Check von docs verify abdeckt - hier fällt eine Drift also niemandem auf. Was pytest an dieser Stelle vom Entwickler erwartet, steht in instructions/dev/testing-conventions.md.

Die CI-Hälfte

.gitea/workflows/ci.yml läuft auf jeden Push/PR gegen main (Content-Pfade ausgenommen) und führt Testsuite, docs verify, instructions verify sowie einen vollständigen setup-instance.md-Replay aus: ein lokal gebauter Release-Tarball, das Preflight-Skript mit --archive in einem leeren Verzeichnis, dann die Schritte der Anleitung - derselbe Pfad, den ein neuer Nutzer tatsächlich geht, nur ohne Download. .gitea/workflows/nightly.yml ist der Drift-Check gegen die Zeit statt gegen einen Commit. .gitea/workflows/release.yml ist Schritt 6 oben.

Drei weitere Workflows tragen die Live-Tests der Tracker-Adapter (Super Productivity, CalDAV): ci.yml führt in einem eigenen Schritt die CalDAV-Hälfte gegen ein Radicale als Prozess aus, tracker-live.yml läuft nachts und deckt beide Anbieter ab, und sp-live-image.yml baut täglich (bei neuer Version) und monatlich (immer) das Image chemenu-sp-live mit der jeweils aktuellen Super-Productivity-Version. Das Image folgt dem Update-Kanal der Desktop-Clients, nicht einer festen Version. Einmalig nach dem allerersten Push muss das Paket von Hand dem Repo torben/chemenu zugeordnet werden. Was die Suite schreibt, wie man sie gegen einen eigenen Tracker laufen lässt und was ein roter Lauf bedeutet, steht in instructions/dev/tracker-testing.md.

Stack-Entwicklung als eigener Sitzungstyp

Drei Skills (instructions/dev/, nur in diesem Ursprungs-Repo vorhanden) führen eine Sitzung, die den Stack selbst statt Wiki-Inhalt bearbeitet, durch drei Phasen: stack-dev arbeitet das Issue aus, bis sein Body „ready“ ist, stack-build baut, publiziert und wartet auf einen grünen CI-Lauf, stack-close prüft den Endzustand des Bodys und veraltete docs/- und Contract-Prosa und schließt das Issue. Übergeben wird über den Zustand im Tracker, nicht über den Kontext einer Sitzung: Jeder Phasenwechsel geht in derselben Sitzung oder nach /clear. stack-dev greift automatisch; stack-build und stack-close startet nur der Betreiber per Slash-Kommando (/stack-build #N, /stack-close) - an genau dieser Stelle fällt die Wahl, ob es in derselben Sitzung weitergeht oder in einer neuen, auf welchem Modell. Einen Modellwechsel mitten in der Sitzung bietet keiner der drei an. Regeln und Phasentabelle stehen in instructions/dev/stack-mode.md, der Issue-Tracker selbst in instructions/dev/issue-tracking.md.