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
10 KiB
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.doctormeldet beide als ausgefüllt. Sie beschreiben den Demo-Betrieb, nicht dich. - Telemetrie an. Ohne
.wikitool-release.jsonist 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 exportliefert 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:
-
Bump eröffnet oder eskaliert den Kandidaten, gewichtet mit
--impact.tools/wikitool version bump --minor --title "Was sich geändert hat" --impact mediumSchreibt
VERSIONalsX.Y.Z-beta.Nund öffnet (oder aktualisiert) den passendenCHANGES.md-Eintrag. Mehrere Bumps für dieselbe Änderung sind normal - jeder aktualisiert denselben Eintrag, statt einen neuen zu eröffnen.--impact high|medium|low(Defaultmedium) gruppiert den Eintrag;tools/wikitool version regradekorrigiert eine Note später, wenn der Gesamteindruck des Kandidaten den Blick auf einen früheren Bump ändert. -
Der Eintrag bekommt seine Prosa - zweigeteilt.
bumpschreibt 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. -
Verify laufen lassen, bevor irgendetwas gepublished wird:
cd tools && .venv/bin/python -m pytest -q tools/wikitool docs verify tools/wikitool instructions verify -
version releasefixiert den Kandidaten, sobald er ausgeliefert werden soll:tools/wikitool version release --title "Zusammenfassender Titel"Streicht den
-beta.N-Suffix ausVERSIONund schließt den Changelog-Eintrag.--titleist 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). -
Publish bewegt
VERSIONaufmain.tools/wikitool publish --message "..."Das Mass-Update-Gate und das Publish-Remote-Gate gelten wie bei jedem anderen Publish - siehe instructions/gates.md.
-
CI übernimmt den Rest.
.gitea/workflows/release.ymlreagiert auf jeden Push, derVERSIONbewegt: Eine suffixbehafteteVERSION(ein Kandidat) lässt den Job sauber überspringen, bevor er die Releases-API überhaupt anfragt - Betas werden nie veröffentlicht. Eine suffixfreieVERSIONbaut die Distribution (dist export), erzeugt Tag und Release und lädt Tarball und Prüfsumme hoch, dazu die beiden Preflight-Skripte und die Anleitungensetup-instance.mdundpreflight.md, auf die der Installationssatz inINSTALL.mdzeigt. 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.