Handbooks konfigurieren
Fünf Vorrangebenen, eine Registry und ein Befehl, der Ihnen genau sagt, welche Ebene gewonnen hat.
Jede Einstellung wird einmal deklariert, in einer Registry-Tabelle. Die CLI-Flags, die
Namen der Umgebungsvariablen, die Schlüssel der Konfigurationsdatei, .env.example,
handbook.config.example.yaml und die
Konfigurationsreferenz werden allesamt daraus
generiert — sie können also nicht auseinanderdriften, und ein Drift-Test lässt den Build
fehlschlagen, wenn es jemand versucht.
Vorrang, höchste Ebene zuerst
- CLI-Flag —
--read-workers 4 - Shell-Umgebung —
HANDBOOK_GENERATE_READ_WORKERS, dannHANDBOOK_READ_WORKERS, dann ein Vendor-Alias wieOPENAI_MODEL - Die
.env-Kaskade — in die Umgebung gemergt, bevor irgendetwas sie liest handbook.config.yaml— gefunden durch Aufwärtslaufen vom cwd, mit Halt an der Git-Wurzel- Registry-Standardwert
Die erste Ebene, die einen Wert liefert, gewinnt; jede Ebene darunter wird für diese Einstellung ignoriert.
handbook.config.yaml
Legen Sie die Datei in der Repository-Wurzel ab und committen Sie sie. Die Suche läuft vom Arbeitsverzeichnis aufwärts und stoppt an einer Repo-Grenze — ein Projekt ohne Konfigurationsdatei erbt also nicht die seines Elternverzeichnisses.
# Paths are resolved relative to THIS FILE, so the config stays portable.
source: ./src
work: ./.handbook
llm:
model: gpt-4o-mini
baseUrl: https://api.openai.com/v1
maxTokens: 16000
concurrency: 16
generate:
detail: deep
synthMode: doctor
narrateLang: en
readWorkers: 12
render:
title: Payments API Handbook
html: true
agentSite: true
llmsTxt: true
sourceBaseUrl: https://github.com/me/api/blob/main
studio:
port: 4860Zwei Dinge, die man wissen sollte:
- Verschachtelung und Abflachung sind dasselbe.
generate: { detail: deep }und ein flachesgenerateDetail: deepbedeuten exakt dasselbe, weil die Datei vor dem Lesen per camelCase-Verkettung abgeflacht wird. - Relative
path-Werte werden gegen das Verzeichnis der Konfigurationsdatei selbst aufgelöst, nicht gegen das cwd. Genau das hält eine committete Konfigurationsdatei funktionsfähig, egal von wo Sie den Befehl ausführen.
Secrets werden hier zurückgewiesen
llmApiKey / OPENAI_API_KEY und llmExtraBody / OPENAI_EXTRA_BODY dürfen niemals in einer
Konfigurationsdatei stehen — Konfigurationsdateien werden committet. Der Loader weist die Datei rundweg
zurück und sagt, warum. Legen Sie beide in .env oder in die Shell-Umgebung. baseUrl dürfen Sie
bedenkenlos committen — es sei denn, die URL selbst trägt Zugangsdaten (https://user:pass@host/v1), was
aus demselben Grund zurückgewiesen wird.
Kopieren Sie zum Einstieg handbook.config.example.yaml; die Datei wird aus der Registry
generiert und listet daher jeden Schlüssel, den es tatsächlich gibt.
Scoping pro Befehl
Jede Einstellung lässt sich auf einen Unterbefehl einschränken, auf allen drei Oberflächen, mit derselben Transformation:
export HANDBOOK_NARRATE_LANG=en # everywhere
export HANDBOOK_GENERATE_NARRATE_LANG=zh # …except generatenarrateLang: en
generate:
narrateLang: zhDie eingeschränkte Form gewinnt immer gegen die flache.
Mehrere Umgebungen
handbook generate --env prod --source ~/code/api --work work/api--env prod (oder HANDBOOK_ENV=prod) tut zwei Dinge:
- Lädt
.env.prod.local→.env.prod→.env.local→.env; der erste Schreiber gewinnt. - Bevorzugt
handbook.config.prod.yamlgegenüber der einfachen Datei — in jedem auf dem Weg nach oben besuchten Verzeichnis, sodass eine benannte Datei eine einfache schlägt, selbst wenn die einfache näher liegt.
Ein typisches Layout:
.env # team baseline, committed
.env.local # your machine, gitignored
.env.prod # team prod settings, committed (no secrets)
.env.prod.local # your prod credentials, gitignored
handbook.config.yaml # defaults
handbook.config.prod.yaml--env-file <path> umgeht die Kaskade vollständig und lädt genau diese eine Datei.
Eine fehlende Datei ist dort ein lauter Fehler, kein Fallback — Sie haben nach einer
bestimmten Datei gefragt.
Fragen, was tatsächlich aufgelöst wurde
handbook config --command generateenvironment prod (--env)
env files .env.prod, .env
config file /repo/handbook.config.prod.yaml
SETTING VALUE FROM
source /Users/me/code/api flag --source
llmModel gpt-4o env HANDBOOK_LLM_MODEL
llmApiKey sk-•••••• env OPENAI_API_KEY
readWorkers 4 handbook.config.prod.yaml (generate.readWorkers)
detail deep handbook.config.prod.yaml (generate.detail)
narrateLang en defaulthandbook config --json # machine-readable
handbook config --check # exit 2 on the first invalid or missing value--check in die CI aufnehmen
Eine vertippte Variable bedeutete früher "lief stillschweigend mit dem Standardwert". --check macht daraus
einen Fehler, der die Variable in der Meldung benennt — deutlich billiger, als es vierzig Minuten tief in
einem Generierungslauf zu entdecken.
config verwendet bewusst den nicht werfenden Resolver: seine Aufgabe ist es,
Konfiguration zu zeigen — auch dann, wenn sie kaputt ist. Ein fehlendes --source
erscheint als sichtbare Zeile — unset (required), statt genau das Werkzeug
lahmzulegen, mit dem Sie exakt dieses Problem debuggen würden.
Was der Resolver erzwingt
-
Ein leerer Wert gilt als nicht gesetzt.
HANDBOOK_TITLE=kann kein Handbook ohne Titel erzeugen. -
Ein gelieferter, aber ungültiger Wert fällt nie auf einen Standardwert durch. Eine vertippte Zahl ist ein Fehler, keine stille 12.
-
Typen werden an der Grenze geprüft, mit der Quelle in der Fehlermeldung:
env HANDBOOK_READ_WORKERS: readWorkers must be an integer >= 1, got "twelve" handbook.config.yaml (generate.detail): detail must be one of brief | deep, got "verbose" -
Pflichtangaben werden nach jeder Ebene geprüft, und der Fehler listet jeden Weg auf, den Wert zu liefern:
source is required: pass --source, set HANDBOOK_GENERATE_SOURCE, or add it to handbook.config.yaml