@marcomigozzi/trailhead 0.4.0 → 0.5.1
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 +22 -15
- package/README.md +23 -16
- package/bin/lib/codex-projection.js +102 -60
- package/bin/lib/codex-projection.test.js +119 -17
- package/bin/trailhead.js +205 -51
- package/bin/trailhead.test.js +195 -15
- package/package.json +1 -1
- package/plugins/trailhead/.claude-plugin/plugin.json +8 -3
- package/plugins/trailhead/agents/trailhead-code-review.md +9 -0
- package/plugins/trailhead/agents/trailhead-codebase-map.md +9 -0
- package/plugins/trailhead/agents/trailhead-debug.md +9 -0
- package/plugins/trailhead/agents/trailhead-executor.md +9 -0
- package/plugins/trailhead/agents/trailhead-fix.md +9 -0
- package/plugins/trailhead/agents/trailhead-plan.md +9 -0
- package/plugins/trailhead/agents/trailhead-research.md +9 -0
- package/plugins/trailhead/commands/adopt.md +1 -1
- package/plugins/trailhead/commands/bug.md +1 -1
- package/plugins/trailhead/commands/config.md +1 -1
- package/plugins/trailhead/commands/dashboard.md +1 -1
- package/plugins/trailhead/commands/grill.md +1 -1
- package/plugins/trailhead/commands/idea.md +1 -1
- package/plugins/trailhead/commands/inbox.md +1 -1
- package/plugins/trailhead/commands/map.md +1 -1
- package/plugins/trailhead/commands/new.md +1 -1
- package/plugins/trailhead/commands/note.md +1 -1
- package/plugins/trailhead/commands/pause.md +1 -1
- package/plugins/trailhead/commands/quick.md +3 -1
- package/plugins/trailhead/commands/resume.md +1 -1
- package/plugins/trailhead/commands/seed.md +1 -1
- package/plugins/trailhead/commands/split.md +1 -1
- package/plugins/trailhead/commands/ticket.md +1 -1
- package/plugins/trailhead/commands/todo.md +1 -1
- package/plugins/trailhead/commands/update.md +1 -1
- package/plugins/trailhead/commands/whiteboard.md +1 -1
- package/plugins/trailhead/commands/work.md +1 -1
- package/plugins/trailhead/hooks/hooks.json +4 -0
- package/plugins/trailhead/hooks/trailhead-commit-guard.js +1 -1
- package/plugins/trailhead/hooks/trailhead-install-guard.js +176 -0
- package/plugins/trailhead/hooks/trailhead-install-guard.test.js +118 -0
- package/plugins/trailhead/hooks/trailhead-secret-guard.js +19 -4
- package/plugins/trailhead/hooks/trailhead-secret-guard.test.js +41 -1
- package/plugins/trailhead/skills/{trailhead/references/configuration.md → _shared/configuration-reference.md} +29 -9
- package/plugins/trailhead/skills/_shared/configuration.md +8 -0
- package/plugins/trailhead/skills/_shared/multi-map.md +27 -0
- package/plugins/trailhead/skills/_shared/out-of-scope.md +11 -0
- package/plugins/trailhead/skills/_shared/principles.md +8 -0
- package/plugins/trailhead/skills/_shared/session-handoff.md +22 -0
- package/plugins/trailhead/skills/_shared/substrate-commands.md +159 -0
- package/plugins/trailhead/skills/_shared/substrate.md +35 -0
- package/plugins/trailhead/skills/{trailhead/references → _shared}/teamwork.md +5 -4
- package/plugins/trailhead/skills/{trailhead/references → _shared}/techniques/acceptance-testing.md +3 -2
- package/plugins/trailhead/skills/_shared/techniques/code-review.md +18 -0
- package/plugins/trailhead/skills/{trailhead/references → _shared}/techniques/codebase-map.md +1 -1
- package/plugins/trailhead/skills/{trailhead/references → _shared}/techniques/debug.md +4 -1
- package/plugins/trailhead/skills/_shared/techniques/plan-review.md +21 -0
- package/plugins/trailhead/skills/_shared/techniques/prototype.md +39 -0
- package/plugins/trailhead/skills/{trailhead/references → _shared}/techniques/research.md +2 -1
- package/plugins/trailhead/skills/_shared/techniques.md +20 -0
- package/plugins/trailhead/skills/_shared/ticket-anatomy.md +32 -0
- package/plugins/trailhead/skills/_shared/ticket-language.md +3 -0
- package/plugins/trailhead/skills/trailhead/SKILL.md +26 -453
- package/plugins/trailhead/skills/trailhead-capture/SKILL.md +29 -0
- package/plugins/trailhead/skills/{trailhead → trailhead-capture}/references/capture.md +4 -4
- package/plugins/trailhead/skills/trailhead-chart/SKILL.md +52 -0
- package/plugins/trailhead/skills/trailhead-chart/references/charting.md +24 -0
- package/plugins/trailhead/skills/{trailhead → trailhead-chart}/references/inbox.md +6 -6
- package/plugins/trailhead/skills/trailhead-manage/SKILL.md +30 -0
- package/plugins/trailhead/skills/{trailhead → trailhead-manage}/references/updating.md +12 -0
- package/plugins/trailhead/skills/trailhead-view/SKILL.md +113 -0
- package/plugins/trailhead/skills/trailhead-work/SKILL.md +66 -0
- package/plugins/trailhead/skills/trailhead-work/references/ticket-engines.md +52 -0
- package/plugins/trailhead/skills/trailhead/references/techniques/code-review.md +0 -14
- package/plugins/trailhead/skills/trailhead/references/techniques/plan-review.md +0 -24
- package/plugins/trailhead/skills/trailhead/references/techniques/prototype.md +0 -18
- /package/plugins/trailhead/skills/{trailhead/references → _shared}/techniques/domain-vocabulary.md +0 -0
- /package/plugins/trailhead/skills/{trailhead/references → _shared}/techniques/grilling.md +0 -0
- /package/plugins/trailhead/skills/{trailhead/references → _shared}/techniques/tdd.md +0 -0
package/README.it.md
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
# Trailhead
|
|
2
6
|
|
|
3
7
|
🇬🇧 [English](README.md) · 🇮🇹 **Italiano**
|
|
4
8
|
|
|
9
|
+
[](https://www.npmjs.com/package/@marcomigozzi/trailhead) [](LICENSE)   
|
|
10
|
+
|
|
11
|
+
</div>
|
|
12
|
+
|
|
5
13
|
**Avvia e conduci grandi progetti come una mappa di ticket su GitHub Issues, risolvendone uno alla volta finché la via verso la destination non è chiara.**
|
|
6
14
|
|
|
7
|
-
`trailhead` è una skill orchestratrice per [Claude Code](https://docs.claude.com/en/docs/claude-code). Dà a un'idea grande e nebbiosa un punto da cui partire (un *trailhead*) e un modo disciplinato per portarla fino a un risultato funzionante, con l'intero piano che vive sul tuo issue tracker invece che in file locali sparsi.
|
|
15
|
+
`trailhead` è una skill orchestratrice per coding agent, che gira su [Claude Code](https://docs.claude.com/en/docs/claude-code) e [Codex CLI](https://developers.openai.com/codex/cli) da un'unica sorgente. Dà a un'idea grande e nebbiosa un punto da cui partire (un *trailhead*) e un modo disciplinato per portarla fino a un risultato funzionante, con l'intero piano che vive sul tuo issue tracker invece che in file locali sparsi.
|
|
8
16
|
|
|
9
17
|
---
|
|
10
18
|
|
|
@@ -18,7 +26,7 @@ Due approcci al lavoro di progetto guidato dagli agenti risolvono ciascuno una m
|
|
|
18
26
|
|
|
19
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.
|
|
20
28
|
|
|
21
|
-
> **trailhead è self-contained
|
|
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.
|
|
22
30
|
|
|
23
31
|
Le scelte di design che ne derivano:
|
|
24
32
|
|
|
@@ -62,12 +70,12 @@ npx @marcomigozzi/trailhead --dir=<path> # punta a una config dir specifica
|
|
|
62
70
|
```
|
|
63
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.
|
|
64
72
|
|
|
65
|
-
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 quattro guardrail come **hook** nativi di Codex (`~/.codex/hooks.json`, abilitando `features.hooks`), 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
|
|
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 quattro guardrail come **hook** nativi di Codex (`~/.codex/hooks.json`, abilitando `features.hooks`), 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.
|
|
66
74
|
|
|
67
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).
|
|
68
76
|
|
|
69
77
|
### Dopo l'installazione
|
|
70
|
-
Riavvia o ricarica il tuo agente così i comandi si registrano, poi esegui **`/trailhead`** per iniziare (smart entry), o `/trailhead:new "<idea>"` per tracciare una mappa. **Su Codex** la superficie è `$trailhead`: esegui **`$trailhead`** per lo smart entry, `$trailhead new "<idea>"` per tracciare, o una skill per-verbo `$trailhead-<verb>`. Nota: una volta installato, l'**hook di commit guard gira a ogni `git commit`** (imponendo i Conventional Commits e bloccando `Co-Authored-By`); disabilita gli hook del plugin nelle impostazioni se non lo vuoi. In ogni caso trailhead è self-contained:
|
|
78
|
+
Riavvia o ricarica il tuo agente così i comandi si registrano, poi esegui **`/trailhead`** per iniziare (smart entry), o `/trailhead:new "<idea>"` per tracciare una mappa. **Su Codex** la superficie è `$trailhead`: esegui **`$trailhead`** per lo smart entry, `$trailhead new "<idea>"` per tracciare, o una skill per-verbo `$trailhead-<verb>`. Nota: una volta installato, l'**hook di commit guard gira a ogni `git commit`** (imponendo i Conventional Commits e bloccando `Co-Authored-By`); disabilita gli hook del plugin nelle impostazioni se non lo vuoi. In ogni caso trailhead è self-contained: nessuna skill o plugin esterna è richiesta, niente preflight, niente version drift.
|
|
71
79
|
|
|
72
80
|
---
|
|
73
81
|
|
|
@@ -234,7 +242,7 @@ Due regole pratiche: i build ticket **non fanno mai auto-grill**: su un'ambiguit
|
|
|
234
242
|
Tutto ciò di cui la mappa ha bisogno è espresso come label GitHub, così lo stato è interrogabile nella UI del tracker:
|
|
235
243
|
|
|
236
244
|
- **Strutturali:** `trailhead:map`, `trailhead:ticket`
|
|
237
|
-
- **Anchor con scope di repo (uno ciascuno per repo, pinnati):** `trailhead:codebase` 🧱 (la codebase map distillata), `trailhead:conventions` 📜 (il modo di lavorare), `trailhead:dashboard` 📊 (l'indice pinnato di mappe + whiteboard + conteggi)
|
|
245
|
+
- **Anchor con scope di repo (uno ciascuno per repo, pinnati):** `trailhead:codebase` 🧱 (la codebase map distillata), `trailhead:conventions` 📜 (il modo di lavorare), `trailhead:dashboard` 📊 (l'indice pinnato di mappe + whiteboard + conteggi); ogni titolo porta la sua icona (come il 🗺 della mappa) così gli anchor pinnati si distinguono a colpo d'occhio
|
|
238
246
|
- **Type (una per ticket):** 🧭 `trailhead:decision` · 🔬 `research` · 🎨 `prototype` · 🔨 `build` · 🐛 `bug` · 🔧 `task`
|
|
239
247
|
- **State:** `trailhead:blocked` (ha un blocker aperto) · `seed` (parcheggiato su un trigger) · `out-of-scope` (chiuso, oltre la destination) · `superseded` (chiuso, splittato in figli)
|
|
240
248
|
- **Container:** `trailhead:whiteboard` (un ticket sciolto, senza mappa, fuori dalla frontier di ogni mappa, sulla frontier propria della whiteboard)
|
|
@@ -289,13 +297,15 @@ Il passo **📊 statusline** offre di installare la status bar di trailhead per
|
|
|
289
297
|
|---|---|---|
|
|
290
298
|
| `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 |
|
|
291
299
|
| `models.{plan,execute,research,review,debug}` | un id modello completo **versionato** (**inherit session**) | quale modello esegue ogni attività; `plan` ed `execute` sono sempre impostati separatamente |
|
|
292
|
-
| `design` | **`disk`** \| `claude.ai/design` | dove vanno i mockup UI: HTML usa-e-getta locale, o
|
|
300
|
+
| `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) |
|
|
301
|
+
| `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` |
|
|
293
302
|
| `design.approval` | **`explicit`** \| `auto` | attendi l'approvazione del mockup prima del codice UI, o procedi senza bloccare |
|
|
294
303
|
| `tdd` | **`seams`** \| `on` \| `off` | come il motore `build` testa |
|
|
295
304
|
| `acceptance.browser` | **`auto`** \| `on` \| `off` | guida il browser in Verify, o ti accompagna in una UAT conversazionale (passo-passo in chat, non una checklist da fare da solo) |
|
|
296
305
|
| `testing.webapp` / `testing.url` | bool / URL | è browser-drivabile, e dove |
|
|
297
306
|
| `plan_review` | **`off`** \| `on` \| CLI list | invia i PLAN di `build` ad AI CLI esterne (Gemini, Codex, …) per un secondo parere e converge sulle loro obiezioni |
|
|
298
307
|
| `plan_review.rounds` | integer (**`2`**) | numero massimo di round converge-and-re-review |
|
|
308
|
+
| `code_review.rounds` | integer (**`2`**) | numero massimo di round fix-and-re-review in Code review prima del checkpoint HITL di confine |
|
|
299
309
|
|
|
300
310
|
**Models.** Ogni chiave esegue la sua attività come **subagent** sul modello che nomini, così l'intera suddivisione per-attività si applica dentro una singola sessione di lavoro, qualunque modello quella sessione esegua:
|
|
301
311
|
|
|
@@ -312,17 +322,14 @@ Esempio di file di config (la stessa forma funziona per il `.trailhead/config.js
|
|
|
312
322
|
{ "ticket": { "language": "en" }, "models": { "plan": "claude-opus-4-8", "execute": "claude-sonnet-5" }, "tdd": "seams", "acceptance": { "browser": "auto" } }
|
|
313
323
|
```
|
|
314
324
|
|
|
315
|
-
**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
|
|
316
|
-
|
|
317
|
-
Alla prima schermata UI, trailhead chiede quale design system usare. Puoi:
|
|
325
|
+
**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`:
|
|
318
326
|
|
|
319
|
-
-
|
|
320
|
-
-
|
|
321
|
-
- **crearne uno nuovo** (ti chiede il nome).
|
|
327
|
+
- **`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.
|
|
328
|
+
- **`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.
|
|
322
329
|
|
|
323
|
-
Fa il caching dell'id scelto in `design.project
|
|
330
|
+
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.
|
|
324
331
|
|
|
325
|
-
|
|
332
|
+
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.
|
|
326
333
|
|
|
327
334
|
---
|
|
328
335
|
|
package/README.md
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
# Trailhead
|
|
2
6
|
|
|
3
7
|
🇬🇧 **English** · 🇮🇹 [Italiano](README.it.md)
|
|
4
8
|
|
|
9
|
+
[](https://www.npmjs.com/package/@marcomigozzi/trailhead) [](LICENSE)   
|
|
10
|
+
|
|
11
|
+
</div>
|
|
12
|
+
|
|
5
13
|
**Start and drive large projects as a map of tickets on GitHub Issues, resolving one at a time until the way to the destination is clear.**
|
|
6
14
|
|
|
7
|
-
`trailhead` is an orchestrator skill for [Claude Code](https://docs.claude.com/en/docs/claude-code). It gives a big, foggy idea a place to begin (a *trailhead*) and a disciplined way to walk it to a working result, with the whole plan living on your issue tracker instead of in scattered local files.
|
|
15
|
+
`trailhead` is an orchestrator skill for coding agents, running on [Claude Code](https://docs.claude.com/en/docs/claude-code) and [Codex CLI](https://developers.openai.com/codex/cli) from a single source. It gives a big, foggy idea a place to begin (a *trailhead*) and a disciplined way to walk it to a working result, with the whole plan living on your issue tracker instead of in scattered local files.
|
|
8
16
|
|
|
9
17
|
---
|
|
10
18
|
|
|
@@ -16,9 +24,9 @@ Two approaches to agent-driven project work each nail one half of the problem:
|
|
|
16
24
|
|
|
17
25
|
- **GSD** (the [open-gsd](https://github.com/open-gsd/gsd-core) workflow system) is brilliant at *doing*. Its `discuss → plan → execute → verify` cycle, atomic commits, and zero-friction capture make the actual construction reliable and reviewable. But its state lives in a local `.planning/` tree, separate from where the team can see it.
|
|
18
26
|
|
|
19
|
-
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
|
|
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.
|
|
20
28
|
|
|
21
|
-
> **trailhead is self-contained
|
|
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.
|
|
22
30
|
|
|
23
31
|
The design choices that fall out of it:
|
|
24
32
|
|
|
@@ -62,12 +70,12 @@ npx @marcomigozzi/trailhead --dir=<path> # target a specific config dir
|
|
|
62
70
|
```
|
|
63
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.
|
|
64
72
|
|
|
65
|
-
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 four guardrails as native Codex **hooks** (`~/.codex/hooks.json`, enabling `features.hooks`), 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
|
|
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 four guardrails as native Codex **hooks** (`~/.codex/hooks.json`, enabling `features.hooks`), 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.
|
|
66
74
|
|
|
67
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).
|
|
68
76
|
|
|
69
77
|
### After installing
|
|
70
|
-
Restart or reload your agent so the commands register, then run **`/trailhead`** to start (smart entry), or `/trailhead:new "<idea>"` to chart a map. **On Codex** the surface is `$trailhead` instead: run **`$trailhead`** for smart entry, `$trailhead new "<idea>"` to chart, or a per-verb `$trailhead-<verb>` skill. Note: once installed, the **commit guard hook runs on every `git commit`** (enforcing Conventional Commits and blocking `Co-Authored-By`); disable the plugin's hooks in settings if you don't want that. Either way trailhead is self-contained: no
|
|
78
|
+
Restart or reload your agent so the commands register, then run **`/trailhead`** to start (smart entry), or `/trailhead:new "<idea>"` to chart a map. **On Codex** the surface is `$trailhead` instead: run **`$trailhead`** for smart entry, `$trailhead new "<idea>"` to chart, or a per-verb `$trailhead-<verb>` skill. Note: once installed, the **commit guard hook runs on every `git commit`** (enforcing Conventional Commits and blocking `Co-Authored-By`); disable the plugin's hooks in settings if you don't want that. Either way trailhead is self-contained: no external skill or plugin is required, no preflight, no version drift.
|
|
71
79
|
|
|
72
80
|
---
|
|
73
81
|
|
|
@@ -234,7 +242,7 @@ Two rules of thumb: build tickets **never auto-grill**: on blocking ambiguity th
|
|
|
234
242
|
Everything the map needs is expressed as GitHub labels, so state is queryable in the tracker UI:
|
|
235
243
|
|
|
236
244
|
- **Structural:** `trailhead:map`, `trailhead:ticket`
|
|
237
|
-
- **Repo-scoped anchors (one each per repo, pinned):** `trailhead:codebase` 🧱 (the distilled codebase map), `trailhead:conventions` 📜 (the way of working), `trailhead:dashboard` 📊 (the pinned index of maps + whiteboard + counts)
|
|
245
|
+
- **Repo-scoped anchors (one each per repo, pinned):** `trailhead:codebase` 🧱 (the distilled codebase map), `trailhead:conventions` 📜 (the way of working), `trailhead:dashboard` 📊 (the pinned index of maps + whiteboard + counts); each title carries its icon (like the map's 🗺) so the pinned anchors stand apart at a glance
|
|
238
246
|
- **Type (one per ticket):** 🧭 `trailhead:decision` · 🔬 `research` · 🎨 `prototype` · 🔨 `build` · 🐛 `bug` · 🔧 `task`
|
|
239
247
|
- **State:** `trailhead:blocked` (has an open blocker) · `seed` (parked on a trigger) · `out-of-scope` (closed, beyond the destination) · `superseded` (closed, split into children)
|
|
240
248
|
- **Container:** `trailhead:whiteboard` (a loose, map-less ticket, off every map's frontier, on the whiteboard's own)
|
|
@@ -289,13 +297,15 @@ The **📊 statusline** step offers to install trailhead's Claude Code status ba
|
|
|
289
297
|
|---|---|---|
|
|
290
298
|
| `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 |
|
|
291
299
|
| `models.{plan,execute,research,review,debug}` | a full **versioned** model id (**inherit session**) | which model runs each activity; `plan` and `execute` are always set separately |
|
|
292
|
-
| `design` | **`disk`** \| `claude.ai/design` | where UI mockups go: local throwaway HTML, or
|
|
300
|
+
| `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) |
|
|
301
|
+
| `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` |
|
|
293
302
|
| `design.approval` | **`explicit`** \| `auto` | wait for mockup approval before UI code, or proceed without blocking |
|
|
294
303
|
| `tdd` | **`seams`** \| `on` \| `off` | how the `build` engine tests |
|
|
295
304
|
| `acceptance.browser` | **`auto`** \| `on` \| `off` | drive the browser in Verify, or walk you through a conversational UAT (step by step in chat, not a checklist to self-serve) |
|
|
296
305
|
| `testing.webapp` / `testing.url` | bool / URL | is it browser-drivable, and where |
|
|
297
306
|
| `plan_review` | **`off`** \| `on` \| CLI list | send `build` PLANs to external AI CLIs (Gemini, Codex, …) for a second opinion and converge on their concerns |
|
|
298
307
|
| `plan_review.rounds` | integer (**`2`**) | max converge-and-re-review rounds |
|
|
308
|
+
| `code_review.rounds` | integer (**`2`**) | max fix-and-re-review rounds in Code review before its boundary HITL checkpoint |
|
|
299
309
|
|
|
300
310
|
**Models.** Each key runs its activity as a **subagent** on the model you name, so the whole per-activity split applies within a single work session, whatever model that session runs on:
|
|
301
311
|
|
|
@@ -312,17 +322,14 @@ Example config file (the same shape works for the project `.trailhead/config.jso
|
|
|
312
322
|
{ "ticket": { "language": "en" }, "models": { "plan": "claude-opus-4-8", "execute": "claude-sonnet-5" }, "tdd": "seams", "acceptance": { "browser": "auto" } }
|
|
313
323
|
```
|
|
314
324
|
|
|
315
|
-
**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
|
|
316
|
-
|
|
317
|
-
On the first UI screen, trailhead asks which design system to use. You can:
|
|
325
|
+
**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`:
|
|
318
326
|
|
|
319
|
-
-
|
|
320
|
-
-
|
|
321
|
-
- **create a new one** (it asks you for the name).
|
|
327
|
+
- **`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.
|
|
328
|
+
- **`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.
|
|
322
329
|
|
|
323
|
-
It caches the chosen id in `design.project
|
|
330
|
+
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.
|
|
324
331
|
|
|
325
|
-
|
|
332
|
+
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.
|
|
326
333
|
|
|
327
334
|
---
|
|
328
335
|
|
|
@@ -90,8 +90,8 @@ This trailhead engine is running on **Codex CLI**, not Claude Code. The installe
|
|
|
90
90
|
## A. Commands
|
|
91
91
|
trailhead is a native Codex skill. Invoke it as \`$trailhead <verb>\` (e.g. \`$trailhead work\`, \`$trailhead new "idea"\`); bare \`$trailhead\` is smart entry. Never \`/trailhead:<verb>\` (that is the Claude Code surface). Whatever you type after the verb is the arguments. For discoverability the installer also projects one thin skill per verb (\`$trailhead-work\`, \`$trailhead-bug\`, …) that just delegates to \`$trailhead <verb>\`, so the verbs surface in the \`$\`-menu; \`$trailhead <verb>\` stays the canonical form and this SKILL.md the single source of truth. (Codex custom prompts under \`~/.codex/prompts/\` are deliberately NOT used: they do not surface as slash commands.)
|
|
92
92
|
|
|
93
|
-
## B. This IS the skill
|
|
94
|
-
Codex loaded this SKILL.md because you invoked \`$trailhead
|
|
93
|
+
## B. This IS the skill; the engine is split across sibling skill dirs
|
|
94
|
+
Codex loaded this SKILL.md because you invoked \`$trailhead\` (or a \`$trailhead-<verb>\` / \`$trailhead-<cluster>\` entry); there is no separate Skill tool to call. The engine is split across sibling skill dirs under \`~/.codex/skills/\`: the dispatcher (\`trailhead/\`), five cluster skills (\`trailhead-chart/\`, \`trailhead-work/\`, \`trailhead-view/\`, \`trailhead-capture/\`, \`trailhead-manage/\`), and the shared core (\`_shared/\`, no SKILL.md). Read every referenced file **relative to the SKILL.md you are currently in**: a \`references/*.md\` from this skill's own dir, and the shared core (\`../_shared/*.md\`, or \`../../_shared/*.md\` from a \`references/\` file) from the sibling \`_shared/\` dir. Where the dispatcher's routing says "call the Skill tool with skill name \`trailhead-<cluster>\` and arguments \`<verb> <rest>\`", there is no Skill tool on Codex: **Read \`../trailhead-<cluster>/SKILL.md\` (the sibling dir) and follow it**, treating \`<verb> <rest>\` as its arguments.
|
|
95
95
|
|
|
96
96
|
## C. AskUserQuestion -> request_user_input
|
|
97
97
|
Where the engine uses \`AskUserQuestion\`, use Codex's \`request_user_input\`: map \`header\`->\`header\`, \`question\`->\`question\`, each option \`{label, description}\`; generate an \`id\` from the header (lowercase, spaces->underscores). Codex has no \`multiSelect\`: present sequential single-selects, or a numbered freeform list and ask for comma-separated numbers. If \`request_user_input\` is unavailable, present the choices as a plain-text numbered list and STOP for the user's reply; do not silently pick a default and proceed.
|
|
@@ -99,7 +99,9 @@ Where the engine uses \`AskUserQuestion\`, use Codex's \`request_user_input\`: m
|
|
|
99
99
|
## D. Subagents (native multi_agent)
|
|
100
100
|
Codex has a subagent toolkit: the multi_agent tools (\`spawn_agent\`, \`send_input\`, \`wait_agent\`, \`resume_agent\`, \`close_agent\`), stable and on by default on supported Codex (the installer gates on the floor that guarantees them). Where the engine delegates to a subagent (research, codebase-map, review, plan, execute, debug), spawn a real Codex subagent with these tools and the technique's own protocol (each technique carries its full protocol in-prompt, so no specialised agent is needed; pass the ticket's \`Scope:\` when relevant). The Claude-only Explore-vs-general-purpose split does not apply: Codex has one subagent kind. A subagent runs as a FRESH session that receives a task prompt, not this conversation; run independent ones in parallel (e.g. the codebase-map readers) and \`wait_agent\` on them.
|
|
101
101
|
|
|
102
|
-
**
|
|
102
|
+
**Never surrender the session to one open-ended \`wait_agent\`; poll instead.** \`wait_agent\` blocks until the subagent returns, so a single unconditional \`wait_agent\` on a long or stalling subagent freezes the whole session with nothing to check: this is the review / plan-review hang. Collect every delegated subagent through a **bounded wait in a poll loop**, not one open-ended blocking call. Give \`wait_agent\` a short timeout (30 to 60s); on each timeout, report a one-line "still running" progress note and loop again, so the session stays responsive and can be checked or interrupted between polls. The two **review** steps, **Code review** and **Cross-AI plan review**, always run this way: backgrounding and polling them (never a blind \`wait_agent\`) is the engine's hard cross-host default, not merely the case where it matters most. They are also the longest quiet activities in the cycle (a full-diff adversarial review, or an external CLI) and the ones most often seen to hang. If your Codex build's \`wait_agent\` exposes no timeout, poll the agent's status/output at intervals instead of blocking, or run the review as a **background job** and check back on it at intervals; the rule is the same either way. When several subagents run in parallel, poll them as a set, a bounded wait cycling across the outstanding handles, reporting which are still running.
|
|
103
|
+
|
|
104
|
+
**Per-technique agent registry (\`agent_type\` dispatch).** The installer always projects all 7 committed trailhead agents as \`~/.codex/agents/trailhead-<technique>.toml\` (one per technique) and enables \`features.multi_agent_v2\`, so Codex always exposes a per-technique agent registry. A TOML whose technique has a \`models.codex.<key>\` pin set carries that OpenAI model (plus its reasoning effort); every other TOML — an unpinned keyed technique, or one of the 2 keyless agents — is pin-less and its subagent inherits the session model. Detect the registry at runtime by introspecting the visible \`spawn_agent\` tool schema (GSD-style, never a config read): if its parameters expose an \`agent_type\` field, spawn each delegated activity as \`spawn_agent(agent_type="trailhead-<technique>", reasoning_effort=…)\` (\`trailhead-plan\` for the Plan step, \`trailhead-execute\` for Execute, likewise research/review/debug, plus the 2 keyless \`trailhead-fix\` and \`trailhead-codebase-map\` for the Fix and Codebase-map steps), which routes it onto that technique's pinned model when one is set, or the session model otherwise. If the \`spawn_agent\` schema exposes NO \`agent_type\` field at all (a Codex build with only base multi_agent v1), spawn with base \`spawn_agent\` and the subagents inherit the one session model. Trust the tool surface you actually see and degrade gracefully: \`multi_agent_v2\` is still under development upstream, so v1 stays a supported runtime.
|
|
103
105
|
|
|
104
106
|
\`config.models.*\` (Claude model ids) still cannot take effect here regardless: Codex's subagent model registry is OpenAI-only, so a Claude id cannot run and those keys collapse to the session model. The honoured namespace on Codex is \`models.codex.*\` (above); the one-time models-collapse notice still applies while a stray \`models.*\` is set and \`models.codex.*\` is empty.
|
|
105
107
|
|
|
@@ -107,10 +109,13 @@ Codex has a subagent toolkit: the multi_agent tools (\`spawn_agent\`, \`send_inp
|
|
|
107
109
|
The engine's \`/clear\` is Codex's \`/new\` (start a fresh session). Command references in a handoff use the skill form (\`$trailhead work <n>\`).
|
|
108
110
|
|
|
109
111
|
## F. Lifecycle hooks (native Codex hooks)
|
|
110
|
-
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 and
|
|
112
|
+
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 and install-guard as \`PreToolUse\` (matcher \`Bash\`) hooks that can veto the command before it runs, the injection-scanner as a \`PostToolUse\` (matcher \`Bash\`) advisory, and check-update as a \`SessionStart\` hook. 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.
|
|
111
113
|
|
|
112
114
|
## G. Design / UI mockups -> local disk
|
|
113
115
|
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.
|
|
116
|
+
|
|
117
|
+
## H. Shell timeouts & background jobs (plan-review's external CLIs)
|
|
118
|
+
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).
|
|
114
119
|
</codex_skill_adapter>`;
|
|
115
120
|
}
|
|
116
121
|
|
|
@@ -145,47 +150,71 @@ policy:
|
|
|
145
150
|
`;
|
|
146
151
|
}
|
|
147
152
|
|
|
148
|
-
// ---
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
//
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
developerInstructions: "You are trailhead's debug subagent on Codex. Find the root cause of the ticket's defect by the scientific method (reproduce, localise, falsifiable hypotheses, confirm, verify), per the Debug technique in the trailhead skill at ~/.codex/skills/trailhead.",
|
|
172
|
-
}),
|
|
153
|
+
// --- codexClusterAgentsYaml ------------------------------------------------
|
|
154
|
+
// UI metadata for a projected cluster skill (trailhead-chart, trailhead-work,
|
|
155
|
+
// ...): a display name + explicit-only invocation, so a cluster never
|
|
156
|
+
// auto-loads into an unrelated turn. Mirrors codexAgentsYaml's shape.
|
|
157
|
+
function codexClusterAgentsYaml(cluster) {
|
|
158
|
+
const short = String(cluster).replace(/^trailhead-/, '');
|
|
159
|
+
return `interface:
|
|
160
|
+
display_name: ${yamlQuote(`Trailhead: ${short}`)}
|
|
161
|
+
short_description: ${yamlQuote(`trailhead ${short} cluster`)}
|
|
162
|
+
default_prompt: ${yamlQuote(`Run $${cluster}`)}
|
|
163
|
+
policy:
|
|
164
|
+
allow_implicit_invocation: false
|
|
165
|
+
`;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// --- CODEX_AGENT_NAME_ALIASES / codexTechniqueKey ---------------------------
|
|
169
|
+
// The 7 committed agent sources (plugins/trailhead/agents/trailhead-*.md) are
|
|
170
|
+
// keyed by their trailhead-<name>.md filename stem. Two of those stems don't
|
|
171
|
+
// match the models.codex.<key> pin namespace, so alias them; every other
|
|
172
|
+
// agent's key is just its name with the trailhead- prefix stripped.
|
|
173
|
+
const CODEX_AGENT_NAME_ALIASES = Object.freeze({
|
|
174
|
+
'trailhead-executor': 'execute',
|
|
175
|
+
'trailhead-code-review': 'review',
|
|
173
176
|
});
|
|
174
177
|
|
|
178
|
+
function codexTechniqueKey(name) {
|
|
179
|
+
return CODEX_AGENT_NAME_ALIASES[name] || String(name).replace(/^trailhead-/, '');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// --- MODEL_KEYS --------------------------------------------------------------
|
|
183
|
+
// The 5 pinnable technique keys, mirroring the models.codex.* namespace. The
|
|
184
|
+
// other 2 committed agents (fix, codebase-map) have no pin key and are always
|
|
185
|
+
// projected pin-less (session model).
|
|
186
|
+
const MODEL_KEYS = new Set(['plan', 'execute', 'research', 'review', 'debug']);
|
|
187
|
+
|
|
175
188
|
// --- codexAgentToml ---------------------------------------------------------
|
|
176
|
-
// Render one Codex custom-agent TOML.
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
189
|
+
// Render one Codex custom-agent TOML. When `model` is empty/absent, the TOML
|
|
190
|
+
// is pin-less: no `model =` line (and so no model_reasoning_effort either),
|
|
191
|
+
// so the subagent inherits the session model. When `model` is present,
|
|
192
|
+
// model_reasoning_effort is emitted only when effort is a non-empty string.
|
|
193
|
+
// developer_instructions is a TOML multi-line literal block ('''...'''); a
|
|
194
|
+
// stray ''' inside the text (none of ours has one, but be safe) is
|
|
195
|
+
// neutralised so it can't close the block early. The basic-string fields
|
|
196
|
+
// (name/description/model/effort) are escaped so a stray " or \ in a source
|
|
197
|
+
// value (description comes from the agent .md frontmatter) can't break the TOML.
|
|
198
|
+
function tomlBasicString(s) {
|
|
199
|
+
return String(s)
|
|
200
|
+
.replace(/\\/g, '\\\\')
|
|
201
|
+
.replace(/"/g, '\\"')
|
|
202
|
+
.replace(/\n/g, '\\n')
|
|
203
|
+
.replace(/\r/g, '\\r')
|
|
204
|
+
.replace(/\t/g, '\\t');
|
|
205
|
+
}
|
|
206
|
+
|
|
180
207
|
function codexAgentToml({ name, description, developerInstructions, model, effort }) {
|
|
181
208
|
const safeInstructions = String(developerInstructions).split("'''").join("''");
|
|
182
209
|
const lines = [
|
|
183
|
-
`name = "${name}"`,
|
|
184
|
-
`description = "${description}"`,
|
|
185
|
-
`model = "${model}"`,
|
|
210
|
+
`name = "${tomlBasicString(name)}"`,
|
|
211
|
+
`description = "${tomlBasicString(description)}"`,
|
|
186
212
|
];
|
|
187
|
-
if (typeof
|
|
188
|
-
lines.push(`
|
|
213
|
+
if (typeof model === 'string' && model.trim() !== '') {
|
|
214
|
+
lines.push(`model = "${tomlBasicString(model)}"`);
|
|
215
|
+
if (typeof effort === 'string' && effort.trim() !== '') {
|
|
216
|
+
lines.push(`model_reasoning_effort = "${tomlBasicString(effort)}"`);
|
|
217
|
+
}
|
|
189
218
|
}
|
|
190
219
|
lines.push(`developer_instructions = '''\n${safeInstructions}\n'''`);
|
|
191
220
|
return lines.join('\n') + '\n';
|
|
@@ -194,43 +223,54 @@ function codexAgentToml({ name, description, developerInstructions, model, effor
|
|
|
194
223
|
// --- codexAgentTomlPlan ------------------------------------------------------
|
|
195
224
|
// Given the resolved models.codex config (a plain object like
|
|
196
225
|
// { plan: "gpt-5.6-terra", execute: { model: "gpt-5.6-sol", effort: "high" } },
|
|
197
|
-
// or null/undefined/{})
|
|
198
|
-
//
|
|
199
|
-
//
|
|
200
|
-
//
|
|
201
|
-
|
|
226
|
+
// or null/undefined/{}) and `agentDefs` (the array from the installer's
|
|
227
|
+
// readAgentDefs(): every committed plugins/trailhead/agents/trailhead-*.md,
|
|
228
|
+
// each { name, description, tools, body }), return the set of
|
|
229
|
+
// trailhead-<technique>.toml writes the installer should make: ONE per agent,
|
|
230
|
+
// uniformly (all 7 project, always). A keyed agent (plan/execute/research/
|
|
231
|
+
// review/debug) carries its models.codex.<key> pin when set, else is
|
|
232
|
+
// pin-less; the 2 keyless agents (fix, codebase-map) are always pin-less.
|
|
233
|
+
// Iterates agentDefs in the given order (readAgentDefs sorts by name) so the
|
|
234
|
+
// write order is deterministic.
|
|
235
|
+
function codexAgentTomlPlan(codexHome, codexModels, agentDefs) {
|
|
202
236
|
const models = codexModels && typeof codexModels === 'object' ? codexModels : {};
|
|
203
237
|
const dir = codexLayout(codexHome).codexAgentsDir;
|
|
238
|
+
const defs = Array.isArray(agentDefs) ? agentDefs : [];
|
|
204
239
|
const writes = [];
|
|
205
240
|
|
|
206
|
-
for (const
|
|
207
|
-
const
|
|
208
|
-
|
|
241
|
+
for (const def of defs) {
|
|
242
|
+
const key = codexTechniqueKey(def.name);
|
|
243
|
+
const name = `trailhead-${key}`;
|
|
244
|
+
const filePath = path.join(dir, `${name}.toml`);
|
|
209
245
|
|
|
210
246
|
let model = null;
|
|
211
247
|
let effort = null;
|
|
212
|
-
if (
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (
|
|
217
|
-
|
|
218
|
-
|
|
248
|
+
if (MODEL_KEYS.has(key) && models[key] != null) {
|
|
249
|
+
const raw = models[key];
|
|
250
|
+
if (typeof raw === 'string') {
|
|
251
|
+
if (raw.trim() !== '') model = raw;
|
|
252
|
+
} else if (typeof raw === 'object') {
|
|
253
|
+
const m = typeof raw.model === 'string' ? raw.model : '';
|
|
254
|
+
if (m.trim() !== '') {
|
|
255
|
+
model = m;
|
|
256
|
+
effort = typeof raw.effort === 'string' ? raw.effort : null;
|
|
257
|
+
}
|
|
219
258
|
}
|
|
220
259
|
}
|
|
221
|
-
if (!model) continue;
|
|
222
260
|
|
|
223
|
-
const
|
|
224
|
-
const
|
|
225
|
-
|
|
261
|
+
const lead = 'You are running on Codex CLI; the trailhead skill lives at ~/.codex/skills/trailhead.\n\n';
|
|
262
|
+
const developerInstructions = lead + convertToCodex(String(def.body || '')).trim();
|
|
263
|
+
|
|
226
264
|
const content = codexAgentToml({
|
|
227
265
|
name,
|
|
228
|
-
description
|
|
229
|
-
|
|
266
|
+
// Route the description through convertToCodex too (like the body), and
|
|
267
|
+
// default a missing frontmatter description to '' rather than "undefined".
|
|
268
|
+
description: convertToCodex(String(def.description || '')),
|
|
269
|
+
developerInstructions,
|
|
230
270
|
model,
|
|
231
271
|
effort,
|
|
232
272
|
});
|
|
233
|
-
writes.push({ technique, name, path: filePath, content });
|
|
273
|
+
writes.push({ technique: key, name, path: filePath, content });
|
|
234
274
|
}
|
|
235
275
|
|
|
236
276
|
return { writes };
|
|
@@ -325,6 +365,7 @@ function codexHookEntries(hooksScriptsDir) {
|
|
|
325
365
|
return [
|
|
326
366
|
{ event: 'PreToolUse', matcher: 'Bash', command: cmd('trailhead-commit-guard.js') },
|
|
327
367
|
{ event: 'PreToolUse', matcher: 'Bash', command: cmd('trailhead-secret-guard.js') },
|
|
368
|
+
{ event: 'PreToolUse', matcher: 'Bash', command: cmd('trailhead-install-guard.js') },
|
|
328
369
|
{ event: 'PostToolUse', matcher: 'Bash', command: cmd('trailhead-issue-injection-scanner.js') },
|
|
329
370
|
{ event: 'SessionStart', matcher: '', command: cmd('trailhead-check-update.js') },
|
|
330
371
|
];
|
|
@@ -388,6 +429,7 @@ module.exports = {
|
|
|
388
429
|
codexSkillAdapterHeader,
|
|
389
430
|
injectCodexAdapterHeader,
|
|
390
431
|
codexAgentsYaml,
|
|
432
|
+
codexClusterAgentsYaml,
|
|
391
433
|
codexAgentToml,
|
|
392
434
|
codexAgentTomlPlan,
|
|
393
435
|
codexVerbSkillContent,
|