Configuration
Three layers, nearest wins, key by key (a key unset at one layer inherits the next):
- Project: a
.trailhead/config.jsonfile at the repo root: overrides for this project, committed so a team shares one config. Config lives in a plain file, never in the map issue; it’s yours to change at any time. - Global:
~/.claude/trailhead/config.json: your standing defaults across every project. - Defaults: the built-in values.
Guided setup
Section titled “Guided setup”/trailhead:config runs a guided, menu-driven setup: pick the scope, then walk each setting (way of working (git, release, isolation), ticket language, models, design + approval, TDD, effort, acceptance testing (with its UAT setup), plan review, statusline) as an icon-labelled menu; no hand-editing JSON. Every step is asked (none skipped). In the models step you pick a profile (High, Balanced, Low) that sets every model key at once, or Manual to choose each key yourself (see Models). config get prints the effective merged config; config set <key> <value> writes one key.
The statusline step offers to install trailhead’s Claude Code status bar: one line with model · project · branch · plan usage (5h % · reset · 7d %) · a context-window bar, plus a second line with the active ticket (▸ #N Title) whenever you’re working one, and a ⬆ trailhead <version> flag when a newer trailhead is available (run /trailhead:update). The project is always the main repo’s name even from an isolated checkout, and the branch carries a (WT) tag in a worktree or (C) in a per-ticket clone (nothing on the original checkout). It’s a global Claude Code setting; if you already run a statusline the setup asks before replacing it, and the script also exposes --ticket-only / --context-only / --usage-only segments to slot into an existing tool.
| Key | Values (default bold) | Effect |
|---|---|---|
ticket.language | an ISO 639-1 code (en) | the language trailhead writes its GitHub prose & commit descriptions in, decoupled from the language it converses in |
models.{plan,execute,research,review,debug,verify,codebase-map} | a full versioned model id (the Balanced profile’s tier default) | which model runs each activity; plan and execute are always set separately. Set a key to inherit session to use the session model instead; see Models |
models.codex.{plan,execute,research,review,debug,verify,codebase-map} | an OpenAI model id, or {model, effort} (inherit session) | the same per-activity split on Codex, which cannot run Claude ids; see Models |
design | disk | artifacts | stitch | where UI mockups go: local throwaway HTML, a Design canvas Artifact on claude.ai (Claude Code only), or Google Stitch (cross-host, via the Stitch MCP). The legacy claude.ai/design value is read as artifacts |
design.surface | canvas | design-system | stitch only: a Stitch project of screens (default) or a shared Stitch design system |
design.system | Design System Artifact URL | artifacts only: the design system installed on the mockup canvas (asked at the first screen if unset) |
design.approval | explicit | auto | wait for mockup approval before UI code, or proceed without blocking |
tdd | seams | on | off | how the build engine tests |
acceptance.browser | auto | on | off | drive the browser in Verify (after asking who drives, AI or human, or skip); off still runs AI-driven checks via commands, and walks you through a conversational UAT for anything only you can do (step by step in chat, not a checklist to self-serve) |
testing.webapp / testing.url | bool / URL | is it browser-drivable, and where |
plan_review | off | on | CLI list | send build PLANs to external AI CLIs (Gemini, Codex, …) for a second opinion and converge on their concerns |
plan_review.rounds | integer (2) | max converge-and-re-review rounds |
code_review.rounds | integer (2) | max fix-and-re-review rounds in Code review before its boundary HITL checkpoint |
effort | standard | lean | how hard the build/bug engine works a change: standard runs every step, lean size-triages small changes and offers to skip heavy ones (plan pass, TDD, cross-AI review, full code review, goal-backward verify). Governs build/bug only: quick always size-triages regardless of this key |
isolation.copy | array of repo-relative paths (unset) | gitignored files and directories (.env, .npmrc, local config) copied from the main checkout into a new worktree or clone workspace right after it is created. Plain paths, no globs; an existing destination is never overwritten; absolute, .. and .git paths are rejected. The project value replaces the global one whole |
preflight.checks | array of shell commands (unset) | project checks the stale-base preflight runs at the working root before UAT and before integration; a non-zero exit stops the ticket. For example, fail on duplicate migration timestamps |
uat.setup | array of {name, run, check?, note?} (unset) | ordered setup run at every UAT start, after the stale-base preflight and before the who-drives ask. A passing check skips the step; after run, check is polled until it passes; note is a rule the agent honours (for example “ask before using the Pixel”). [] means no setup needed |
uat.accounts | object role to {user, secret} (unset) | named test accounts for UAT. secret must be a $ENV reference (a literal is rejected); machine-specific values (device id, local URL, a personal user) should be $ENV references too, so the committed config stays generic |
isolation.copy, preflight.checks and the uat.* keys can be written nested ({"uat": {"setup": [...]}}) or flat ("uat.setup": [...]); if one file carries both, the nested form wins and a warning says so.
git, release, and isolation aren’t config.json keys: they’re conventions-header keys stored in the repo’s trailhead:conventions issue, reachable from the guided setup’s way-of-working step (see Core concepts for the full header).
Models
Section titled “Models”Each key runs its activity as a subagent on the model you name, so the whole per-activity split applies within a single work session, whatever model that session runs on:
planandexecuteare the build/bug engine’s steps. Execute is a subagent too, and it commits tomain.research,review,debug,verify(the goal-backward Verify check), andcodebase-map(the codebase-map reader fan-out) each run on their own key.
The main session stays the orchestrator. It holds the interactive moments (a build’s Discuss, and Verify’s acceptance/UAT) and it does charting, grilling, and ticket-writing on its own model. No key governs ticket quality, so run charting sessions on your strong model.
Tiers and their defaults
Section titled “Tiers and their defaults”Rather than pinning ids by hand, trailhead thinks in three tiers and resolves each to a concrete model id when you set up. The current defaults:
| Tier | Claude (models.*) | Codex (models.codex.*) |
|---|---|---|
| strong | claude-opus-5-5 | gpt-5.6-sol, effort high |
| standard | claude-sonnet-5-5 | gpt-5.6-terra, effort medium |
| fast | claude-haiku-5-5 | gpt-5.6-luna, effort low |
Claude keys take an id only. Codex keys take a bare OpenAI model id or a {model, effort} pair, where the effort is projected as the model’s reasoning effort. Always store a full versioned id, never a bare opus or sonnet.
Profiles
Section titled “Profiles”A profile assigns a tier to each of the seven keys. In /trailhead:config, picking High, Balanced or Low applies it whole (no further per-key questions); Manual asks each key yourself, and plan and execute are always two separate questions. The idea behind all three is smart at every level: research is never the strongest tier, and execute and debug are never the fastest.
| Profile | plan | execute | research | review | debug | verify | codebase-map |
|---|---|---|---|---|---|---|---|
| High | strong | strong | standard | strong | strong | strong | standard |
| Balanced (default) | strong | standard | standard | standard | standard | standard | fast |
| Low | standard | standard | fast | fast | standard | fast | fast |
Balanced is the default profile. On Claude, a models.* key you leave unset resolves to its Balanced tier at load time, so a project with no config still gets sensible models without anyone choosing. A models.codex.* key is different: left unset, it inherits the session model, and only a profile or a pin gives it a Codex tier. To use the session model for a Claude key instead of its Balanced default, set it explicitly to inherit session. An unknown id is never fatal: trailhead warns and inherits the session model.
On Codex, picking a profile seeds models.codex.* instead. Re-run the installer afterwards (the same --host=codex install command) so the pins are re-projected into ~/.codex/agents/trailhead-*.toml; the menu updates the config, the installer regenerates those files. The Claude models.* keys cannot run on Codex and are ignored there (they stay in your config untouched for when you work on Claude Code).
Example config file (the same shape works for the project .trailhead/config.json and the global ~/.claude/trailhead/config.json):
{ "ticket": { "language": "en" }, "models": { "plan": "claude-opus-5-5", "execute": "claude-sonnet-5-5" }, "tdd": "seams", "acceptance": { "browser": "auto" } }Pinned model review
Section titled “Pinned model review”When a release moves a tier’s default (for example fast went from Haiku 4.5 to claude-haiku-5-5), a key you pinned to the old default would silently stay behind. trailhead notices and offers a review:
- When it triggers. A pinned
models.*ormodels.codex.*id is older than the new default of the tier it belonged to. Unset keys already follow the new default and are never flagged; ids trailhead does not recognise (custom ones) are never flagged either. - Where you see it. At the start of a session, from the SessionStart hook (see Hooks) and again when a trailhead skill loads its config, once per session either way. On hosts without a hook bus the same check runs inline at session start.
- What it lists. Each stale pin as
key: old -> new, naming the config file it actually came from. The review looks at your effective config: the global file merged under the project file, the project winning key by key, so a stale pin inherited from the global file is flagged even in a project that pins nothing itself. - Three choices. Update (write the new ids; a Codex effort is left as it was), keep (change nothing; you are not asked again for these defaults), or open
/trailhead:configto pick per key.
The check itself is read-only: showing the notice never records anything, so it keeps coming back until you actually answer one of the three choices. Only then is the answer recorded in .trailhead/model-defaults-ack, a gitignored file. If no project is found above the working directory, the review runs on the global config alone and its acknowledgement is stored next to it, in the trailhead/model-defaults-ack file under your Claude config directory.
Design mockups
Section titled “Design mockups”design: disk (the default) drops a throwaway static HTML mockup next to the code and links it from the ticket. design: artifacts builds the mockup as a Design canvas Artifact on claude.ai through Claude Code’s built-in Artifact tool (nothing to install), with the design system in design.system installed on the canvas and the canvas URL cached in design.project. design: stitch uses the Google Stitch MCP, the hosted option that also runs on Codex; there design.surface picks a Stitch project (canvas) or a Stitch design system (design-system). design.approval decides whether the build waits for your explicit go-ahead (explicit) or proceeds right after surfacing the mockup (auto).
The legacy value claude.ai/design is read as artifacts: the standalone Claude Design site closes on 2026-12-14. The full flow, the fallbacks and the migration steps are in Design mockups.
Next: Design mockups for how the mockup step works on Artifacts, Stitch or disk, then Hooks for the guardrails that enforce parts of this discipline.