@marcomigozzi/trailhead 0.8.0 → 0.8.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.
@@ -118,6 +118,22 @@ for (const cl of ['trailhead-chart', 'trailhead-work', 'trailhead-view', 'trailh
118
118
  // A cluster's ../_shared/ reference target actually resolves as a sibling.
119
119
  ok('codex: trailhead-work/../_shared/substrate.md resolves', fs.existsSync(path.join(codexDir, 'skills', 'trailhead-work', '..', '_shared', 'substrate.md')));
120
120
 
121
+ // --- #139: single-sourced "Load first, in order" shared section --------------
122
+ ok('codex: _shared/load-first.md projected', fs.existsSync(path.join(codexDir, 'skills', '_shared', 'load-first.md')));
123
+ for (const cl of ['trailhead', 'trailhead-chart', 'trailhead-work', 'trailhead-view', 'trailhead-capture', 'trailhead-manage']) {
124
+ ok(`codex: ${cl}/../_shared/load-first.md resolves as a sibling`, fs.existsSync(path.join(codexDir, 'skills', cl, '..', '_shared', 'load-first.md')));
125
+ ok(`codex: ${cl} SKILL.md references ../_shared/load-first.md`, fs.readFileSync(path.join(codexDir, 'skills', cl, 'SKILL.md'), 'utf8').includes('../_shared/load-first.md'));
126
+ }
127
+ // Source-level anti-drift: the shared core-list signature line lives ONLY in
128
+ // _shared/load-first.md, never duplicated back into a cluster SKILL.md.
129
+ const sourceSkillsDir = path.join(__dirname, '..', 'plugins', 'trailhead', 'skills');
130
+ const loadFirstSignature = '`../_shared/principles.md`: refer by name';
131
+ const loadFirstSourcePath = path.join(sourceSkillsDir, '_shared', 'load-first.md');
132
+ ok('source: _shared/load-first.md carries the core-list signature line', fs.readFileSync(loadFirstSourcePath, 'utf8').includes(loadFirstSignature));
133
+ for (const cl of ['trailhead', 'trailhead-chart', 'trailhead-work', 'trailhead-view', 'trailhead-capture', 'trailhead-manage']) {
134
+ ok(`source: ${cl}/SKILL.md does NOT duplicate the core-list signature line`, !fs.readFileSync(path.join(sourceSkillsDir, cl, 'SKILL.md'), 'utf8').includes(loadFirstSignature));
135
+ }
136
+
121
137
  // --- codex hooks (#29) --------------------------------------------------------
122
138
  const codexHooksJsonPath = path.join(codexDir, 'hooks.json');
123
139
  ok('codex: hooks.json exists', fs.existsSync(codexHooksJsonPath));
@@ -249,6 +265,12 @@ for (const cl of ['trailhead-chart', 'trailhead-work', 'trailhead-view', 'trailh
249
265
  ok(`claude: skills/${cl}/SKILL.md exists`, fs.existsSync(path.join(claudeDir, 'skills', cl, 'SKILL.md')));
250
266
  }
251
267
  ok('claude: cluster ../_shared/ reference resolves', fs.existsSync(path.join(claudeDir, 'skills', 'trailhead-work', '..', '_shared', 'substrate.md')));
268
+ // #139: single-sourced "Load first, in order" shared section, projected on Claude too.
269
+ ok('claude: skills/_shared/load-first.md exists', fs.existsSync(path.join(claudeDir, 'skills', '_shared', 'load-first.md')));
270
+ ok('claude: trailhead-work/../_shared/load-first.md resolves', fs.existsSync(path.join(claudeDir, 'skills', 'trailhead-work', '..', '_shared', 'load-first.md')));
271
+ for (const cl of ['trailhead', 'trailhead-chart', 'trailhead-work', 'trailhead-view', 'trailhead-capture', 'trailhead-manage']) {
272
+ ok(`claude: ${cl} SKILL.md references ../_shared/load-first.md`, fs.readFileSync(path.join(claudeDir, 'skills', cl, 'SKILL.md'), 'utf8').includes('../_shared/load-first.md'));
273
+ }
252
274
  ok('claude: commands/trailhead/work.md exists', fs.existsSync(path.join(claudeDir, 'commands', 'trailhead', 'work.md')));
253
275
  ok('claude: commands/trailhead/auto.md exists', fs.existsSync(path.join(claudeDir, 'commands', 'trailhead', 'auto.md')));
254
276
  ok('claude: hooks/trailhead-commit-guard.js exists', fs.existsSync(path.join(claudeDir, 'hooks', 'trailhead-commit-guard.js')));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marcomigozzi/trailhead",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
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.8.0",
3
+ "version": "0.8.1",
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",
@@ -0,0 +1,16 @@
1
+ # Load first, in order
2
+
3
+ The **shared-core load contract**, single-sourced here and referenced by every cluster `SKILL.md`: the dispatcher `trailhead/` and the five clusters `trailhead-chart` / `trailhead-work` / `trailhead-view` / `trailhead-capture` / `trailhead-manage`. Each cluster's own `## Load first, in order` points here in a line, then states its cluster-specific isolation posture; this file holds the part that is identical for all of them.
4
+
5
+ The paths below are written **relative to the cluster `SKILL.md` that pointed you here** (exactly as that `SKILL.md`'s own shared-core references are), so `../_shared/` resolves to this directory from any cluster.
6
+
7
+ Before doing anything, read the shared core, in order:
8
+
9
+ 1. `../_shared/principles.md`: refer by name, result-oriented output, no em-dashes, git per conventions, one ticket per session.
10
+ 2. `../_shared/ticket-language.md`: write all Issue prose and commit bodies in `config.ticket.language` (default `en`), independent of the chat language.
11
+ 3. `../_shared/substrate.md`: the GitHub-Issues model: labels, the frontier query, the map / ticket / dashboard / whiteboard anatomy, and the base-command cookbook pointer.
12
+ 4. `../_shared/session-handoff.md`: how every resolution closes (`/clear` first, then the next command).
13
+ 5. `../_shared/configuration.md`: the three config layers and the load contract.
14
+ 6. `../_shared/techniques.md`: the technique index and the subagent-type rule.
15
+
16
+ Load the **effective config** (per `../_shared/configuration.md`) at session start, from the map's project root (`.trailhead/config.json` plus the global file), before any isolation workspace is set up.
@@ -2,6 +2,7 @@
2
2
  Interrogate the human live, one question at a time, until the decision is unambiguous and its rationale is captured. This is human-in-the-loop: the decision is theirs, so never answer on their behalf, never assume an answer you haven't heard, never proceed on silence.
3
3
 
4
4
  - **Map the decision as a tree.** Every choice branches into the choices that hang off it. The *frontier* is every question whose prerequisites are already settled: the ones you can ask now without guessing. A question whose answer depends on another still-open one isn't on the frontier yet; it arrives there the moment that answer lands. You don't ask the frontier in a batch: you pick one from it, and recompute after the answer.
5
+ - **Breadth before depth: enumerate the whole surface first.** When the subject is a space with many parts (mapping an app or a project's scope, not a single isolated choice), open by enumerating every functional area it implies (for a video player: media library, search, thumbnails, filters, genres, the player itself, ...) and get them all onto the record before deep-diving any one. Depth on the current thread is seductive, but the tree only ever grows the questions you actually raise, so an area you never name never enters it and stays silently missing. Fan out first (name every area), then converge each. The deliverable is coverage of the whole surface, not a deep answer on one corner of it.
5
6
  - **One question at a time, with your pick.** Number the question, state it, and offer your recommended answer. Then stop and wait. Each answer reshapes the tree: settled decisions push the frontier outward. Recompute and ask the next. Grilling stays human-decides: the **grilled questions themselves never offer the delegate option** (a recommended answer is not the delegate option), because converging a decision is the human's. A separate meta-ask a call-site may put *before* grilling (e.g. the `build`/`quick` Discuss "do you want a grilling round?") is its own advisory choice and can offer delegate/defer per that call-site. **When a grilled decision is genuinely blocked on a prerequisite, offer defer in prose** (state it in words as part of the question), per the recipe in `../choices.md`.
6
7
  - **Facts are your job, decisions are theirs.** When a question needs a fact from the environment (filesystem, code, tools), go find it yourself; never ask the human what you could look up. Only questions downstream of that lookup wait; ask the rest now.
7
8
  - **Refuse vague and hedged answers.** "Good," "fast," "simple," "users," "later" are not answers: probe. *Fast how: sub-second, or handles large datasets? Users: the Customer or the operator?* Make the abstract concrete: "walk me through it," "give me an example," "what does that actually look like?"
@@ -10,5 +11,5 @@ Interrogate the human live, one question at a time, until the decision is unambi
10
11
  - **Steelman and play devil's advocate.** State the strongest case for the option they're leaning away from. Attack the option they favor from its weakest seam. If it survives, the decision is stronger; if it cracks, you found the real question.
11
12
  - **Detect and open up tradeoffs.** When "or / versus / torn between / which is better" appears, pause: name what each side optimizes for, what each sacrifices, which aligns with the goal, then recommend with reasoning. Skip for trivial or already-decided choices.
12
13
  - **Play back your understanding** before closing each branch: restate the decision and its rationale in your words and have them confirm or correct.
13
- - **Stop only when the frontier is empty**: every branch visited, nothing silently assumed, the choice unambiguous *and* the why recorded.
14
+ - **Stop only when the frontier is empty**: every branch visited, nothing silently assumed, the choice unambiguous *and* the why recorded. **For a multi-part space** (per the breadth bullet above) also require every functional area to have been enumerated and visited: an empty frontier reached while whole areas were never raised is a false finish, because the tree only ever grew the questions you raised. A single isolated choice has no areas to enumerate, so its empty frontier is a real finish.
14
15
 
@@ -8,18 +8,7 @@ argument-hint: "[new|adopt|work|quick|whiteboard|ticket|inbox|map|dashboard|conf
8
8
 
9
9
  ## Load first, in order
10
10
 
11
- Before doing anything, read the shared core (paths relative to this file):
12
-
13
- `_shared/` is a **sibling** of this cluster's own directory (reached at `../_shared/`), never a child of it: the cluster dir holds only this cluster's own files (its `SKILL.md`, and a `references/` dir if it has one), so `_shared/` does not show up in a listing of it, and that absence never means the core is missing. Resolve and read `../_shared/`; never treat "no `_shared/` inside my own cluster dir" as "no shared core installed" and skip the core.
14
-
15
- 1. `../_shared/principles.md`: refer by name, result-oriented output, no em-dashes, git per conventions, one ticket per session.
16
- 2. `../_shared/ticket-language.md`: write all Issue prose and commit bodies in `config.ticket.language` (default `en`), independent of the chat language.
17
- 3. `../_shared/substrate.md`: the GitHub-Issues model: labels, the frontier query, the map / ticket / dashboard / whiteboard anatomy, and the base-command cookbook pointer.
18
- 4. `../_shared/session-handoff.md`: how every resolution closes (`/clear` first, then the next command).
19
- 5. `../_shared/configuration.md`: the three config layers and the load contract.
20
- 6. `../_shared/techniques.md`: the technique index and the subagent-type rule.
21
-
22
- Load the **effective config** (per `../_shared/configuration.md`) at session start, from the map's project root (`.trailhead/config.json` plus the global file), before any isolation workspace is set up.
11
+ Before doing anything, read `../_shared/load-first.md` and follow it: the shared-core load contract (the six core files, in order, then the effective config). `_shared/` is a **sibling** of this cluster's own directory (at `../_shared/`), never a child of it; its absence from a listing of the cluster dir is expected, not a missing core.
23
12
 
24
13
  ## Routing: verb to engine
25
14
 
@@ -9,18 +9,9 @@ argument-hint: "[bug|todo|idea|seed|note] [--of <ticket>] <text>"
9
9
 
10
10
  ## Load first, in order
11
11
 
12
- Before doing anything, read the shared core (paths relative to this file):
12
+ Before doing anything, read `../_shared/load-first.md` and follow it: the shared-core load contract (the six core files, in order, then the effective config). `_shared/` is a **sibling** of this cluster's own directory (at `../_shared/`), never a child of it; its absence from a listing of the cluster dir is expected, not a missing core.
13
13
 
14
- `_shared/` is a **sibling** of this cluster's own directory (reached at `../_shared/`), never a child of it: the cluster dir holds only this cluster's own files (its `SKILL.md`, and a `references/` dir if it has one), so `_shared/` does not show up in a listing of it, and that absence never means the core is missing. Resolve and read `../_shared/`; never treat "no `_shared/` inside my own cluster dir" as "no shared core installed" and skip the core.
15
-
16
- 1. `../_shared/principles.md`: refer by name, result-oriented output, no em-dashes, git per conventions, one ticket per session.
17
- 2. `../_shared/ticket-language.md`: write all Issue prose and commit bodies in `config.ticket.language` (default `en`), independent of the chat language.
18
- 3. `../_shared/substrate.md`: the GitHub-Issues model: labels, the frontier query, the map / ticket / dashboard / whiteboard anatomy, and the base-command cookbook pointer.
19
- 4. `../_shared/session-handoff.md`: how every resolution closes (`/clear` first, then the next command).
20
- 5. `../_shared/configuration.md`: the three config layers and the load contract.
21
- 6. `../_shared/techniques.md`: the technique index and the subagent-type rule.
22
-
23
- Load the **effective config** (per `../_shared/configuration.md`) at session start, from the map's project root (`.trailhead/config.json` plus the global file). A capture writes at most one issue; no isolation workspace is set up.
14
+ A capture writes at most one issue; no isolation workspace is set up.
24
15
 
25
16
  ## Routing: verb to engine
26
17
 
@@ -9,18 +9,7 @@ argument-hint: "[new|adopt|ticket|inbox|grill] [idea | <type> <title> | issue |
9
9
 
10
10
  ## Load first, in order
11
11
 
12
- Before doing anything, read the shared core (paths relative to this file):
13
-
14
- `_shared/` is a **sibling** of this cluster's own directory (reached at `../_shared/`), never a child of it: the cluster dir holds only this cluster's own files (its `SKILL.md`, and a `references/` dir if it has one), so `_shared/` does not show up in a listing of it, and that absence never means the core is missing. Resolve and read `../_shared/`; never treat "no `_shared/` inside my own cluster dir" as "no shared core installed" and skip the core.
15
-
16
- 1. `../_shared/principles.md`: refer by name, result-oriented output, no em-dashes, git per conventions, one ticket per session.
17
- 2. `../_shared/ticket-language.md`: write all Issue prose and commit bodies in `config.ticket.language` (default `en`), independent of the chat language.
18
- 3. `../_shared/substrate.md`: the GitHub-Issues model: labels, the frontier query, the map / ticket / dashboard / whiteboard anatomy, and the base-command cookbook pointer.
19
- 4. `../_shared/session-handoff.md`: how every resolution closes (`/clear` first, then the next command).
20
- 5. `../_shared/configuration.md`: the three config layers and the load contract.
21
- 6. `../_shared/techniques.md`: the technique index and the subagent-type rule.
22
-
23
- Load the **effective config** (per `../_shared/configuration.md`) at session start, from the map's project root (`.trailhead/config.json` plus the global file), before any isolation workspace is set up.
12
+ Before doing anything, read `../_shared/load-first.md` and follow it: the shared-core load contract (the six core files, in order, then the effective config). `_shared/` is a **sibling** of this cluster's own directory (at `../_shared/`), never a child of it; its absence from a listing of the cluster dir is expected, not a missing core.
24
13
 
25
14
  ## Routing: verb to engine
26
15
 
@@ -7,8 +7,8 @@ The user invokes with a loose idea.
7
7
 
8
8
  0. **Ensure a tracker repo exists (offer to create one if missing).** Everything trailhead writes lives on a GitHub repo's Issues, so before charting, confirm the current directory has one. Detect it with `gh repo view`: on success a GitHub repo with a remote is present, so say nothing and proceed. If there is **no GitHub repo** (no `origin` / GitHub remote, or `gh repo view` fails), **stop and ask the user** whether to create one, offering **private (default)** or **public**. On their choice: if the directory is not yet a git repo, `git init` and make an initial commit first; then `gh repo create <name> --private|--public --source=. --remote=origin --push` (take `<name>` from the directory, confirmed with the user), so the repo exists on GitHub with `origin` set. Charting continues only once a GitHub repo is in place: every step below writes to its Issues. If the user declines to create one, there is nowhere to chart, so stop and say so. This never fires when a repo already exists (`/trailhead:adopt` and re-charting on an existing repo skip straight past it).
9
9
  1. **Name the destination.** Run the **Grilling** + **Domain vocabulary** techniques to pin down what this map tends toward. The destination fixes the scope, so it's settled first. Default: a working artifact.
10
- 2. **Map the frontier.** Grill again, **breadth-first**: fan out across the whole space rather than deep on one thread, surfacing the open decisions and the first steps takeable now. **If no fog surfaces** (the way is already clear, the whole thing fits one session) you don't need a map: stop and ask how to proceed. **Harvest parked work:** from **earlier maps on this repo**, gather the artifacts their *Out of scope* `→ future map` breadcrumbs point at (**parked seeds/todos**, see **Out of scope**) **and the ideas** left in their *Not yet specified* fog, then **ask the user which belong in *this* map**; pull the chosen seeds/todos in as tickets and the chosen ideas in as fog (or as tickets, if now sharp enough), and leave (or update the destination on) the rest.
11
- 3. **Create the map** (`trailhead:map`): Destination and Notes filled in, Decisions-so-far empty, the fog sketched into *Not yet specified*. Run the **first-use repo setup** (see **Substrate** → `../../_shared/substrate-commands.md`) now: labels **and** the label-guard check/install. Once the map issue has its number `<n>`, **create its per-map label `trailhead:map-<n>`** (every ticket of this map carries it and is a native sub-issue of the map; the map issue itself is found by its number, so it does **not** carry the label; see **Multiple maps on one repo**). **If this repo already has another open `trailhead:map`**, tell the user the new map runs concurrently (its own scoped frontier) and set it as the active map (`.trailhead/active-map`). Then set up **conventions**: if no `trailhead:conventions` issue exists, run a **brief conventions brainstorming** (breadth-first, in the spirit of grilling but short: a handful of questions, not a full session) to surface the project's way of working: `git:` `main`|`pr`, `release:` `command`|`auto`, and `isolation:` `none`|`worktree` (the header, the last asked as *"will more than one session run on a single clone at once?"* → `worktree`; a monorepo leans `worktree`), **plus** the narrative a new contributor would need: release/deploy specifics (environments, manual steps, OTA vs full build, versioning), tooling that must be driven a certain way (a specific MCP/CLI, e.g. a Lovable project piloted via its MCP), code & style rules, testing/UAT norms. Distil into the issue (header + prose); link it from the map's Notes. Don't invent: leave out or ask what you can't determine. If one already exists, just link it (reuse across maps). Finally, **ensure the repo's `trailhead:dashboard` index issue exists** (see **The dashboard**): create and pin it if missing (the fixed 3rd pinned slot, alongside codebase + conventions), then **write it to list this map** (charting a map is a structural event); if it already exists, refresh it.
10
+ 2. **Map the frontier.** Grill again, **breadth-first**: **enumerate every functional area the destination implies** and **capture each one (headed for a fog entry under *Not yet specified* at minimum) before deep-diving any single area**. Fan out across the whole space rather than deep on one thread, surfacing the open decisions and the first steps takeable now. **The deliverable is the coverage the map will carry, not the grilling transcript: every area the destination implies must land on the map at step 3, as fog or as a ticket, so nothing is silently missing.** **If no fog surfaces** (the way is already clear, the whole thing fits one session) you don't need a map: stop and ask how to proceed. **Harvest parked work:** from **earlier maps on this repo**, gather the artifacts their *Out of scope* `→ future map` breadcrumbs point at (**parked seeds/todos**, see **Out of scope**) **and the ideas** left in their *Not yet specified* fog, then **ask the user which belong in *this* map**; pull the chosen seeds/todos in as tickets and the chosen ideas in as fog (or as tickets, if now sharp enough), and leave (or update the destination on) the rest.
11
+ 3. **Create the map** (`trailhead:map`): Destination and Notes filled in, Decisions-so-far empty, the fog sketched into *Not yet specified*. **Every functional area enumerated in step 2 must appear here, as a fog entry or a ticket, before moving on: the map is the coverage deliverable.** Run the **first-use repo setup** (see **Substrate** → `../../_shared/substrate-commands.md`) now: labels **and** the label-guard check/install. Once the map issue has its number `<n>`, **create its per-map label `trailhead:map-<n>`** (every ticket of this map carries it and is a native sub-issue of the map; the map issue itself is found by its number, so it does **not** carry the label; see **Multiple maps on one repo**). **If this repo already has another open `trailhead:map`**, tell the user the new map runs concurrently (its own scoped frontier) and set it as the active map (`.trailhead/active-map`). Then set up **conventions**: if no `trailhead:conventions` issue exists, run a **brief conventions brainstorming** (breadth-first, in the spirit of grilling but short: a handful of questions, not a full session) to surface the project's way of working: `git:` `main`|`pr`, `release:` `command`|`auto`, and `isolation:` `none`|`worktree` (the header, the last asked as *"will more than one session run on a single clone at once?"* → `worktree`; a monorepo leans `worktree`), **plus** the narrative a new contributor would need: release/deploy specifics (environments, manual steps, OTA vs full build, versioning), tooling that must be driven a certain way (a specific MCP/CLI, e.g. a Lovable project piloted via its MCP), code & style rules, testing/UAT norms. Distil into the issue (header + prose); link it from the map's Notes. Don't invent: leave out or ask what you can't determine. If one already exists, just link it (reuse across maps). Finally, **ensure the repo's `trailhead:dashboard` index issue exists** (see **The dashboard**): create and pin it if missing (the fixed 3rd pinned slot, alongside codebase + conventions), then **write it to list this map** (charting a map is a structural event); if it already exists, refresh it.
12
12
  4. **Create the tickets you can specify now** as child issues (each with `trailhead:ticket` + its type + this map's `trailhead:map-<n>` label, **plus `trailhead:blocked` when the mapped dependency graph already shows it has a blocker**, and set as a **native sub-issue** of the map, see **Child→map link** under Substrate), then wire the blocking in a **second pass** (issues need ids before they can reference each other): for each ticket **read its Question and wire a blocker for every still-open ticket whose output it consumes** (don't stop at the first/obvious one) by wiring its `## Blocked by` line + native dependency together (moves 1-2 of the three-move wiring; the `trailhead:blocked` label, move 3, already rode in at creation, see **Substrate**). **Set the blocked label at creation, not via a post-creation `--add-label` pass:** a bulk `--add-label` burst spawns one repo-side label-guard run per ticket and reddens the Actions history with sheddable no-op runs; riding the label in the ticket's `issues.opened` event avoids that entirely. Wiring sorts them into frontier (unblocked) and blocked; the rest stays fog.
13
13
  5. **Fire the research subagents.** For each `research` ticket created, run the **Research** technique in parallel, findings on a `research/<name>` branch with a pointer from the ticket.
14
14
  6. **Offer config, then stop.** Charting is one session's work; it hand-resolves nothing. Before ending, make the **first-time config offer** (see **First-time config offer** in `../SKILL.md`): the project now has a fresh map and no `.trailhead/config.json`, so put the **two-way choice** to the user, **accept as-is** (writes `{}`) or **run `/trailhead:config`** for the guided menu, and let them pick. Name both paths; don't pre-fill the config keys and ask for an inline edit, and don't interview them key-by-key here (that's `/trailhead:config`'s job). Once the file exists it's never offered again. **No `trailhead:codebase` issue is created here**: greenfield has no code to map yet. It's created later, once the repo has substantial code (see Mode 2 step 1 and the **Codebase** row under Substrate), so at chart two of the three permanent pins (the dashboard + conventions) are filled and the codebase slot fills in later. Maps are never pinned.
@@ -19,6 +19,6 @@ When the code already exists (project in progress). Like Mode 1, but start from
19
19
  1. **Map the codebase (once per repo).** Heavy step, *only* at adoption: it does not repeat per ticket, and **not per map**. First check for an existing **`trailhead:codebase`** issue: if one exists (an earlier map on this repo created it) and the code hasn't materially drifted, just **link it** from this map's Notes and skip the fan-out. Otherwise run the **Codebase map** technique (a parallel fan-out of reader subagents) for a structured understanding (architecture, stack, decisions already embodied, risk areas) and distil the essence into the repo's **`trailhead:codebase` issue** (create it, label `trailhead:codebase`), then link that issue from the map's Notes. Discard the raw. Because it's a standalone repo-scoped issue, the next map reuses it instead of re-deriving or losing it.
20
20
  2. **Name the destination of the remaining stretch.** **Grilling** + **Domain vocabulary**, **seeded by the map you just built**: not "what is the project" but "what's left to reach working / the next milestone".
21
21
  3. **Backfill the decisions already made.** Choices already embodied in the code (now visible from the map) or stated by the user go into `Decisions so far` as **ticket-less** lines (they're already closed), so the map reflects reality and doesn't pretend greenfield. Link to code/commits where useful.
22
- 4. **Map the frontier of the remainder** → tickets specifiable now + fog in *Not yet specified*, then wire the blocking and fire the research. **Harvest parked work** (todos *and* ideas) from earlier maps on this repo (their `→ future map` *Out of scope* lines and their *Not yet specified* fog), asking the user which belong here, as in Mode 1 step 2. As Mode 1, steps 4–6.
22
+ 4. **Map the frontier of the remainder**, **breadth-first as in Mode 1 step 2**: enumerate every functional area still standing between the code and the destination and **land each on the map (fog in *Not yet specified* at minimum) before deep-diving any one**, so the map makes every remaining section visible; the map, not the transcript, is the deliverable to check for that coverage. This yields → tickets specifiable now + fog in *Not yet specified*, then wire the blocking and fire the research. **Harvest parked work** (todos *and* ideas) from earlier maps on this repo (their `→ future map` *Out of scope* lines and their *Not yet specified* fog), asking the user which belong here, as in Mode 1 step 2. As Mode 1, steps 4–6.
23
23
 
24
24
  The tracker is the existing repo's (`gh` in its directory); run the **first-use repo setup** (see `../../_shared/substrate-commands.md`) on first use (missing `trailhead:*` labels **and** the label-guard check/install (adopting an existing repo is exactly when the guard tends to be missing)) and set up the `trailhead:conventions` issue via a **brief conventions brainstorming** (see Mode 1 step 3), but here, **seed the questions from what's discoverable** so you confirm rather than ask blind: an existing `CLAUDE.md`/`AGENTS.md`, CI workflows, the PR-vs-`main` git history, package scripts, deploy config. **Detect a monorepo** (a `pnpm-workspace.yaml`, a `workspaces` field, an `nx.json`/`turbo.json`, or several packages under `packages/`|`apps/`) and, if found, propose `isolation: worktree` and note that tickets should carry a `Scope:` line, **unless the buildable units are path-bound** (see below). **Detect git submodules** (a `.gitmodules` file) and, if found, add the prose rule that submodule work is committed **inside the submodule + a gitlink bump in the parent**, isolated at the submodule (not the superproject); a submodule path is a natural `Scope:` (see **Working as a team**). **Before proposing `worktree`, check for path-bound tooling** (a React Native/Expo app, native toolchains, a package whose build depends on a local `node_modules`/bundler cache/absolute-path config): those don't build from a worktree, so for them propose **`isolation: clone`** (a per-ticket clone that installs its own deps and builds), or `isolation: none` + **serialize** if the user doesn't want per-ticket clones. Worktree is for units that build from any path. Propose the values you inferred and let the human correct/complete them; create the issue if absent, link it from the map's Notes. Also **ensure the repo's `trailhead:dashboard` index issue exists** (see **The dashboard**): create and pin it if missing (the fixed 3rd pinned slot, alongside codebase + conventions) and write it to list this map.
@@ -9,18 +9,9 @@ argument-hint: "[config|update] [get|set …]"
9
9
 
10
10
  ## Load first, in order
11
11
 
12
- Before doing anything, read the shared core (paths relative to this file):
12
+ Before doing anything, read `../_shared/load-first.md` and follow it: the shared-core load contract (the six core files, in order, then the effective config). `_shared/` is a **sibling** of this cluster's own directory (at `../_shared/`), never a child of it; its absence from a listing of the cluster dir is expected, not a missing core.
13
13
 
14
- `_shared/` is a **sibling** of this cluster's own directory (reached at `../_shared/`), never a child of it: the cluster dir holds only this cluster's own files (its `SKILL.md`, and a `references/` dir if it has one), so `_shared/` does not show up in a listing of it, and that absence never means the core is missing. Resolve and read `../_shared/`; never treat "no `_shared/` inside my own cluster dir" as "no shared core installed" and skip the core.
15
-
16
- 1. `../_shared/principles.md`: refer by name, result-oriented output, no em-dashes, git per conventions, one ticket per session.
17
- 2. `../_shared/ticket-language.md`: write all Issue prose and commit bodies in `config.ticket.language` (default `en`), independent of the chat language.
18
- 3. `../_shared/substrate.md`: the GitHub-Issues model: labels, the frontier query, the map / ticket / dashboard / whiteboard anatomy, and the base-command cookbook pointer.
19
- 4. `../_shared/session-handoff.md`: how every resolution closes (`/clear` first, then the next command).
20
- 5. `../_shared/configuration.md`: the three config layers and the load contract.
21
- 6. `../_shared/techniques.md`: the technique index and the subagent-type rule.
22
-
23
- Load the **effective config** (per `../_shared/configuration.md`) at session start, from the map's project root (`.trailhead/config.json` plus the global file). These admin verbs resolve no ticket and set up no isolation workspace.
14
+ These admin verbs resolve no ticket and set up no isolation workspace.
24
15
 
25
16
  ## Routing: verb to engine
26
17
 
@@ -9,18 +9,9 @@ argument-hint: "[map|dashboard|whiteboard] [map]"
9
9
 
10
10
  ## Load first, in order
11
11
 
12
- Before doing anything, read the shared core (paths relative to this file):
12
+ Before doing anything, read `../_shared/load-first.md` and follow it: the shared-core load contract (the six core files, in order, then the effective config). `_shared/` is a **sibling** of this cluster's own directory (at `../_shared/`), never a child of it; its absence from a listing of the cluster dir is expected, not a missing core.
13
13
 
14
- `_shared/` is a **sibling** of this cluster's own directory (reached at `../_shared/`), never a child of it: the cluster dir holds only this cluster's own files (its `SKILL.md`, and a `references/` dir if it has one), so `_shared/` does not show up in a listing of it, and that absence never means the core is missing. Resolve and read `../_shared/`; never treat "no `_shared/` inside my own cluster dir" as "no shared core installed" and skip the core.
15
-
16
- 1. `../_shared/principles.md`: refer by name, result-oriented output, no em-dashes, git per conventions, one ticket per session.
17
- 2. `../_shared/ticket-language.md`: write all Issue prose and commit bodies in `config.ticket.language` (default `en`), independent of the chat language.
18
- 3. `../_shared/substrate.md`: the GitHub-Issues model: labels, the frontier query, the map / ticket / dashboard / whiteboard anatomy, and the base-command cookbook pointer.
19
- 4. `../_shared/session-handoff.md`: how every resolution closes (`/clear` first, then the next command).
20
- 5. `../_shared/configuration.md`: the three config layers and the load contract.
21
- 6. `../_shared/techniques.md`: the technique index and the subagent-type rule.
22
-
23
- Load the **effective config** (per `../_shared/configuration.md`) at session start, from the map's project root (`.trailhead/config.json` plus the global file). These are read-only renders: no isolation workspace is set up.
14
+ These are read-only renders: no isolation workspace is set up.
24
15
 
25
16
  ## Routing: verb to engine
26
17
 
@@ -9,18 +9,9 @@ argument-hint: "[work|quick|pause|resume|split|auto] [ticket | \"text\" | note]"
9
9
 
10
10
  ## Load first, in order
11
11
 
12
- Before doing anything, read the shared core (paths relative to this file):
12
+ Before doing anything, read `../_shared/load-first.md` and follow it: the shared-core load contract (the six core files, in order, then the effective config). `_shared/` is a **sibling** of this cluster's own directory (at `../_shared/`), never a child of it; its absence from a listing of the cluster dir is expected, not a missing core.
13
13
 
14
- `_shared/` is a **sibling** of this cluster's own directory (reached at `../_shared/`), never a child of it: the cluster dir holds only this cluster's own files (its `SKILL.md`, and a `references/` dir if it has one), so `_shared/` does not show up in a listing of it, and that absence never means the core is missing. Resolve and read `../_shared/`; never treat "no `_shared/` inside my own cluster dir" as "no shared core installed" and skip the core.
15
-
16
- 1. `../_shared/principles.md`: refer by name, result-oriented output, no em-dashes, git per conventions, one ticket per session.
17
- 2. `../_shared/ticket-language.md`: write all Issue prose and commit bodies in `config.ticket.language` (default `en`), independent of the chat language.
18
- 3. `../_shared/substrate.md`: the GitHub-Issues model: labels, the frontier query, the map / ticket / dashboard / whiteboard anatomy, and the base-command cookbook pointer.
19
- 4. `../_shared/session-handoff.md`: how every resolution closes (`/clear` first, then the next command).
20
- 5. `../_shared/configuration.md`: the three config layers and the load contract.
21
- 6. `../_shared/techniques.md`: the technique index and the subagent-type rule.
22
-
23
- Load the **effective config** (per `../_shared/configuration.md`) at session start, from the map's project root (`.trailhead/config.json` 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 workspace inherits this config, never re-resolves it from the isolated copy's own root. **For an explicit `work <n>` / `quick <n>`, the named-ticket Preflight below runs *before* this config load:** never load config, or anything else, for a ticket that turns out closed.
14
+ Config is a property of the project/map, not the working directory: an isolation workspace inherits this config, never re-resolves it from the isolated copy's own root. **For an explicit `work <n>` / `quick <n>`, the named-ticket Preflight below runs *before* this config load:** never load config, or anything else, for a ticket that turns out closed.
24
15
 
25
16
  ## Routing: verb to engine
26
17