Skip to content

Configuration

Three layers, nearest wins, key by key (a key unset at one layer inherits the next):

  • Project: a .trailhead/config.json file 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.

/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.

KeyValues (default bold)Effect
ticket.languagean 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
designdisk | artifacts | stitchwhere 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.surfacecanvas | design-systemstitch only: a Stitch project of screens (default) or a shared Stitch design system
design.systemDesign System Artifact URLartifacts only: the design system installed on the mockup canvas (asked at the first screen if unset)
design.approvalexplicit | autowait for mockup approval before UI code, or proceed without blocking
tddseams | on | offhow the build engine tests
acceptance.browserauto | on | offdrive 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.urlbool / URLis it browser-drivable, and where
plan_reviewoff | on | CLI listsend build PLANs to external AI CLIs (Gemini, Codex, …) for a second opinion and converge on their concerns
plan_review.roundsinteger (2)max converge-and-re-review rounds
code_review.roundsinteger (2)max fix-and-re-review rounds in Code review before its boundary HITL checkpoint
effortstandard | leanhow 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.copyarray 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.checksarray 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.setuparray 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.accountsobject 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).

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:

  • plan and execute are the build/bug engine’s steps. Execute is a subagent too, and it commits to main.
  • research, review, debug, verify (the goal-backward Verify check), and codebase-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.

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:

TierClaude (models.*)Codex (models.codex.*)
strongclaude-opus-5-5gpt-5.6-sol, effort high
standardclaude-sonnet-5-5gpt-5.6-terra, effort medium
fastclaude-haiku-5-5gpt-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.

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.

Profileplanexecuteresearchreviewdebugverifycodebase-map
Highstrongstrongstandardstrongstrongstrongstandard
Balanced (default)strongstandardstandardstandardstandardstandardfast
Lowstandardstandardfastfaststandardfastfast

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" } }

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.* or models.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:config to 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: 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.