Handbooks
Referenz

Umgebungsvariablen

Jede Variable, die Handbooks liest, die Benennungsregel, die sie erzeugt, die .env-Kaskade und die, die nie in eine Konfigurationsdatei gehören.

Die Benennungsregel

Jede Einstellung hat einen camelCase-Schlüssel in der Registry. Drei Namen werden daraus durch dieselbe Transformation abgeleitet:

OberflächeAus readWorkersBezogen auf generate
Flag--read-workers <n>
UmgebungHANDBOOK_READ_WORKERSHANDBOOK_GENERATE_READ_WORKERS
Konfigurationsdatei-SchlüsselreadWorkersgenerateReadWorkers, oder verschachtelt generate: { readWorkers: }

Die befehlsbezogene Form schlägt immer die flache. Genau das erlaubt es zu sagen „erzähle auf Chinesisch, aber nur beim Generieren“, ohne sonst etwas anzufassen.

export HANDBOOK_NARRATE_LANG=en              # everywhere
export HANDBOOK_GENERATE_NARRATE_LANG=zh     # …except generate

Einige wenige Einstellungen sind nur befehlsbezogen, weil sich ihre Bedeutung je Befehl ändert: --out (HANDBOOK_RENDER_OUT, HANDBOOK_SKILL_OUT, HANDBOOK_PLAN_OUT), --handbook (HANDBOOK_SKILL_HANDBOOK, HANDBOOK_PLAN_HANDBOOK), das --lang von skill (HANDBOOK_SKILL_BODY_LANG) sowie --detail / --narrate-lang von resync (HANDBOOK_RESYNC_CARD_DETAIL, HANDBOOK_RESYNC_PROSE_LANG).

Hersteller-Aliase

Sieben Einstellungen akzeptieren zusätzlich die Namen, die Leute ohnehin schon exportiert haben:

EinstellungAlias
llmApiKeyOPENAI_API_KEY
llmProviderOPENAI_PROVIDER
llmModelOPENAI_MODEL
llmBaseUrlOPENAI_BASE_URL
llmMaxTokensOPENAI_MAX_TOKENS
llmTimeoutOPENAI_TIMEOUT
llmExtraBodyOPENAI_EXTRA_BODY

Die Suchreihenfolge ist: befehlsbezogen HANDBOOK_<CMD>_<KEY> → flach HANDBOOK_<KEY> → der Hersteller-Alias.

Bootstrap-Variablen

Drei Einstellungen werden vor allem anderen aufgelöst, weil alles andere von ihnen abhängt. Keine von ihnen kann von dem gesetzt werden, was sie lädt — ein --env-Schlüssel in handbook.config.yaml hätte niemanden mehr, der ihn liest.

Variable / FlagWas sie tut
HANDBOOK_ENV / --env <name>Wählt eine umgebungsspezifische .env-Kaskade und bevorzugt handbook.config.<name>.yaml
--env-file <path> / HANDBOOK_ENV_FILELädt genau diese eine Datei und umgeht die Kaskade. Eine fehlende Datei ist ein lauter Fehler. Bevorzuge die Variable: Node >= 20.6 besitzt --env-file ebenfalls und sucht vorab danach, sodass ein fehlender Pfad als node: <path>: not found (Exit 9) stirbt, bevor Handbooks läuft. Das Flag schlägt die Variable, wenn beide gesetzt sind
--config <path>Benennt genau eine Konfigurationsdatei und umgeht die Suche

Die .env-Kaskade

Ohne --env-file lädt die CLI eine Kaskade von .env*-Dateien aus dem aktuellen Verzeichnis, höchster Vorrang zuerst:

#DateiWerGeltungsbereichCommittet?
1die Shell-Umgebunggewinnt immer
2.env.<name>.localpersönlichnur diese Umgebungnein (gitignored)
3.env.<name>Teamnur diese Umgebungja
4.env.localpersönlichjede Umgebungnein (gitignored)
5.envTeamBasislinieja

Zeilen 2 und 3 gelten nur, wenn --env/HANDBOOK_ENV eine Umgebung benennt. Ist keines von beiden gesetzt, laden nur die Zeilen 4 und 5.

Die ganze Kaskade ist „rufe sie in dieser Reihenfolge auf, der erste Schreiber gewinnt“, denn das Laden einer Datei überschreibt nie einen bereits gesetzten Schlüssel. Diese eine Regel hält die Shell über jeder Datei, ganz ohne zusätzliche Logik irgendwo.

handbook generate --env prod --source ~/code/api --work work/api
# loads .env.prod.local → .env.prod → .env.local → .env
# and prefers handbook.config.prod.yaml over handbook.config.yaml

Die Kaskade gilt nur im aktuellen Verzeichnis

Anders als handbook.config.yaml — das durch Hochlaufen bis zur Git-Wurzel gefunden wird — werden .env-Dateien aus dem Verzeichnis gelesen, in dem du den Befehl ausführst. .env bedeutet „diese Maschine, genau jetzt“. Führe LLM-gestützte Befehle aus der Repository-Wurzel aus oder übergib --env-file.

Was der .env-Parser akzeptiert

KEY=value, ein optionales export -Präfix, Leerzeilen, #-Kommentarzeilen, Werte in einfachen und doppelten Anführungszeichen (die Anführungszeichen werden entfernt) und einen abschließenden Inline-Kommentar # bei einem Wert ohne Anführungszeichen. CRLF, LF und blankes CR als Zeilenenden funktionieren alle. Keine mehrzeiligen Werte.

Ein leerer Wert gilt als nicht gesetztHANDBOOK_TITLE= erzeugt kein Handbuch ohne Titel.

Geheimnisse

Zwei Einstellungen sind in der Registry als secret markiert — llmApiKey / OPENAI_API_KEY und llmExtraBody / OPENAI_EXTRA_BODY. Für beide gilt:

  • sie sind nie ein Kommandozeilen-Flag (Flags landen in der Shell-History und in der ps-Ausgabe);
  • sie werden abgelehnt, wenn sie in einer Konfigurationsdatei auftauchen, mit einer Meldung, die den Grund nennt — Konfigurationsdateien werden committet;
  • sie werden in der Ausgabe von handbook config maskiert.

llmExtraBody ist ein Geheimnis, weil er frei formulierbar ist. Er mischt alles, was du hineinschreibst, in jeden Anfrage-Body, und Gateways nehmen Auth-Daten dort durchaus entgegen — das Werkzeug kann also nicht aufzählen, was darin steht, und ein Tuning-Feld nicht von Zugangsdaten unterscheiden. Ein Flag gibt es dafür gar nicht; nimm die Umgebungsvariable.

llmBaseUrl ist bewusst kein Geheimnis: Ein Team, das jeden Checkout auf dasselbe gemeinsame Gateway richtet, hat einen legitimen Grund, den Wert zu committen. Nur eine URL mit eingebetteten Zugangsdaten (https://user:pass@gw.internal/v1) wird in einer Konfigurationsdatei abgelehnt — dort und sonst nirgends.

handbook.config.yaml: llmApiKey must not appear in a config file (it gets committed)
— use .env or the shell environment instead

Docker

Das Image backt HANDBOOK_SOURCE=/src und HANDBOOK_WORK=/work ein, du musst also nur Volumes einhängen:

docker run --rm -v "$PWD:/src:ro" -v handbook-work:/work handbook:local analyze

Dockers eigenes --env-file legt sich über das .env-Laden der Werkzeugkette — beide greifen, und eine so übergebene OPENAI_*-Variable ist genau so sichtbar wie ein Shell-Export. .env*-Dateien werden nie ins Image gebacken; siehe .dockerignore.

Sehen, was tatsächlich aufgelöst wurde

handbook config --command generate

gibt die aktive Umgebung aus, jede .env-Datei, die die Kaskade geladen hat, die aufgelöste Konfigurationsdatei und eine Zeile pro Einstellung mit ihrer Herkunft — flag, env, file oder default.

handbook config --check    # exit 2 on the first invalid or missing value

Setze --check in die CI

Eine vertippte Variable bedeutete früher „lief still mit dem Standardwert“. Jetzt ist es ein Fehlschlag, und die Variable steht in der Meldung — was in der CI viel billiger zu finden ist als vierzig Minuten in einen Generierungslauf hinein.

Die vollständige Liste

Jede Variable, mit Typ, Standardwert und Dokumentation, steht auf der Seite Konfigurationsreferenz — die aus derselben Registry generiert wird, die auch die CLI liest, und deshalb nicht abweichen kann.

.env.example in der Repository-Wurzel wird ebenfalls aus dieser Registry generiert. Jede Zeile darin beginnt auskommentiert, das Kopieren der ganzen Datei ist also gefahrlos.

Auf dieser Seite