Handbooks
Reference

Configuration reference

Every Handbooks setting, with its flag, environment variable, config-file key, type and default — generated from the registry.

Generated by pnpm run config:docs from the settings registry — do not hand-edit; packages/cli/src/docs-drift.test.ts fails the build if this drifts from SETTINGS.

Precedence

Every setting resolves through the same layers, highest priority first: flag > shell env > .env > handbook.config.yaml > default. The first layer that supplies a value wins and every layer below it is ignored for that setting. Run handbook config — or handbook config --command <name> to see one subcommand only — to check what actually resolved and which layer it came from.

Naming

One camelCase key in the registry drives all three surfaces at once: a flag, an environment variable, and a config-file key. Prefixing any of them with a command name scopes that surface to one subcommand, and it is the same transform on all three — HANDBOOK_<KEY> becomes HANDBOOK_<COMMAND>_<KEY>, and key becomes <command>Key whether written flat or nested one level under <command>:. A setting marked (scoped) below only accepts the prefixed env name, because its meaning changes per command (--out, --lang in the skill package).

Bootstrap

Three top-level settings point at the layers above, and are themselves outside the registry, resolved once before every other setting — which is also why none of them can be set by the thing they load: an --env key inside handbook.config.yaml, an --env-file line inside .env, or a --config key inside that same file would have nothing left to read it.

  • --env <name> (or HANDBOOK_ENV) selects a per-environment cascade — the only one of the three with both a flag and an environment-variable form, since it names an environment rather than pointing at one exact file.
  • --env-file <path> loads exactly that one file, bypassing the cascade below.
  • --config <path> names one exact config file, bypassing the environment-aware discovery below (default: the nearest handbook.config.yaml-family file found by walking up from the working directory, stopping at a repo boundary).

The .env cascade

With no --env-file, the CLI loads a cascade of .env* files instead of one fixed file, highest precedence first. The existing applyEnvFile rule — never override a key already set — is what makes a cascade nothing more than "call it in this order, first file to set a key wins":

#filewhoscopecommitted?
1shell environmentalways wins
2.env.<name>.localpersonalthis environment onlyno (gitignored)
3.env.<name>teamthis environment onlyyes
4.env.localpersonalevery environmentno (gitignored)
5.envteambaselineyes

Rows 2 and 3 only apply when --env/HANDBOOK_ENV names an environment. With neither set, only rows 4 and 5 load — exactly what loaded before this cascade existed, so an existing setup with no .env.local sees no change at all.

Config-file discovery with an environment

--config aside, discovery still walks up from the working directory and stops at a repo boundary, but at every directory visited it now checks first for handbook.config.<name>.{yaml,yml,json} (only when an environment is named) before the plain handbook.config.yaml et al. — so a named file always wins over a plain file sitting in that same directory, even when a plain file exists at a level closer to the working directory. With no environment named, discovery is unchanged.

Run handbook config to see which environment is active and exactly which files it loaded, in precedence order — a cascade on top of four value layers is too many possible sources to track from memory, and a layer this command cannot show is no different from a layer that does not work.

Worked example for readWorkers (flag --read-workers <n>, default 12):

surfaceflatscoped to generate
envHANDBOOK_READ_WORKERSHANDBOOK_GENERATE_READ_WORKERS
handbook.config.yaml keyreadWorkersgenerateReadWorkers

The config-file forms are interchangeable: a flat readWorkers: ... and a nested generate: { readWorkers: ... } mean the same thing, because the file is flattened by the same camelCase join before it is read.

analyze

keyflagenvtypedefaultdoc
logLevelHANDBOOK_LOG_LEVELenum (debug|info|warn|error|silent)infolog verbosity; -v/--verbose and -q/--quiet are shorthand for debug/error
source--source <dir>HANDBOOK_SOURCEpathrequiredsource root; required for analyze/generate/plan/apply, optional elsewhere (hash freshness for validate/skill, and the tree a backup belongs to for rollback)
work--work <dir>HANDBOOK_WORKpathrequiredwork directory holding pipeline artifacts; optional for skill, where it adds coverage.json
lang--lang <lang>HANDBOOK_LANGenum (auto, plus any registered language)autosource language; auto detects and merges every registered language

generate

keyflagenvtypedefaultdoc
logLevelHANDBOOK_LOG_LEVELenum (debug|info|warn|error|silent)infolog verbosity; -v/--verbose and -q/--quiet are shorthand for debug/error
llmApiKeyHANDBOOK_LLM_API_KEY, OPENAI_API_KEYstring"" (empty)API key for the LLM endpoint; use EMPTY for keyless local endpoints. Never a flag and never allowed in the config file
llmProvider--provider <name>HANDBOOK_LLM_PROVIDER, OPENAI_PROVIDERenum (openai|anthropic|gemini)openaiLLM wire format; 'openai' covers every OpenAI-compatible endpoint (most of them)
llmModel--model <id>HANDBOOK_LLM_MODEL, OPENAI_MODELstringgpt-4o-minimodel identifier
llmBaseUrl--base-url <url>HANDBOOK_LLM_BASE_URL, OPENAI_BASE_URLstringhttps://api.openai.com/v1any OpenAI-compatible endpoint (hosted, vLLM, LiteLLM, a proxy); a URL with embedded credentials is refused in the config file, which gets committed
llmMaxTokens--max-tokens <n>HANDBOOK_LLM_MAX_TOKENS, OPENAI_MAX_TOKENSint16000max output tokens per request
llmTimeout--timeout <sec>HANDBOOK_LLM_TIMEOUT, OPENAI_TIMEOUTint300per-request deadline in seconds; a stalled call is retried rather than allowed to hold a phase hostage
llmMaxRetries--llm-retries <n>HANDBOOK_LLM_MAX_RETRIESint6retry attempts per request; 0 means a single attempt
llmRetryBackoff--llm-retry-backoff <sec>HANDBOOK_LLM_RETRY_BACKOFFint3base backoff between retries, in seconds
llmConcurrency--llm-concurrency <n>HANDBOOK_LLM_CONCURRENCYint16global cap on concurrent requests through one client
llmExtraBodyHANDBOOK_LLM_EXTRA_BODY, OPENAI_EXTRA_BODYjsonvendor fields merged into every request body; model/messages/token fields cannot be overridden. Free-form, so it is treated as a secret: never a flag and never allowed in the config file
source--source <dir>HANDBOOK_SOURCEpathrequiredsource root; required for analyze/generate/plan/apply, optional elsewhere (hash freshness for validate/skill, and the tree a backup belongs to for rollback)
work--work <dir>HANDBOOK_WORKpathrequiredwork directory holding pipeline artifacts; optional for skill, where it adds coverage.json
lang--lang <lang>HANDBOOK_LANGenum (auto, plus any registered language)autosource language; auto detects and merges every registered language
phase--phase <spec>HANDBOOK_PHASEstringallall | 1 | 2 | 2a | 2b | 2c | 3, or a comma list
strategy--strategy <s>HANDBOOK_STRATEGYenum (file|member)file (default) or member; unset keeps the work dir's recorded strategy
skeleton--skeleton <path>HANDBOOK_SKELETONpathuser-authored skeleton.yaml, required for the member strategy
narrateLang--narrate-lang <l>HANDBOOK_NARRATE_LANGenum (en|zh|hi|es|pt|ru|ja|de)enprose language
detail--detail <d>HANDBOOK_DETAILenum (brief|deep)briefcard depth
synthMode--synth-mode <m>HANDBOOK_SYNTH_MODEenum (oneshot|doctor)oneshotskeleton synthesis mode
maxDoctorRounds--max-doctor-rounds <n>HANDBOOK_MAX_DOCTOR_ROUNDSint6doctor convergence rounds
readWorkers--read-workers <n>HANDBOOK_READ_WORKERSint12concurrent card batches
readBatchSize--read-batch-size <n>HANDBOOK_READ_BATCH_SIZEintfiles per card batch; unset means 1 for --detail deep and 8 for brief
maxCharsPerFile--max-chars-per-file <n>HANDBOOK_MAX_CHARS_PER_FILEint0truncate each file at n chars; 0 means no limit
assignBatchSize--assign-batch-size <n>HANDBOOK_ASSIGN_BATCH_SIZEint25cards per assignment batch
assignWorkers--assign-workers <n>HANDBOOK_ASSIGN_WORKERSint12concurrent assignment batches
organizeWorkers--organize-workers <n>HANDBOOK_ORGANIZE_WORKERSint8concurrent stage-organize calls
narrateWorkers--narrate-workers <n>HANDBOOK_NARRATE_WORKERSint8concurrent narration calls
resume--resumeHANDBOOK_RESUMEboolfalseskip files that already have a completed card
refresh--refreshHANDBOOK_REFRESHboolfalseignore phase-3 caches
llmCache--llm-cacheHANDBOOK_LLM_CACHEboolfalsecache raw LLM replies under /phase3/cache; disabled by --refresh

render

keyflagenvtypedefaultdoc
logLevelHANDBOOK_LOG_LEVELenum (debug|info|warn|error|silent)infolog verbosity; -v/--verbose and -q/--quiet are shorthand for debug/error
work--work <dir>HANDBOOK_WORKpathrequiredwork directory holding pipeline artifacts; optional for skill, where it adds coverage.json
title--title <title>HANDBOOK_TITLEstringSystem Handbookhandbook title for rendered outputs
out--out <dir>HANDBOOK_RENDER_OUT (scoped)pathoutput location; render defaults to /handbook, plan writes a file, skill writes a directory
html--htmlHANDBOOK_HTMLboolfalsealso render the multi-page HTML site under /html
htmlSingle--html-singleHANDBOOK_HTML_SINGLEboolfalsealso render a single self-contained HTML page
agentSite--agent-siteHANDBOOK_AGENT_SITEboolfalsealso render the agent locator index under /agent
llmsTxt--llms-txtHANDBOOK_LLMS_TXTboolfalsealso write llms.txt and llms-full.txt next to the markdown
sourceBaseUrl--source-base-url <url>HANDBOOK_SOURCE_BASE_URLstringlink file cards to the source at /

skill

keyflagenvtypedefaultdoc
logLevelHANDBOOK_LOG_LEVELenum (debug|info|warn|error|silent)infolog verbosity; -v/--verbose and -q/--quiet are shorthand for debug/error
source--source <dir>HANDBOOK_SOURCEpathsource root; required for analyze/generate/plan/apply, optional elsewhere (hash freshness for validate/skill, and the tree a backup belongs to for rollback)
work--work <dir>HANDBOOK_WORKpathwork directory holding pipeline artifacts; optional for skill, where it adds coverage.json
out--out <dir>HANDBOOK_SKILL_OUT (scoped)pathrequiredoutput location; render defaults to /handbook, plan writes a file, skill writes a directory
handbook--handbook <dir>HANDBOOK_SKILL_HANDBOOK (scoped)pathrequiredrendered handbook directory; required for skill, optional context for plan
name--name <slug>HANDBOOK_NAMEstringrequiredskill slug (lowercase-hyphen)
project--project <name>HANDBOOK_PROJECTstringhuman project name for prose
agentDir--agent-dir <dir>HANDBOOK_AGENT_DIRpathrendered agent locator site; ships under references/agent/
bodyLang--lang <l>HANDBOOK_SKILL_BODY_LANG (scoped)enum (en|zh|hi|es|pt|ru|ja|de)enSKILL.md body language; frontmatter stays English for routing

validate

keyflagenvtypedefaultdoc
logLevelHANDBOOK_LOG_LEVELenum (debug|info|warn|error|silent)infolog verbosity; -v/--verbose and -q/--quiet are shorthand for debug/error
source--source <dir>HANDBOOK_SOURCEpathsource root; required for analyze/generate/plan/apply, optional elsewhere (hash freshness for validate/skill, and the tree a backup belongs to for rollback)
skill--skill <dir>HANDBOOK_SKILLpathrequiredskill directory to validate

plan

keyflagenvtypedefaultdoc
logLevelHANDBOOK_LOG_LEVELenum (debug|info|warn|error|silent)infolog verbosity; -v/--verbose and -q/--quiet are shorthand for debug/error
llmApiKeyHANDBOOK_LLM_API_KEY, OPENAI_API_KEYstring"" (empty)API key for the LLM endpoint; use EMPTY for keyless local endpoints. Never a flag and never allowed in the config file
llmProvider--provider <name>HANDBOOK_LLM_PROVIDER, OPENAI_PROVIDERenum (openai|anthropic|gemini)openaiLLM wire format; 'openai' covers every OpenAI-compatible endpoint (most of them)
llmModel--model <id>HANDBOOK_LLM_MODEL, OPENAI_MODELstringgpt-4o-minimodel identifier
llmBaseUrl--base-url <url>HANDBOOK_LLM_BASE_URL, OPENAI_BASE_URLstringhttps://api.openai.com/v1any OpenAI-compatible endpoint (hosted, vLLM, LiteLLM, a proxy); a URL with embedded credentials is refused in the config file, which gets committed
llmMaxTokens--max-tokens <n>HANDBOOK_LLM_MAX_TOKENS, OPENAI_MAX_TOKENSint16000max output tokens per request
llmTimeout--timeout <sec>HANDBOOK_LLM_TIMEOUT, OPENAI_TIMEOUTint300per-request deadline in seconds; a stalled call is retried rather than allowed to hold a phase hostage
llmMaxRetries--llm-retries <n>HANDBOOK_LLM_MAX_RETRIESint6retry attempts per request; 0 means a single attempt
llmRetryBackoff--llm-retry-backoff <sec>HANDBOOK_LLM_RETRY_BACKOFFint3base backoff between retries, in seconds
llmConcurrency--llm-concurrency <n>HANDBOOK_LLM_CONCURRENCYint16global cap on concurrent requests through one client
llmExtraBodyHANDBOOK_LLM_EXTRA_BODY, OPENAI_EXTRA_BODYjsonvendor fields merged into every request body; model/messages/token fields cannot be overridden. Free-form, so it is treated as a secret: never a flag and never allowed in the config file
source--source <dir>HANDBOOK_SOURCEpathrequiredsource root; required for analyze/generate/plan/apply, optional elsewhere (hash freshness for validate/skill, and the tree a backup belongs to for rollback)
out--out <dir>HANDBOOK_PLAN_OUT (scoped)pathoutput location; render defaults to /handbook, plan writes a file, skill writes a directory
handbook--handbook <dir>HANDBOOK_PLAN_HANDBOOK (scoped)pathrendered handbook directory; required for skill, optional context for plan
request--request <text>HANDBOOK_REQUESTstringrequiredthe natural-language change request
maxTurns--max-turns <n>HANDBOOK_MAX_TURNSint30agent turn budget

apply

keyflagenvtypedefaultdoc
logLevelHANDBOOK_LOG_LEVELenum (debug|info|warn|error|silent)infolog verbosity; -v/--verbose and -q/--quiet are shorthand for debug/error
source--source <dir>HANDBOOK_SOURCEpathrequiredsource root; required for analyze/generate/plan/apply, optional elsewhere (hash freshness for validate/skill, and the tree a backup belongs to for rollback)
plan--plan <file>HANDBOOK_PLANpathrequiredplan file produced by handbook plan
dryRun--dry-runHANDBOOK_DRY_RUNboolfalseverify only, never write
backupRoot--backup-root <dir>HANDBOOK_BACKUP_ROOTpathwhere backups go; defaults to /.handbook-patches

rollback

keyflagenvtypedefaultdoc
logLevelHANDBOOK_LOG_LEVELenum (debug|info|warn|error|silent)infolog verbosity; -v/--verbose and -q/--quiet are shorthand for debug/error
source--source <dir>HANDBOOK_SOURCEpathsource root; required for analyze/generate/plan/apply, optional elsewhere (hash freshness for validate/skill, and the tree a backup belongs to for rollback)
backup--backup <dir>HANDBOOK_BACKUPpathrequiredbackup directory containing manifest.json
force--forceHANDBOOK_FORCEboolfalserestore even files that changed after the patch

resync

keyflagenvtypedefaultdoc
logLevelHANDBOOK_LOG_LEVELenum (debug|info|warn|error|silent)infolog verbosity; -v/--verbose and -q/--quiet are shorthand for debug/error
llmApiKeyHANDBOOK_LLM_API_KEY, OPENAI_API_KEYstring"" (empty)API key for the LLM endpoint; use EMPTY for keyless local endpoints. Never a flag and never allowed in the config file
llmProvider--provider <name>HANDBOOK_LLM_PROVIDER, OPENAI_PROVIDERenum (openai|anthropic|gemini)openaiLLM wire format; 'openai' covers every OpenAI-compatible endpoint (most of them)
llmModel--model <id>HANDBOOK_LLM_MODEL, OPENAI_MODELstringgpt-4o-minimodel identifier
llmBaseUrl--base-url <url>HANDBOOK_LLM_BASE_URL, OPENAI_BASE_URLstringhttps://api.openai.com/v1any OpenAI-compatible endpoint (hosted, vLLM, LiteLLM, a proxy); a URL with embedded credentials is refused in the config file, which gets committed
llmMaxTokens--max-tokens <n>HANDBOOK_LLM_MAX_TOKENS, OPENAI_MAX_TOKENSint16000max output tokens per request
llmTimeout--timeout <sec>HANDBOOK_LLM_TIMEOUT, OPENAI_TIMEOUTint300per-request deadline in seconds; a stalled call is retried rather than allowed to hold a phase hostage
llmMaxRetries--llm-retries <n>HANDBOOK_LLM_MAX_RETRIESint6retry attempts per request; 0 means a single attempt
llmRetryBackoff--llm-retry-backoff <sec>HANDBOOK_LLM_RETRY_BACKOFFint3base backoff between retries, in seconds
llmConcurrency--llm-concurrency <n>HANDBOOK_LLM_CONCURRENCYint16global cap on concurrent requests through one client
llmExtraBodyHANDBOOK_LLM_EXTRA_BODY, OPENAI_EXTRA_BODYjsonvendor fields merged into every request body; model/messages/token fields cannot be overridden. Free-form, so it is treated as a secret: never a flag and never allowed in the config file
work--work <dir>HANDBOOK_WORKpathrequiredwork directory holding pipeline artifacts; optional for skill, where it adds coverage.json
title--title <title>HANDBOOK_TITLEstringSystem Handbookhandbook title for rendered outputs
case--case <dir>HANDBOOK_CASEpathrequiredcase directory: edited/ + plan.md + change.diff
useLlm--no-llmHANDBOOK_USE_LLMbooltrueset false for a structural refresh only, with prose marked stale
refreshRendered--no-renderHANDBOOK_REFRESH_RENDEREDbooltrueset false to skip refreshing already-rendered outputs under /handbook
corrections--corrections <file>HANDBOOK_CORRECTIONSpathagent-reported corrections.jsonl; its files widen the refresh set
cardDetail--detail <d>HANDBOOK_RESYNC_CARD_DETAIL (scoped)enum (brief|deep)card depth for regenerated cards; unset matches the existing handbook
proseLang--narrate-lang <l>HANDBOOK_RESYNC_PROSE_LANG (scoped)enum (en|zh|hi|es|pt|ru|ja|de)prose language for regenerated cards; unset matches the existing handbook

studio

keyflagenvtypedefaultdoc
logLevelHANDBOOK_LOG_LEVELenum (debug|info|warn|error|silent)infolog verbosity; -v/--verbose and -q/--quiet are shorthand for debug/error
llmApiKeyHANDBOOK_LLM_API_KEY, OPENAI_API_KEYstring"" (empty)API key for the LLM endpoint; use EMPTY for keyless local endpoints. Never a flag and never allowed in the config file
llmProvider--provider <name>HANDBOOK_LLM_PROVIDER, OPENAI_PROVIDERenum (openai|anthropic|gemini)openaiLLM wire format; 'openai' covers every OpenAI-compatible endpoint (most of them)
llmModel--model <id>HANDBOOK_LLM_MODEL, OPENAI_MODELstringgpt-4o-minimodel identifier
llmBaseUrl--base-url <url>HANDBOOK_LLM_BASE_URL, OPENAI_BASE_URLstringhttps://api.openai.com/v1any OpenAI-compatible endpoint (hosted, vLLM, LiteLLM, a proxy); a URL with embedded credentials is refused in the config file, which gets committed
llmMaxTokens--max-tokens <n>HANDBOOK_LLM_MAX_TOKENS, OPENAI_MAX_TOKENSint16000max output tokens per request
llmTimeout--timeout <sec>HANDBOOK_LLM_TIMEOUT, OPENAI_TIMEOUTint300per-request deadline in seconds; a stalled call is retried rather than allowed to hold a phase hostage
llmMaxRetries--llm-retries <n>HANDBOOK_LLM_MAX_RETRIESint6retry attempts per request; 0 means a single attempt
llmRetryBackoff--llm-retry-backoff <sec>HANDBOOK_LLM_RETRY_BACKOFFint3base backoff between retries, in seconds
llmConcurrency--llm-concurrency <n>HANDBOOK_LLM_CONCURRENCYint16global cap on concurrent requests through one client
llmExtraBodyHANDBOOK_LLM_EXTRA_BODY, OPENAI_EXTRA_BODYjsonvendor fields merged into every request body; model/messages/token fields cannot be overridden. Free-form, so it is treated as a secret: never a flag and never allowed in the config file
port--port <n>HANDBOOK_PORTint4860port to listen on; 0 picks any free port
host--host <addr>HANDBOOK_HOSTstring127.0.0.1bind address; stays on loopback unless you set it (containers need 0.0.0.0). The CSRF guard still requires a loopback Host header
stateDir--state-dir <dir>HANDBOOK_STATE_DIRpathwhere studio.json and managed work dirs live; defaults to $HOME/.handbook-studio

config

keyflagenvtypedefaultdoc
logLevelHANDBOOK_LOG_LEVELenum (debug|info|warn|error|silent)infolog verbosity; -v/--verbose and -q/--quiet are shorthand for debug/error
forCommand--command <name>HANDBOOK_FOR_COMMANDstringshow only the settings that apply to this subcommand; its env/file/default layers are inspectable here, but that command's own flags are not (pass them to the command itself)
json--jsonHANDBOOK_JSONboolfalsemachine-readable output
check--checkHANDBOOK_CHECKboolfalsevalidate only; exit non-zero if anything is invalid or missing

On this page