Handbooks
Konzepte

Das Arbeitsverzeichnis

Jedes Artefakt, das die Pipeline erzeugt: wo es liegt, was es validiert und was sich gefahrlos löschen lässt.

Das Arbeitsverzeichnis (--work) ist der Ort, an dem alles liegt, was die Pipeline erzeugt. Eines pro dokumentiertem Repository.

<work>/
  phase1/
    graph.json          the call graph — everything downstream reads this
    functions.csv       every function, flat, for grepping or a spreadsheet
    graph.dot           Graphviz:  dot -Tsvg graph.dot -o graph.svg
    dropped-calls.json  calls we could NOT resolve, categorized — not hidden
    scan-coverage.json  files we could NOT read or fully parse — not counted as covered
  phase2/
    cards/<rel>.json    one card per source file, mirroring the source tree
    cards/_coverage.json  how many files got prose, and which did not
    cards/_rejected/    replies that produced no usable card (capped at 20)
    skeleton.yaml       the stage spine
    assignment.json     file → stage
    organization.yaml   intra-stage groups + reading order
    strategy.json       which strategy produced the above
  phase3/
    narration.json      stage and system prose
    registers.json      cross-stage state registers
    cache/              content-hash caches for prose and registers
  handbook/             the rendered output, once you run `render`
  run-manifest.json     model, phases, timings and token usage of the last good run

Drei Eigenschaften, auf die Verlass ist

Alles wird beim Lesen schema-validiert

Jedes Artefakt trägt ein version-Feld und wird beim Laden mit zod validiert. Ein korruptes oder von Hand editiertes Artefakt schlägt laut fehl und nennt sich selbst:

handbook: error: work/myrepo/phase2/skeleton.yaml: stages.3.id: Invalid

Es propagiert nie in eine spätere Phase.

Zwei bewusste Ausnahmen, beide aus Resilienz, nicht aus Nachlässigkeit:

  • Karten — eine einzelne nicht parsebare Kartendatei wird übersprungen, ist aber nicht fatal. Ein einziges fremdes oder halb synchronisiertes JSON im Kartenverzeichnis würde sonst das Fortsetzen, die Phasen 2b/2c/3 und jedes Laden des Modells zum Absturz bringen.
  • languages-Metadaten in graph.json — optional, weil es hier keinen Mechanismus zur Artefakt-Migration gibt und jeder Graph, der vor der Einführung der Treue-Deklarationen geschrieben wurde, weiterhin validieren muss. unparsedFiles ist aus demselben Grund optional: Fehlt es, ist die Analyse älter als dieser Nachweis — es heißt nicht, dass nichts fehlgeschlagen ist.

Jeder Schreibvorgang ist atomar

In eine Temporärdatei schreiben, dann umbenennen. Ein Absturz mitten im Schreiben hinterlässt nie ein halb geschriebenes Artefakt, an dem der nächste Lauf erstickt.

Ein Lauf pro Arbeitsverzeichnis

generate und resync nehmen denselben re-entranten Verzeichnis-Lock. Ein gleichzeitiger CLI-Lauf und ein Studio-Job auf denselben Artefakten würden ihre Schreibvorgänge verschränken; der zweite wird stattdessen mit einer klaren Meldung abgewiesen.

Was gefahrlos möglich ist

AktionSicher?Anmerkung
Das ganze Arbeitsverzeichnis löschenAußerhalb wurde nichts verändert. Von Grund auf neu generieren.
Es in Git committenAlles Text. Praktisch, um nachzuvollziehen, was eine Regenerierung geändert hat.
phase3/cache/ löschenKostet beim nächsten Lauf einen komplett neuen Erzähltext.
phase2/cards/_rejected/ löschenNur Diagnostik. Wird zu Beginn eines neuen Kartendurchlaufs automatisch geleert.
skeleton.yaml von Hand editierenWird beim Lesen validiert, und --skeleton existiert genau dafür.
graph.json von Hand editieren⚠️Es ist generiert. Stattdessen analyze erneut ausführen.
phase2/strategy.json löschen⚠️Der nächste Lauf fällt auf file zurück, was zu den Artefakten passen kann — oder nicht.
Es öffentlich teilen⚠️Karten zitieren und beschreiben Ihre Quellen. Wie Quellcode behandeln.

Von Hand lesen

Der Graph ist der interessante Teil:

# how big is this codebase, really
jq '.metadata | {files: (.scannedFiles|length), nInternalFunctions, nEdges}' phase1/graph.json

# the busiest functions — where a change is most likely to fan out
jq -r '.nodes | to_entries | map(select(.value.kind=="internal"))
       | sort_by(-.value.nCallers) | .[:15]
       | .[] | "\(.value.nCallers)\t\(.value.qualname)\t\(.value.file)"' phase1/graph.json

# what could not be resolved, by category
jq '.metadata.byCategory' phase1/dropped-calls.json

# which files the scan could not turn into facts, and why
jq '.metadata.byReason, .files' phase1/scan-coverage.json

# which files never got prose
jq '.missing' phase2/cards/_coverage.json

functions.csv existiert aus demselben Grund — manchmal ist das schnellste Werkzeug eine Tabellenkalkulation.

Die zwei Abdeckungsdateien beantworten verschiedene Fragen

_coverage.json beantwortet „welche Dateien konnte das Modell nicht beschreiben?“. scan-coverage.json beantwortet die Frage darunter: „welche Dateien hat der Parser überhaupt nie zu lesen geschafft?“ — mit einem reason von unreadable, unparsable oder partial.

Die ersten beiden steuern keine Fakten bei und fallen deshalb auch aus scannedFiles in graph.json heraus: Nichts Nachgelagertes schreibt eine Karte über eine Datei, die niemand geöffnet hat, und zählt sie danach als beschrieben. partial-Dateien bleiben — tree-sitter hat sich vom Syntaxfehler erholt, und die gefundenen Funktionen sind echt, bloß unvollständig.

Ein leeres files-Array heißt: Jede gescannte Datei wurde sauber geparst. Das ist eine Aussage; ein schlicht fehlendes Artefakt ist keine.

Wo sonst noch geschrieben wird

Handbooks schreibt an genau zwei Stellen außerhalb des Arbeitsverzeichnisses, beide opt-in über den ausgeführten Befehl:

  • <source>/.handbook-patches/ — von apply angelegt, enthält Backups und deren Manifeste. Eine .gitignore wird automatisch hineingeschrieben, damit Backups nie in Git landen.
  • $HOME/.handbook-studio/ — Studios Repository-Registry und seine automatisch angelegten Arbeitsverzeichnisse. Mit --state-dir verschiebbar.

Auf dieser Seite