@marcomigozzi/trailhead 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.it.md CHANGED
@@ -26,7 +26,7 @@ Due approcci al lavoro di progetto guidato dagli agenti risolvono ciascuno una m
26
26
 
27
27
  Lavorando su entrambi, uno schema continuava a ripresentarsi: **usa una mappa e un onboarding in stile Wayfinder per decidere la forma del lavoro, poi un motore in stile GSD per costruire ogni pezzo, senza mai lasciare l'issue tracker.** `trailhead` è quello schema trasformato in un'unica skill, una sua interpretazione autonoma di entrambe le idee anziché un wrapper attorno all'una o all'altra.
28
28
 
29
- > **trailhead è self-contained** nel senso che ha **zero dipendenze da plugin esterni**: gli agent di trailhead e i built-in dell'host vanno bene, e nessun'altra skill o plugin è richiesta. Wayfinder e GSD sono *ispirazione*, non dipendenze. Ogni tecnica che quei sistemi impacchettano come skill separata (grilling, TDD, debugging sistematico, codebase mapping, code review) è **integrata qui come protocollo inline**. Il core di trailhead non invoca nessun'altra skill; ogni tecnica del motore dispatcha al **proprio agent `trailhead-*`** (`trailhead-executor`, `trailhead-plan`, `trailhead-research`, `trailhead-code-review`, `trailhead-debug`, più `trailhead-fix` e `trailhead-codebase-map`), scritto una volta come file `agents/trailhead-*.md` versionato e **proiettato su ogni host** (su Codex diventa `~/.codex/agents/trailhead-*.toml` generato dalla stessa sorgente). Questi agent sono **thin** (identità + tool policy + un modello guidato dalla config, con il protocollo della tecnica iniettato allo spawn) e girano sul toolkit di subagent nativo dell'host (il tool `Agent` integrato di Claude Code, oppure il toolkit `multi_agent` di Codex). L'unica cosa da installare è trailhead stesso. C'è un'unica eccezione opt-in: la modalità mockup hosted. Quando abilitata, `claude.ai/design` costruisce il mockup su claude.ai/design (solo Claude): per default una canvas (la skill integrata `/design` pubblicata come Artifact, o un progetto creato a mano nella web app, non guidato da MCP) o, per una libreria di componenti condivisa, un progetto design-system tramite DesignSync (l'MCP `claude-design` più la skill `/design-sync`, l'unica superficie guidata da MCP). Una terza modalità, `stitch`, usa l'MCP Google Stitch e funziona sia su **Claude Code sia su Codex**, quindi è l'opzione hosted cross-host. Se l'MCP della modalità configurata non è connesso, offre un'installazione una tantum e ripiega sui mockup su disco locale se rifiuti; su Codex, dove `claude.ai/design` non è disponibile, offre di passare a `stitch` prima di ripiegare sul disco locale.
29
+ > **trailhead è self-contained** nel senso che ha **zero dipendenze da plugin esterni**: gli agent di trailhead e i built-in dell'host vanno bene, e nessun'altra skill o plugin è richiesta. Wayfinder e GSD sono *ispirazione*, non dipendenze. Ogni tecnica che quei sistemi impacchettano come skill separata (grilling, TDD, debugging sistematico, codebase mapping, code review) è **integrata qui come protocollo inline**. Il core di trailhead non invoca nessun'altra skill; ogni tecnica del motore dispatcha al **proprio agent `trailhead-*`** (`trailhead-executor`, `trailhead-plan`, `trailhead-research`, `trailhead-code-review`, `trailhead-debug`, più `trailhead-fix` e `trailhead-codebase-map`), scritto una volta come file `agents/trailhead-*.md` versionato e **proiettato su ogni host** (su Codex diventa `~/.codex/agents/trailhead-*.toml` generato dalla stessa sorgente). Questi agent sono **thin** (identità + tool policy + un modello guidato dalla config, con il protocollo della tecnica iniettato allo spawn) e girano sul toolkit di subagent nativo dell'host (il tool `Agent` integrato di Claude Code, oppure il toolkit `multi_agent` di Codex). L'unica cosa da installare è trailhead stesso. C'è un'unica eccezione opt-in: la modalità mockup hosted. Quando abilitata, `artifacts` costruisce il mockup come canvas Design **Artifact** su claude.ai tramite il tool `Artifact` integrato in Claude Code (solo Claude Code, niente da installare), con il tuo design system installato sul canvas. Una seconda modalità hosted, `stitch`, usa l'MCP Google Stitch e funziona sia su **Claude Code sia su Codex**, quindi è l'opzione cross-host; se il suo MCP non è connesso, offre un'installazione una tantum e ripiega sui mockup su disco locale se rifiuti. Dove il tool `Artifact` non c'è (Codex, sessioni con API key), offre di passare a `stitch` prima di ripiegare sul disco locale.
30
30
 
31
31
  Le scelte di design che ne derivano:
32
32
 
@@ -70,7 +70,7 @@ npx @marcomigozzi/trailhead --dir=<path> # punta a una config dir specifica
70
70
  ```
71
71
  Su **Claude Code** copia la skill (+ le sue `references/`), i comandi `/trailhead:*`, gli hook (in `hooks/`, registrati in `settings.json`) incluso un **update check** al SessionStart, e i template di label-guard + statusline, in modo idempotente.
72
72
 
73
- Su **Codex CLI** (`--codex`) proietta una skill nativa Codex invocata come **`$trailhead`** (`$trailhead work`, `$trailhead new "idea"`, …), una skill sottile **`$trailhead-<verb>`** per ogni verbo per la discoverability, le sei guardrail come **hook** nativi di Codex (`~/.codex/hooks.json`, abilitando `features.hooks`; la search guard è solo per Claude Code e non è proiettata su Codex), e i pin di modello per-tecnica da **`models.codex.*`** in `~/.codex/agents/`. Serve Codex **0.145.0+** (l'installer fa un gate su `codex --version`). La modalità mockup `claude.ai/design` non è disponibile su Codex; lì l'opzione hosted è la modalità cross-host `design: stitch` (MCP Google Stitch), con il disco locale come ripiego.
73
+ Su **Codex CLI** (`--codex`) proietta una skill nativa Codex invocata come **`$trailhead`** (`$trailhead work`, `$trailhead new "idea"`, …), una skill sottile **`$trailhead-<verb>`** per ogni verbo per la discoverability, le sei guardrail come **hook** nativi di Codex (`~/.codex/hooks.json`, abilitando `features.hooks`; la search guard è solo per Claude Code e non è proiettata su Codex), e i pin di modello per-tecnica da **`models.codex.*`** in `~/.codex/agents/`. Serve Codex **0.145.0+** (l'installer fa un gate su `codex --version`). La modalità mockup `artifacts` (il tool `Artifact` di Claude Code) non è disponibile su Codex; lì l'opzione hosted è la modalità cross-host `design: stitch` (MCP Google Stitch), con il disco locale come ripiego.
74
74
 
75
75
  Ri-esegui l'install per aggiornare, oppure esegui **`/trailhead:update`** (Claude) / **`$trailhead update`** (Codex) da dentro l'agente: rileva come trailhead è stato installato e installa la versione più recente dove è sicuro farlo (un `git pull` per un dev-symlink, una ri-esecuzione `npx` per npm, o `/plugin update` per il plugin). Quando esiste una versione più recente, la statusline mostra un flag `⬆ trailhead <version>` (Claude).
76
76
 
@@ -130,7 +130,7 @@ Frontier iniziale = ①③④, tre persone possono partire in parallelo. Poi:
130
130
  - **① research** → un subagent legge la documentazione, restituisce un finding pronto per la decisione, chiude → sblocca ②.
131
131
  - **② decision** → dirama le opzioni, grill per scegliere native vs custom, registra il perché.
132
132
  - **③ task** → l'agente ti consegna una checklist (servono i *tuoi* account Google/GitHub); tu registri le app, lui registra dove vivono le credenziali.
133
- - **④ prototype** → una schermata di login grezza (sul progetto claude.ai/design configurato), approvata prima del codice UI.
133
+ - **④ prototype** → una schermata di login grezza (sul canvas Artifacts configurato), approvata prima del codice UI.
134
134
  - Con ②③④ chiusi, **⑤ build** si diploma → discuss → plan → execute (commit atomici, TDD ai seam dell'auth) → verify (test + code review + acceptance: chiesto chi guida, l'agente va AI-driven e guida il browser attraverso il vero flusso di login).
135
135
  - Dopo il rilascio noti un redirect sbagliato in prod → `/trailhead:bug --of ⑤ "GitHub redirect goes to localhost"` → un nuovo ticket che porta `Regression of: ⑤`, lavorato repro → diagnose → fix → verify. ⑤ resta chiuso.
136
136
 
@@ -229,7 +229,7 @@ Ogni tipo ha il proprio motore inline: nessuna skill esterna viene invocata.
229
229
  |---|---|---|---|
230
230
  | 🧭 `decision` | una scelta | HITL | diverge le opzioni se non chiare, poi grill per convergere su una |
231
231
  | 🔬 `research` | un fatto | AFK | un subagent su un branch usa-e-getta (l'unico tipo eseguito in parallelo) |
232
- | 🎨 `prototype` | una direzione approvata | HITL | un artefatto grezzo usa-e-getta a cui reagire; le schermate UI passano da qui (disco, o un progetto claude.ai/design configurato) prima del codice UI |
232
+ | 🎨 `prototype` | una direzione approvata | HITL | un artefatto grezzo usa-e-getta a cui reagire; le schermate UI passano da qui (disco, un canvas Artifacts, o Stitch) prima del codice UI |
233
233
  | 🔨 `build` | codice funzionante | HITL/AFK | `discuss → plan → execute → verify`: commit atomici, TDD ai seam, **prima un mockup per la UI rivolta all'utente** (tecnica Prototype, gated da `design.approval`), code review + acceptance testing (chiede chi guida, AI o umano, poi browser-drive o UAT conversazionale passo-passo) |
234
234
  | 🐛 `bug` | codice corretto | HITL/AFK | `repro → diagnose → fix → verify`; un difetto in lavoro chiuso è un ticket *nuovo* (`Regression of:`), non una riapertura |
235
235
  | 🔧 `task` | un cambiamento di stato esterno | HITL/AFK | lavoro manuale che sblocca una decision (provisioning accessi, spostamento dati, iscrizioni) |
@@ -304,8 +304,9 @@ Il passo **📊 statusline** offre di installare la status bar di trailhead per
304
304
  |---|---|---|
305
305
  | `ticket.language` | un codice ISO 639-1 (**`en`**) | la lingua in cui trailhead **scrive** la sua prosa GitHub e le descrizioni dei commit, disaccoppiata dalla lingua in cui conversa |
306
306
  | `models.{plan,execute,research,review,debug,verify,codebase-map}` | un id modello completo **versionato** (**inherit session**) | quale modello esegue ogni attività; `plan` ed `execute` sono sempre impostati separatamente |
307
- | `design` | **`disk`** \| `claude.ai/design` \| `stitch` | dove vanno i mockup UI: HTML usa-e-getta locale, claude.ai/design via l'MCP ufficiale Claude Design di Anthropic, o Google Stitch (cross-host, via l'MCP Stitch) |
308
- | `design.surface` | **`canvas`** \| `design-system` | sotto `claude.ai/design` o `stitch`, quale superficie: un progetto canvas (default) o un progetto design-system via `/design-sync` |
307
+ | `design` | **`disk`** \| `artifacts` \| `stitch` | dove vanno i mockup UI: HTML usa-e-getta locale, un canvas Design **Artifact** su claude.ai (solo Claude Code), o Google Stitch (cross-host, via l'MCP Stitch). Il vecchio valore `claude.ai/design` viene letto come `artifacts` |
308
+ | `design.surface` | **`canvas`** \| `design-system` | solo `stitch`: un progetto Stitch di schermate (default) o un design system Stitch condiviso |
309
+ | `design.system` | URL di un Design System Artifact | solo `artifacts`: il design system installato sul canvas dei mockup (chiesto alla prima schermata se non impostato) |
309
310
  | `design.approval` | **`explicit`** \| `auto` | attendi l'approvazione del mockup prima del codice UI, o procedi senza bloccare |
310
311
  | `tdd` | **`seams`** \| `on` \| `off` | come il motore `build` testa |
311
312
  | `acceptance.browser` | **`auto`** \| `on` \| `off` | guida il browser in Verify (dopo aver chiesto chi guida, AI o umano); `off` esegue comunque controlli AI-driven via comandi, e ti accompagna in una UAT conversazionale per ciò che solo tu puoi fare (passo-passo in chat, non una checklist da fare da solo) |
@@ -330,14 +331,13 @@ Esempio di file di config (la stessa forma funziona per il `.trailhead/config.js
330
331
  { "ticket": { "language": "en" }, "models": { "plan": "claude-opus-5-5", "execute": "claude-sonnet-5-5" }, "tdd": "seams", "acceptance": { "browser": "auto" } }
331
332
  ```
332
333
 
333
- **Design mockups.** `design: disk` (il default) deposita un mockup HTML statico usa-e-getta accanto al codice e lo collega dal ticket. `design: claude.ai/design` invece costruisce il mockup su claude.ai/design (canvas tramite la skill integrata `/design` o un progetto creato a mano nella web app; design-system tramite l'**MCP ufficiale Claude Design** di Anthropic, `claude mcp add --scope user --transport http claude-design https://api.anthropic.com/v1/design/mcp`, accedi con `/design-login`), dove lo affini visivamente, e `design: stitch` usa l'**MCP Google Stitch** (`claude mcp add --scope user --transport http stitch https://stitch.googleapis.com/mcp`), il generatore UI di Google basato su Gemini che gira sia su **Claude Code sia su Codex** (l'opzione hosted cross-host). Entrambe onorano `design.surface`:
334
+ **Design mockups.** `design: disk` (il default) deposita un mockup HTML statico usa-e-getta accanto al codice e lo collega dal ticket. `design: artifacts` costruisce il mockup come **canvas Design Artifact** su claude.ai, tramite il tool `Artifact` integrato in Claude Code (niente da installare), dove lo affini visivamente, lo commenti e lo esporti; `design: stitch` usa l'**MCP Google Stitch** (`claude mcp add --scope user --transport http stitch https://stitch.googleapis.com/mcp`), il generatore UI di Google basato su Gemini che gira sia su **Claude Code sia su Codex** (l'opzione hosted cross-host).
334
335
 
335
- - **`canvas`** (default): una schermata singola a cui reagire, modificabile ed esportabile come prototipo live. Sotto `claude.ai/design` è la skill integrata `/design` (pubblicata come Artifact) o un progetto claude.ai/design creato a mano nella web app; sotto `stitch` è un progetto Stitch.
336
- - **`design-system`**: un progetto design-system guidato da **DesignSync** (la skill `/design-sync` più l'MCP `claude-design`), per una libreria di componenti condivisa tenuta in sync.
336
+ Con **`artifacts`**, alla prima schermata UI trailhead aggancia un canvas: **sceglierne uno esistente**, **incollare un URL**, oppure **crearne uno nuovo** (ti chiede il nome), e ne mette in cache l'URL in `design.project`. Ogni schermata (e ogni variante) è una propria tavola, raggruppata in una pagina del canvas per ticket; il design system in `design.system` (quello predefinito del tuo account, o quello che scegli) viene installato sul canvas, così colori, tipografia e componenti sono a portata di mano. I messaggi di approvazione riportano l'URL del canvas più il nome di ogni tavola. Una volta che approvi, trailhead **rilegge** le tavole (nel caso tu le abbia modificate live) prima di scrivere qualsiasi codice UI.
337
337
 
338
- Alla prima schermata UI, trailhead si aggancia a una superficie: per un progetto **Stitch** o un **design-system claude.ai/design** può **sceglierne uno esistente**, **incollare un URL**, oppure **crearne uno nuovo** (ti chiede il nome); per una **canvas claude.ai/design** non esiste la creazione via MCP, quindi usa la skill `/design` (un **Artifact**) o un progetto web-app di cui incolli l'URL `/p/<id>`. Fa il caching dell'id/URL scelto in `design.project`; un progetto già in cache da prima mantiene la superficie `design-system` a meno che tu non imposti `design.surface`, così i setup esistenti non cambiano. Ogni schermata viene aggiunta lì, e la sua URL è collegata dal ticket. Una volta che approvi, trailhead **ri-fetcha** il design corrente (nel caso tu l'abbia modificato live) prima di scrivere qualsiasi codice UI.
338
+ Con **`stitch`**, `design.surface` sceglie un progetto Stitch di schermate (`canvas`, default) o un design system Stitch condiviso (`design-system`); trailhead lo sceglie, incolla o crea allo stesso modo, e offre una volta di installare l'MCP Stitch se non è connesso (se rifiuti, ripiega sul disco locale).
339
339
 
340
- Se l'MCP della modalità hosted non è connesso, trailhead **offre di installarlo una volta** (`claude mcp add ...`); se rifiuti, ripiega sul disco locale. (La superficie **canvas** di `claude.ai/design` non richiede MCP, quindi per lei non viene offerto nulla; solo la superficie **design-system** ha l'offerta di installazione.) Su Codex `claude.ai/design` non è disponibile, quindi trailhead offre di passare a `stitch` (cross-host) prima di ripiegare sul disco locale. `design.approval` decide se il build attende il tuo esplicito via libera (`explicit`), o procede subito dopo aver mostrato il mockup (`auto`); non tocca l'offerta di installazione una tantum, che compare in entrambi i casi.
340
+ **Passare da claude.ai/design.** Il sito standalone di Claude Design chiude il 14/12/2026 e i suoi design ora vivono in Claude come Artifacts. Una config che dice ancora `design: claude.ai/design` continua a funzionare come `artifacts` (trailhead te lo dice una volta e offre di riscrivere la chiave), ma un progetto claude.ai/design in cache non è riutilizzabile: migra i design system dal banner della pagina Artifacts e lascia che trailhead agganci un nuovo canvas. Dove il tool `Artifact` non c'è (Codex, o una sessione con API key), trailhead offre di passare a `stitch` prima di ripiegare sul disco locale. `design.approval` decide se il build attende il tuo esplicito via libera (`explicit`), o procede subito dopo aver mostrato il mockup (`auto`).
341
341
 
342
342
  ---
343
343
 
package/README.md CHANGED
@@ -26,7 +26,7 @@ Two approaches to agent-driven project work each nail one half of the problem:
26
26
 
27
27
  Working across both, one pattern kept recurring: **use a Wayfinder-style map and onboarding to decide the shape of the work, then a GSD-style engine to build each piece, without ever leaving the issue tracker.** `trailhead` is that pattern made into a set of cohesion-clustered skills over a shared core, its own self-contained take on both ideas rather than a wrapper around either.
28
28
 
29
- > **trailhead is self-contained** in the sense that it has **zero external-plugin dependencies**: trailhead-owned agents and the host's built-ins are fine, and no other skill or plugin is required. Wayfinder and GSD are *inspiration*, not dependencies. Every technique those systems package as a separate skill (grilling, TDD, systematic debugging, codebase mapping, code review) is **built in here as an inline protocol**. trailhead's core invokes no other skill; each engine technique dispatches to **trailhead's own `trailhead-*` agent** (`trailhead-executor`, `trailhead-plan`, `trailhead-research`, `trailhead-code-review`, `trailhead-debug`, plus `trailhead-fix` and `trailhead-codebase-map`), authored once as a committed `agents/trailhead-*.md` file and **projected to each host** (Codex gets `~/.codex/agents/trailhead-*.toml` generated from that same source). These agents are **thin** (identity + tool policy + a config-driven model, with the technique protocol injected at spawn) and run on the host's native subagent toolkit (Claude Code's built-in `Agent` tool, or Codex's `multi_agent` toolkit). The only thing to install is trailhead itself. There is one opt-in exception: hosted mockup mode. When enabled, `claude.ai/design` builds the mockup on claude.ai/design (Claude only): by default a canvas (the built-in `/design` skill published as an Artifact, or a hand-made web-app project, not MCP-driven) or, for a shared component library, a design-system project via DesignSync (the `claude-design` MCP plus the `/design-sync` skill, the only MCP-driven surface). A third mode, `stitch`, uses the Google Stitch MCP and works on **both Claude Code and Codex**, so it's the cross-host hosted option. If a hosted mode's MCP isn't connected, it offers a one-time install and falls back to local-disk mockups if you decline; on Codex, where `claude.ai/design` isn't available, it offers to switch to `stitch` before falling to local disk.
29
+ > **trailhead is self-contained** in the sense that it has **zero external-plugin dependencies**: trailhead-owned agents and the host's built-ins are fine, and no other skill or plugin is required. Wayfinder and GSD are *inspiration*, not dependencies. Every technique those systems package as a separate skill (grilling, TDD, systematic debugging, codebase mapping, code review) is **built in here as an inline protocol**. trailhead's core invokes no other skill; each engine technique dispatches to **trailhead's own `trailhead-*` agent** (`trailhead-executor`, `trailhead-plan`, `trailhead-research`, `trailhead-code-review`, `trailhead-debug`, plus `trailhead-fix` and `trailhead-codebase-map`), authored once as a committed `agents/trailhead-*.md` file and **projected to each host** (Codex gets `~/.codex/agents/trailhead-*.toml` generated from that same source). These agents are **thin** (identity + tool policy + a config-driven model, with the technique protocol injected at spawn) and run on the host's native subagent toolkit (Claude Code's built-in `Agent` tool, or Codex's `multi_agent` toolkit). The only thing to install is trailhead itself. There is one opt-in exception: hosted mockup mode. When enabled, `artifacts` builds the mockup as a Design canvas **Artifact** on claude.ai through Claude Code's built-in `Artifact` tool (Claude Code only, nothing to install), with your design system installed on the canvas. A second hosted mode, `stitch`, uses the Google Stitch MCP and works on **both Claude Code and Codex**, so it's the cross-host option; if its MCP isn't connected, it offers a one-time install and falls back to local-disk mockups if you decline. Where the `Artifact` tool isn't available (Codex, API-key sessions), it offers to switch to `stitch` before falling to local disk.
30
30
 
31
31
  The design choices that fall out of it:
32
32
 
@@ -70,7 +70,7 @@ npx @marcomigozzi/trailhead --dir=<path> # target a specific config dir
70
70
  ```
71
71
  On **Claude Code** it copies the skill (+ its `references/`), the `/trailhead:*` commands, the hooks (into `hooks/`, registered in `settings.json`) including a SessionStart **update check**, and the label-guard + statusline templates, idempotently.
72
72
 
73
- On **Codex CLI** (`--codex`) it projects a native Codex skill invoked as **`$trailhead`** (`$trailhead work`, `$trailhead new "idea"`, …), one thin **`$trailhead-<verb>`** skill per verb for discoverability, the six guardrails as native Codex **hooks** (`~/.codex/hooks.json`, enabling `features.hooks`; the search guard is Claude-Code-only and isn't projected to Codex), and per-technique subagent model pins from **`models.codex.*`** into `~/.codex/agents/`. Codex **0.145.0+** is required (the installer gates on `codex --version`). The `claude.ai/design` mockup mode isn't available on Codex; the cross-host `design: stitch` mode (Google Stitch MCP) is the hosted option there, with local disk as the fallback.
73
+ On **Codex CLI** (`--codex`) it projects a native Codex skill invoked as **`$trailhead`** (`$trailhead work`, `$trailhead new "idea"`, …), one thin **`$trailhead-<verb>`** skill per verb for discoverability, the six guardrails as native Codex **hooks** (`~/.codex/hooks.json`, enabling `features.hooks`; the search guard is Claude-Code-only and isn't projected to Codex), and per-technique subagent model pins from **`models.codex.*`** into `~/.codex/agents/`. Codex **0.145.0+** is required (the installer gates on `codex --version`). The `artifacts` mockup mode (Claude Code's `Artifact` tool) isn't available on Codex; the cross-host `design: stitch` mode (Google Stitch MCP) is the hosted option there, with local disk as the fallback.
74
74
 
75
75
  Re-run the install to update, or run **`/trailhead:update`** (Claude) / **`$trailhead update`** (Codex) from inside the agent: it detects how trailhead was installed and installs the newer version where that is safe (a `git pull` for a dev-symlink, an `npx` re-run for npm, or `/plugin update` for the plugin). When a newer version exists, the statusline shows a `⬆ trailhead <version>` flag (Claude).
76
76
 
@@ -130,7 +130,7 @@ Initial frontier = ①③④, three people can start in parallel. Then:
130
130
  - **① research** → a subagent reads the docs, returns a decision-ready finding, closes → unblocks ②.
131
131
  - **② decision** → diverge the options, grill to choose native vs custom, record the why.
132
132
  - **③ task** → the agent hands you a checklist (it needs *your* Google/GitHub accounts); you register the apps, it records where the credentials live.
133
- - **④ prototype** → a rough login screen (on the configured claude.ai/design project), approved before UI code.
133
+ - **④ prototype** → a rough login screen (on the configured Artifacts canvas), approved before UI code.
134
134
  - With ②③④ closed, **⑤ build** graduates → discuss → plan → execute (atomic commits, TDD at the auth seams) → verify (tests + code review + acceptance: asked who drives, the agent goes AI-driven and drives the browser through the real login flow).
135
135
  - After it ships you spot a wrong redirect in prod → `/trailhead:bug --of ⑤ "GitHub redirect goes to localhost"` → a new ticket carrying `Regression of: ⑤`, worked repro → diagnose → fix → verify. ⑤ stays closed.
136
136
 
@@ -229,7 +229,7 @@ Each type has its own inline engine: no external skill is invoked.
229
229
  |---|---|---|---|
230
230
  | 🧭 `decision` | a choice | HITL | diverge the options if unclear, then grill to converge on one |
231
231
  | 🔬 `research` | a fact | AFK | a subagent on a throwaway branch (the only type run in parallel) |
232
- | 🎨 `prototype` | an approved direction | HITL | a rough throwaway artifact to react to; UI screens go through this (disk, or a configured claude.ai/design project) before UI code |
232
+ | 🎨 `prototype` | an approved direction | HITL | a rough throwaway artifact to react to; UI screens go through this (disk, an Artifacts canvas, or Stitch) before UI code |
233
233
  | 🔨 `build` | working code | HITL/AFK | `discuss → plan → execute → verify`: atomic commits, TDD at seams, **a mockup first for user-facing UI** (Prototype technique, gated by `design.approval`), code review + acceptance testing (asks who drives, AI or human, then browser-drive or conversational step-by-step UAT) |
234
234
  | 🐛 `bug` | corrected code | HITL/AFK | `repro → diagnose → fix → verify`; a defect in closed work is a *new* ticket (`Regression of:`), not a reopen |
235
235
  | 🔧 `task` | an external state change | HITL/AFK | manual work that unblocks a decision (provision access, move data, sign up) |
@@ -304,8 +304,9 @@ The **📊 statusline** step offers to install trailhead's Claude Code status ba
304
304
  |---|---|---|
305
305
  | `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 |
306
306
  | `models.{plan,execute,research,review,debug,verify,codebase-map}` | a full **versioned** model id (**inherit session**) | which model runs each activity; `plan` and `execute` are always set separately |
307
- | `design` | **`disk`** \| `claude.ai/design` \| `stitch` | where UI mockups go: local throwaway HTML, claude.ai/design via Anthropic's official Claude Design MCP, or Google Stitch (cross-host, via the Stitch MCP) |
308
- | `design.surface` | **`canvas`** \| `design-system` | under `claude.ai/design` or `stitch`, which surface: a canvas project (default) or a design-system project via `/design-sync` |
307
+ | `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` |
308
+ | `design.surface` | **`canvas`** \| `design-system` | `stitch` only: a Stitch project of screens (default) or a shared Stitch design system |
309
+ | `design.system` | Design System Artifact URL | `artifacts` only: the design system installed on the mockup canvas (asked at the first screen if unset) |
309
310
  | `design.approval` | **`explicit`** \| `auto` | wait for mockup approval before UI code, or proceed without blocking |
310
311
  | `tdd` | **`seams`** \| `on` \| `off` | how the `build` engine tests |
311
312
  | `acceptance.browser` | **`auto`** \| `on` \| `off` | drive the browser in Verify (after asking who drives, AI or human); `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) |
@@ -330,14 +331,13 @@ Example config file (the same shape works for the project `.trailhead/config.jso
330
331
  { "ticket": { "language": "en" }, "models": { "plan": "claude-opus-5-5", "execute": "claude-sonnet-5-5" }, "tdd": "seams", "acceptance": { "browser": "auto" } }
331
332
  ```
332
333
 
333
- **Design mockups.** `design: disk` (the default) drops a throwaway static HTML mockup next to the code and links it from the ticket. `design: claude.ai/design` instead builds the mockup on claude.ai/design (canvas via the built-in `/design` skill or a hand-made web-app project; design-system via Anthropic's **official Claude Design MCP**, `claude mcp add --scope user --transport http claude-design https://api.anthropic.com/v1/design/mcp`, sign in with `/design-login`), where you refine it visually, and `design: stitch` uses the **Google Stitch MCP** (`claude mcp add --scope user --transport http stitch https://stitch.googleapis.com/mcp`), Google's Gemini-powered UI generator that runs on **both Claude Code and Codex** (the cross-host hosted option). Both honour `design.surface`:
334
+ **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), where you refine it visually, comment on it and export it; `design: stitch` uses the **Google Stitch MCP** (`claude mcp add --scope user --transport http stitch https://stitch.googleapis.com/mcp`), Google's Gemini-powered UI generator that runs on **both Claude Code and Codex** (the cross-host hosted option).
334
335
 
335
- - **`canvas`** (default): a one-off screen to react to, editable and exportable as a live prototype. Under `claude.ai/design` it's the built-in `/design` skill (published as an Artifact) or a claude.ai/design project made by hand in the web app; under `stitch` it's a Stitch project.
336
- - **`design-system`**: a design-system project driven by **DesignSync** (the `/design-sync` skill plus the `claude-design` MCP), for a shared component library kept in sync.
336
+ With **`artifacts`**, on the first UI screen trailhead attaches a canvas: **pick an existing one**, **paste a URL**, or **create a new one** (it asks you for the name), and caches its URL in `design.project`. Each screen (and each variant) is its own artboard, grouped in a canvas page per ticket; the design system in `design.system` (your account's default one, or the one you pick) is installed on the canvas so its colours, type and components are at hand. Approval messages carry the canvas URL plus the name of each artboard. Once you approve, trailhead **re-fetches** the artboards (in case you edited them live) before writing any UI code.
337
337
 
338
- On the first UI screen, trailhead attaches to a surface: for a **Stitch** project or a **claude.ai/design design-system**, it can **pick an existing one**, **paste a URL**, or **create a new one** (it asks you for the name); for a **claude.ai/design canvas** there is no create-via-MCP, so it uses the `/design` skill (an **Artifact**) or a web-app project whose `/p/<id>` URL you **paste**. It caches the chosen id/URL in `design.project`; a project already cached from before keeps the `design-system` surface unless you set `design.surface`, so existing setups don't change. Each screen is added there, and its URL is linked from the ticket. Once you approve, trailhead **re-fetches** the current design (in case you edited it live) before writing any UI code.
338
+ With **`stitch`**, `design.surface` picks a Stitch project of screens (`canvas`, default) or a shared Stitch design system (`design-system`); trailhead picks, pastes or creates it the same way, and offers once to install the Stitch MCP if it isn't connected (decline and it falls back to local disk).
339
339
 
340
- If a hosted mode's MCP isn't connected, trailhead **offers to install it once** (`claude mcp add ...`); decline and it falls back to local disk. (The `claude.ai/design` **canvas** surface needs no MCP, so nothing is offered for it; only the **design-system** surface has an install offer.) On Codex, `claude.ai/design` isn't available, so trailhead offers to switch to `stitch` (cross-host) before falling to local disk. `design.approval` decides whether the build waits for your explicit go-ahead (`explicit`), or proceeds right after surfacing the mockup (`auto`); it doesn't affect the one-time install offer, which prompts either way.
340
+ **Moving from claude.ai/design.** The standalone Claude Design site closes on 2026-12-14 and its designs now live in Claude as Artifacts. A config that still says `design: claude.ai/design` keeps working as `artifacts` (trailhead tells you once and offers to rewrite the key), but a cached claude.ai/design project can't be reused: migrate your design systems from the Artifacts page banner and let trailhead attach a new canvas. Where the `Artifact` tool isn't available (Codex, or an API-key session), trailhead offers to switch to `stitch` before falling to local disk. `design.approval` decides whether the build waits for your explicit go-ahead (`explicit`), or proceeds right after surfacing the mockup (`auto`).
341
341
 
342
342
  ---
343
343
 
@@ -115,8 +115,8 @@ The engine's \`/clear\` is Codex's \`/new\` (start a fresh session). Command ref
115
115
  ## F. Lifecycle hooks (native Codex hooks)
116
116
  Codex has a hook bus, so trailhead's guardrails run as **real Codex hooks**, not degraded prose. The installer registers them in \`~/.codex/hooks.json\`: commit-guard, secret-guard, install-guard and body-guard as \`PreToolUse\` (matcher \`Bash\`) hooks that can veto the command before it runs, secret-read-guard as a \`PreToolUse\` (matcher \`Read|Bash\`) hook that denies reads of \`.env\`/\`.env.*\`/\`.secrets\`, the injection-scanner as a \`PostToolUse\` (matcher \`Bash\`) advisory, mockup-link-stop as a \`Stop\` hook (when your final reply asks to approve a mockup without carrying its link, it continues the turn so you rewrite the ask with the URL or file path in the prose), and check-update as a \`SessionStart\` hook. On Codex, file reads happen through shell commands rather than a native Read-tool event, so the secret-read guard's enforcement here runs via its **Bash** arm (protection is not lost); the \`Read\` half of its matcher is a Claude-Code-native path, registered on Codex too only so it fires without changes if a future Codex version adds an equivalent event. search-guard is Claude-Code-specific (it only prevents arming Claude's \`Read()\` deny rule under bypass permissions, a mechanism Codex lacks), so it is not projected to Codex at all. They use the same wire format they use on Claude Code (JSON on stdin, a \`decision\`/\`permissionDecision\` verdict on stdout), which Codex accepts. The host-independent git \`commit-msg\` hook is still installed at repo first-use as well (defence in depth), exactly as on Claude. Codex gates hooks behind \`features.hooks = true\` and reviews them for trust on first start: the installer enables the flag, and Codex will ask you to trust trailhead's hooks the next time it starts.
117
117
 
118
- ## G. Design / UI mockups -> local disk
119
- The \`claude.ai/design\` mockup mode (DesignSync: the \`claude_design\` MCP + the \`/design-sync\` skill) does not exist on Codex, so it **collapses to local-disk mockups** here: whatever \`config.design\` says, the Prototype technique's \`disk\` path is the only one available. Produce a throwaway static HTML mockup next to the code, link it from the ticket, and never attempt DesignSync / claude.ai/design on Codex (there is no \`claude_design\` MCP or \`/design-sync\` skill to call). \`config.design.approval\` still applies unchanged: \`explicit\` waits for the user's go-ahead before any UI code, \`auto\` surfaces the mockup and proceeds.
118
+ ## G. Design / UI mockups: artifacts -> stitch offer, else local disk
119
+ The \`artifacts\` mockup mode (a Design canvas Artifact built with Claude Code's \`Artifact\` tool; the legacy \`claude.ai/design\` value means the same) does not exist on Codex: there is no \`Artifact\` tool here. When \`config.design\` names it, follow the Prototype technique's fallback: **offer once to switch this project to \`design: stitch\`** (the Google Stitch MCP runs on Codex too), and only on decline produce a throwaway static HTML mockup next to the code (\`disk\`), link it from the ticket, and say why. Never try to create or edit an Artifact on Codex. \`config.design.approval\` still applies unchanged: \`explicit\` waits for the user's go-ahead before any UI code, \`auto\` surfaces the mockup and proceeds.
120
120
 
121
121
  ## H. Shell timeouts & background jobs (plan-review's external CLIs)
122
122
  The **Cross-AI plan review** technique invokes each external reviewer CLI (\`codex exec\`, \`gemini -p\`, \`qwen -p\`, …) through Claude Code's **Bash tool**, and tells the engine to beat that tool's ~2-minute default cut by setting its \`timeout\` parameter to the 10-minute max, or launching the call with \`run_in_background: true\` and collecting it later. Those are Claude Bash-tool knobs with no Codex equivalent, so map the *intent* onto Codex's own shell/exec tool. Reviews never block the session (the engine's hard cross-host default), so **the default is to background the reviewers** and collect them by polling, never block on them: launch each with a trailing \`&\` (or your shell tool's background form), **redirect its stdin from \`/dev/null\` and its output to a file** (\`codex exec … "<prompt>" < /dev/null > out.txt 2>&1 &\`), and poll/collect when it finishes, so several reviewers run in parallel instead of serially eating the wall-clock; or wrap each reviewer invocation in a §D subagent so the long-running call sits behind the multi_agent poll loop. Where a reviewer must run synchronously instead, give that call its **own long timeout** (the \`timeout_ms\` / equivalent on Codex's shell/exec tool, set to several minutes, never the short default), so a reviewer that legitimately runs for minutes is not cut mid-review. Either way plan-review's own rule is unchanged: never rely on a short default timeout, retry once at the wide margin, then drop a still-slow reviewer rather than let it wedge the build. **Close the reviewer's stdin when backgrounding it** (\`< /dev/null\`): \`codex exec\` reads additional prompt input from stdin and blocks on EOF, so a backgrounded reviewer that inherits an open or attached stdin sits idle at "Reading additional input from stdin..." (0% CPU) forever instead of running (passing the prompt as an argument does not exempt it). Guard the poll loop too: a reviewer pinned at 0% CPU with no output past a threshold is stuck, so surface it and drop it after the one retry rather than reporting "still running" indefinitely. This is the external-CLI **shell** path; §D covers the separate **subagent** (\`wait_agent\`) path, and the two are distinct (an external reviewer CLI is a plain shell call, not a spawned Codex subagent).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marcomigozzi/trailhead",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "description": "Start and drive large projects as a map of tickets on GitHub Issues. Map-based onboarding + a discuss→plan→execute→verify engine, all on the Issues. Installs the trailhead skill, commands, and hooks into your agent's config dir.",
5
5
  "bin": {
6
6
  "trailhead": "bin/trailhead.js"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trailhead",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "description": "Start and drive large projects as a map of tickets on GitHub Issues, resolving one at a time. Map-based onboarding + a discuss→plan→execute→verify engine with atomic commits, all on the Issues. Ships as a dispatcher plus cohesion-clustered skills over a shared core; depends on nothing beyond an authenticated gh CLI.",
5
5
  "author": {
6
6
  "name": "Marco Migozzi",
@@ -52,7 +52,7 @@ ok('mockup offer whose option description mentions approval is NOT an approval a
52
52
  header: 'Scope',
53
53
  options: [
54
54
  { label: 'Va bene così', description: 'Procedo con lo scope descritto' },
55
- { label: 'Prima un mockup', description: 'Disegno la pagina su claude.ai/design e attendo approvazione prima di scriverla' },
55
+ { label: 'Prima un mockup', description: 'Disegno la pagina su un canvas Artifacts e attendo approvazione prima di scriverla' },
56
56
  ],
57
57
  }],
58
58
  }));
@@ -68,7 +68,7 @@ ok('unrelated ask is not detected', !isMockupApprovalAsk({
68
68
  ok('malformed input is not detected', !isMockupApprovalAsk({}) && !isMockupApprovalAsk(null));
69
69
 
70
70
  // --- hasLink ---
71
- ok('https URL counts as a link', hasLink('Ecco: https://claude.ai/design/p/abc?file=faq.html'));
71
+ ok('https URL counts as a link', hasLink('Ecco: https://claude.ai/artifact/AbC123xyz'));
72
72
  ok('absolute html path counts as a link', hasLink('Mockup in /home/u/app/mockups/faq.html'));
73
73
  ok('relative html path counts as a link', hasLink('apri `mockups/faq.html`'));
74
74
  ok('markdown link to a file counts', hasLink('[faq](mockups/faq.html)'));
@@ -88,7 +88,7 @@ ok('prose right before the ask is collected', /pronto su MyApp/.test(proseBefore
88
88
 
89
89
  const linkBeforeTools = [
90
90
  userPrompt('lavora #12'),
91
- text('Mockup: https://claude.ai/design/p/abc'),
91
+ text('Mockup: https://claude.ai/artifact/AbC123xyz'),
92
92
  toolUse('Bash'),
93
93
  toolResult('ok'),
94
94
  text('Pronto.'),
@@ -125,7 +125,7 @@ function runHook(payload) {
125
125
  const r1 = runHook({ tool_name: 'AskUserQuestion', tool_input: approvalInput, transcript_path: writeTranscript(failing) });
126
126
  ok('approval ask without a link in the prose is blocked (exit 2)', r1.code === 2 && /MOCKUP_LINK_MISSING/.test(r1.out));
127
127
 
128
- const withLink = [...failing.slice(0, 4), text('Mockup: https://claude.ai/design/p/abc?file=faq.html'), failing[5]];
128
+ const withLink = [...failing.slice(0, 4), text('Mockup: https://claude.ai/artifact/AbC123xyz'), failing[5]];
129
129
  const r2 = runHook({ tool_name: 'AskUserQuestion', tool_input: approvalInput, transcript_path: writeTranscript(withLink) });
130
130
  ok('approval ask with a link in the prose is allowed', r2.code === 0 && r2.out.trim() === '');
131
131
 
@@ -19,7 +19,7 @@ const noLink = [
19
19
  '1. Approvo',
20
20
  '2. Chiedo modifiche',
21
21
  ].join('\n');
22
- const withLink = noLink.replace('pronto su MyApp', 'pronto: https://claude.ai/design/p/abc?file=faq.html');
22
+ const withLink = noLink.replace('pronto su MyApp', 'pronto: https://claude.ai/artifact/AbC123xyz');
23
23
 
24
24
  // --- isMockupApprovalMessage ---
25
25
  ok('IT approval reply is detected', isMockupApprovalMessage(noLink));
@@ -7,8 +7,9 @@ Effective config = built-in defaults ← global `~/.claude/trailhead/config.json
7
7
  | `models.{plan,execute,research,review,debug,verify,codebase-map}` | a model id (**Balanced-profile default**) | model for that activity; an unset key resolves to its default **Balanced** tier, see note |
8
8
  | `models.codex.{plan,execute,research,review,debug,verify,codebase-map}` | an OpenAI model id (**inherit session**) | per-activity subagent model on **Codex** (OpenAI ids), the honoured namespace there; independent of `models.*` (Claude ids); projected into `~/.codex/agents/trailhead-*.toml` and dispatched by `agent_type`. See note |
9
9
  | `ticket.language` | an ISO 639-1 code (**`en`**) | the language trailhead **writes** its GitHub prose in (ticket titles/bodies, engine comments, map body & commit descriptions), see note. Independent of the language the agent converses in |
10
- | `design` | **`disk`** \| `claude.ai/design` \| `stitch` | mode for UI mockups (**Prototype**). `disk` = throwaway local HTML (any host); `claude.ai/design` = create/edit the mockup on claude.ai/design via Anthropic's **official Claude Design MCP** (`claude mcp add --scope user --transport http claude-design https://api.anthropic.com/v1/design/mcp`, auth `/design-login`), **Claude only**; `stitch` = create/edit the mockup via the **Google Stitch MCP** (`claude mcp add --scope user --transport http stitch https://stitch.googleapis.com/mcp`), the **cross-host** hosted option (Claude Code **and** Codex). A hosted mode's projectId is created/reused at execution and cached in `design.project`; which surface it uses is `design.surface`. If the configured mode's MCP isn't connected, Prototype offers a one-time install before falling back (see Prototype). **On Codex** `claude.ai/design` isn't available, so Prototype **offers to switch to `stitch`** (cross-host) before degrading to `disk`; `stitch` and `disk` run on Codex unchanged |
11
- | `design.surface` | **`canvas`** \| `design-system` | under a hosted `design` mode (`claude.ai/design` or `stitch`), which surface the mockup lives on. `canvas` = a single surface of screens to react to (under `claude.ai/design`: a `/design` **Artifact** or a hand-made web-app project, **not** MCP-created; under `stitch`: a Stitch project), editable visually and exportable as a live prototype. `design-system` = push components into a shared design-system project (a `PROJECT_TYPE_DESIGN_SYSTEM` synced via DesignSync `/design-sync`, or a Stitch design system), for a shared component library. **Back-compat:** unset, a cached `design.project` infers `design-system` (that's what the key meant before this key existed); with no cached project, `canvas`. See Prototype |
10
+ | `design` | **`disk`** \| `artifacts` \| `stitch` | mode for UI mockups (**Prototype**). `disk` = throwaway local HTML (any host); `artifacts` = build the mockup as a **Design canvas Artifact** on claude.ai through Claude Code's built-in `Artifact` tool (no MCP, no login step), **Claude Code signed in with a claude.ai account only**; `stitch` = create/edit the mockup via the **Google Stitch MCP** (`claude mcp add --scope user --transport http stitch https://stitch.googleapis.com/mcp`), the **cross-host** hosted option (Claude Code **and** Codex). A hosted mode's canvas/project is created or reused at execution and cached in `design.project`. **Legacy:** `claude.ai/design` (the standalone Claude Design site, closing 2026-12-14) is read as `artifacts`, with a one-time notice and an offer to rewrite the key. Where the `Artifact` tool is missing (Codex, API-key sessions) Prototype **offers to switch to `stitch`** before degrading to `disk`; `stitch` and `disk` run on Codex unchanged |
11
+ | `design.surface` | **`canvas`** \| `design-system` | **`stitch` only**: which surface the mockup lives on. `canvas` = a Stitch project of screens to react to; `design-system` = push components into a shared Stitch design system. Ignored under `artifacts` (always a Design canvas; a design system is installed on it via `design.system`, never written to) and under `disk`. See Prototype |
12
+ | `design.system` | Design System Artifact URL (**unset**) | **`artifacts` only**: the design system installed on the mockup canvas (its tokens and, when it ships them, its components). Unset at the first screen: the account's default design system if one is marked, else trailhead lists them and asks (or none), then caches the pick here |
12
13
  | `design.approval` | **`explicit`** \| `auto` | must a mockup be explicitly approved before the build proceeds to UI code? |
13
14
  | `tdd` | **`seams`** \| `on` \| `off` | how the `build` engine tests |
14
15
  | `acceptance.browser` | **`auto`** \| `on` \| `off` | how **Acceptance testing** runs |
@@ -62,7 +63,7 @@ If a value is unset, it resolves to its **Balanced**-profile default for that ac
62
63
 
63
64
  **acceptance.browser.** The drive-mode ask (AI-driven vs human-driven, see the Acceptance testing technique) **always comes first, before any step runs**: no value of this key pre-answers it. This key only governs whether and how an AI-driven step uses the browser once that ask is answered AI-driven: `auto` (default) = browser-drive when `testing.webapp` + `testing.url` are set, or (when `testing.webapp` is set but `testing.url` is unset) first try to auto-detect the target URL (running dev server, package scripts, dev-server/framework config, project config) and propose it, driving against the accepted URL; when no URL can be determined, fall back per the Acceptance testing technique (ask the human for the URL, or the guided UAT for that step); `on` = always attempt browser-driving, auto-detecting the URL the same way when `testing.url` is unset; `off` = never drive a browser. **`off` disables *browser-driving*, not acceptance, and not AI-driven checking**: AI-driven still runs its non-browser checks via commands / the test suite for whatever steps allow it; only a step that genuinely needs the human (or the whole UAT, under human-driven) gets the guided UAT walkthrough. The Verify step honours this.
64
65
 
65
- **design.surface.** Under `design: claude.ai/design`, which Claude Design surface the mockup lives on. `canvas` (default) = a one-off screen to react to, edited visually and exportable as a live prototype; under `claude.ai/design` it is **not** MCP-driven (no MCP creates a regular canvas project): it's the built-in `/design` skill published as an **Artifact**, or a claude.ai/design project made by hand in the web app whose `/p/<id>` URL you paste. `design-system` = a `PROJECT_TYPE_DESIGN_SYSTEM` project driven by DesignSync (the `/design-sync` slice of the official Claude Design MCP), for a shared component library kept in sync. Unset, it infers from `design.project`: a cached project (which, before this key, was always a design system) means `design-system`; no cached project means `canvas`. The Prototype technique honours this; when the **`design-system`** surface's MCP isn't connected it **offers a one-time install** (`claude mcp add ... claude-design`, then `/design-login`) before falling to disk (the `canvas` surface needs no MCP, so no install offer). Under `design: stitch` the same key applies: `canvas` = a Stitch project with generated screens, `design-system` = a Stitch design system; the install offer and disk fallback work the same way (no intra-provider chain, the Stitch MCP either connects or falls to disk). Ignored under `design: disk`.
66
+ **design.surface / design.system.** Under `design: stitch`, `design.surface` picks the surface: `canvas` (default) = a Stitch project with generated screens, `design-system` = a Stitch design system; the install offer and disk fallback are in Prototype (the Stitch MCP either connects or falls to disk). Under `design: artifacts` there is one surface, a **Design canvas Artifact** (`design.project` = its URL), and `design.surface` is ignored; `design.system` names the **Design System Artifact** installed on that canvas, a read-only reference: screens are never pushed into it. **Back-compat:** a `design.project` left from the standalone claude.ai/design (a bare project id or a `claude.ai/design/p/<id>` URL) is not reusable; Prototype says so once and attaches a new canvas. Ignored under `design: disk`.
66
67
 
67
68
  **design.approval.** `explicit` (default) = a UI mockup must be **explicitly approved by the user** before the `build` engine writes any real UI code; surface the mockup and wait for a clear go-ahead. `auto` = surface the mockup and proceed without blocking on a confirmation (the user can still object). The Prototype technique honours this.
68
69
 
@@ -104,7 +105,7 @@ Example `config.json` (same shape for the project `.trailhead/config.json` and t
104
105
  - **The per-key questions (Manual path only): always two separate questions, one for `plan` and one for `execute`; never merge them into a single model pick.** Ask each as its own `AskUserQuestion` menu (current value pre-selected), and offer the **same versioned lineup** to both. Each option is a **full model id with its version**; never a bare family alias (`opus`/`sonnet`/`haiku`), which can't say *which* live version. Build the list from the models actually reachable **at setup time** (verify, don't trust this file verbatim), offering **at least the two most recent versions per family**, e.g. `claude-fable-5`, `claude-opus-5-5` / `claude-opus-5`, `claude-sonnet-5-5` / `claude-sonnet-5`, `claude-haiku-5-5` / `claude-haiku-4-5`, plus **inherit session** (the no-override option, the session model). If that lineup exceeds the menu's option cap, drill **family → version** or include a free-id "Other" so every recent version stays reachable. The rarer `research`/`review`/`debug`/`verify`/`codebase-map` sit behind an "Advanced" option, each its own separate choice, same versioned rule.
105
106
  - **Anti-pattern, never do this (in the Manual path):** a single screen whose options are *combined* plan+execute presets, e.g. `🧠 Plan 4.8 / Exec Sonnet 5`, `🚀 Tutto Opus 5`, `Plan Opus 5 / Exec Sonnet 5`. That bundles the two decisions into one pick. Forbidden. In Manual, Plan is asked, answered, and only then is Execute asked, as a second menu: two questions, two answers, always. (A **named tier profile** applied whole is **not** this anti-pattern: it is a coherent per-key tier assignment chosen deliberately, not an ad-hoc plan+execute combo, which is why picking a profile is terminal.)
106
107
  - **On Codex (host-detected), the Manual path asks `models.codex.*` instead of the Claude lineup.** Same discipline: `plan` and `execute` as two separate `AskUserQuestion` menus, never merged; the rarer `research`/`review`/`debug`/`verify`/`codebase-map` behind Advanced, each its own choice. Offer OpenAI model ids verified reachable at setup time (do not trust this list verbatim): `gpt-5.6-sol` (flagship) / `gpt-5.6-terra` (balanced) / `gpt-5.6-luna` (fast), plus **inherit session** (default). Avoid the retiring `gpt-5.4` / `gpt-5.4-mini` and the deprecated `gpt-5.3-codex`. Write the answers to `models.codex.*`; the Claude `models.*` lineup is not asked on Codex (those ids cannot run there). After writing, tell the user to **re-run the installer** (the same `--host=codex` install command) so the pins are re-projected into `~/.codex/agents/trailhead-*.toml`: the menu updates `.trailhead/config.json`, the installer is what regenerates the TOMLs and enables `features.multi_agent_v2`.
107
- 5. **🎨 Design**: 💾 Local disk · 🖼️ claude.ai/design (Anthropic's official Claude Design MCP, Claude only) · 🧵 Stitch (Google Stitch MCP, cross-host: Claude Code + Codex). *Mode only, don't ask for a URL here; the concrete project is created or reused at execution time and its projectId cached in `design.project` (see Prototype).* If claude.ai/design or Stitch is picked, ask the **🖼️ Design surface**: 🖌️ Canvas (a single project of screens to react to; default; **who makes it:** on claude.ai/design you do, the `/design` Artifact or a hand-made web-app project, not MCP-driven; on Stitch the MCP generates the screens) · 🧩 Design system (push components into a shared design-system project, for a shared library; **the MCP creates and syncs it**) → `design.surface`. Then **✅ Mockup approval**: 🖐️ Explicit (wait for a go-ahead before UI code) · ⏩ Auto (proceed without blocking).
108
+ 5. **🎨 Design**: 💾 Local disk · 🖼️ Artifacts (a Design canvas on claude.ai, built with Claude Code's `Artifact` tool; Claude Code only) · 🧵 Stitch (Google Stitch MCP, cross-host: Claude Code + Codex). *Mode only, don't ask for a URL here; the canvas/project is created or reused at execution time and cached in `design.project` (see Prototype).* If Stitch is picked, ask the **🖼️ Design surface**: 🖌️ Canvas (a Stitch project of screens to react to; default) · 🧩 Design system (push components into a shared Stitch design system) → `design.surface`. If Artifacts is picked, optionally ask the **🧩 Design system** to install on the canvas (list the account's Design System Artifacts, or "decide at the first screen") → `design.system`. Then **✅ Mockup approval**: 🖐️ Explicit (wait for a go-ahead before UI code) · ⏩ Auto (proceed without blocking).
108
109
  6. **🧪 TDD**: 🎯 Seams only · ✅ On (all definable behaviour) · ⛔ Off.
109
110
  7. **⚖️ Effort**: how hard the `build`/`bug` engine works each change (`effort`). 🛠️ **Standard** (default; every step runs) · 🍃 **Lean** (size-triage small changes and offer to skip heavy steps, on an explicit yes only: the plan pass, TDD, cross-AI review, the full code review, the goal-backward verify; correctness checks always stay). Governs `build`/`bug` only: `quick` always size-triages regardless.
110
111
  8. **🖥️ Acceptance testing**: 🤖 Auto · ▶️ Always browser · 🚫 No browser (acceptance still runs, starting with the drive-mode ask; only browser-driving is off, see `acceptance.browser` above). If browser is enabled, ask **🔗 base URL** and confirm it's a web app.
@@ -5,4 +5,4 @@ Three layers, **nearest wins**, key by key; a key unset at one layer inherits th
5
5
  - **Global**: `~/.claude/trailhead/config.json` (honour `$CLAUDE_CONFIG_DIR`): your standing defaults across every project.
6
6
  - **Defaults**: the built-in values documented in `configuration-reference.md`.
7
7
 
8
- Load the effective config at the start of a work session, **from the map's project root** (`.trailhead/config.json` at the superproject repo root) plus the global file, **before** any isolation workspace is set up. **Config is a property of the project/map, not the working directory**: an `isolation: worktree`/`clone` workspace **inherits** the config loaded here and must **never re-resolve it from the isolated copy's own root**. A per-ticket clone is always a clone of the **superproject** (never of a submodule alone), so its `.trailhead/config.json` is present when the project commits one and absent when it doesn't; either way re-resolving there is wrong, because the workspace must reuse the config already resolved from the original checkout, not load it afresh (an absent file would silently fall back to defaults, which is exactly how a `design: claude.ai/design` project ends up wrongly using `disk` in a clone). Config **writes** too (e.g. caching `design.project`) target the project's `.trailhead/config.json` in the original checkout, never the clone. **The main session orchestrates and holds the HITL moments** (the `build`/`bug` Discuss's "stop and ask", Verify's acceptance/UAT); **every model key runs as a subagent** (`plan`, `execute` (an *executor subagent* implementing with atomic commits on `models.execute`), `research`, `review`, `debug`, `verify`, `codebase-map`) so the whole per-activity model split applies in one session whatever model it runs on. Run Execute inline only when `models.execute` is unset or equals the session model. **On a subagent-less host** (`subagentToolkit == none`) there is nothing to fan out into: every activity runs inline. **Separately, on a host that can't honour the model keys** (`honorsModelKeys == false`, e.g. Codex, whose subagents run on its own OpenAI models) every `models.*` key collapses to the single session model even though the activities still fan out; when any `models.*` is set there the engine surfaces a **one-time** session-start notice that the split is not taking effect (the keys stay in `.trailhead/config.json` for when the project next runs on Claude Code). On Codex the per-activity split is available through a parallel `models.codex.*` namespace (OpenAI model ids), the honoured namespace there (projected into per-technique `~/.codex/agents/*.toml` and dispatched at runtime by `agent_type`), while `models.*` (Claude ids) still collapse to the single session model; the collapse notice points at `models.codex.*` and goes silent once it is set. A host without a hook bus (`hookBus == none`) also runs a lightweight inline update check at session start (no SessionStart hook, no statusline). After an update changes the tier defaults, a pinned-model review offer surfaces too, once per session and until the user answers it (see `../_shared/load-first.md` for the check/ack sequence and `configuration-reference.md`'s Pinned model review). See `configuration-reference.md`. The **keys, their values, the model/tdd/acceptance semantics, and the guided menu setup live in `configuration-reference.md`**: read it when running `/trailhead:config` or when you need a key's exact meaning. `/trailhead:config` with no args runs the guided setup; `config get` prints the merged config; `config set <key> <value>` writes one key.
8
+ Load the effective config at the start of a work session, **from the map's project root** (`.trailhead/config.json` at the superproject repo root) plus the global file, **before** any isolation workspace is set up. **Config is a property of the project/map, not the working directory**: an `isolation: worktree`/`clone` workspace **inherits** the config loaded here and must **never re-resolve it from the isolated copy's own root**. A per-ticket clone is always a clone of the **superproject** (never of a submodule alone), so its `.trailhead/config.json` is present when the project commits one and absent when it doesn't; either way re-resolving there is wrong, because the workspace must reuse the config already resolved from the original checkout, not load it afresh (an absent file would silently fall back to defaults, which is exactly how a `design: artifacts` project ends up wrongly using `disk` in a clone). Config **writes** too (e.g. caching `design.project`) target the project's `.trailhead/config.json` in the original checkout, never the clone. **The main session orchestrates and holds the HITL moments** (the `build`/`bug` Discuss's "stop and ask", Verify's acceptance/UAT); **every model key runs as a subagent** (`plan`, `execute` (an *executor subagent* implementing with atomic commits on `models.execute`), `research`, `review`, `debug`, `verify`, `codebase-map`) so the whole per-activity model split applies in one session whatever model it runs on. Run Execute inline only when `models.execute` is unset or equals the session model. **On a subagent-less host** (`subagentToolkit == none`) there is nothing to fan out into: every activity runs inline. **Separately, on a host that can't honour the model keys** (`honorsModelKeys == false`, e.g. Codex, whose subagents run on its own OpenAI models) every `models.*` key collapses to the single session model even though the activities still fan out; when any `models.*` is set there the engine surfaces a **one-time** session-start notice that the split is not taking effect (the keys stay in `.trailhead/config.json` for when the project next runs on Claude Code). On Codex the per-activity split is available through a parallel `models.codex.*` namespace (OpenAI model ids), the honoured namespace there (projected into per-technique `~/.codex/agents/*.toml` and dispatched at runtime by `agent_type`), while `models.*` (Claude ids) still collapse to the single session model; the collapse notice points at `models.codex.*` and goes silent once it is set. A host without a hook bus (`hookBus == none`) also runs a lightweight inline update check at session start (no SessionStart hook, no statusline). After an update changes the tier defaults, a pinned-model review offer surfaces too, once per session and until the user answers it (see `../_shared/load-first.md` for the check/ack sequence and `configuration-reference.md`'s Pinned model review). See `configuration-reference.md`. The **keys, their values, the model/tdd/acceptance semantics, and the guided menu setup live in `configuration-reference.md`**: read it when running `/trailhead:config` or when you need a key's exact meaning. `/trailhead:config` with no args runs the guided setup; `config get` prints the merged config; `config set <key> <value>` writes one key.
@@ -17,7 +17,7 @@ Automated tests prove the code does what the *code* intended; acceptance testing
17
17
  - **When the human can only run it later** (on-device, hardware you don't have right now), record the full numbered checklist in the `VERIFY` comment as the durable artifact and mark UAT **explicitly pending**, but the walkthrough stays conversational **when they come to run it**: never shrink it to a vague one-liner ("just check it on the device"), and never let "automated passed" quietly stand in for it. Deferring *where/when* the human runs it is fine; replacing the live step-by-step with a self-serve checklist is not.
18
18
  - **Pending UAT must stay tracked: a closed ticket is not tracking.** Don't resolve/close a user-facing ticket on unconfirmed acceptance and leave the checklist as a comment on the closed issue, where nobody will look. The default is to **keep the ticket open** until the human confirms the UAT passes (closing on green you didn't see is a premature close). **When UAT hasn't been run at Resolve, pose the choice to the human and wait for an explicit answer, never decide it for them:** (a) **run the UAT now**, in this session, with no ticket (opens with the drive-mode ask above, then the guided conversational walkthrough or AI-driven checks, resolving only on a confirmed pass; a failing step becomes a fix or a `bug` follow-up and an incomplete/blocked step is marked pending and tracked, per the failing-step and partial-run rules above, never a silent close), or (b) **open a UAT ticket** to run it later. **Never open a UAT ticket without asking, and never let silence or an ambiguous reply default to either path.** Only when the human picks (b) do you **open a follow-up ticket before that close** that carries the pending UAT and links back to the parent with a `UAT of: <parent name>(link)` pointer in the body. Route it the way `../choices.md` routes a deferred choice: a **`trailhead:seed`** (kept blocked) when the run is gated on a future external trigger not yet true (hardware you don't have, a device out of reach), or a follow-up **`task`** on the frontier when it's just scheduled or batched work you could pick up any time. Either way the follow-up **carries the full numbered checklist and, when it comes to resolution, opens with the drive-mode ask above before running the guided conversational walkthrough**, never a self-serve check-off. **Never close a user-facing ticket on a chosen-deferred UAT with nothing opened**: the parent may close as agreed, but the owed UAT stays visible on the tracker as its own ticket, linked to the parent, until it is actually performed. The pending check must be visible on the tracker, not buried.
19
19
 
20
- **Mockup-fidelity check (when the ticket had an approved mockup).** If the change was preceded by an approved mockup (the **Prototype** technique produced one and it was approved and recorded at Execute), acceptance testing MUST check the built screen **against that approved mockup**, not merely against "what the user wanted" in the abstract. Pull the mockup's current state to compare against (re-fetch it in `claude.ai/design` / `stitch` mode via the technique's re-fetch rule, or open the linked `disk` mockup); never compare from memory. Walk it **element by element and state by state**, layout, spacing, sizing, colour, typography, copy, and every state it shows (empty, loading, error, hover, active, disabled, and the like), enumerating from the approved mockup itself (the spec) and cross-checking the executor's recorded Execute-step fidelity list and any element it flagged infeasible, and confirm each is reproduced. Record the per-element and per-state result in the `VERIFY` comment. Any **unforced** deviation is an acceptance finding, never waved through as "close enough"; a genuinely infeasible part must already have been raised with the user at Execute (per the Prototype technique), not surface here as a silent drift.
20
+ **Mockup-fidelity check (when the ticket had an approved mockup).** If the change was preceded by an approved mockup (the **Prototype** technique produced one and it was approved and recorded at Execute), acceptance testing MUST check the built screen **against that approved mockup**, not merely against "what the user wanted" in the abstract. Pull the mockup's current state to compare against (re-fetch it in `artifacts` / `stitch` mode via the technique's re-fetch rule, or open the linked `disk` mockup); never compare from memory. Walk it **element by element and state by state**, layout, spacing, sizing, colour, typography, copy, and every state it shows (empty, loading, error, hover, active, disabled, and the like), enumerating from the approved mockup itself (the spec) and cross-checking the executor's recorded Execute-step fidelity list and any element it flagged infeasible, and confirm each is reproduced. Record the per-element and per-state result in the `VERIFY` comment. Any **unforced** deviation is an acceptance finding, never waved through as "close enough"; a genuinely infeasible part must already have been raised with the user at Execute (per the Prototype technique), not surface here as a silent drift.
21
21
 
22
22
  Acceptance failures are findings like any other: a `bug` follow-up or a fix on this ticket before it resolves.
23
23
 
@@ -8,36 +8,35 @@ If genuinely ambiguous and the user's unreachable, default by context (backend m
8
8
 
9
9
  **For UI tickets specifically:** before writing any real UI code, **ask the user whether they want mockups first** (default yes for a new screen). If yes, route by `config.design` (see [Configuration](../configuration.md#configuration)). This ask is an advisory choice that **offers** the delegate option, per the injection recipe in `../choices.md`.
10
10
 
11
- **Route strictly by `config.design`; disk is not a shortcut.** Read `config.design` (and its cached `design.project`) *before* producing anything, and obey it. When it names a hosted mode (`claude.ai/design` or `stitch`), the mockup **must** be built there, reusing the cached `design.project` when present. **Producing a local disk mockup while `config.design` names a hosted mode is a defect**, never a convenient default: `disk` is used only when `config.design` is literally `disk`, or as the explicit, announced fallback the chain below reaches after the hosted mode's MCP offer is declined or unavailable. If you cannot reach the configured mode, run its offer/fallback and **tell the user why**; never silently shortcut to disk. When unsure of the mode, re-read this technique before routing, do not guess.
11
+ **Route strictly by `config.design`; disk is not a shortcut.** Read `config.design` (and its cached `design.project` / `design.system`) *before* producing anything, and obey it. When it names a hosted mode (`artifacts` or `stitch`), the mockup **must** be built there, reusing the cached `design.project` when present. **Producing a local disk mockup while `config.design` names a hosted mode is a defect**, never a convenient default: `disk` is used only when `config.design` is literally `disk`, or as the explicit, announced fallback the chain below reaches when the hosted mode is unavailable or its offer is declined. If you cannot reach the configured mode, run its offer/fallback and **tell the user why**; never silently shortcut to disk. When unsure of the mode, re-read this technique before routing, do not guess.
12
+
13
+ **Legacy value `claude.ai/design`.** The standalone Claude Design site (claude.ai/design) closes on 2026-12-14 and its designs now live in Claude as **Artifacts**. A config still reading `design: claude.ai/design` is treated as **`artifacts`**: say so once per session and offer to rewrite the key (`/trailhead:config`). A cached `design.project` that is a claude.ai/design project id or `claude.ai/design/p/<id>` URL **cannot be reused** (standalone projects don't migrate automatically): tell the user once, point them to the migration (design systems: the **Artifacts** page banner "Migrate team design systems"; projects: download the archive from the standalone site, or ask trailhead to rebuild the screens on a canvas), and attach a new canvas as below. **Make the re-attach one click:** when offering the canvas (and, if unset, `design.system`), first list the Design canvases and Design System Artifacts (`list` with `type: "Design"` / `"Design System"`) whose title matches the repo's or the product's name (e.g. `ZipTv2 — Mockup`, `ZipTv2`), as the pre-selected options, before the generic pick / paste / create; on the user's pick write `design.project` / `design.system` and drop the legacy `design.surface` in the same config write. Never call the `claude-design` MCP or DesignSync to make a mockup: DesignSync is only for the user-started `/design-sync` skill.
12
14
 
13
15
  - **`disk`** (the default config *value*, not a fallback to pick at will): a throwaway static HTML mockup next to the code, linked from the ticket as an asset (on a throwaway branch, out of main). Fast, self-contained.
14
- - **`claude.ai/design` mode**: build the mockup on claude.ai/design, where the user edits it visually. `config.design.surface` picks which surface (unset, a cached `design.project` infers `design-system`, so an existing project keeps its surface; see [Configuration](../configuration.md#configuration)). The two surfaces are reached by **different mechanisms** (see below): `design-system` is driven by the DesignSync MCP, while `canvas` is **not** MCP-driven (no MCP call creates or drives a regular claude.ai/design canvas project). On the **first** UI screen for this map you attach to a canvas or a project; **cache its id/URL in the project `.trailhead/config.json` under `design.project`** and **later screens reuse** it. **Link the specific screen** back from the ticket: the canvas **Artifact** URL (or a hand-made web-app project's `claude.ai/design/p/<id>`), or the design-system project's `claude.ai/design/p/<projectId>/…` URL, not merely the project. **With several screens, link each screen separately** (its own artboard/file URL), not only the index screen.
15
- - **`canvas` (default)**: a one-off screen to react to, editable visually. **No MCP creates or drives a claude.ai/design canvas project** (the `claude-design` MCP only creates `PROJECT_TYPE_DESIGN_SYSTEM` projects), so a canvas is produced one of two real ways: (a) the built-in **`/design` skill** → a canvas published as an **Artifact** (`claude.ai/code/artifact/<id>`), a preview of the Claude Design editor inside Claude Code, editable and exportable there; this is the default and the only in-session path. (b) a regular claude.ai/design project **created by hand in the web app**, whose `claude.ai/design/p/<id>` URL you then **paste in** to attach. Cache the Artifact URL / pasted `/p/<id>` in `design.project`; later screens are added to the same Artifact/project. **When the canvas holds more than one screen, maintain an index (overview) screen and keep it in sync:** every time you produce or add a screen, regenerate the index from the **current** screen set so it lists the new one too (never leave a stale index behind that misses later screens), size its per-screen tiles/thumbnails **large enough to read comfortably** (a legible preview, not a postage stamp), and give each screen its **own standalone artboard/file, linkable on its own outside the index** (openable directly, not only through an index tile). **Do not** try to create a canvas project via the MCP: no such call exists.
16
- - **`design-system`**: push the mockup as a component into a **design-system project** via the **`/design-sync` skill + `claude-design` MCP (DesignSync)**, the design-system slice of the same official MCP, for a shared component library kept in sync. On the first screen, three paths: (a) **pick an existing one**, listing the **10 most-recently-updated** design systems from DesignSync `list_projects` (sorted `updatedAt` desc); (b) **paste a URL**, taking the projectId from a `claude.ai/design/p/<id>` link and confirming with `get_project` that it's a `PROJECT_TYPE_DESIGN_SYSTEM`; (c) **create a new one** (name from the user), then `create_project`. Later screens reuse it (`finalize_plan` → `write_files`). **DesignSync only targets `PROJECT_TYPE_DESIGN_SYSTEM` projects**: verify with `get_project` before pushing; a regular `PROJECT_TYPE_PROJECT` **cannot** be driven by DesignSync (nor by any MCP); reach a regular claude.ai/design project through the `canvas` surface instead (the `/design` skill's Artifact, or a hand-made web-app project).
17
- - **Missing MCP (`design-system` only): offer to install it once, don't degrade silently.** When `design: claude.ai/design` is configured with the **`design-system`** surface but its MCP (DesignSync) isn't connected, **surface the enable steps once** before falling back: `claude mcp add --scope user --transport http claude-design https://api.anthropic.com/v1/design/mcp`, then `/design-login`. Let the user **install-and-retry or decline**; never auto-install. If they install and it connects, use the surface. If they decline (or it still doesn't connect), fall to `disk` and **don't re-offer for the rest of the session**. This is a one-time **infrastructure** prompt, **orthogonal to `design.approval`**: `auto` only skips the wait on *mockup* approval, it never silences the install offer (an MCP can't be auto-installed), though a decline degrades without blocking, in keeping with `auto`. The **`canvas`** surface needs **no MCP** (the `/design` skill is built into Claude Code; the web-app path needs only a browser), so there is nothing to install or offer for it.
18
- - **Fallback chain** once the offer is declined or doesn't apply: the **`design-system`** surface needs DesignSync connected; if it isn't, fall to `disk`, and say so. The **`canvas`** surface needs no MCP, so on Claude Code it is always available (the `/design` skill) and doesn't fall back for a missing MCP. **On a host without the `/design` skill and the `claude-design` MCP (e.g. Codex), `claude.ai/design` mode isn't available at all** (neither surface). Because **`stitch` mode is cross-host** (below), don't degrade silently there: **offer once to switch this project to `design: stitch`** (with the Stitch install offer if its MCP isn't connected), and only on decline fall back to `disk`. Offer this once per session; on decline, don't re-ask. (On Claude the three modes stay independent explicit choices, no auto-redirect between them.)
19
- - **`stitch` mode**: create/edit the mockup via the **Google Stitch MCP** (`https://stitch.googleapis.com/mcp`), Google's Gemini-powered UI generator. Unlike `claude.ai/design`, the Stitch MCP is a standard HTTP MCP that runs on **both Claude Code and Codex**, so it's the **cross-host** hosted option. `config.design.surface` picks the surface (the same key as claude.ai/design), and on the **first** UI screen for this map you attach to a Stitch project; **cache the chosen projectId in the project `.trailhead/config.json` under `design.project`** and **later screens reuse** it. Because `design.project` is shared with `claude.ai/design`, **verify the cached id belongs to Stitch (`get_project`) before reusing it**, and re-attach if it doesn't. **Link the specific screen** back from the ticket.
16
+ - **`artifacts` mode**: build the mockup as a **Design canvas Artifact** on claude.ai (the `Artifact` tool, built into Claude Code: no MCP to install, no login step), where the user edits it visually, comments on it and exports it. The canvas follows its Artifact type's own instructions (the `SKILL.md` the create/read result carries): read them and obey them; the essentials are below.
17
+ - **Attach a canvas once per map.** On the **first** UI screen for this map: a cached `design.project` that is an Artifact URL (`claude.ai/artifact/<id>` or `claude.ai/code/artifact/<id>`) → reuse it. Otherwise offer three paths: (a) **pick an existing one** (Artifact `list` with `type: "Design"`, the 10 most recent); (b) **paste a URL**; (c) **create a new one**: `quickstart` with `intent: "design"`, then `publish` with its `type_url`, a `title` (the map's or product's name, from the user, don't invent it) and `auto_open: "after_first_write"`, nothing else. **Cache the canvas URL in the project `.trailhead/config.json` under `design.project`**; later screens are added to the same canvas.
18
+ - **Design system.** `design.system` (a Design System Artifact URL) is installed on the canvas: its `project/tokens.json` copied to `project/ds/<folder>/tokens.json` plus a record in the index's `designSystems`, the way the type's `design-system-components.md` says (and its components mounted when its README names a bundle global). Unset on the first screen: use the account's default design system when `quickstart` marks one; otherwise name the listed systems and ask which (or none), and cache the choice in `design.system`. **Screens never get pushed into a design system**: a DS is a read-only reference the canvas installs.
19
+ - **One artboard per screen (and per variant).** Each screen is its own `project/<Name>.dc.html` (names: letters, digits, `_ . -`, no spaces; the format rules in the type's `format.md`, above all the exact `<script src="./support.js"></script>` head line, all UI as markup, never script-built); structurally different variants sit side by side as separate artboards. Group a ticket's screens in a canvas **page** (`pages` entry `t<issue#>`, named after the ticket) so each ticket's mockups are browsable on their own; the canvas itself is the overview, no hand-made index screen. App screens get a fixed root (`w`×`h`, e.g. phone 390×844); web pages and dashboards are fluid with `expand: "fill"`. An artboard is at most 8000px tall: split a longer screen into consecutive artboards.
20
+ - **Publishing.** Write the files under one scratchpad folder at their canvas paths and publish with `url`, `root` = the folder holding `project/`, `file_path` = `project/canvas.json` (sent only when boards, pages or notes change, after re-reading it), `files` = the changed artboards. **Before publishing to a canvas this session didn't create, `read` its whole URL first** (a publish to an unread artifact is refused). Upload images with `asset: true` and use the returned `/_blob/<id>` url; no other network than Google Fonts.
21
+ - **Host availability and fallback.** The `Artifact` tool exists only on Claude Code signed in with a claude.ai account. When it isn't available (Codex, or an API-key session), `artifacts` mode can't run: because **`stitch` mode is cross-host** (below), **offer once to switch this project to `design: stitch`** (with the Stitch install offer if its MCP isn't connected), and only on decline fall back to `disk`, saying so. Offer once per session; on decline, don't re-ask.
22
+ - **`stitch` mode**: create/edit the mockup via the **Google Stitch MCP** (`https://stitch.googleapis.com/mcp`), Google's Gemini-powered UI generator. The Stitch MCP is a standard HTTP MCP that runs on **both Claude Code and Codex**, so it's the **cross-host** hosted option. `config.design.surface` picks the surface, and on the **first** UI screen for this map you attach to a Stitch project; **cache the chosen projectId in the project `.trailhead/config.json` under `design.project`** and **later screens reuse** it. Because `design.project` is shared with `artifacts`, **verify the cached id belongs to Stitch (`get_project`) before reusing it**, and re-attach if it doesn't. **Link the specific screen** back from the ticket.
20
23
  - **`canvas` (default)**: a Stitch project with generated screens to react to: `generate_screen_from_text` for the first screen (or `generate_variants` for structurally different alternatives), `edit_screens` to refine, `get_screen` / `list_screens` to read back. On the first screen ask which Stitch project to attach to: (a) **pick an existing one** (`list_projects`); (b) **paste a project URL**; (c) **create a new one** (`create_project`, name from the user, don't invent it). Later screens are added to the same project.
21
24
  - **`design-system`**: push the mockup into a **Stitch design system** (`create_design_system` / `create_design_system_from_design_md` / `apply_design_system`, read/update via `list_design_systems` / `update_design_system`) for a shared component library. On the first screen: (a) **pick an existing one** (`list_design_systems`); (b) **paste a URL**; (c) **create a new one** (name from the user). Later screens reuse it.
22
- - **Missing MCP: offer to install it once** (the same rule as claude.ai/design): if the Stitch MCP isn't connected, surface the enable step once, `claude mcp add --scope user --transport http stitch https://stitch.googleapis.com/mcp` (authenticate if prompted), and let the user install-and-retry or decline; never auto-install. On decline (or a still-missing MCP), fall back to `disk`, and say so. There's no intra-provider chain: the Stitch MCP either connects or falls to `disk`. One-time infrastructure prompt, **orthogonal to `design.approval`** (see above).
23
-
24
- **Publishing a screen to a `design-system` surface is not done until its index is updated and no loose copy is left (either provider).** Every push of a screen into a design system (DesignSync `finalize_plan` → `write_files`, or Stitch `apply_design_system` / `update_design_system`) must, as part of the *same* publish: (a) **update the design-system index** to list the new screen, regenerating it from the current screen set so nothing is missed, so the design system stays the single browsable source of truth; and (b) **treat the indexed screen as the sole artifact**, never also leaving behind or handing back a separate loose `.html` (a scratchpad copy) that can drift from the indexed screen. This index update is a **mandatory, verified** step of the publish, not an optional afterthought: confirm the index lists the new screen before treating the publish as done. (The `canvas` surface states the equivalent index rule inline above; this makes the `design-system` branch match it.)
25
+ - **Missing MCP: offer to install it once**: if the Stitch MCP isn't connected, surface the enable step once, `claude mcp add --scope user --transport http stitch https://stitch.googleapis.com/mcp` (authenticate if prompted), and let the user install-and-retry or decline; never auto-install. On decline (or a still-missing MCP), fall back to `disk`, and say so. One-time infrastructure prompt, **orthogonal to `design.approval`**: `auto` only skips the wait on *mockup* approval, it never silences the install offer.
25
26
 
26
- **Author full-viewport mockups with an intrinsic height, not `100vh` (any card-rendered surface).** A design-system pane renders each screen as a card with no real viewport, so a full-viewport app shell sized `height: 100vh` collapses to a thin strip (only the titlebar shows). Give the app shell an intrinsic fixed height instead (e.g. `height: 800px`); a flowing or scrolling page (like an overview index) renders fine because its content gives it real height, but a single-viewport app does not.
27
+ **Publishing a screen to a Stitch `design-system` is not done until its index is updated and no loose copy is left.** Every push of a screen into a Stitch design system (`apply_design_system` / `update_design_system`) must, as part of the *same* publish: (a) **update the design-system index** to list the new screen, regenerating it from the current screen set so nothing is missed; and (b) **treat the indexed screen as the sole artifact**, never also leaving behind a separate loose `.html` that can drift from it. Confirm the index lists the new screen before treating the publish as done.
27
28
 
28
- **Two DesignSync mechanics the publish must get right (DesignSync surface).** Specific to a DesignSync design system, alongside the shared index rule above:
29
- - **Screen files at project ROOT, not in subfolders, even when a twin already lives in one.** The Design System pane lists only root-level `.html` as openable Pages; a screen in a subfolder (`chat-states/loading.html`) opens **blank** and is never offered in the Pages menu. The manifest / `@dsCard` still embeds such a screen as a thumbnail in `index.html`, but that is the index, not the Pages menu, and there is no way today to surface a subfolder screen in Pages. So **always publish each screen as a flat root file**, and do **not** mirror an existing project's subfolder grouping: if a sibling screen already sits under a folder (`chat-states/`), that placement is the anomaly to avoid (its own Page is unreachable too), not a convention to inherit. The legitimate grouping need (browse the "Chat states" screens together) is served by the **index**, which groups the thumbnails via the manifest / `@dsCard`: grouping is an index/browsing concern, never a filesystem-folder one. Every openable Page stays a flat root `.html`.
30
- - **Verify the index against the real `_ds_manifest.json`.** `register_assets` does **not** rewrite an existing manifest, so after any screen add, move, rename, or delete the manifest goes **stale** (keeps listing old or deleted paths). After such a change, read `_ds_manifest.json` and confirm it lists the current flat screen paths, rewriting it directly if not. This is the concrete, verified form of the index-update step above.
29
+ **Author full-viewport mockups with an intrinsic height, not `100vh`.** Canvas artboards and design-system cards render each screen with no real viewport, so a full-viewport app shell sized `height: 100vh` collapses or clips. Give the app shell an intrinsic fixed height instead (e.g. `height: 800px`); a flowing or scrolling page renders fine because its content gives it real height.
31
30
 
32
31
  Either way the rough screen is **reacted to before real UI code**.
33
32
 
34
- **"Surface the mockup" means: put its link in the same message that asks for the reaction.** The user can't react to what they can't open. Every message that asks to approve, react to, or pick between mockups **must carry, in that same message and right before the question**, the direct clickable location of each screen it refers to: the file path (`disk`), the Artifact / claude.ai/design project URL (`canvas`), the design-system project URL plus the screen's page (`design-system`), or the Stitch project/screen URL (`stitch`), one line per screen or variant. A link given earlier in the conversation, only in a ticket comment, or implied ("the mockup above") does **not** count: scrollback scrolls away. **Write the link(s) in the plain prose of the message, never inside a structured prompt**: an options picker renders its question and options as plain text, so a link put there is not clickable (above all on mobile). When the approval then goes through a structured prompt, keep every link in the prose just before it and let the picker ask only a plain yes/no: approve the mockup (yes) or request changes (no); for a pick between variants, name each variant in the options and keep their links in the prose. If you don't have a link to show yet (publish failed, URL not returned), **do not ask for approval**: fix the publish or report the failure first. The project's or design system's **name is not a link** ("the mockup is ready on MyApp" without the URL fails this rule), and the link must sit in the reply **text**, not only in your reasoning. A hook enforces this: on Claude Code the **mockup-link guard** blocks a mockup-approval `AskUserQuestion` whose preceding reply text carries no URL or file path; on Codex **mockup-link-stop** continues a final reply that asks for the approval without one. When either fires, write the link(s) in the prose and ask again.
33
+ **"Surface the mockup" means: put its link in the same message that asks for the reaction.** The user can't react to what they can't open. Every message that asks to approve, react to, or pick between mockups **must carry, in that same message and right before the question**, the direct clickable location of each screen it refers to: the file path (`disk`), the canvas Artifact URL plus the **artboard title** of each screen (`artifacts`: one canvas URL, then one line per screen or variant naming its artboard and page, since artboards have no URL of their own), or the Stitch project/screen URL (`stitch`). A link given earlier in the conversation, only in a ticket comment, or implied ("the mockup above") does **not** count: scrollback scrolls away. **Write the link(s) in the plain prose of the message, never inside a structured prompt**: an options picker renders its question and options as plain text, so a link put there is not clickable (above all on mobile). When the approval then goes through a structured prompt, keep every link in the prose just before it and let the picker ask only a plain yes/no: approve the mockup (yes) or request changes (no); for a pick between variants, name each variant in the options and keep their links in the prose. If you don't have a link to show yet (publish failed, URL not returned), **do not ask for approval**: fix the publish or report the failure first. The project's or canvas's **name is not a link** ("the mockup is ready on MyApp" without the URL fails this rule), and the link must sit in the reply **text**, not only in your reasoning. A hook enforces this: on Claude Code the **mockup-link guard** blocks a mockup-approval `AskUserQuestion` whose preceding reply text carries no URL or file path; on Codex **mockup-link-stop** continues a final reply that asks for the approval without one. When either fires, write the link(s) in the prose and ask again.
35
34
 
36
35
  How approval gates the build depends on `config.design.approval`:
37
36
  - **`explicit` (default)**: surface the mockup and **wait for the user's clear go-ahead**; do not write UI code until they approve. Record the approval on the ticket, then proceed.
38
37
  - **`auto`**: surface the mockup and **proceed without blocking** on a confirmation (the user can still object). Record the direction on the ticket.
39
38
 
40
- **In `claude.ai/design` mode, re-fetch the design before you build on it.** Between surfacing the mockup and writing the UI code the user may have edited it directly on claude.ai/design, so once it's approved (or, in `auto`, right before you consume it), pull the **current** state before building from it: on the **`design-system`** surface via DesignSync (`list_files` → `get_file`); on the **`canvas`** surface re-read the Artifact (or the web-app project) directly, there is no MCP fetch. Build from *that*, never from the version you last pushed. Note on the ticket that the design was re-fetched at that point.
39
+ **In a hosted mode, re-fetch the design before you build on it.** Between surfacing the mockup and writing the UI code the user may have edited it directly (on the canvas or in Stitch), so once it's approved (or, in `auto`, right before you consume it), pull the **current** state before building from it: in `artifacts` mode `read` the canvas's `project/canvas.json` and each approved artboard's `project/<Name>.dc.html`; in `stitch` mode `get_screen`. Build from *that*, never from the version you last published. Note on the ticket that the design was re-fetched at that point.
41
40
 
42
41
  **Once a mockup is approved, reproduce it with 100% fidelity, not an approximation.** The approved mockup is the spec, not a mood board: match its layout, spacing, sizing, colour, typography, copy, and **every state it shows** (empty, loading, error, hover, active, disabled, and the like). "In the spirit of" the mockup is not the bar; faithful to the pixel is. This is not licence to improve or reinterpret it while building: if something in the approved mockup is genuinely infeasible, wrong, or missing a state, **stop and raise it with the user** and get the mockup (or the decision) updated, never silently deviate. An unforced departure from an approved mockup is a defect, and Verify checks the built screen against the approved mockup, not against a loose retelling of it: **Acceptance testing** runs the element-by-element and state-by-state mockup-fidelity check, and **Goal-backward verification** carries fidelity as an explicit goal claim (see their technique files).
43
42
 
@@ -10,7 +10,7 @@ The ticket engines call these by name. Each technique's full protocol lives in i
10
10
  |---|---|---|
11
11
  | **Grilling** | `techniques/grilling.md` | interrogate the human, one question at a time, to converge on a decision |
12
12
  | **Domain vocabulary** | `techniques/domain-vocabulary.md` | build a precise shared glossary so each term means one thing |
13
- | **Prototype** | `techniques/prototype.md` | throwaway artifact for "how should it look/behave"; routes UI mockups (disk / claude.ai/design / stitch) |
13
+ | **Prototype** | `techniques/prototype.md` | throwaway artifact for "how should it look/behave"; routes UI mockups (disk / artifacts / stitch) |
14
14
  | **Research** | `techniques/research.md` | a focused subagent gathers a decision-ready fact from primary sources |
15
15
  | **TDD** | `techniques/tdd.md` | RED → GREEN → REFACTOR at the seams; no implementation before a failing test |
16
16
  | **Codebase map** | `techniques/codebase-map.md` | one-time fan-out of 5 read-only readers, distilled into the repo's `trailhead:codebase` issue |
@@ -30,7 +30,7 @@ The ticket that *builds*. Lean cycle, all in **ticket comments**:
30
30
 
31
31
  1. **Discuss**: **never auto-grill.** Start from Plan. If reading the ticket surfaces blocking ambiguity, **stop and ask the user** whether they want a **Grilling** round: don't launch it on your own initiative. Only on their assent run the short round and post a `DISCUSS` comment with the closed choices. The user may also ask for it themselves at any time. Advisory choices raised here **offer** the delegate/defer options, per the injection recipe in `../../_shared/choices.md`.
32
32
  2. **Plan**: a `PLAN` comment: the steps, the seams, the files touched, the verification criteria. Apply **TDD** per `config.tdd` (`seams`/`on`/`off`). Produce this plan via a *planner subagent* on `config.models.plan` (dispatch the **`trailhead-plan`** agent, read-only, passing `config.models.plan` as the model override; inline when the model is unset or equals the session model; Execute then runs as its own subagent, see below). If `config.plan_review` is on, run **Cross-AI plan review** before Execute: send the plan to external AI CLIs and converge on their concerns. Now that the files/seam are known, run the **undeclared-coupling check** (`../../_shared/teamwork.md`) against in-progress tickets. **Plan to sufficiency:** stop once you can name the steps, seams, and files with confidence, and never re-read a file already read in this planning pass; act when you have enough to plan, rather than re-deriving what the pass already established. **The single exception:** under an accepted `lean` skip (see the Size triage above), produce a short inline plan here instead of the planner subagent, and skip Cross-AI plan review; absent that accepted skip, this step runs in full as described.
33
- 3. **Execute**: **if this ticket changes user-facing UI (a new screen, a redesign, a changed layout), run the Prototype technique FIRST, before any real UI code**: surface a mockup to react to (its clickable link always in the same message as the approval question, per the Prototype technique), routed by `config.design` (disk / claude.ai/design / stitch) and gated by `config.design.approval` (`explicit` waits for a go-ahead, `auto` proceeds after surfacing). **Route by `config.design` and never shortcut a hosted mode to a local disk mockup**: when `config.design` is `claude.ai/design` or `stitch`, the mockup is built there (reusing a cached `design.project`); `disk` is only for `config.design: disk` or the technique's explicit, announced fallback, never a convenience default. Read `config.design` before producing anything. For a redesign or new screen the default is to offer mockups; don't jump straight to code on a UI ticket. **Once the mockup is approved, reproduce it with 100% fidelity** (layout, spacing, sizing, colour, type, copy, and every state), never a loose approximation "in the spirit of" it; if part of the approved mockup is genuinely infeasible, stop and raise it rather than silently deviate (full statement in the **Prototype** technique, `../../_shared/techniques/prototype.md`). **Make fidelity verifiable, not a hope:** before finishing Execute, enumerate the approved mockup's elements and states, confirm each is reproduced, and **record that enumerated fidelity list as a ticket comment** (noting any element raised as infeasible with its resolution), so Verify works from a durable checklist instead of reconstructing intent. At Verify, **Acceptance testing** checks the built screen against the approved mockup (element by element, state by state) and **Goal-backward verification** carries fidelity as an explicit goal claim (see `../../_shared/techniques/acceptance-testing.md` and `../../_shared/techniques/verify.md`). Then implement with **atomic commits** (conventional commits, each with a `Refs: #<n>` trailer for this ticket, see **Principles** in `../../_shared/principles.md`; the trailer is also what scopes Verify's review and goal check, per **Ticket diff** in `../../_shared/techniques/code-review.md`), following the repo's `trailhead:conventions` `git:`, straight to `main` by default, or a feature branch + PR when `git: pr`. **Under `isolation: worktree`, do the work in this ticket's `git worktree`** (`trailhead/t<n>` branch), integrating to the trunk at Resolve (see `../../_shared/teamwork.md`). One commit = one verifiable step. Run this via an **executor subagent on `config.models.execute`** (dispatch the **`trailhead-executor`** agent, full tools that can Edit/Write/commit, passing `config.models.execute` as the model override; inline when the model is unset or equals the session model); the commits land on `main`, visible. **Before installing any new dependency, run the verify-before-install gate** (slopsquatting barrier): check the package's legitimacy (name / typosquat similarity to popular packages, age / first-seen date, download counts, repository metadata present and matching) and **stop and ask the user on a suspicious result** (block-and-ask), never installing on your own judgement. On a host with a hook bus the `trailhead-install-guard` `PreToolUse` hook enforces this, blocking a named public-registry install (npm / PyPI / crates.io / Go / RubyGems) until it is vetted; once vetted, proceed by re-running the exact install command prefixed with `TRAILHEAD_VERIFIED_INSTALL=1`. New scope surfacing mid-execute is captured/split, not worked here.
33
+ 3. **Execute**: **if this ticket changes user-facing UI (a new screen, a redesign, a changed layout), run the Prototype technique FIRST, before any real UI code**: surface a mockup to react to (its clickable link always in the same message as the approval question, per the Prototype technique), routed by `config.design` (disk / artifacts / stitch) and gated by `config.design.approval` (`explicit` waits for a go-ahead, `auto` proceeds after surfacing). **Route by `config.design` and never shortcut a hosted mode to a local disk mockup**: when `config.design` is `artifacts` (or the legacy `claude.ai/design`) or `stitch`, the mockup is built there (reusing a cached `design.project`); `disk` is only for `config.design: disk` or the technique's explicit, announced fallback, never a convenience default. Read `config.design` before producing anything. For a redesign or new screen the default is to offer mockups; don't jump straight to code on a UI ticket. **Once the mockup is approved, reproduce it with 100% fidelity** (layout, spacing, sizing, colour, type, copy, and every state), never a loose approximation "in the spirit of" it; if part of the approved mockup is genuinely infeasible, stop and raise it rather than silently deviate (full statement in the **Prototype** technique, `../../_shared/techniques/prototype.md`). **Make fidelity verifiable, not a hope:** before finishing Execute, enumerate the approved mockup's elements and states, confirm each is reproduced, and **record that enumerated fidelity list as a ticket comment** (noting any element raised as infeasible with its resolution), so Verify works from a durable checklist instead of reconstructing intent. At Verify, **Acceptance testing** checks the built screen against the approved mockup (element by element, state by state) and **Goal-backward verification** carries fidelity as an explicit goal claim (see `../../_shared/techniques/acceptance-testing.md` and `../../_shared/techniques/verify.md`). Then implement with **atomic commits** (conventional commits, each with a `Refs: #<n>` trailer for this ticket, see **Principles** in `../../_shared/principles.md`; the trailer is also what scopes Verify's review and goal check, per **Ticket diff** in `../../_shared/techniques/code-review.md`), following the repo's `trailhead:conventions` `git:`, straight to `main` by default, or a feature branch + PR when `git: pr`. **Under `isolation: worktree`, do the work in this ticket's `git worktree`** (`trailhead/t<n>` branch), integrating to the trunk at Resolve (see `../../_shared/teamwork.md`). One commit = one verifiable step. Run this via an **executor subagent on `config.models.execute`** (dispatch the **`trailhead-executor`** agent, full tools that can Edit/Write/commit, passing `config.models.execute` as the model override; inline when the model is unset or equals the session model); the commits land on `main`, visible. **Before installing any new dependency, run the verify-before-install gate** (slopsquatting barrier): check the package's legitimacy (name / typosquat similarity to popular packages, age / first-seen date, download counts, repository metadata present and matching) and **stop and ask the user on a suspicious result** (block-and-ask), never installing on your own judgement. On a host with a hook bus the `trailhead-install-guard` `PreToolUse` hook enforces this, blocking a named public-registry install (npm / PyPI / crates.io / Go / RubyGems) until it is vetted; once vetted, proceed by re-running the exact install command prefixed with `TRAILHEAD_VERIFIED_INSTALL=1`. New scope surfacing mid-execute is captured/split, not worked here.
34
34
  4. **Verify**: a `VERIFY` comment: run the tests / the plan's criterion; then the **Code review** technique, scoped to the ticket's own commits per its **Ticket diff** rule (`../../_shared/techniques/code-review.md`: the `Refs: #<n>` set, read per commit, recomputed each round, an empty set surfaced as an error, never a `<base>...HEAD` range) (its subagent reviews *adversarially*: it doesn't defer to a `CLAUDE.md` convention or a "settled decision" memory), and carries the review's counts line and findings ledger, per code-review.md, **run in the background and collected by polling, never a blind blocking wait** (a hard engine default on every host, see *Reviews never block the session* in `../../_shared/techniques.md`); **read the review's leading `status:` tag to branch deterministically: `status: clean` -> proceed to Resolve, `status: issues_found` -> iterate the fix-and-re-review loop (or run the HITL checkpoint) before resolving**; then the **Goal-backward verification** technique on `config.models.verify` (does the change deliver what the ticket promised, backward from its `Question` and the `PLAN`'s criteria; the read-only `trailhead-verify` subagent, on the same **Ticket diff** set), **run in the background and collected by polling** like Code review, branching on its leading `status:` tag (`status: met` -> proceed, `status: gaps_found` -> loop back to Execute for the gap or run the HITL checkpoint before resolving, `status: inconclusive` as the leading tag (all gaps cleared) -> a per-reason-class HITL checkpoint with no auto-retry, never auto-resolving over the unevaluated goal); then **Acceptance testing** if the change is user-facing, opening with the drive-mode ask (`../../_shared/techniques/acceptance-testing.md`): AI-driven, or **walk the user through a guided UAT conversationally, one step at a time**, never a checklist dumped in a comment: interactive by design, so it runs inline, not backgrounded. Report the outcome honestly (if a test fails, say so). **The single exception:** under an accepted `lean` skip, run a lighter inline review pass instead of the full Code-review subagent and a quick inline goal check instead of the full Goal-backward verification subagent (or skip either only when the change is truly cosmetic); the lighter inline review still uses the same finding IDs, counts line, and ledger, and the same no-`open` gate, per code-review.md; the tests / criterion and the honest outcome report still run regardless. At a HITL checkpoint here, an advisory sub-choice (which fix, how to proceed) **offers** the delegate option, per the injection recipe in `../../_shared/choices.md`; the accept/resolve decision stays the human's.
35
35
  5. **Resolve**: a resolution comment with what was done → `gh issue close` → update `Decisions so far` on the map (a body read-modify-write: obey the **Fail-safe body rewrites** rule in `../../_shared/substrate.md`). **Disposition gate (before the close)**: the latest `VERIFY` comment's findings ledger covers every finding the counts line counts and none of them is `open`; the resolution comment links that ledger rather than duplicating it; otherwise do not `gh issue close` (per code-review.md's Disposition gate). **Pending-UAT guard (before the close).** If Verify left acceptance testing **not yet run** (it would otherwise be deferred), **pose the two-way choice to the user and wait for an explicit answer, never open a ticket unilaterally**: (a) run the UAT now, in this session, with no ticket (opens with the drive-mode ask, `../../_shared/techniques/acceptance-testing.md`), or (b) open a UAT follow-up ticket to run it later. On (a), run the guided walkthrough now and resolve **only on a confirmed pass** (a failing step becomes a fix or a `bug` follow-up and an incomplete/blocked step is marked pending and tracked, per the guided-UAT rules in `../../_shared/techniques/acceptance-testing.md`, not a silent close); on (b), **open the follow-up ticket carrying the owed UAT first**, linked back to this parent (a `task` on the frontier or a `trailhead:seed` gated on the run, per *Pending UAT must stay tracked* in `../../_shared/techniques/acceptance-testing.md`). **Never open a UAT ticket without asking, never `gh issue close` on a chosen-deferred UAT with nothing opened, and never let silence or an ambiguous reply default to either path.** When acceptance was already completed at Verify, this guard doesn't fire. **Post-commit self-check (before the comment goes out).** For each commit the comment cites, confirm the hash resolves (`git cat-file -e <hash>^{commit}`, or `git show --stat <hash>`) and that every file the comment names as touched actually appears in that commit's diff (`git -c core.quotepath=false show --name-only --format= <hash>`, with `core.quotepath=false` so a non-ASCII filename compares plainly instead of in git's C-quoted form); correct or drop any citation that fails the check, so a hallucinated or mis-stated commit never lands in the tracker record. **If this change materially altered the codebase** (a new module/layer, dependency, seam, or build/test command), **patch the affected facet of the `trailhead:codebase` issue** (see **Codebase** in `../../_shared/substrate.md`) in place (a line or two, not a re-map). Then close the session with the **Session handoff** ritual (`../../_shared/session-handoff.md`): `/clear` + next command.
36
36