Add pathfinder BRIEF mode, resolved-date tracking, and decide-menu-checkpoint cadence (v2.3.0)

AI Assisted
This commit is contained in:
2026-09-03 07:18:34 -07:00
parent 9a81b9cd24
commit fa568a960d
24 changed files with 627 additions and 241 deletions
+2 -2
View File
@@ -67,7 +67,7 @@ plan2code/
|------|------|---------|
| `plan2code-init.md` | Init | Generate AGENTS.md as index + `.agents-docs/` section files (progressive discovery) |
| `plan2code-init-update.md` | Update | Update AGENTS.md with learnings; detects and routes edits to `.agents-docs/` files |
| `plan2code-0-pathfinder.md` | 0 | Chart a foggy idea as a local map of decision questions under `specs/<idea>/pathfinder/`, resolve one per session, hand a seeded PLAN-DRAFT to Step 1 |
| `plan2code-0-pathfinder.md` | 0 | Chart a foggy idea as a local map of decision questions under `specs/<idea>/pathfinder/`, resolve them one at a time, hand a seeded PLAN-DRAFT to Step 1 |
| `plan2code-quick-task.md` | quick | Lightweight planning for small tasks (standalone — not a pipeline step) |
| `plan2code-1-plan.md` | 1 | Requirements analysis & architecture |
| `plan2code-1b-revise-plan.md` | 1b | Mid-implementation revisions |
@@ -96,7 +96,7 @@ Some workflows use companion reference files for depth that exceeds the 11k char
**How the installer handles them:** the directory is copied verbatim to `skills/<skill-name>/references/`, so `Read references/<file>.md` resolves consistently for every agent. There is one output format, with no flat-file sibling directory or path rewrite.
Reference files are NOT subject to the 11,000 character limit. The review workflow pioneered this pattern (`verification-protocol`, `dimensions`, `false-positives`, `session-end`); the init-update workflow also uses it (`ai-agent-file-sync` for its Step 7), `plan2code-4-finalize.md` uses it for STEP 6.5 (`community-feedback-submission`), and `plan2code-0-pathfinder.md` leans on it hardest (`chart`, `grilling`, `questions`, `resolve`, `handoff`, `trail`, `github-issues` — the orchestrator is a dispatcher, the depth lives in the references). Other workflows can adopt it when a source file's detail exceeds the 11k limit.
Reference files are NOT subject to the 11,000 character limit. The review workflow pioneered this pattern (`verification-protocol`, `dimensions`, `false-positives`, `session-end`); the init-update workflow also uses it (`ai-agent-file-sync` for its Step 7), `plan2code-4-finalize.md` uses it for STEP 6.5 (`community-feedback-submission`), and `plan2code-0-pathfinder.md` leans on it hardest (`chart`, `grilling`, `questions`, `resolve`, `handoff`, `trail`, `github-issues`, `brief` — the orchestrator is a dispatcher, the depth lives in the references). Other workflows can adopt it when a source file's detail exceeds the 11k limit.
## Repo-Local Skills (`.claude/skills/`)
File diff suppressed because one or more lines are too long
+16
View File
@@ -2,6 +2,22 @@
All notable changes to Plan2Code will be documented in this file.
## v2.3.0
### ✨ Added
- **`plan2code-0-pathfinder`: `Resolved:` date on question files** — a sixth schema line recording the day each decision landed. Reconcile backfills older maps from `Claimed:` (today if unclaimed), and resolved map rows now carry the date in italics beside the gist. On the GitHub Issues backend the issue's own close date fills this role, so there is nothing to write and nothing to backfill.
- **`plan2code-0-pathfinder`: BRIEF mode** — asking for a `brief`, `recap`, or `minutes` writes a dated, plain-English report to `pathfinder/briefs/brief-<YYYYMMDD>.md`: what was decided in the range, what was ruled out, what is ready to decide next, what is still blocked, and what is next. Zero pathfinder machinery in the file — no numbers, markers, or jargon — so it doubles as meeting minutes for a joint Product and Engineering session. New `references/brief.md`; BRIEF mode never claims or resolves a question. The brief file stays on local disk on both backends.
### 🔧 Changed
- **`plan2code-0-pathfinder`: MODE B cadence is now decide → menu → checkpoint** — questions still resolve strictly one at a time, but a session no longer ends after one. Recording a decision leads to a continue-or-stop fork-menu (new Trail Footer **Form C**, with the resume command always visible as the stop branch), and a fresh session is *recommended* after about three decisions — or after a heavy, contested, or locked one — to protect context quality rather than forced by the rules.
- **`plan2code-0-pathfinder`: every user-facing question uses the structured question UI when available** — intent gate, destination and frontier grills, recap confirmations, sketch reactions, `legwork · HITL` completion, and the new fork-menu. The old detail test that routed gnarly questions to prose Q blocks is gone: trade-offs go in option descriptions, composed answers come back through `Other`, and an artifact is shown in prose immediately before the tool rather than replacing it. Prose Q blocks are now fallback only, for when the tool does not exist.
- **`plan2code-0-pathfinder`: the breadth-first frontier grill gains seven product axes** — user value, success measurement, target user, rollout, analytics, support and docs, and legal/compliance, each with a sample probe. Inapplicable axes are named and skipped up front, and with Product in the room engineering and product batches alternate so neither team spectates. New group-session grilling rules: address the room, record who broke a tie, and never record a contested pick as decided — both positions go under `## Evidence` and the question stays open.
## v2.2.0
### ✨ Added
+3 -2
View File
@@ -23,7 +23,8 @@ specs/
└── <feature-name>/
├── pathfinder/ # From Step 0 (optional, if charted locally)
│ ├── map.md # the map: destination, decisions, fog
── questions/NN-<slug>.md # one decision question per file
── questions/NN-<slug>.md # one decision question per file
│ └── briefs/brief-<date>.md # plain-English decision summaries
│ # (GitHub Issues backend: map issue + sub-issues instead)
├── PLAN-DRAFT-<date>.md # From Step 1 (verified plan)
├── PLAN-CONVERSATION-<date>.md # From Step 1 (conversation log)
@@ -83,7 +84,7 @@ Learned something during a session?
└── /plan2code-init-update → Add learnings to AGENTS.md
Too unclaer to plan? (big idea, don't yet know what the questions are)
└── /plan2code-0-pathfinder → chart it, clear one decision per session
└── /plan2code-0-pathfinder → chart it, clear the decisions one at a time
└── then → /plan2code-1-plan (resumes at Phase 4)
Is it a quick, small task?
+9 -5
View File
@@ -12,7 +12,7 @@ agent, and the next engineer all start from the same specs.
Six commands, each posted separately. Two of them are optional.
Version 2.2.0 · MIT · 📖 [plan2code.jparkerweb.com](https://plan2code.jparkerweb.com)
Version 2.3.0 · MIT · 📖 [plan2code.jparkerweb.com](https://plan2code.jparkerweb.com)
---
@@ -90,7 +90,7 @@ implementation is where most agent drift starts.
| Command | Use it when |
|---------|-------------|
| `/plan2code-0-pathfinder` | The idea is too big and unclear to plan. Charts it as decisions, clears one per session, hands a hot plan draft to Step 1 |
| `/plan2code-0-pathfinder` | The idea is too big and unclear to plan. Charts it as decisions, clears them one at a time, hands a hot plan draft to Step 1 |
| `/plan2code-1-plan` | Starting a feature. Full requirements → architecture pass |
| `/plan2code-2-document` | Planning is done. Turn the plan into phase specs |
| `/plan2code-3-implement` | Build the next phase (one per conversation) |
@@ -129,7 +129,8 @@ your-project/
│ └── task-api/ ← in progress
│ ├── pathfinder/ ← only if you charted it in Step 0
│ │ ├── map.md the destination, the decisions, the fog
│ │ ── questions/NN-<slug>.md one decision per file
│ │ ── questions/NN-<slug>.md one decision per file
│ │ └── briefs/brief-<date>.md plain-English decision summaries
│ ├── PLAN-DRAFT-20260804.md ← Step 1: the verified plan
│ ├── PLAN-CONVERSATION-*.md ← Step 1: how you got there
│ ├── overview.md ← Step 2: phase list + parallel groups
@@ -181,8 +182,11 @@ destination; Step 1 then walks it.
sub-issue per decision, native blocking, so your team can see and work the frontier in the tracker).
2. **Chart the map** — a breadth-first grilling surfaces the open decisions. Anything you can phrase
*sharply* becomes a question file; anything you can only sense stays listed as fog.
3. **Clear one question per session** — resolving a question burns off the fog behind it, graduating
whatever just became sharp into new questions.
3. **Clear the questions one at a time** — resolving one burns off the fog behind it, graduating
whatever just became sharp into new questions. After each decision it offers a menu: take the next
question here, or start fresh — recommended after about three, to keep the agent sharp.
Ask for a **brief** at any point and you get a dated, plain-English summary of what has been
decided, what is still open, and what is next — meeting minutes, with no jargon in them.
4. **Hand off** — when nothing is left to decide, it writes a `PLAN-DRAFT` that
`/plan2code-1-plan` resumes from at Phase 4, with requirements, context, and scope already
answered.
+3 -2
View File
@@ -271,10 +271,11 @@ footer .wrap{display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;
<span class="mark">Opt<br>00</span>
<h3>Pathfinder<span class="flag">New in 2.0</span></h3>
<code>/plan2code-0-pathfinder</code>
<p>For an idea that arrives too foggy to plan. It charts the idea as a map of decision questions and clears exactly one per session until nothing is left to decide.</p>
<p>For an idea that arrives too foggy to plan. It charts the idea as a map of decision questions and clears them one at a time until nothing is left to decide.</p>
<p class="pen">it never answers its own questions — that's the point</p>
<ul>
<li>One decision per file, one file per session</li>
<li>One decision per file, cleared one at a time</li>
<li>Ask for a brief — plain-English minutes, any time</li>
<li>Research questions fan out to parallel agents</li>
<li>Clears at ≥18/25 on four confidence dimensions</li>
<li>Hands a hot plan draft to Step 1</li>
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "plan2code",
"version": "2.2.0",
"version": "2.3.0",
"private": true,
"bin": {
"plan2code": "./install.js"
+36 -34
View File
@@ -10,47 +10,49 @@ Start all PATHFINDER MODE responses with '🧭 [PATHFINDER: Chart - Step X: Name
## Role
Pathfinder, not architect. An idea has arrived too big or unclear to plan. Chart the way as a map of decision **questions**, then clear them ONE PER SESSION until nothing is left to decide. Hand off to `/plan2code-1-plan`.
Pathfinder, not architect. An idea has arrived too big or unclear to plan. Chart the way as a map of decision **questions**, then clear them one at a time until nothing is left to decide. Hand off to `/plan2code-1-plan`.
Read references/grilling.md
> Fallback: ≤3 independent probes/turn, each with a recommendation, re-ask any skipped; structured tool first, prose only on a detail-test trip; plain English, no jargon; facts you look up, decisions are the human's.
> Fallback: ≤3 independent probes/turn, each with a recommendation, re-ask any skipped; AskUserQuestion for every question, prose only if unavailable; plain English; facts you look up, decisions are the human's.
## Backend
The map lives in ONE of two places — the human's pick at Chart Step 1, never yours:
- **local** (default) — files under `specs/<idea>/pathfinder/`. Private, gitignored, solo.
- **github** — a `pathfinder:map` issue whose questions are sub-issues, driven by `gh`. Shared, visible in the tracker UI, parallel.
- **github** — a `pathfinder:map` issue whose questions are sub-issues, driven by `gh`. Shared, visible in the tracker, parallel.
Read references/github-issues.md — REQUIRED on `github`, skip it on `local`.
Read references/github-issues.md — REQUIRED on `github`, skip on `local`.
> Fallback: map = issue labelled `pathfinder:map` titled `Map: <idea>`; questions = its sub-issues, labelled `pathfinder:<type>-<mode>`; blocking = native issue dependencies; claim = assign `@me`; resolve = `## Answer` comment, then close.
> Fallback: map = a `pathfinder:map` issue titled `Map: <idea>`; questions = its sub-issues, labelled `pathfinder:<type>-<mode>`; blocking = native dependencies; claim = assign `@me`; resolve = `## Answer` comment, then close.
Recorded as the first `## Ground rules` bullet (`**Backend:** local|github`), never re-asked, never switched. Either way the PLAN-DRAFT lands in local `specs/<idea>/` — downstream steps read files, not issues.
Recorded as the first `## Ground rules` bullet (`**Backend:** local|github`), never re-asked or switched. Either way the PLAN-DRAFT lands in local `specs/<idea>/` — downstream steps read files, not issues.
## Project Context
Load `./AGENTS.md` if it exists — its conventions govern; never re-ask what it answers. If missing, do NOT ask here; fold it into the Step 0 gate batch: *"No `AGENTS.md`. Pathfinder can chart without it. Continue, or run `plan2code-init` first?"* Record it in `## Ground rules` so no later session re-asks.
Load `./AGENTS.md` if it exists — its conventions govern; never re-ask what it answers. If missing, fold it into the Step 0 gate batch: *"No `AGENTS.md`. Pathfinder can chart without it. Continue, or run `plan2code-init` first?"* Record it in `## Ground rules`.
## Rules
- **Plan, don't do.** Every question resolves a DECISION. The pull to just build it is the edge of the map — hand off.
- **Confirm before creating anything.** No files, no issues, until the Intent Gate (Step 0) and backend pick (Step 1) return.
- **One question per session** (`research` excepted — parallel subagents).
- **One question at a time** (`research` excepted — parallel); fork-menu between decisions, fresh session after ~3.
- **Refer by name.** "[Export format](<link>)", never "02" or "#42" in prose. Bare ids belong on `Blocked by:` lines and in commands.
- **HITL questions are never self-answered.** Ask and wait. An agent that answers its own grill has broken the skill.
- **HITL questions are never self-answered.** Ask and wait; an agent that answers its own grill has broken the skill.
- **Questions are ground truth; the map is a rebuildable index.** A filled `## Answer` beats any state marker; detail lives in one place.
- **Never write implementation code** into the project. Sketches are throwaway, living only under `specs/<idea>/pathfinder/sketch-NN/`.
- **Never write implementation code** into the project. Sketches are throwaway, living only under `pathfinder/sketch-NN/`.
- **Reserved names — never create inside `pathfinder/`:** `overview.md`, `phase-<N>.md`, `PLAN-DRAFT-*.md`, `PLAN-CONVERSATION-*.md`.
- **Never emit the loop's completion tokens under `specs/`** — `TASK_COMPLETE`, `PHASE_COMPLETE`, `ALL_TASKS_COMPLETE`, `IMPLEMENTATION_COMPLETE`, `SPEC_COMPLETE`, `WORK_COMPLETE`. It scans for them.
- **No `- [ ]` checkboxes inside question files**, and no `METRICS_JSON` anywhere. Pathfinder is not a metered step.
- **No `- [ ]` checkboxes inside question files**, and no `METRICS_JSON` anywhere.
## Auto-Discovery and Mode Selection
⚠️ `specs/` is gitignored — NEVER use Glob (silently fails). Shell only: `ls specs/` (Bash) or `Get-ChildItem specs/` (PS).
⚠️ `specs/` is gitignored — NEVER use Glob. Shell only: `ls specs/` (Bash) or `Get-ChildItem specs/` (PS).
**Identify the target idea FIRST** (from the argument, or ask), then evaluate for THAT idea — first match wins. An issue URL or number as the argument means `github`; else look for a local map, then `gh issue list --label pathfinder:map` for `Map: <idea>`.
**Brief/recap/minutes asked?** → read references/brief.md: reconcile, write plain-English `briefs/brief-<YYYYMMDD>.md` (decisions in range, still open, next step), STOP. Never resolves.
**Identify the idea FIRST** (from the argument, or ask), then evaluate for THAT idea — first match wins. An issue URL or number means `github`; else look for a local map, then `gh issue list --label pathfinder:map` for `Map: <idea>`.
| Condition | Route |
|---|---|
@@ -61,13 +63,13 @@ Load `./AGENTS.md` if it exists — its conventions govern; never re-ask what it
| Map `**Status:** Cleared` | Point at the PLAN-DRAFT and `/plan2code-1-plan`. STOP |
| Map exists, `**Status:**` unreadable | MODE B — Step 2 rebuilds and sets it |
Each idea has its own map. Never chart two in one session.
One idea per session, each with its own map.
## Questions
Read references/questions.md — the `local` format. On `github` the backend playbook's equivalence table replaces it, and there is no checklist: the frontier is a live query.
Read references/questions.md — the `local` format. On `github` the backend playbook's equivalence table replaces it: no checklist, the frontier is a live query.
> Fallback (`local`): `map.md` indexes; `questions/NN-<slug>.md` hold the decisions, `00` is codebase context, five `Key: value` schema lines each. Markers, rebuilt from the files each session: `[ ]` open — **the frontier** · `[/]` claimed · `[x]` resolved · `[!]` blocked · `[-]` out of scope.
> Fallback (`local`): `map.md` indexes; `questions/NN-<slug>.md` hold the decisions, `00` is codebase context, six `Key: value` lines each, `Resolved:` dating it. Markers, rebuilt from the files each session: `[ ]` open — **the frontier** · `[/]` claimed · `[x]` resolved · `[!]` blocked · `[-]` out of scope.
## MODE A: Chart
@@ -75,17 +77,17 @@ Read references/chart.md
> Fallback: confirm the outcome with the human FIRST; only then grill the destination, then breadth-first; write the map and one question per sharp decision.
0. `[Step 0: Intent Gate]` **Before creating anything**, ask which outcome and WAIT: **chart a map** (foggy — Step 1), **`/plan2code-1-plan`** (clear — STOP), **`/plan2code-quick-task`** (tiny — STOP). HITL, never self-select "chart".
1. `[Step 1: Name and backend]` Only after the gate returns "chart." Confirm the kebab-case idea name, then ask — HITL, never self-picked — **local files or GitHub Issues?** Recommend `local` for solo work; offer `github` only if its preflight passes, naming the repo's visibility. THEN the first write.
0. `[Step 0: Intent Gate]` **Before creating anything**, use AskUserQuestion for the outcome and WAIT: **chart a map** (foggy — Step 1), **`/plan2code-1-plan`** (clear — STOP), **`/plan2code-quick-task`** (tiny — STOP). HITL, never self-select "chart".
1. `[Step 1: Name and backend]` Only after the gate says "chart." Confirm the kebab-case idea name, then ask — HITL, never self-picked — **local files or GitHub Issues?** Recommend `local` for solo work; offer `github` only if preflight passes, naming the repo's visibility. THEN the first write.
2. `[Step 2: Destination]` Grill until it is one or two lines. It fixes scope — settle it first.
3. `[Step 3: Recon]` Explore the codebase; record codebase context, resolved on the spot, `legwork · AFK`. On `github` hold it until Step 6 so a Step 4 off-ramp leaves no litter.
4. `[Step 4: Map the frontier]` Grill again **breadth-first**: fan out, never deep on one thread. Surface the open decisions and what is takeable now.
5. `[Step 5: Create the map]` `**Status:** Charting`, Destination, Ground rules (backend first), an empty index, the fog in `## Not yet specified`. Say once where it lives and who can see it.
6. `[Step 6: Write the questions]` One per decision you can phrase sharply NOW, dependency order, `Blocked by:` filled the same pass — on `github`, create them all first, wire the edges second. The rest stays fog. Always include a `grill · HITL` testing-posture question; `/plan2code-1-plan` Phase 1 needs it.
5. `[Step 5: Create the map]` `**Status:** Charting`, Destination, Ground rules (backend first), an empty index, the fog in `## Not yet specified`. Say once where it lives and who sees it.
6. `[Step 6: Write the questions]` One per decision you can phrase sharply NOW, dependency order, `Blocked by:` filled the same pass — on `github`, create all first, wire edges second. The rest stays fog. Include a `grill · HITL` testing-posture question; `/plan2code-1-plan` Phase 1 needs it.
7. `[Step 7: Index]` Fill `## Question Checklist` from the files (`local` only). Set `**Status:** Working`.
8. `[Step 8: Fire research]` One subagent per `research` question, in parallel. Each reads primary sources, writes to that question's `## Evidence` — never decides. Then Session End.
8. `[Step 8: Fire research]` One subagent per `research` question, in parallel. Each reads primary sources, writes to its `## Evidence` — never decides. Then Session End.
**No fog at Step 4?** Small enough to plan directly: do NOT create the map, keep the recon as a local file, attach it to `/plan2code-1-plan`, STOP. Charting resolves nothing by hand — stop at Step 8.
**No fog at Step 4?** Small enough to plan directly: create no map, keep the recon as a local file, attach it to `/plan2code-1-plan`, STOP. Charting resolves nothing by hand — stop at Step 8.
## MODE B: Work
@@ -96,14 +98,14 @@ Read references/resolve.md
Assume NO memory of any prior session.
1. `[Step 1: Load]` Read the map whole. No question yet.
2. `[Step 2: Reconcile]` **Always.** Read every question. `## Answer` written but the state disagrees? The answer wins. Claimed with no `## Answer`? A crash: release it, say so. Rebuild every marker from the questions.
2. `[Step 2: Reconcile]` **Always.** Read every question. `## Answer` written but the state disagrees? The answer wins. Claimed with no `## Answer`? A crash: release it, say so. Rebuild every marker from the questions; backfill a missing `Resolved:` date from the claim.
3. `[Step 3: Frontier]` Every question open, unclaimed, and unblocked. First in order.
4. `[Step 4: Choose and claim]` The question the user named, else first on the frontier. Mark it claimed on the question and the map, **saved before any work.** Frontier empty but questions remain? All blocked — report the chain, STOP. Stranded on an `out-of-scope` blocker? Re-frame or rule out, re-run Step 3. Nothing open? Go to The Clearing Gate.
4. `[Step 4: Choose and claim]` The one the user named, else first on the frontier. Mark it claimed on the question and the map, **saved before any work.** Frontier empty but questions remain? All blocked — report the chain, STOP. Stranded on an `out-of-scope` blocker? Re-frame or rule out, re-run Step 3. Nothing open? The Clearing Gate.
5. `[Step 5: Zoom]` Read the claimed question in full, plus any closed question it references. Obey `## Ground rules`.
6. `[Step 6: Resolve]` Route by type per the resolve playbook. HITL needs the human's own words.
7. `[Step 7: Record]` Write `## Answer`: the decision, what was rejected and why, consequences, a one-line `**Gist:**`. Sources under `## Evidence`. Mark it resolved, index the gist on the map, bump `**Updated:**`.
7. `[Step 7: Record]` Write `## Answer`: the decision, what was rejected and why, consequences, a one-line `**Gist:**`. Sources under `## Evidence`. Mark it resolved, dated today, index the gist + date on the map, bump `**Updated:**`.
8. `[Step 8: Graduate]` Fog now sharp? Write those questions, delete the graduated bullets. Past the destination? Rule it out of scope, one line in `## Out of scope`. Invalidated? Re-frame or rule out.
9. `[Step 9: Gate]` Run The Clearing Gate, then Session End.
9. `[Step 9: Menu]` Run The Clearing Gate. Not cleared: fork-menu (Form C) — pick → Step 4, stop → Session End.
## The Clearing Gate
@@ -116,21 +118,21 @@ The map clears only when ALL hold:
1. Nothing open, claimed, or blocked
2. `## Not yet specified` is EMPTY
3. The destination is reachable with nothing left to decide
4. Every confidence dimension (Requirements, Feasibility, Integration, Risk) scores ≥ 18/25
4. All four confidence dimensions score ≥ 18/25
Any failing: name it, keep working. All passing: follow the handoff playbook, set `**Status:** Cleared`, stop. The PLAN-DRAFT is always a local file `/plan2code-1-plan` cannot read a tracker.
Any failing: name it, keep working. All passing: follow the handoff playbook, set `**Status:** Cleared`, stop. The PLAN-DRAFT is always local — `/plan2code-1-plan` cannot read a tracker.
## Trail Footer
Read references/trail.md
> Fallback: once the map exists, close every response with a one-line path of markers (`●` done · `◉` here · `○` open · `⊘` blocked · `⊝` out of scope) from `START` to `⚑`, a numbered legend of question names, plus a plain-English confidence note.
> Fallback: once the map exists, end every response with a marker path (`●` done · `◉` here · `○` open · `⊘` blocked · `⊝` out of scope) `START``⚑`, a named legend, a plain-English confidence note, one closer.
Once the map exists the trail closes EVERY response, then ONE closer by turn type, not map status. Asking the human anything → `WAITING ON YOU · answer here, in this conversation:` and the open items; never a resume command. Ending the session → `NEXT STEP · start a new conversation and run:` plus `/plan2code-0-pathfinder specs/<idea>/pathfinder` (the map issue URL on `github`), or `/plan2code-1-plan` once `Cleared`.
Once the map exists the trail closes EVERY response, then ONE closer by turn type. Asking anything → Form B: `WAITING ON YOU · answer here, in this conversation:` + open items, no command. Menu after a decision → Form C: `NEXT UP` picks + `OR START FRESH`. Session end → Form A: `NEXT STEP · start a new conversation and run:` + `/plan2code-0-pathfinder specs/<idea>/pathfinder` (map issue URL on `github`), or `/plan2code-1-plan` once `Cleared`.
## Session End
Report the question resolved (by name), its gist, what graduated from the fog, what's still open. Nothing to commit — a `local` map is gitignored, a `github` map is already on the tracker. Then the mascot, then the Trail Footer.
Report each question resolved (name + gist), what graduated, what's still open; offer a brief for today. Nothing to commit — `local` is gitignored, `github` already on the tracker. Then the mascot, then the Trail Footer.
```
@@ -146,11 +148,11 @@ Report the question resolved (by name), its gist, what graduated from the fog, w
| Issue | Action |
|---|---|
| Session stops mid-question, or the map drifted | Release the claim, note why. Work Step 2 repairs the map; the questions always win. |
| Session stops mid-question, or map drift | Release the claim, note why. Work Step 2 repairs both; questions win. |
| Frontier empty, fog remains | Not sharp yet. Grill it into a question, or clear the map |
| Reference file missing | Use the fallback blockquote under its `Read` line |
| `gh` fails mid-session on a `github` map | Report it and STOP. Falling back to local forks the map |
| User wants to skip to planning | Their call. Say what is undecided, route to `/plan2code-1-plan` |
| `gh` fails mid-session on a `github` map | Report and STOP. Falling back to local forks the map |
| User skips to planning | Their call. Name what is undecided, route to `/plan2code-1-plan` |
## Learning Capture
@@ -0,0 +1,102 @@
# Brief Playbook
> Loaded when the user's argument asks for a brief. Produces one plain-English report file for a date range — the artifact a PM pastes into Slack or reads aloud in a meeting. The only mutation BRIEF mode ever performs is the Work Step 2 reconcile; it never claims, resolves, or answers a question.
> **Backend note.** The report is IDENTICAL either way — same sections, same plain-English rules — and the brief file always lands on **local disk** under `specs/<idea>/pathfinder/briefs/`, even on `**Backend:** github`. What differs is where the inputs come from: on `github` the range filter reads each question issue's close date instead of a `Resolved:` line, and the open / blocked / out-of-scope sections come from the frontier query rather than the checklist — see `github-issues.md`.
## When it fires
The argument (or message) asks for a `brief`, `summary`, `recap`, or `minutes` for an idea, with an optional range:
```
/plan2code-0-pathfinder write a brief for today for specs/<idea>/pathfinder
/plan2code-0-pathfinder brief since 2026-08-15 for specs/<idea>/pathfinder
/plan2code-0-pathfinder full brief for specs/<idea>/pathfinder
```
Range grammar is deliberately loose: `today` (the default when unstated) · `this week` · `since <date>` · an explicit `<date>..<date>` · `full` (everything since the map was created). Get today's date from the shell — never guess it.
No `map.md` for the idea? There is nothing to brief — say so and route to charting. `**Status:** Cleared`? A brief is still legitimate: cover the full history and point at the PLAN-DRAFT in `## Next step`.
## Procedure
1. **Resolve the idea** exactly as Auto-Discovery does (shell only — `specs/` is gitignored, Glob silently fails).
2. **Reconcile first, in full** (Work Step 2): files win over markers, stale claims reset to `open`, absent `Resolved:` dates backfilled from `Claimed:`. Save the repaired map. A brief must never disagree with the map it summarizes — this is why BRIEF mode reconciles rather than reporting drift.
3. **Filter**: resolved questions whose `Resolved:` date falls in the range. Out-of-scope rulings are NOT date-filtered — they are standing scope boundaries and appear in every brief.
4. **Write** `specs/<idea>/pathfinder/briefs/brief-<YYYYMMDD>.md` (create `briefs/` if absent). The filename carries today's date regardless of range — the `**Covers:**` line disambiguates. Same-day re-runs overwrite: a brief is a report, not a record; the question files remain the record.
5. **Report** in chat: the file path, the range, one line on any reconcile repairs. Then the Trail Footer, Form A (the session is over; the command routes by map status as usual).
## The template
Substitute real content; keep the section order. `<in range>` reads naturally per range: "Decided today", "Decided this week", "Decided so far" (full).
```markdown
# Audit log export - decisions brief
**Covers:** 2026-09-02 · **Map:** 6 of 9 decisions made
## Where this is headed
<The destination, verbatim from the map.>
## Decided today
- **Export format** - CSV with a UTF-8 BOM plus a SHA-256 manifest file.
Rejected: JSONL (recipients open these in Excel); XLSX (harder to verify byte-for-byte).
*Recorded as hard to reverse.*
- **Export authorization** - new tenant-scoped compliance role; self-events included but flagged.
Rejected: reusing the admin role (no tenant scoping today).
## Ruled out
- **SIEM push connector** - continuous streaming is a separate effort with its own owner.
## Open - ready to decide next
- **Delivery channel** - can now be decided; the row-count ceiling it was waiting on landed today.
- **Testing posture** - needs Product and Engineering together.
## Open - waiting on something first
- **Redaction rules** - waiting on Legal's answer about exporting raw payloads.
## Still taking shape
- How far back an export may reach - depends on a retention answer nobody has yet.
## How solid is this?
Solid overall, but risk handling is borderline - one limit has no decided behavior past it yet.
## Next step
Run: `/plan2code-0-pathfinder specs/audit-log-export/pathfinder`
---
*Full reasoning behind every decision: `specs/audit-log-export/pathfinder/questions/`*
```
**How each section is built:**
| Section | Source | Rendering rule |
|---|---|---|
| Heading + `**Covers:**` | Idea name in words; the range; `<resolved>/<total>` using the trail's counting rule (out-of-scope rows excluded from the total) | |
| Where this is headed | `## Destination`, verbatim | Never paraphrase it |
| Decided `<in range>` | Resolved files with `Resolved:` in range | Question name bold, gist as the first line, rejected alternatives compressed to ONE line each with the why in parentheses. `Locked: yes` renders as *Recorded as hard to reverse.* — never the word "locked" |
| Ruled out | `## Out of scope`, all of it | One line each: name + why |
| Open - ready to decide next | The frontier (open, unclaimed, unblocked) | Flag anything a resolution in range just unblocked: "can now be decided; X landed <day>" |
| Open - waiting on something first | `[!]` blocked rows | Name the blocker in plain words ("waiting on the export format decision"), never `Blocked by: 02` |
| Still taking shape | `## Not yet specified` | Lightly rephrase each bullet into one plain sentence |
| How solid is this? | The map's `**Confidence:**` line | ONLY via trail.md's plain-English mapping (solid / solid-but-borderline / not yet). Omit the section if the map has no confidence line |
| Next step | Map status | `Working`/`Charting` → the pathed resume command; `Cleared` → point at the PLAN-DRAFT and `/plan2code-1-plan` |
Nothing decided in the range? Keep the file honest: "No decisions were recorded in this period." under Decided, and render the open sections as usual — a meeting that only surfaced questions still gets minutes.
## Rules
- **Zero pathfinder machinery in the file.** No `NN` numbers, no markers, no `Type:`/`State:` tokens, no fog/frontier/grill vocabulary, no `Locked:`. Questions are referred to by name only, no links. The audience may never open a terminal.
- **Scraper safety, same as the PLAN-DRAFT:** no `%`, no raw `NN/25` scores, and no bare `Requirements` / `Feasibility` / `Integration` / `Risk` followed by a number anywhere in the file. The plain-English confidence line is the only rendering permitted.
- **Standing `specs/` rules apply:** no loop tokens, no `- [ ]` checkboxes, no `METRICS_JSON`.
- **Rejections are one line each.** The brief summarizes; the question file argues. The closing pointer line covers readers who want the full reasoning.
- **BRIEF mode does not count as question work.** One-question-per-session accounting is untouched; no claim is ever taken.
- **Do not edit an old brief to "update" it.** Yesterday's brief reflects yesterday's map — write today's instead. Same-day overwrite only.
@@ -14,7 +14,7 @@ Pathfinder builds an apparatus — a directory, a map, a file per decision. That
You already have the idea name from Auto-Discovery. Do NOT create the directory yet. Say, in substance:
> "This is Pathfinder. Nothing exists for `<idea>` yet. Pathfinder charts a map of the open decisions when an idea is big or unclear to plan — but that is overhead if this is small or already clear. Three ways to go:
> - **Chart it** — I map the open decisions, one per session, then hand a draft to `/plan2code-1-plan`.
> - **Chart it** — I map the open decisions, we clear them one at a time, then hand a draft to `/plan2code-1-plan`.
> - **Straight to `/plan2code-1-plan`** — the way looks clear enough to plan now.
> - **`/plan2code-quick-task`** — small enough to just do.
>
@@ -23,7 +23,7 @@ You already have the idea name from Auto-Discovery. Do NOT create the directory
Rules for the gate:
- **It is HITL.** You recommend; the human chooses. Never self-select "chart" and start creating files because it is the default path — that is exactly the failure this gate exists to stop.
- **Read the request honestly.** A one-line bugfix, or a change with no open decisions, is not a charting job — recommend an off-ramp and mean it. Reserve "chart" for real fog: several unsettled decisions, unclear scope, or competing designs.
- **Read the request honestly.** A one-line bugfix, or a change with no open decisions, is not a charting job — recommend an off-ramp and mean it. Reserve "chart" for real fog: several unsettled decisions, unclear scope, or competing designs. A joint Product + Engineering kickoff on a fresh idea is the canonical "chart it" case — a new feature explored by two teams is fog almost by definition.
- **No disk writes.** Naming the idea and talking is free. Creating `specs/<idea>/pathfinder/` is not — it waits for an explicit "chart."
- **On an off-ramp, route and STOP.** Point at `/plan2code-1-plan` or `/plan2code-quick-task`, create nothing, end the session. If `AGENTS.md` is absent, mention `/plan2code-init` first, as with any handoff.
@@ -52,7 +52,7 @@ Two round trips, not six. Three probes each — exactly the cap, so neither batc
Batch 2 bends the independence test on purpose. The arrival signal (5) can shift under the smallest arrival (4), so strictly it should be held back — but holding it costs a third round trip to catch a conflict that is rare and cheap to spot. The trade is to send them together and reconcile at the recap: if the smallest arrival comes back materially smaller than the artifact you were told about, re-check the arrival signal against it before writing the destination. A knowing trade here, not a licence to batch dependent probes elsewhere.
**Both batches go out as numbered Q blocks — this grill is the other standing exception to the tool-first rule.** Probes 2, 3, 4, and 5 need the human's own phrasing — the destination is written into `map.md` verbatim as agreed, so a clicked option label is not something you can write down. That is the detail test's first row, four times over. Probe 6 names categories but the category is the worthless half of the answer: "deadline" changes nothing, "Q3 close, and the SEC audit lands Nov 1" changes the delivery question, the testing posture, and the out-of-scope line at once. Only probe 1 would survive a picker on its own, and it rides in a Q block anyway, because one tripping probe downgrades the whole batch. Do not reach for the structured question tool here.
**Both batches go through the structured question tool.** Give each probe genuine candidate options with trade-offs and a recommendation; the built-in `Other` path is where the human composes the actor, boundary, arrival signal, or forcing-function detail in their own words. A clicked option is not written verbatim as the destination — the recap-confirmation tool call turns all six answers into the agreed one-or-two-line destination before disk write.
**Probe 1 — the artifact**
@@ -155,6 +155,7 @@ Type: legwork · AFK
State: resolved
Blocked by: none
Claimed: 2026-08-03 09:12
Resolved: 2026-08-03
Locked: no
## Question
@@ -272,16 +273,18 @@ Say it out loud so the human tracks the move, then jump:
Two mechanics keep the fan-out honest:
1. **Round-robin the areas.** Before you start, list the axes you intend to cross: data, surface, permissions, volume, delivery, failure, operations, testing. Take one probe per axis before any second probe on any axis.
1. **Round-robin the areas.** Before you start, list the axes you intend to cross — engineering axes (data, surface, permissions, volume, delivery, failure, operations, testing) AND product axes (user value, success measurement, target user, rollout, analytics, support & docs, legal/compliance). Not every axis applies to every destination: name the ones that do before the first probe, say which you are skipping and why, then take one probe per axis before any second probe on any axis.
2. **Ask for the axis you have not touched.** Near the end: "What have I not asked about that would embarrass us to discover in week three?"
**Breadth-first is the ideal batch.** One probe per axis means the probes are independent by construction — that is what breadth-first *means* — so this grill should run as batches of three, not as a stream of singles. Seven axes is three turns. If you catch yourself wanting to batch two probes on the same axis, that is depth wearing a batch's clothes; pull back.
**Breadth-first is the ideal batch.** One probe per axis means the probes are independent by construction — that is what breadth-first *means* — so this grill should run as batches of three, not as a stream of singles. If you catch yourself wanting to batch two probes on the same axis, that is depth wearing a batch's clothes; pull back.
**With Product in the room, the product axes are not optional.** A joint Product + Engineering session that only fans out across engineering axes produces a map Product cannot answer for — and vice versa. Alternate: an engineering batch, then a product batch, so neither team spectates for three turns straight.
### Sample breadth probes
Each opens a different axis. Send 1-3 as one batch and 4-6 as the next, then probe 7 alongside the "what have I not asked about" closer above; note each answer and move.
Each opens a different axis. Batch three at a time in list order (skipping axes you ruled inapplicable), with probe 7 riding alongside the "what have I not asked about" closer above; note each answer and move.
**They go out as numbered Q blocks — this grill is one of the two standing exceptions to the tool-first rule.** Several of the probes do name alternatives, so they would pass the detail test on its own terms, and that is exactly the trap: the output of this grill is not a decision, it is a *sort* into sharp question or fog, and sorting takes the elaboration around the answer. A clicked label leaves you nothing to sort with. The structured question tool earns its keep in MODE B, where a claimed question already has named alternatives and the sorting is long done.
**Every batch goes through the structured question tool.** The output is a *sort* into sharp question or fog, so the option descriptions carry the framing and the built-in `Other` path captures elaboration the named choices miss. Never ask these probes as a prose list when the tool exists.
1. **Data** — "What is the smallest and largest thing an operator could reasonably ask for in one export? Give me both ends."
2. **Surface** — "Where does this start: a button in the admin UI, a scheduled thing, an API call someone scripts?"
@@ -291,6 +294,16 @@ Each opens a different axis. Send 1-3 as one batch and 4-6 as the next, then pro
6. **Operations** — "Six months from now someone asks who exported what. Does this feature audit itself?"
7. **Testing** — "What would you need to see pass before you would let this near a customer's compliance data?" *(This one always runs — see the mandatory testing-posture question below.)*
The product axes, same style — one sample probe each:
8. **User value** — "A compliance officer gets this feature Monday morning. What stops being painful for them that day?"
9. **Success measurement** — "Three months after ship, what number or behavior tells you this was worth building?"
10. **Target user** — "Who is this for first — every tenant, one segment, one named customer who asked?"
11. **Rollout** — "Does this land for everyone at once, behind a flag, or piloted with one tenant first?"
12. **Analytics** — "What do you want to know about how people actually use it — and is any of that instrumented today?"
13. **Support & docs** — "A support ticket about this lands in week one. What does the agent need to see to answer it without escalating?"
14. **Legal / compliance** — "Does anything here touch data retention, privacy, or a regulator's definition of a record?"
Record each answer as one line in your working notes with an area label. At the end of the grill you will have two piles: lines you can turn into a sharp question, and lines you cannot. The second pile is the fog.
---
@@ -390,6 +403,8 @@ Say once, at Step 5: *"This map lives in gitignored `specs/` — local to you, n
# Map: audit-log-export
*Decisions live in `questions/` — one file each. This file is just the index.*
**Status:** Working
**Updated:** 2026-08-03
**Confidence:** Requirements-clarity 18/25 · Feasibility-technical 14/25 · Integration-points 16/25 · Risk-assessment 14/25
@@ -417,8 +432,8 @@ plan, not at shipped code. Continuous streaming to external systems is not on th
obeyed while resolving it. Nothing here is re-asked. -->
- `AGENTS.md` exists and governs. Its conventions are not re-litigated by any question here.
- One question _file_ per session. `research` questions may run as parallel subagents.
- Grill probes are batched per the grilling playbook — at most three per turn, through the structured question tool unless the detail test forces prose Q blocks.
- One question _file_ at a time; the fork-menu between decisions; a fresh session recommended after ~3. `research` questions may run as parallel subagents.
- Every user-facing question uses the structured question tool when available; probes batch at most three. Prose Q blocks are fallback only when the tool is unavailable.
- Questions are put to the human in plain English. Technical terms only where the term is the decision.
- HITL questions are answered by the human in their own words. Never self-answered.
- No new runtime dependency is assumed without a `research` question backing it.
@@ -442,10 +457,11 @@ plan, not at shipped code. Continuous streaming to external systems is not on th
<!-- Rebuilt from questions/ every session — the files are ground truth, this is an index.
[ ] open (the frontier) · [/] claimed · [x] resolved · [!] open but blocked
[-] out of scope. Resolved rows carry the one-line gist from the question's Answer. -->
[-] out of scope. Resolved rows carry the one-line gist from the question's Answer,
then the Resolved: date in italics — briefs filter on these dates. -->
- [x] [Codebase context](./questions/00-codebase-context.md) — Node/Express/Knex/React with a BullMQ-to-S3 export precedent; `audit_events` is 180M rows partitioned monthly, no `actor_id` index, `requireAdmin` has no tenant scoping.
- [x] [Export format](./questions/01-export-format.md) — CSV with a UTF-8 BOM and RFC 4180 quoting, plus a sidecar SHA-256 manifest; JSONL rejected because recipients open these in Excel.
- [x] [Codebase context](./questions/00-codebase-context.md) — Node/Express/Knex/React with a BullMQ-to-S3 export precedent; `audit_events` is 180M rows partitioned monthly, no `actor_id` index, `requireAdmin` has no tenant scoping. *(2026-08-03)*
- [x] [Export format](./questions/01-export-format.md) — CSV with a UTF-8 BOM and RFC 4180 quoting, plus a sidecar SHA-256 manifest; JSONL rejected because recipients open these in Excel. *(2026-08-03)*
- [/] [Row-count ceiling](./questions/02-row-count-ceiling.md)
- [ ] [Export authorization](./questions/03-export-authorization.md)
- [ ] [Testing posture](./questions/04-testing-posture.md)
@@ -489,7 +505,7 @@ plan, not at shipped code. Continuous streaming to external systems is not on th
## The question-file template
Five contiguous `Key: value` lines after the H1. Not YAML. No frontmatter delimiters. No `- [ ]` checkboxes anywhere inside a question file — use plain bullets, including for legwork checklists.
Six contiguous `Key: value` lines after the H1. Not YAML. No frontmatter delimiters. No `- [ ]` checkboxes anywhere inside a question file — use plain bullets, including for legwork checklists.
`## Question` is written at charting. `## Answer` is appended only when the question resolves. `## Evidence` holds sources, links, and artifacts, and a `research` subagent writes into it during Chart Step 8 without deciding anything.
@@ -504,6 +520,7 @@ Type: grill · HITL
State: open
Blocked by: none
Claimed: none
Resolved: none
Locked: yes
## Question
@@ -544,6 +561,7 @@ Type: grill · HITL
State: resolved
Blocked by: none
Claimed: 2026-08-03 10:41
Resolved: 2026-08-03
Locked: yes
## Question
@@ -626,6 +644,7 @@ Type: grill · HITL
State: open
Blocked by: none
Claimed: none
Resolved: none
Locked: no
## Question
@@ -4,7 +4,7 @@
>
> **Local-file maps never load this file.** If `## Ground rules` says `**Backend:** local`, close it and use `questions.md`.
Everything the skill says about *judgement* is unchanged by the backend: the fog-vs-question test, the destination grill, one question per session, HITL is never self-answered, the Clearing Gate rubric. This file changes only *where the bytes go*.
Everything the skill says about *judgement* is unchanged by the backend: the fog-vs-question test, the destination grill, one question at a time, the decide-menu-checkpoint cadence, HITL is never self-answered, the Clearing Gate rubric. This file changes only *where the bytes go*.
---
@@ -83,6 +83,7 @@ This is the whole mapping. Everything below expands a row.
| `Blocked by: 02, 04` | Native issue dependencies (`dependencies/blocked_by`) |
| `Locked: yes` | The `pathfinder:locked` label |
| `Claimed: <timestamp>` | GitHub's own assignment event in the timeline |
| `Resolved: <YYYY-MM-DD>` | The issue's own close timestamp (`closedAt`) — nothing to write, nothing to backfill |
| `## Question Checklist` in `map.md` | **Nothing** — the frontier is a live query, not a written list |
| `## Not yet specified`, `## Out of scope`, `## Ground rules`, `## Destination`, `## Glossary` | The same sections, in the map issue body |
| `sketch-NN/` | Still local disk — see *What stays on local disk* |
@@ -145,7 +146,8 @@ plan, not at shipped code. Continuous streaming to external systems is not on th
- **Backend:** github — this issue is the map; questions are its sub-issues.
- `AGENTS.md` exists and governs. Its conventions are not re-litigated by any question here.
- One question _issue_ per session. `research` questions may run as parallel subagents.
- One question _issue_ at a time; the fork-menu between decisions; a fresh session recommended after ~3. `research` questions may run as parallel subagents.
- Every user-facing question uses the structured question tool when available; probes batch at most three. Prose Q blocks are fallback only when the tool is unavailable.
- HITL questions are answered by the human in their own words. Never self-answered.
- Sketches are throwaway and live on local disk only, under `specs/audit-log-export/pathfinder/sketch-<issue>/`.
@@ -316,12 +318,14 @@ gh issue close <n> --reason completed
# 3. Append the gist to the map's Decisions so far (read body, edit, write back).
gh issue view <map-number> --json body --jq .body > /tmp/map.md
# ...append: - [Export format](<issue-url>) — <gist>
# ...append: - [Export format](<issue-url>) — <gist> *(YYYY-MM-DD)*
gh issue edit <map-number> --body-file /tmp/map.md
```
Then bump `**Updated:**` and re-score `**Confidence:**` in the same map edit.
**The close date IS the `Resolved:` date.** There is no line to set and none to backfill — `closedAt` is written by GitHub the moment step 2 runs, and a brief filters on it. Stamp the same date in italics on the `## Decisions so far` line so the map reads as a dated record on its own.
**Never edit the question body to hold the answer.** The body is the question as asked; the comment is the answer. Editing the body rewrites history and destroys the record of what was actually put to the human — which is half of why the answer is defensible three weeks later.
### Editing the map body safely
@@ -355,6 +359,8 @@ Much shorter here — the tracker holds the state, so there is no checklist to r
Then re-read `## Not yet specified` in full — that part is identical to local mode, and the bullet left behind after its question exists is just as corrosive here.
Local mode's `Resolved:` backfill has no counterpart here: `closedAt` cannot be absent on a closed issue. If a `## Decisions so far` line is missing its date, take the date from `closedAt` during the index-drift repair above.
---
## What stays on local disk
@@ -392,6 +398,22 @@ NEXT STEP · start a new conversation and run:
Form B is unchanged — a turn that asks the human something still says `WAITING ON YOU`, still names the outstanding probes, and still emits no resume command.
Form C — the fork-menu after a recorded decision — is unchanged in shape, with two substitutions: the takeable options come from the frontier query rather than the checklist rows, and the `OR START FRESH` command carries the map issue URL. The `RECOMMENDED` marker and the ~3-decision checkpoint work exactly as `trail.md` describes.
---
## BRIEF mode
The report is identical either way, and the file still lands on **local disk** at `specs/<idea>/pathfinder/briefs/brief-<YYYYMMDD>.md` — a brief is a plain-English artifact for people, not tracker state, and writing it as an issue comment would bury it. Three substitutions against `brief.md`:
| `brief.md` says | Here |
|---|---|
| Filter resolved questions by `Resolved:` in range | Filter the map's sub-issues closed as completed by `closedAt` in range |
| Reconcile backfills absent `Resolved:` dates | Nothing to backfill; run the three reconcile checks above instead |
| Open / blocked / out-of-scope sections read the checklist | They read the frontier query — unassigned-unblocked, `blocked_by > 0`, and `pathfinder:out-of-scope` respectively |
`## Not yet specified`, `## Destination`, and `**Confidence:**` come from the map issue body, same as always. The no-machinery rule tightens rather than relaxes: no `#numbers`, no label names, no `gh` commands in the file. The reader may never have opened the tracker either.
---
## Handoff (The Clearing Gate)
@@ -3,7 +3,9 @@
Grilling is how a `grill · HITL` question resolves, how Chart Step 2 names the destination, and how Chart Step 4 maps the frontier. It is also the fallback for any question whose type gives you no better route. The output of a grill is a decision in the human's own words — never a decision you made on their behalf.
**Probe ≠ question file.** A *probe* is one turn of the interrogation; a *question file* is one `questions/NN-<slug>.md` on the map. Batching applies to probes only. **One question file per session still holds**resolving three question files in one sitting is not what this is.
**Probe ≠ question file.** A *probe* is one turn of the interrogation; a *question file* is one `questions/NN-<slug>.md` on the map. Batching applies to probes only. **One question file at a time still holds**a batch of three probes resolves ONE file; a session moves to the next file only through the fork-menu between decisions (resolve.md §Cadence), never by interleaving two grills.
**Grilling a room.** When several people answer — a Product + Engineering session — the mechanics are unchanged, plus three rules: address probes to the room, not a person, unless one person owns the call; the recap must capture the decision in the room's words, and whose call broke any tie is worth a clause in the `## Answer`; and a contested pick is NOT a decision — when Product and Engineering disagree, record both positions under `## Evidence`, leave the question `open`, and move on (or offer a `sketch` — reacting to something concrete resolves more standoffs than argument). Never average two positions into an answer nobody actually gave.
## The interview protocol
@@ -15,8 +17,8 @@ The old rule here was one probe per turn. It was safe and it was unusably slow:
|---|---|
| Up to 3 probes per turn, never more | Past three the human skims, and a skimmed answer is worse than none. Three is a ceiling, not a quota — send two if only two are independent. |
| Only batch mutually independent probes | The independence test below. A probe whose wording or recommendation shifts based on another probe's answer waits for the next turn. |
| Reach for the structured question tool first | It is the intended channel, not the leftover bin. Shape the batch so it fits — three probes, plain headers, options a description can carry — and fall back to prose only when the detail test genuinely trips. |
| A probe that needs detail goes in prose, never in options | The detail test below. Batching buys round trips; it must never buy them by shrinking a decision to fit a picker. |
| Use the structured question tool for every question when available | The built-in UI is the primary experience: selectable answers, visible skips, and `Other` for composition. Prose provides context, never the answer control. |
| Keep detail in descriptions, context, and `Other` | Batching buys round trips; it must never buy them by shrinking a decision to fit a picker. |
| Wait for the whole batch before sending the next | Their answers reshape what comes next. Pre-writing turn 2 wastes it. |
| Recommend an answer with every probe | A bare question makes the human do all the work. A recommendation gives them something to push against, which is faster and sharper. |
| Write it in plain English; keep the technical word only where that word IS the decision | A probe the human has to decode is a probe they answer approximately. See *Say it in plain English*. |
@@ -66,7 +68,7 @@ Every probe gets read once, by a busy human, in a terminal. Write it the way you
| "the sacrificial boundary" | "name one thing people would assume is included that you are willing to cut" |
| "shall I set `Locked: yes`?" | "worth recording why we picked this, so nobody re-opens it in six months?" |
| "Q3 is blocked by 02" | "the export format question has to land before this one" |
| "this batch trips the detail test" | nothing — that call is yours, not theirs |
| "the UI cannot handle this question" | nothing — put context before the tool and preserve `Other` |
**Refer to questions by name, never by number** — "[Export format](./questions/04-export-format.md)", not "04". The number means something to the file system and to nobody else.
@@ -88,58 +90,37 @@ In doubt, hold it back. A held probe costs one extra round trip. A dependent pro
Independent probes are usually the ones that came from **different areas** — data, interface, security, operations, testing. Dependent probes are usually consecutive steps down one thread.
### Delivering a batch: choosing the channel
### Delivering a batch: structured UI first
Two channels — the environment's structured question tool, or numbered Q blocks in prose. **Choose before you write a word, and choose per batch, not per probe.** One channel per turn: a batch split across a tool popup and a loose prose question loses the prose half every time, because the human answers in the tool and never scrolls back.
**Use the environment's structured question tool for every user-facing question when it is available.** This includes destination probes, frontier probes, claimed-question grills, recap confirmations, lock offers, sketch reactions, intent gates, and fork-menus. The built-in UI is faster to scan, preserves visible skips, and always provides an `Other` path for composed answers. Numbered prose Q blocks exist only as the fallback when the tool is unavailable.
**The tool is where you start.** Assemble the batch for it — three probes, a plain two-or-three-word header each, alternatives a sentence or two of description can carry — and only then run the detail test to see whether anything forces you out. Prose is the exception you fall back to, not the safe default you retreat to. Two things make the tool worth the effort: a skipped probe comes back *visibly* skipped, and a picker is answerable in one pass by a human who has thirty seconds. Neither survives the move to prose.
One question object per probe, up to three per call. Never split a batch between a tool popup and prose — the prose half gets lost when the human answers in the UI.
The two failure directions are opposite and both real. Retreating to prose out of caution costs you the visible skip and the fast reply. Forcing a genuinely gnarly decision into a picker costs you the reasoning, which is worse. The detail test below is where that line sits — run it honestly in both directions.
**Composed answers still use the tool.** Do not invent a false-complete option set merely to make a picker. Offer the genuine candidates you know; the automatic `Other` option is where the human composes a boundary, rationale, hybrid, old-incident detail, or alternative you could not know. When no genuine candidate exists, offer useful control choices such as `Use recommendation` and `Defer for now`; the human writes the real answer through `Other`. A click is still followed by the normal recap-confirmation turn, which captures reasoning in the human's words.
**Whichever channel you pick, the turn closes with the waiting footer.** A turn that sends a batch is a **Form B turn** in `trail.md`: the Trail Footer under it names the outstanding probes after `WAITING ON YOU` and carries **no** resume command. Emitting "start a NEW conversation" above an unanswered batch tells the human to leave the session you are sitting in — they walk, and the batch you built to save round trips costs you the whole decision instead. Same for the recap turn below, which is also waiting on them.
**Artifacts do not force prose questions.** Show the state table, fake request/response, ASCII UI, or worked example in the response, then immediately invoke the structured tool for the pointed reaction probes. The artifact is prose; the questions are UI controls. Never ask "thoughts?" outside the tool.
#### The detail test — the only things that force you out of the tool
**Never reshape the decision to fit the tool.** Descriptions carry trade-offs; `Other` carries composition. Split bundled decisions into separate probes and rename colliding short headers. Do not cut a real alternative or hide complexity. If the UI cannot represent the question faithfully even with descriptions + `Other`, state the full context immediately before the tool and keep the actual answer control in the tool.
Numbered Q blocks are **required, not merely permitted**, if *any* probe in the batch trips *any* row below. One tripping probe downgrades the whole batch.
These four rows are the whole list. Nothing else forces prose — not a long question, not a hard decision, not a `Locked: yes`, not your discomfort with the widget.
| Trip | Looks like | Not this |
|---|---|---|
| The answer must be composed, not picked | "Name one thing a reasonable person would assume is in scope that you are willing to cut." There is no option set, because inventing one puts words in their mouth. | A decision with genuine named alternatives, however weighty. Write the options. |
| The probe needs an artifact inline to be answerable | A state table, a fake request/response pair, an ASCII UI, a worked example with real numbers — effectively every `sketch` probe | A probe that merely *mentions* a file path, a format, or a number. Those go in the question text. |
| An option cannot be conveyed even in its description | Each alternative needs a worked paragraph before it means anything — a migration path, a failure sequence, a schema | An alternative that needs one or two sentences of trade-off. That is what the description field is for. |
| The alternatives themselves are unknown to you | You cannot name the losing options at all, because the frame is theirs — a contract, an old incident, an org politics fact | You can name them but cannot say why each loses. Name them, recommend one, and let the recap turn supply the reasoning. |
Three things that look like trips and are not:
- **One label bundling several decisions** — "authentic counts, one-use per attempt, restored on death" is three answers wearing one coat. The fix is to **split it into separate probes**, not to write prose. Three separated probes is exactly one batch.
- **Two probes colliding on the tool's short header limit** (16 characters in Claude Code) — `Export scope` twice is unanswerable, but the fix is to rename them (`Date range`, `Who can run`) or to hold one for the next turn. Reword before you retreat.
- **A hybrid is possible** — the free-text escape hatch takes "the header from B with the list from C" fine. Trip only when you can already predict the answer *will* be a composition, which is the first row.
**`Locked: yes` on its own does not trip the test.** A lock's `## Answer` owes every alternative and the reason each lost — but if *you* can already name the alternatives, you have written the options, and the recap turn turns the pick into words the human said. A lock trips only on the fourth row, where you cannot name them at all. Treating every lock as an automatic downgrade sends almost every MODE B decision worth grilling to prose, which defeats the point — MODE B is exactly where a claimed question already has named alternatives and the tool earns its keep.
**Nothing tripped? Use the structured tool.** Not "may" — do. It is the intended channel, and it is where the visible-skip guarantee behind the partial-answer discipline below comes from.
**Never reshape a probe to fit the tool.** Reaching for the tool first is not licence to shrink a decision into it. The failure mode is not that the tool rejects a gnarly probe — it is that it *accepts* one. You compress a decision with real texture into three tidy options, the human clicks the least-bad one, and you have recorded a decision with no reasoning behind it. That answer cannot satisfy `## Answer`'s obligation to name what was rejected and why, and nobody finds out until handoff, when the PLAN-DRAFT's Architecture section turns out to have nothing to say. Splitting a bundled probe or renaming a colliding header is reshaping the *batch* and is always right. Cutting a real alternative, or thinning a description until the trade-off disappears, is reshaping the *decision* and is always wrong. When the honest choice is between paragraphs and dishonest options, write the paragraphs.
The turn closes with the waiting footer (Form B in `trail.md`): it names outstanding probes and carries no resume command. The recap confirmation is also asked through the tool and remains Form B.
#### The structured tool
The default channel, and the one you build the batch for. One question object per probe, up to three in a single call:
The primary channel. One question object per probe, up to three in a single call:
- **Header** — the decision in two or three plain words (`Export format`, `Size cap`). Not a type, not a marker, not a number.
- **Question** — the probe, with its why-it-matters. This is prose and it is not rationed; the same sentences you would have written in a Q block go here.
- **Options** — the genuine alternatives, each described by its trade-off, with the recommended one named as such in its description. Two to four; the free-text escape hatch covers the rest. Label plainly, then let the description carry the precise term: `One file per message` labelling the `.eml`-in-a-ZIP option, with `.eml` named in the description.
A short *label* is not a short *decision*. The label is a handle — `Fixed tick count` — and the description carries the trade-off that makes it choosable. A probe only trips the third detail-test row when even that description cannot hold the option. A label bundling several independent answers is not that row — it is a probe that wants splitting.
A short *label* is not a short *decision*. The label is a handle — `Fixed tick count` — and the description carries the trade-off that makes it choosable. A label bundling several independent answers is a probe that wants splitting.
**A click is a decision, not a sentence.** The HITL rule wants an `## Answer` traceable to something the human actually said, and a selected option label is thin evidence on its own. What makes tool-delivered answers legitimate is the recap turn in *Landing the grill* — you play the choices back in prose and they confirm or correct in their own words. Never skip the recap on the grounds that the tool already captured the answer; the tool captured the *pick*, and the recap captures the *agreement*.
**A click is a decision, not a sentence.** The HITL rule wants an `## Answer` traceable to something the human actually said, and a selected option label is thin evidence on its own. What makes tool-delivered answers legitimate is the recap turn in *Landing the grill* — you play the choices back in the tool's question text and they confirm or correct in their own words. Never skip the recap on the grounds that the tool already captured the answer; the tool captured the *pick*, and the recap captures the *agreement*.
**If a reply comes back thinner than the decision** — a bare click on something you now realise carries weight — do not paper over it. Fold the why into the recap turn as one more probe before writing the `## Answer`.
#### Numbered Q blocks
The mandatory channel for anything the detail test catches, and the fallback anywhere the structured tool does not exist. Give each probe the room the tool would have denied it.
Fallback ONLY when the structured question tool does not exist or its call fails. Never choose prose merely because the answer is detailed, composed, architectural, `Locked: yes`, or attached to an artifact — descriptions + `Other` + context immediately before the tool cover those cases.
**Copy this shape exactly.** The blank lines are load-bearing, not decoration:
@@ -188,14 +169,14 @@ A batch is only worth sending if the human can read it. These are mechanical, an
| **The question itself gets its own line, not a run-on with the heading** | `**Q1 — Export format.** When a custodian…` buries the decision inside a paragraph. Name it, break, then ask it. |
| **Never use spaces to convey structure** | Whatever hierarchy you indent by hand disappears on render. Structure comes from blank lines, bullets, and bold — nothing else. |
The same applies to the recap turn in *Landing the grill*: it is prose the human has to check line by line, so give each recapped decision its own bullet.
For the recap in *Landing the grill*, summarize each decision in the structured tool's question text and ask the human to confirm or correct it; use `Other` for corrections.
### When answers come back partial
Assume they will. The human answers two and drops one, and the dropped one is often the hardest and most valuable.
1. **Diff what came back against what you sent.** Skipped, answered with "Other: skip", or silently omitted all count as unanswered.
2. **Lead the next turn with the unanswered probes**, at their original numbers, restated in full. Not "you missed Q3" — the whole probe again, with its recommendation, because they have lost the context by now. Unanswered probes come *before* any new probe, and they count against the cap of three.
2. **Lead the next tool call with the unanswered probes**, using their original headers and full wording. Not "you missed Export scope" — the whole probe again, with its recommendation, because they have lost the context by now. Unanswered probes come *before* any new probe, and they count against the cap of three.
3. **Skipped twice, stop pushing.** Record it under `## Evidence` as an open probe with your recommendation verbatim, then either narrow it into something answerable or spin it out — a fresh question file if you can phrase it sharply, a `## Not yet specified` line if you cannot.
4. **Never promote your own recommendation into `## Answer`.** A probe the human declined twice is unanswered, not decided. Writing it up as decided is self-answering a HITL question, which breaks the skill.
@@ -334,7 +315,7 @@ Offer it, do not impose it: *"This one looks hard to reverse and the reasoning w
Chart Step 6 requires this question. It exists because `/plan2code-1-plan` Phase 1 asks for exactly three things and stalls without them: testing types, whether tests run after each phase, and the coverage target. A map that clears without answering them hands the human a plan session that immediately re-asks.
The first three probes below pass the independence test against each other — none reads differently under another's answer — so **send all three as one batch**. This is the canonical worked example of a full batch, and it is the canonical case for the structured tool: every one of the three has named alternatives you can already write, the answers are fixed literals rather than prose, and nothing in the batch trips the detail test.
The first three probes below pass the independence test against each other — none reads differently under another's answer — so **send all three as one structured-tool batch**. Every probe has named alternatives and fixed literals; `Other` remains available.
| Probe | Recommend by default |
|---|---|
@@ -373,10 +354,10 @@ If a decision survives all six with no answer, it is not ready to leave the map.
| Drip-feeding one probe at a time | Twelve open questions on the map, one probe per response, the human gives up on session four | Batch up to three independent probes. On a charted map the human's round trips are the scarce resource, not your token budget. |
| Losing a probe the human skipped | Sent three, got two back, moved on and never mentioned the third | Diff the batch. Lead the next turn with what came back empty, restated in full. |
| A batch of naked questions | Three one-liners with no recommendations and no why-it-matters | Every probe in a batch carries its own recommendation and its own stake. Otherwise you have offloaded the thinking, not the round trips. |
| Sending a batch as a wall of text | Three probes hard-wrapped across source lines with their options indented, all collapsing into one paragraph on render | Blank line between every element, options as a bullet list, `---` between probes. The three-probe cap exists so the human reads all three; an unreadable batch gets skimmed, and a skimmed answer is worse than none. |
| Flattening a gnarly probe into a picker | An architectural decision reduced to three option labels because the batch was already going through the structured tool | Run the detail test. One tripping probe sends the whole batch to numbered Q blocks. A clicked option records no reasoning, and the `## Answer` needs reasoning. |
| Defaulting to prose when nothing tripped | A clean three-probe batch written as Q blocks "to be safe", or downgraded just because the question will be `Locked: yes` | The detail test is a test, not a preference, and it is four rows long. Nothing tripped means the tool: you gain visibly skipped probes, and the recap turn still captures the reasoning a lock needs. |
| Retreating to prose over a fixable batch | Two probes collided on the 16-character header, or one option label was bundling three answers, so the whole batch went to Q blocks | Neither is a detail-test trip. Rename the headers; split the bundled probe. Reshape the batch, never the decision. |
| Asking in prose when the tool exists | Numbered Q blocks or a loose "which one?" despite AskUserQuestion being available | Put every answer control in the structured UI. Use descriptions for trade-offs and `Other` for composition. Prose may provide context or an artifact immediately before the tool, never the question itself. |
| Flattening a gnarly probe into labels | An architectural decision reduced to three option labels with no useful descriptions | Keep the tool, not the flattening: put the real trade-off in each description, preserve `Other`, and recap the reasoning before recording. |
| Treating an artifact as an excuse for prose | An ASCII UI followed by "thoughts?" | Show the artifact, then invoke the structured tool with pointed reaction probes naming the rows/elements. |
| Retreating to prose over a fixable batch | Two probes collide on the short header, or one label bundles three answers | Rename the headers; split the bundled probe. Reshape the batch, never the decision. |
| Sending four probes because the tool accepts four | A fourth probe added to a clean batch of three because there was room in the call | The cap is three regardless of what the environment allows. The ceiling is the human's attention, not the tool's schema. |
| Grilling in Pathfinder's own vocabulary | "The frontier has one takeable `grill · HITL` — shall we graduate 02 out of the fog and lock it?" | Plain English. Markers, types, `NN` numbers, and fog are your bookkeeping; the human is deciding about their product. |
| Plain-washing the load-bearing term | "Do you want the friendly file or the compact one?" where the real choice is `.eml`-in-a-ZIP versus NDJSON | Plain wording, precise nouns. Name the formats and gloss them; a decision made on a euphemism cannot be written into `## Answer`. |
@@ -384,7 +365,7 @@ If a decision survives all six with no answer, it is not ready to leave the map.
| Accepting a vague answer and moving on | "Handle it sensibly" → recorded as the decision | Push once more, concretely: "Sensibly meaning we drop the attachment, or fail the whole job?" A vague answer is not an answer. |
| Leading the human to your preferred answer | "You'd want Postgres here, right?" | Recommend openly, then present the real alternatives with their real merits. A recommendation invites a fight; a leading question suppresses one. |
| Grilling past the decision into implementation | "Should the retry helper take a callback or return a promise?" | That is the plan's job, or the implementer's. Stop at the decision. The pull to keep going is the edge of the map. |
| Drifting off the claimed question | Claimed `[Export format](./questions/04-export-format.md)`, forty minutes later deep in auth | Name the drift out loud, capture the new thread as a fresh question or as a line in `## Not yet specified`, and return. One question _file_ per session. |
| Drifting off the claimed question | Claimed `[Export format](./questions/04-export-format.md)`, forty minutes later deep in auth | Name the drift out loud, capture the new thread as a fresh question or as a line in `## Not yet specified`, and return. One question _file_ at a time — switching happens at the menu, not mid-grill. |
| Self-answering a HITL question | An `## Answer` with no words the human said | Delete it. Reopen the question. See the HITL rule. |
| Recording the decision but not the rejections | "We chose event-driven." | Rejections are half the record — and mandatory when `Locked: yes`. Ask what else was on the table before you close. |
| Grilling a fact | "How long does the retention sweep take?" | If it is measurable, measure it — or make it a `research · AFK` question. Do not make the human guess at their own system. |
@@ -396,7 +377,7 @@ If a decision survives all six with no answer, it is not ready to leave the map.
When the branch is walked out. **Steps 1-3 are ONE turn, not three** — recap, confirmation request, and lock offer go out together, because a lock offer sent after a separate confirmation costs a round trip to ask a yes/no the human could have answered alongside the recap.
1. Recap the decisions in order, in the human's own terms, using glossary vocabulary. Include anything a structured-tool reply left implicit, so the confirmation covers the reasoning and not just the picks.
2. Ask for the confirmation. Do not skip this — the recap is where the human catches the one thing you misheard, and where a clicked option becomes words they said.
3. Apply the Lock test in the same message. Offer, do not impose.
2. Ask for confirmation through the structured question tool (`Confirm` / `Correct via Other`). Do not skip this — the recap is where the human catches the one thing you misheard, and where a clicked option becomes words they said.
3. Apply the Lock test as another question in the same tool call. Offer, do not impose.
4. Write `## Answer` per Work Step 7: the decision, what was rejected and why, consequences, and a one-line `**Gist:**`. Evidence, links, and transcript fragments go under `## Evidence`.
5. Anything the grill surfaced that belongs to a different question goes to the map — a fresh question if you can phrase it sharply, `## Not yet specified` if you cannot, `## Out of scope` if it sits past the destination.
@@ -10,6 +10,7 @@ specs/<idea>/
├── pathfinder/
│ ├── map.md <- the index
│ ├── questions/NN-<slug>.md <- 00-codebase-context.md always exists
│ ├── briefs/brief-<YYYYMMDD>.md <- plain-English reports, written by BRIEF mode only
│ └── sketch-NN/ <- optional runnable sketch, throwaway
└── PLAN-DRAFT-<YYYYMMDD>.md <- written ONLY when the map clears
```
@@ -20,22 +21,25 @@ specs/<idea>/
`NN` is zero-padded from `00`, assigned in dependency order (blockers lower), **never reused or renumbered** — links and `Blocked by:` would rot silently. Next = max + 1. `00` is always `00-codebase-context.md`, never anything else. Gaps in the sequence are normal and harmless.
## The five schema lines
## The six schema lines
Each question file carries five contiguous `Key: value` lines after its H1 — NOT YAML frontmatter, no `---` delimiters:
Each question file carries six contiguous `Key: value` lines after its H1 — NOT YAML frontmatter, no `---` delimiters:
| Line | Values |
|---|---|
| `Type:` | `grill · HITL` \| `research · AFK` \| `sketch · HITL` \| `legwork · HITL` \| `legwork · AFK` — one token, so type and mode cannot drift |
| `State:` | `open` \| `claimed` \| `resolved` \| `out-of-scope` |
| `Blocked by:` | `none` \| `02, 04` |
| `Claimed:` | `none` \| `<YYYY-MM-DD HH:mm>` |
| `Claimed:` | `none` \| `<YYYY-MM-DD HH:mm>` — a work-in-progress lock, not a completion record |
| `Resolved:` | `none` \| `<YYYY-MM-DD>` — set in the same write as `State: resolved` (Work Step 7). The date the decision landed; briefs filter on it |
| `Locked:` | `yes` only when hard to reverse AND surprising without context AND a real trade-off |
**Backfill (older maps):** a file with a filled `## Answer` but `Resolved: none` (or no `Resolved:` line at all) gets the line backfilled at reconcile — from the `Claimed:` date, or today if `Claimed: none`. Say so once in the session report.
**Type meanings.** **grill** (default) — a decision only the human can make. **research** — a fact outside this directory gates it. **sketch** — the human needs something concrete to react to. **legwork** — manual work that must happen before a decision is possible.
## Markers and blocking
**Map markers**, rebuilt from the files every session: `[ ]` open — **these rows ARE the frontier** · `[/]` claimed · `[x]` resolved · `[!]` open but blocked · `[-]` out of scope.
**Map markers**, rebuilt from the files every session: `[ ]` open — **these rows ARE the frontier** · `[/]` claimed · `[x]` resolved · `[!]` open but blocked · `[-]` out of scope. Resolved rows carry the gist plus the `Resolved:` date in italics: `— <gist> *(YYYY-MM-DD)*`.
**Unblocked** ⟺ every `NN` in `Blocked by:` is `resolved`. **Stranded:** a blocker gone `out-of-scope` never resolves — the question is not merely blocked. Re-frame its `## Question` to drop the dependency, or rule it out too. Never leave it sitting.
@@ -14,7 +14,7 @@ Every question resolves into the SAME shape — a filled `## Answer` plus whatev
| `legwork · HITL` | Human does, agent waits | No | The human confirmed it is done |
| `grill · HITL` | Human decides, agent interrogates | No — but probes batch, up to 3 per turn | The human said it in their own words |
**One question _file_ per session** holds for every row except `research`. HITL rows are never self-answered — an agent that writes its own `## Answer` on a `grill` has broken the skill.
**One question _file_ at a time** holds for every row except `research` — several may resolve in one session, but strictly in sequence, per the Cadence below. HITL rows are never self-answered — an agent that writes its own `## Answer` on a `grill` has broken the skill.
Every file you create along the way — question files, sketch READMEs — opens with the banner:
@@ -22,6 +22,34 @@ Every file you create along the way — question files, sketch READMEs — opens
---
## Cadence: decide → menu → checkpoint
The Work loop no longer ends after one decision. It ends when the human stops it, or when the checkpoint recommends stopping — whichever comes first. This holds for a solo developer and for a Product + Engineering room alike; a meeting is just a session with more people answering, and needs no special invocation.
```
claim ONE → resolve → recap → confirm → record → mark map [x]
→ MENU (trail.md Form C): takeable frontier + resume command, human picks or stops
→ claim the next … repeat …
```
**The menu turn.** After every recorded decision, use the structured question tool per trail.md §Form C: offer up to three takeable questions (from the map's checklist rows — name + gist, no file re-reads) plus `Start fresh`; `Other` covers another frontier name. Flag anything just unblocked, mark exactly one description `RECOMMENDED`, and print the resume command under `OR START FRESH` before the tool. Lowest `NN` stays the *recommendation* default, never the selection — the human picks.
**The checkpoint is the menu with the recommendation flipped.** The old one-per-session rule had two jobs: crash-safety and context hygiene — a fresh window per decision keeps the model sharp. Sequential claims preserve the first. The checkpoint preserves the second: after **~3 questions resolved this session** (soft cap), or earlier after a heavy, contested, or `Locked: yes` decision that would benefit from settling overnight, mark the tool's `Start fresh` option RECOMMENDED and say why in the question text — "to keep me sharp." The human can override in either direction; a recommendation is something to push against, not a gate.
The restart costs one paste and loses nothing: every claim, answer, and map update hits disk before anything else happens, and the next session assumes no memory anyway. The fresh session reconciles, renders the trail, and presents the menu again.
**In-loop hygiene** — what keeps each cycle lean between checkpoints:
- Read only what the cycle needs: the claimed question file plus resolved neighbors' *gists* (Work Step 5). Never re-read the whole `questions/` directory between cycles — reconcile ran once at session start, and this session is the only writer.
- The menu renders from the map's checklist rows, never from re-reading question files.
- Strictly one claim open at any moment. Claim → record → release, then the menu. Never two.
**Group sessions.** When Product and Engineering (or any room) work the map together, the grilling playbook's group-session rules apply: probes address the room, the recap captures the decision in the room's words, and a contested pick is never recorded as decided — both positions go under `## Evidence`, the question stays `open`, and the menu moves on (or offer to convert it to `sketch`; reacting to something concrete resolves more standoffs than argument). At Session End, offer `write a brief for today` — the brief doubles as the meeting minutes.
**Stopping is always legitimate.** Ending after one decision is fine. The skill no longer forces deliberation time between decisions; it *advises* it, via the checkpoint, where a decision was heavy enough to deserve settling overnight.
---
## `research · AFK`
The only type an agent resolves alone, and the only type that may run several at once. Charting fires them in a batch at Chart Step 8; MODE B fires any that appear later the same way.
@@ -77,6 +105,7 @@ Type: research · AFK
State: resolved
Blocked by: none
Claimed: 2026-08-03 14:02
Resolved: 2026-08-03
Locked: no
## Question
@@ -167,9 +196,9 @@ Rules for a paper sketch: use REAL-looking content, never placeholders. Real cus
Present it, then ask the pointed questions the sketch actually opens — up to three, batched, in the same turn as the artifact. A sketch is the one place where several probes come free: the human has the whole picture in front of them, so a second and third question cost them almost nothing, and a state table with three questionable rows should not take three sessions.
Pointed is the discipline that survives batching. Never "thoughts?" — every probe names its row or element: "row 5 says a flagged message still archives when retention expires. Right, or does the hold pin it in place?" Sketches always trip the detail test's second row — the artifact has to sit inline, and a picker cannot carry it — so this is a numbered Q block below the sketch, never a structured tool call. This is the one place the tool-first rule is settled in advance; do not re-litigate it per sketch.
Pointed is the discipline that survives batching. Never "thoughts?" — every probe names its row or element: "row 5 says a flagged message still archives when retention expires. Right, or does the hold pin it in place?" Show the artifact inline, then immediately invoke the structured question tool for up to three pointed reaction probes. The artifact stays in prose; every answer control stays in the UI, with `Other` available for hybrids and corrections.
Follow the Q-block formatting rules in `grilling.md` for the probes below the artifact — blank line between every element, options as a bullet list, `---` between probes. A sketch batch is the easiest one to render as a wall of text, because the artifact above it already ate the human's attention.
Follow the structured-tool rules in `grilling.md`: short distinct headers, the pointed question plus why-it-matters in the question field, genuine alternatives with trade-offs in descriptions, and one recommendation per probe.
Putting up a sketch is a **Form B turn** in `trail.md`: close it with `WAITING ON YOU` naming the probes, never a resume command. The human is meant to react to the artifact in this conversation, and a footer telling them to start a new one throws the sketch away.
@@ -339,7 +368,7 @@ Numbered, specific, and verifiable — every line names the exact place to click
Tell me when 1-5 are done, plus the two values from steps 4 and 5.
```
Then stop and wait. Do not guess the answers, do not proceed to the next question, do not mark it resolved on the assumption it went fine.
Immediately after the checklist, invoke the structured question tool: `Done` · `Blocked` · `Need help` · `Defer`; the question text names every value the human must include, and `Other` carries those values/details. Then stop and wait. Do not guess, proceed, or mark it resolved on the assumption it went fine.
Handing over a checklist is a **Form B turn** in `trail.md` — close with `WAITING ON YOU` naming the checklist and the values you asked for, and no resume command. The human may be gone for hours, but the session is still theirs to come back to; only park it as a session end (Form A) once you are actually stopping.
@@ -382,12 +411,12 @@ Rule the question `out-of-scope`, mark the map row `[-]`, add one line to `## Ou
## `grill · HITL`
The default type: a decision only the human can make. Route to **the grilling playbook** — it owns the interrogation technique, the batching rules (up to three independent probes per turn), the detail test that decides whether the batch goes through the structured question tool (the default) or numbered Q blocks (the fallback), and the recommend-then-ask pattern.
The default type: a decision only the human can make. Route to **the grilling playbook** — it owns the interrogation technique, structured-question-tool-first delivery, batching rules (up to three independent probes per turn), prose fallback when the tool is unavailable, and the recommend-then-ask pattern.
Three things this playbook adds on top:
- **Zoom before you grill.** Work Step 5 already had you read the claimed question plus anything it references. Bring the resolved neighbors' gists into the first message so the human is not re-litigating settled ground.
- **Batch probes, not question files.** One question file per session is unchanged. A batch of three probes resolves ONE `questions/NN-*.md`; it is not licence to close three of them.
- **Batch probes, not question files.** One question file at a time is unchanged. A batch of three probes resolves ONE `questions/NN-*.md`; the next file starts only after this one's menu turn (§Cadence).
- **The human's own words.** A `grill` resolves only through live exchange. Never write the `## Answer` from what you inferred they would probably say — and a probe they skipped twice is unanswered, not decided.
A good grill `## Answer` contains four things:
@@ -401,7 +430,7 @@ A good grill `## Answer` contains four things:
## Writing the `## Answer`
Same anatomy for every type. Append it at Work Step 7; never edit `## Question` to match the answer.
Same anatomy for every type. Append it at Work Step 7; never edit `## Question` to match the answer. In the same write, set `State: resolved` **and** `Resolved:` to today's date (`YYYY-MM-DD`, from the shell, never guessed) — the date is what lets a brief report "decided on <day>", so a resolution without it is incomplete.
| Part | Required | Content |
|---|---|---|
@@ -456,10 +485,10 @@ The gist is what gets copied into the map row. It is not a summary of the answer
- Carries the number or name that matters, if there is one.
- Never the full answer. If it needs a semicolon and a subordinate clause, cut it.
The map row it produces:
The map row it produces — gist, then the `Resolved:` date in italics:
```markdown
- [x] [Export format](./questions/03-export-format.md) — one `.eml` per message in 2 GB ZIP parts, manifest.csv carries SHA-256
- [x] [Export format](./questions/03-export-format.md) — one `.eml` per message in 2 GB ZIP parts, manifest.csv carries SHA-256 *(2026-08-03)*
```
---
@@ -14,8 +14,9 @@ It is **presentation only**. Rebuild it fresh from `map.md` each response; never
| Situation | Footer? |
|---|---|
| `map.md` exists and the turn **ends the session** — Session End, a cleared map, a fully blocked frontier | **Yes**, both parts: the trail, then the resume command |
| `map.md` exists and the turn **asks the human something** — a probe batch, a sketch put up for reaction, a `legwork · HITL` checklist | **Yes**, but with the waiting form of Part 2. Never a resume command — see below |
| `map.md` exists and the turn **ends the session** — Session End, a cleared map, a fully blocked frontier | **Yes**, both parts: the trail, then the resume command (Form A) |
| `map.md` exists and the turn **asks the human something** — a probe batch, a sketch put up for reaction, a `legwork · HITL` checklist | **Yes**, but with the waiting form of Part 2 (Form B). Never a resume command — see below |
| `map.md` exists and the turn **offers the menu after a recorded decision** — the continue-or-stop fork of the Work cadence | **Yes**, the fork form of Part 2 (Form C): the takeable questions AND the resume command as the stop branch |
| Intent Gate (Step 0), the no-fog off-ramp, or any route-and-stop before Step 5 | **No** — no map on disk yet, and no path to resume. There is nothing to draw. |
One idea per session, so there is only ever one trail. Draw the trail for the active idea and no other.
@@ -70,7 +71,7 @@ How each line is built, top to bottom:
### Part 2 — the next line
Part 2 answers exactly one question for the human: **is this turn over, or is it my move?** It has two forms, and the **turn type** picks between them — not the map's status.
Part 2 answers exactly one question for the human: **is this turn over, or is it my move?** It has three forms, and the **turn type** picks between them — not the map's status.
#### Form A — the turn ends the session
@@ -104,6 +105,28 @@ Name every outstanding item at its stable number so a partial reply is cheap to
One exception: `grilling.md`'s unreachable-human procedure. Parking a mid-grill question and stopping IS a session end — use Form A, and say in the body that the question is parked mid-grill with its batch outstanding.
#### Form C — the menu after a recorded decision
Used ONLY on the Work cadence's fork-menu turn (resolve.md §Cadence), immediately after an `## Answer` landed and the map row flipped `[x]`. It is the one legitimate hybrid: an *explicit* continue-or-stop fork where the resume command IS the stop branch, not a farewell.
First print the stop branch, clearly labeled:
```
OR START FRESH · new conversation, paste:
`/plan2code-0-pathfinder specs/audit-log-export/pathfinder`
```
Then invoke the structured question tool (header `Next step`) asking: "Continue here, or start fresh? Everything is saved." Options: up to three takeable question names, then `Start fresh`. Put each question's gist / newly-unblocked note in its description. The automatic `Other` path lets the human name another frontier question not shown. Mark one option's description `RECOMMENDED` — early in the session that is a question; at the checkpoint it is `Start fresh`.
Rules for Form C:
- **The command label is mandatory and exact:** `OR START FRESH · new conversation, paste:`. It makes the command the stop branch, not a farewell. Never render a bare command on a menu turn.
- **The choice itself always uses the structured tool.** Never print `NEXT UP` as a prose menu when the tool exists.
- Options come from the map's checklist rows (names + gists), takeable questions only. Flag anything the decision just recorded unblocked. The fourth slot is `Start fresh`; `Other` covers a frontier question omitted from the top three.
- **The recommendation carries the checkpoint** (resolve.md §Cadence): early in a session recommend a question; after ~3 resolved this session — or after a heavy, contested, or `Locked: yes` decision — recommend `Start fresh`, with the reason said in the question text ("to keep me sharp").
- **Form C never replaces Form B.** A turn that asks probes, shows a sketch, or hands over a checklist is Form B, no command. Form C fires only between decisions, when nothing is claimed.
- If the human walks away mid-menu, nothing is stranded: no claim is open, and the command to come back is already on screen.
---
## State-by-state examples
@@ -165,7 +188,7 @@ At `Cleared` the named legend is optional — the destination is reached and the
## Discipline
- **Never print a resume command on a turn that asks a question.** The footer must not tell the human to leave a conversation you are still waiting in. Before you write Part 2, ask whether the response above it ends with something for them to answer; if it does, Form B, no exceptions but the parked-grill one.
- **Never print a bare resume command on a turn that asks a question.** The footer must not tell the human to leave a conversation you are still waiting in. Before you write Part 2, ask whether the response above it ends with something for them to answer: mid-question (probes, sketch, checklist) → Form B, no command, no exceptions but the parked-grill one; between decisions at the fork-menu → Form C, where the command appears ONLY under its `OR START FRESH` label as the explicit stop branch.
- **Alignment is not the point.** Glyphs sit in `NN` order and the legend names them in the same order; do not burn effort column-aligning numbers under waypoints across variable-width glyphs. Legibility over pixels.
- **Rebuild, never cache.** The markers come from the current `map.md`, which Work Step 2 has already reconciled against the question files this session. A footer that disagrees with the checklist above it means you drew from memory.
- **One trail.** Never render two ideas' trails, and never invent a stop the map does not list.
@@ -0,0 +1,102 @@
# Brief Playbook
> Loaded when the user's argument asks for a brief. Produces one plain-English report file for a date range — the artifact a PM pastes into Slack or reads aloud in a meeting. The only mutation BRIEF mode ever performs is the Work Step 2 reconcile; it never claims, resolves, or answers a question.
> **Backend note.** The report is IDENTICAL either way — same sections, same plain-English rules — and the brief file always lands on **local disk** under `specs/<idea>/pathfinder/briefs/`, even on `**Backend:** github`. What differs is where the inputs come from: on `github` the range filter reads each question issue's close date instead of a `Resolved:` line, and the open / blocked / out-of-scope sections come from the frontier query rather than the checklist — see `github-issues.md`.
## When it fires
The argument (or message) asks for a `brief`, `summary`, `recap`, or `minutes` for an idea, with an optional range:
```
/plan2code-0-pathfinder write a brief for today for specs/<idea>/pathfinder
/plan2code-0-pathfinder brief since 2026-08-15 for specs/<idea>/pathfinder
/plan2code-0-pathfinder full brief for specs/<idea>/pathfinder
```
Range grammar is deliberately loose: `today` (the default when unstated) · `this week` · `since <date>` · an explicit `<date>..<date>` · `full` (everything since the map was created). Get today's date from the shell — never guess it.
No `map.md` for the idea? There is nothing to brief — say so and route to charting. `**Status:** Cleared`? A brief is still legitimate: cover the full history and point at the PLAN-DRAFT in `## Next step`.
## Procedure
1. **Resolve the idea** exactly as Auto-Discovery does (shell only — `specs/` is gitignored, Glob silently fails).
2. **Reconcile first, in full** (Work Step 2): files win over markers, stale claims reset to `open`, absent `Resolved:` dates backfilled from `Claimed:`. Save the repaired map. A brief must never disagree with the map it summarizes — this is why BRIEF mode reconciles rather than reporting drift.
3. **Filter**: resolved questions whose `Resolved:` date falls in the range. Out-of-scope rulings are NOT date-filtered — they are standing scope boundaries and appear in every brief.
4. **Write** `specs/<idea>/pathfinder/briefs/brief-<YYYYMMDD>.md` (create `briefs/` if absent). The filename carries today's date regardless of range — the `**Covers:**` line disambiguates. Same-day re-runs overwrite: a brief is a report, not a record; the question files remain the record.
5. **Report** in chat: the file path, the range, one line on any reconcile repairs. Then the Trail Footer, Form A (the session is over; the command routes by map status as usual).
## The template
Substitute real content; keep the section order. `<in range>` reads naturally per range: "Decided today", "Decided this week", "Decided so far" (full).
```markdown
# Audit log export - decisions brief
**Covers:** 2026-09-02 · **Map:** 6 of 9 decisions made
## Where this is headed
<The destination, verbatim from the map.>
## Decided today
- **Export format** - CSV with a UTF-8 BOM plus a SHA-256 manifest file.
Rejected: JSONL (recipients open these in Excel); XLSX (harder to verify byte-for-byte).
*Recorded as hard to reverse.*
- **Export authorization** - new tenant-scoped compliance role; self-events included but flagged.
Rejected: reusing the admin role (no tenant scoping today).
## Ruled out
- **SIEM push connector** - continuous streaming is a separate effort with its own owner.
## Open - ready to decide next
- **Delivery channel** - can now be decided; the row-count ceiling it was waiting on landed today.
- **Testing posture** - needs Product and Engineering together.
## Open - waiting on something first
- **Redaction rules** - waiting on Legal's answer about exporting raw payloads.
## Still taking shape
- How far back an export may reach - depends on a retention answer nobody has yet.
## How solid is this?
Solid overall, but risk handling is borderline - one limit has no decided behavior past it yet.
## Next step
Run: `/plan2code-0-pathfinder specs/audit-log-export/pathfinder`
---
*Full reasoning behind every decision: `specs/audit-log-export/pathfinder/questions/`*
```
**How each section is built:**
| Section | Source | Rendering rule |
|---|---|---|
| Heading + `**Covers:**` | Idea name in words; the range; `<resolved>/<total>` using the trail's counting rule (out-of-scope rows excluded from the total) | |
| Where this is headed | `## Destination`, verbatim | Never paraphrase it |
| Decided `<in range>` | Resolved files with `Resolved:` in range | Question name bold, gist as the first line, rejected alternatives compressed to ONE line each with the why in parentheses. `Locked: yes` renders as *Recorded as hard to reverse.* — never the word "locked" |
| Ruled out | `## Out of scope`, all of it | One line each: name + why |
| Open - ready to decide next | The frontier (open, unclaimed, unblocked) | Flag anything a resolution in range just unblocked: "can now be decided; X landed <day>" |
| Open - waiting on something first | `[!]` blocked rows | Name the blocker in plain words ("waiting on the export format decision"), never `Blocked by: 02` |
| Still taking shape | `## Not yet specified` | Lightly rephrase each bullet into one plain sentence |
| How solid is this? | The map's `**Confidence:**` line | ONLY via trail.md's plain-English mapping (solid / solid-but-borderline / not yet). Omit the section if the map has no confidence line |
| Next step | Map status | `Working`/`Charting` → the pathed resume command; `Cleared` → point at the PLAN-DRAFT and `/plan2code-1-plan` |
Nothing decided in the range? Keep the file honest: "No decisions were recorded in this period." under Decided, and render the open sections as usual — a meeting that only surfaced questions still gets minutes.
## Rules
- **Zero pathfinder machinery in the file.** No `NN` numbers, no markers, no `Type:`/`State:` tokens, no fog/frontier/grill vocabulary, no `Locked:`. Questions are referred to by name only, no links. The audience may never open a terminal.
- **Scraper safety, same as the PLAN-DRAFT:** no `%`, no raw `NN/25` scores, and no bare `Requirements` / `Feasibility` / `Integration` / `Risk` followed by a number anywhere in the file. The plain-English confidence line is the only rendering permitted.
- **Standing `specs/` rules apply:** no loop tokens, no `- [ ]` checkboxes, no `METRICS_JSON`.
- **Rejections are one line each.** The brief summarizes; the question file argues. The closing pointer line covers readers who want the full reasoning.
- **BRIEF mode does not count as question work.** One-question-per-session accounting is untouched; no claim is ever taken.
- **Do not edit an old brief to "update" it.** Yesterday's brief reflects yesterday's map — write today's instead. Same-day overwrite only.
+32 -13
View File
@@ -14,7 +14,7 @@ Pathfinder builds an apparatus — a directory, a map, a file per decision. That
You already have the idea name from Auto-Discovery. Do NOT create the directory yet. Say, in substance:
> "This is Pathfinder. Nothing exists for `<idea>` yet. Pathfinder charts a map of the open decisions when an idea is big or unclear to plan — but that is overhead if this is small or already clear. Three ways to go:
> - **Chart it** — I map the open decisions, one per session, then hand a draft to `/plan2code-1-plan`.
> - **Chart it** — I map the open decisions, we clear them one at a time, then hand a draft to `/plan2code-1-plan`.
> - **Straight to `/plan2code-1-plan`** — the way looks clear enough to plan now.
> - **`/plan2code-quick-task`** — small enough to just do.
>
@@ -23,7 +23,7 @@ You already have the idea name from Auto-Discovery. Do NOT create the directory
Rules for the gate:
- **It is HITL.** You recommend; the human chooses. Never self-select "chart" and start creating files because it is the default path — that is exactly the failure this gate exists to stop.
- **Read the request honestly.** A one-line bugfix, or a change with no open decisions, is not a charting job — recommend an off-ramp and mean it. Reserve "chart" for real fog: several unsettled decisions, unclear scope, or competing designs.
- **Read the request honestly.** A one-line bugfix, or a change with no open decisions, is not a charting job — recommend an off-ramp and mean it. Reserve "chart" for real fog: several unsettled decisions, unclear scope, or competing designs. A joint Product + Engineering kickoff on a fresh idea is the canonical "chart it" case — a new feature explored by two teams is fog almost by definition.
- **No disk writes.** Naming the idea and talking is free. Creating `specs/<idea>/pathfinder/` is not — it waits for an explicit "chart."
- **On an off-ramp, route and STOP.** Point at `/plan2code-1-plan` or `/plan2code-quick-task`, create nothing, end the session. If `AGENTS.md` is absent, mention `/plan2code-init` first, as with any handoff.
@@ -52,7 +52,7 @@ Two round trips, not six. Three probes each — exactly the cap, so neither batc
Batch 2 bends the independence test on purpose. The arrival signal (5) can shift under the smallest arrival (4), so strictly it should be held back — but holding it costs a third round trip to catch a conflict that is rare and cheap to spot. The trade is to send them together and reconcile at the recap: if the smallest arrival comes back materially smaller than the artifact you were told about, re-check the arrival signal against it before writing the destination. A knowing trade here, not a licence to batch dependent probes elsewhere.
**Both batches go out as numbered Q blocks — this grill is the other standing exception to the tool-first rule.** Probes 2, 3, 4, and 5 need the human's own phrasing — the destination is written into `map.md` verbatim as agreed, so a clicked option label is not something you can write down. That is the detail test's first row, four times over. Probe 6 names categories but the category is the worthless half of the answer: "deadline" changes nothing, "Q3 close, and the SEC audit lands Nov 1" changes the delivery question, the testing posture, and the out-of-scope line at once. Only probe 1 would survive a picker on its own, and it rides in a Q block anyway, because one tripping probe downgrades the whole batch. Do not reach for the structured question tool here.
**Both batches go through the structured question tool.** Give each probe genuine candidate options with trade-offs and a recommendation; the built-in `Other` path is where the human composes the actor, boundary, arrival signal, or forcing-function detail in their own words. A clicked option is not written verbatim as the destination — the recap-confirmation tool call turns all six answers into the agreed one-or-two-line destination before disk write.
**Probe 1 — the artifact**
@@ -155,6 +155,7 @@ Type: legwork · AFK
State: resolved
Blocked by: none
Claimed: 2026-08-03 09:12
Resolved: 2026-08-03
Locked: no
## Question
@@ -272,16 +273,18 @@ Say it out loud so the human tracks the move, then jump:
Two mechanics keep the fan-out honest:
1. **Round-robin the areas.** Before you start, list the axes you intend to cross: data, surface, permissions, volume, delivery, failure, operations, testing. Take one probe per axis before any second probe on any axis.
1. **Round-robin the areas.** Before you start, list the axes you intend to cross — engineering axes (data, surface, permissions, volume, delivery, failure, operations, testing) AND product axes (user value, success measurement, target user, rollout, analytics, support & docs, legal/compliance). Not every axis applies to every destination: name the ones that do before the first probe, say which you are skipping and why, then take one probe per axis before any second probe on any axis.
2. **Ask for the axis you have not touched.** Near the end: "What have I not asked about that would embarrass us to discover in week three?"
**Breadth-first is the ideal batch.** One probe per axis means the probes are independent by construction — that is what breadth-first *means* — so this grill should run as batches of three, not as a stream of singles. Seven axes is three turns. If you catch yourself wanting to batch two probes on the same axis, that is depth wearing a batch's clothes; pull back.
**Breadth-first is the ideal batch.** One probe per axis means the probes are independent by construction — that is what breadth-first *means* — so this grill should run as batches of three, not as a stream of singles. If you catch yourself wanting to batch two probes on the same axis, that is depth wearing a batch's clothes; pull back.
**With Product in the room, the product axes are not optional.** A joint Product + Engineering session that only fans out across engineering axes produces a map Product cannot answer for — and vice versa. Alternate: an engineering batch, then a product batch, so neither team spectates for three turns straight.
### Sample breadth probes
Each opens a different axis. Send 1-3 as one batch and 4-6 as the next, then probe 7 alongside the "what have I not asked about" closer above; note each answer and move.
Each opens a different axis. Batch three at a time in list order (skipping axes you ruled inapplicable), with probe 7 riding alongside the "what have I not asked about" closer above; note each answer and move.
**They go out as numbered Q blocks — this grill is one of the two standing exceptions to the tool-first rule.** Several of the probes do name alternatives, so they would pass the detail test on its own terms, and that is exactly the trap: the output of this grill is not a decision, it is a *sort* into sharp question or fog, and sorting takes the elaboration around the answer. A clicked label leaves you nothing to sort with. The structured question tool earns its keep in MODE B, where a claimed question already has named alternatives and the sorting is long done.
**Every batch goes through the structured question tool.** The output is a *sort* into sharp question or fog, so the option descriptions carry the framing and the built-in `Other` path captures elaboration the named choices miss. Never ask these probes as a prose list when the tool exists.
1. **Data** — "What is the smallest and largest thing an operator could reasonably ask for in one export? Give me both ends."
2. **Surface** — "Where does this start: a button in the admin UI, a scheduled thing, an API call someone scripts?"
@@ -291,6 +294,16 @@ Each opens a different axis. Send 1-3 as one batch and 4-6 as the next, then pro
6. **Operations** — "Six months from now someone asks who exported what. Does this feature audit itself?"
7. **Testing** — "What would you need to see pass before you would let this near a customer's compliance data?" *(This one always runs — see the mandatory testing-posture question below.)*
The product axes, same style — one sample probe each:
8. **User value** — "A compliance officer gets this feature Monday morning. What stops being painful for them that day?"
9. **Success measurement** — "Three months after ship, what number or behavior tells you this was worth building?"
10. **Target user** — "Who is this for first — every tenant, one segment, one named customer who asked?"
11. **Rollout** — "Does this land for everyone at once, behind a flag, or piloted with one tenant first?"
12. **Analytics** — "What do you want to know about how people actually use it — and is any of that instrumented today?"
13. **Support & docs** — "A support ticket about this lands in week one. What does the agent need to see to answer it without escalating?"
14. **Legal / compliance** — "Does anything here touch data retention, privacy, or a regulator's definition of a record?"
Record each answer as one line in your working notes with an area label. At the end of the grill you will have two piles: lines you can turn into a sharp question, and lines you cannot. The second pile is the fog.
---
@@ -390,6 +403,8 @@ Say once, at Step 5: *"This map lives in gitignored `specs/` — local to you, n
# Map: audit-log-export
*Decisions live in `questions/` — one file each. This file is just the index.*
**Status:** Working
**Updated:** 2026-08-03
**Confidence:** Requirements-clarity 18/25 · Feasibility-technical 14/25 · Integration-points 16/25 · Risk-assessment 14/25
@@ -417,8 +432,8 @@ plan, not at shipped code. Continuous streaming to external systems is not on th
obeyed while resolving it. Nothing here is re-asked. -->
- `AGENTS.md` exists and governs. Its conventions are not re-litigated by any question here.
- One question _file_ per session. `research` questions may run as parallel subagents.
- Grill probes are batched per the grilling playbook — at most three per turn, through the structured question tool unless the detail test forces prose Q blocks.
- One question _file_ at a time; the fork-menu between decisions; a fresh session recommended after ~3. `research` questions may run as parallel subagents.
- Every user-facing question uses the structured question tool when available; probes batch at most three. Prose Q blocks are fallback only when the tool is unavailable.
- Questions are put to the human in plain English. Technical terms only where the term is the decision.
- HITL questions are answered by the human in their own words. Never self-answered.
- No new runtime dependency is assumed without a `research` question backing it.
@@ -442,10 +457,11 @@ plan, not at shipped code. Continuous streaming to external systems is not on th
<!-- Rebuilt from questions/ every session — the files are ground truth, this is an index.
[ ] open (the frontier) · [/] claimed · [x] resolved · [!] open but blocked
[-] out of scope. Resolved rows carry the one-line gist from the question's Answer. -->
[-] out of scope. Resolved rows carry the one-line gist from the question's Answer,
then the Resolved: date in italics — briefs filter on these dates. -->
- [x] [Codebase context](./questions/00-codebase-context.md) — Node/Express/Knex/React with a BullMQ-to-S3 export precedent; `audit_events` is 180M rows partitioned monthly, no `actor_id` index, `requireAdmin` has no tenant scoping.
- [x] [Export format](./questions/01-export-format.md) — CSV with a UTF-8 BOM and RFC 4180 quoting, plus a sidecar SHA-256 manifest; JSONL rejected because recipients open these in Excel.
- [x] [Codebase context](./questions/00-codebase-context.md) — Node/Express/Knex/React with a BullMQ-to-S3 export precedent; `audit_events` is 180M rows partitioned monthly, no `actor_id` index, `requireAdmin` has no tenant scoping. *(2026-08-03)*
- [x] [Export format](./questions/01-export-format.md) — CSV with a UTF-8 BOM and RFC 4180 quoting, plus a sidecar SHA-256 manifest; JSONL rejected because recipients open these in Excel. *(2026-08-03)*
- [/] [Row-count ceiling](./questions/02-row-count-ceiling.md)
- [ ] [Export authorization](./questions/03-export-authorization.md)
- [ ] [Testing posture](./questions/04-testing-posture.md)
@@ -489,7 +505,7 @@ plan, not at shipped code. Continuous streaming to external systems is not on th
## The question-file template
Five contiguous `Key: value` lines after the H1. Not YAML. No frontmatter delimiters. No `- [ ]` checkboxes anywhere inside a question file — use plain bullets, including for legwork checklists.
Six contiguous `Key: value` lines after the H1. Not YAML. No frontmatter delimiters. No `- [ ]` checkboxes anywhere inside a question file — use plain bullets, including for legwork checklists.
`## Question` is written at charting. `## Answer` is appended only when the question resolves. `## Evidence` holds sources, links, and artifacts, and a `research` subagent writes into it during Chart Step 8 without deciding anything.
@@ -504,6 +520,7 @@ Type: grill · HITL
State: open
Blocked by: none
Claimed: none
Resolved: none
Locked: yes
## Question
@@ -544,6 +561,7 @@ Type: grill · HITL
State: resolved
Blocked by: none
Claimed: 2026-08-03 10:41
Resolved: 2026-08-03
Locked: yes
## Question
@@ -626,6 +644,7 @@ Type: grill · HITL
State: open
Blocked by: none
Claimed: none
Resolved: none
Locked: no
## Question
@@ -4,7 +4,7 @@
>
> **Local-file maps never load this file.** If `## Ground rules` says `**Backend:** local`, close it and use `questions.md`.
Everything the skill says about *judgement* is unchanged by the backend: the fog-vs-question test, the destination grill, one question per session, HITL is never self-answered, the Clearing Gate rubric. This file changes only *where the bytes go*.
Everything the skill says about *judgement* is unchanged by the backend: the fog-vs-question test, the destination grill, one question at a time, the decide-menu-checkpoint cadence, HITL is never self-answered, the Clearing Gate rubric. This file changes only *where the bytes go*.
---
@@ -83,6 +83,7 @@ This is the whole mapping. Everything below expands a row.
| `Blocked by: 02, 04` | Native issue dependencies (`dependencies/blocked_by`) |
| `Locked: yes` | The `pathfinder:locked` label |
| `Claimed: <timestamp>` | GitHub's own assignment event in the timeline |
| `Resolved: <YYYY-MM-DD>` | The issue's own close timestamp (`closedAt`) — nothing to write, nothing to backfill |
| `## Question Checklist` in `map.md` | **Nothing** — the frontier is a live query, not a written list |
| `## Not yet specified`, `## Out of scope`, `## Ground rules`, `## Destination`, `## Glossary` | The same sections, in the map issue body |
| `sketch-NN/` | Still local disk — see *What stays on local disk* |
@@ -145,7 +146,8 @@ plan, not at shipped code. Continuous streaming to external systems is not on th
- **Backend:** github — this issue is the map; questions are its sub-issues.
- `AGENTS.md` exists and governs. Its conventions are not re-litigated by any question here.
- One question _issue_ per session. `research` questions may run as parallel subagents.
- One question _issue_ at a time; the fork-menu between decisions; a fresh session recommended after ~3. `research` questions may run as parallel subagents.
- Every user-facing question uses the structured question tool when available; probes batch at most three. Prose Q blocks are fallback only when the tool is unavailable.
- HITL questions are answered by the human in their own words. Never self-answered.
- Sketches are throwaway and live on local disk only, under `specs/audit-log-export/pathfinder/sketch-<issue>/`.
@@ -316,12 +318,14 @@ gh issue close <n> --reason completed
# 3. Append the gist to the map's Decisions so far (read body, edit, write back).
gh issue view <map-number> --json body --jq .body > /tmp/map.md
# ...append: - [Export format](<issue-url>) — <gist>
# ...append: - [Export format](<issue-url>) — <gist> *(YYYY-MM-DD)*
gh issue edit <map-number> --body-file /tmp/map.md
```
Then bump `**Updated:**` and re-score `**Confidence:**` in the same map edit.
**The close date IS the `Resolved:` date.** There is no line to set and none to backfill — `closedAt` is written by GitHub the moment step 2 runs, and a brief filters on it. Stamp the same date in italics on the `## Decisions so far` line so the map reads as a dated record on its own.
**Never edit the question body to hold the answer.** The body is the question as asked; the comment is the answer. Editing the body rewrites history and destroys the record of what was actually put to the human — which is half of why the answer is defensible three weeks later.
### Editing the map body safely
@@ -355,6 +359,8 @@ Much shorter here — the tracker holds the state, so there is no checklist to r
Then re-read `## Not yet specified` in full — that part is identical to local mode, and the bullet left behind after its question exists is just as corrosive here.
Local mode's `Resolved:` backfill has no counterpart here: `closedAt` cannot be absent on a closed issue. If a `## Decisions so far` line is missing its date, take the date from `closedAt` during the index-drift repair above.
---
## What stays on local disk
@@ -392,6 +398,22 @@ NEXT STEP · start a new conversation and run:
Form B is unchanged — a turn that asks the human something still says `WAITING ON YOU`, still names the outstanding probes, and still emits no resume command.
Form C — the fork-menu after a recorded decision — is unchanged in shape, with two substitutions: the takeable options come from the frontier query rather than the checklist rows, and the `OR START FRESH` command carries the map issue URL. The `RECOMMENDED` marker and the ~3-decision checkpoint work exactly as `trail.md` describes.
---
## BRIEF mode
The report is identical either way, and the file still lands on **local disk** at `specs/<idea>/pathfinder/briefs/brief-<YYYYMMDD>.md` — a brief is a plain-English artifact for people, not tracker state, and writing it as an issue comment would bury it. Three substitutions against `brief.md`:
| `brief.md` says | Here |
|---|---|
| Filter resolved questions by `Resolved:` in range | Filter the map's sub-issues closed as completed by `closedAt` in range |
| Reconcile backfills absent `Resolved:` dates | Nothing to backfill; run the three reconcile checks above instead |
| Open / blocked / out-of-scope sections read the checklist | They read the frontier query — unassigned-unblocked, `blocked_by > 0`, and `pathfinder:out-of-scope` respectively |
`## Not yet specified`, `## Destination`, and `**Confidence:**` come from the map issue body, same as always. The no-machinery rule tightens rather than relaxes: no `#numbers`, no label names, no `gh` commands in the file. The reader may never have opened the tracker either.
---
## Handoff (The Clearing Gate)
@@ -3,7 +3,9 @@
Grilling is how a `grill · HITL` question resolves, how Chart Step 2 names the destination, and how Chart Step 4 maps the frontier. It is also the fallback for any question whose type gives you no better route. The output of a grill is a decision in the human's own words — never a decision you made on their behalf.
**Probe ≠ question file.** A *probe* is one turn of the interrogation; a *question file* is one `questions/NN-<slug>.md` on the map. Batching applies to probes only. **One question file per session still holds**resolving three question files in one sitting is not what this is.
**Probe ≠ question file.** A *probe* is one turn of the interrogation; a *question file* is one `questions/NN-<slug>.md` on the map. Batching applies to probes only. **One question file at a time still holds**a batch of three probes resolves ONE file; a session moves to the next file only through the fork-menu between decisions (resolve.md §Cadence), never by interleaving two grills.
**Grilling a room.** When several people answer — a Product + Engineering session — the mechanics are unchanged, plus three rules: address probes to the room, not a person, unless one person owns the call; the recap must capture the decision in the room's words, and whose call broke any tie is worth a clause in the `## Answer`; and a contested pick is NOT a decision — when Product and Engineering disagree, record both positions under `## Evidence`, leave the question `open`, and move on (or offer a `sketch` — reacting to something concrete resolves more standoffs than argument). Never average two positions into an answer nobody actually gave.
## The interview protocol
@@ -15,8 +17,8 @@ The old rule here was one probe per turn. It was safe and it was unusably slow:
|---|---|
| Up to 3 probes per turn, never more | Past three the human skims, and a skimmed answer is worse than none. Three is a ceiling, not a quota — send two if only two are independent. |
| Only batch mutually independent probes | The independence test below. A probe whose wording or recommendation shifts based on another probe's answer waits for the next turn. |
| Reach for the structured question tool first | It is the intended channel, not the leftover bin. Shape the batch so it fits — three probes, plain headers, options a description can carry — and fall back to prose only when the detail test genuinely trips. |
| A probe that needs detail goes in prose, never in options | The detail test below. Batching buys round trips; it must never buy them by shrinking a decision to fit a picker. |
| Use the structured question tool for every question when available | The built-in UI is the primary experience: selectable answers, visible skips, and `Other` for composition. Prose provides context, never the answer control. |
| Keep detail in descriptions, context, and `Other` | Batching buys round trips; it must never buy them by shrinking a decision to fit a picker. |
| Wait for the whole batch before sending the next | Their answers reshape what comes next. Pre-writing turn 2 wastes it. |
| Recommend an answer with every probe | A bare question makes the human do all the work. A recommendation gives them something to push against, which is faster and sharper. |
| Write it in plain English; keep the technical word only where that word IS the decision | A probe the human has to decode is a probe they answer approximately. See *Say it in plain English*. |
@@ -66,7 +68,7 @@ Every probe gets read once, by a busy human, in a terminal. Write it the way you
| "the sacrificial boundary" | "name one thing people would assume is included that you are willing to cut" |
| "shall I set `Locked: yes`?" | "worth recording why we picked this, so nobody re-opens it in six months?" |
| "Q3 is blocked by 02" | "the export format question has to land before this one" |
| "this batch trips the detail test" | nothing — that call is yours, not theirs |
| "the UI cannot handle this question" | nothing — put context before the tool and preserve `Other` |
**Refer to questions by name, never by number** — "[Export format](./questions/04-export-format.md)", not "04". The number means something to the file system and to nobody else.
@@ -88,58 +90,37 @@ In doubt, hold it back. A held probe costs one extra round trip. A dependent pro
Independent probes are usually the ones that came from **different areas** — data, interface, security, operations, testing. Dependent probes are usually consecutive steps down one thread.
### Delivering a batch: choosing the channel
### Delivering a batch: structured UI first
Two channels — the environment's structured question tool, or numbered Q blocks in prose. **Choose before you write a word, and choose per batch, not per probe.** One channel per turn: a batch split across a tool popup and a loose prose question loses the prose half every time, because the human answers in the tool and never scrolls back.
**Use the environment's structured question tool for every user-facing question when it is available.** This includes destination probes, frontier probes, claimed-question grills, recap confirmations, lock offers, sketch reactions, intent gates, and fork-menus. The built-in UI is faster to scan, preserves visible skips, and always provides an `Other` path for composed answers. Numbered prose Q blocks exist only as the fallback when the tool is unavailable.
**The tool is where you start.** Assemble the batch for it — three probes, a plain two-or-three-word header each, alternatives a sentence or two of description can carry — and only then run the detail test to see whether anything forces you out. Prose is the exception you fall back to, not the safe default you retreat to. Two things make the tool worth the effort: a skipped probe comes back *visibly* skipped, and a picker is answerable in one pass by a human who has thirty seconds. Neither survives the move to prose.
One question object per probe, up to three per call. Never split a batch between a tool popup and prose — the prose half gets lost when the human answers in the UI.
The two failure directions are opposite and both real. Retreating to prose out of caution costs you the visible skip and the fast reply. Forcing a genuinely gnarly decision into a picker costs you the reasoning, which is worse. The detail test below is where that line sits — run it honestly in both directions.
**Composed answers still use the tool.** Do not invent a false-complete option set merely to make a picker. Offer the genuine candidates you know; the automatic `Other` option is where the human composes a boundary, rationale, hybrid, old-incident detail, or alternative you could not know. When no genuine candidate exists, offer useful control choices such as `Use recommendation` and `Defer for now`; the human writes the real answer through `Other`. A click is still followed by the normal recap-confirmation turn, which captures reasoning in the human's words.
**Whichever channel you pick, the turn closes with the waiting footer.** A turn that sends a batch is a **Form B turn** in `trail.md`: the Trail Footer under it names the outstanding probes after `WAITING ON YOU` and carries **no** resume command. Emitting "start a NEW conversation" above an unanswered batch tells the human to leave the session you are sitting in — they walk, and the batch you built to save round trips costs you the whole decision instead. Same for the recap turn below, which is also waiting on them.
**Artifacts do not force prose questions.** Show the state table, fake request/response, ASCII UI, or worked example in the response, then immediately invoke the structured tool for the pointed reaction probes. The artifact is prose; the questions are UI controls. Never ask "thoughts?" outside the tool.
#### The detail test — the only things that force you out of the tool
**Never reshape the decision to fit the tool.** Descriptions carry trade-offs; `Other` carries composition. Split bundled decisions into separate probes and rename colliding short headers. Do not cut a real alternative or hide complexity. If the UI cannot represent the question faithfully even with descriptions + `Other`, state the full context immediately before the tool and keep the actual answer control in the tool.
Numbered Q blocks are **required, not merely permitted**, if *any* probe in the batch trips *any* row below. One tripping probe downgrades the whole batch.
These four rows are the whole list. Nothing else forces prose — not a long question, not a hard decision, not a `Locked: yes`, not your discomfort with the widget.
| Trip | Looks like | Not this |
|---|---|---|
| The answer must be composed, not picked | "Name one thing a reasonable person would assume is in scope that you are willing to cut." There is no option set, because inventing one puts words in their mouth. | A decision with genuine named alternatives, however weighty. Write the options. |
| The probe needs an artifact inline to be answerable | A state table, a fake request/response pair, an ASCII UI, a worked example with real numbers — effectively every `sketch` probe | A probe that merely *mentions* a file path, a format, or a number. Those go in the question text. |
| An option cannot be conveyed even in its description | Each alternative needs a worked paragraph before it means anything — a migration path, a failure sequence, a schema | An alternative that needs one or two sentences of trade-off. That is what the description field is for. |
| The alternatives themselves are unknown to you | You cannot name the losing options at all, because the frame is theirs — a contract, an old incident, an org politics fact | You can name them but cannot say why each loses. Name them, recommend one, and let the recap turn supply the reasoning. |
Three things that look like trips and are not:
- **One label bundling several decisions** — "authentic counts, one-use per attempt, restored on death" is three answers wearing one coat. The fix is to **split it into separate probes**, not to write prose. Three separated probes is exactly one batch.
- **Two probes colliding on the tool's short header limit** (16 characters in Claude Code) — `Export scope` twice is unanswerable, but the fix is to rename them (`Date range`, `Who can run`) or to hold one for the next turn. Reword before you retreat.
- **A hybrid is possible** — the free-text escape hatch takes "the header from B with the list from C" fine. Trip only when you can already predict the answer *will* be a composition, which is the first row.
**`Locked: yes` on its own does not trip the test.** A lock's `## Answer` owes every alternative and the reason each lost — but if *you* can already name the alternatives, you have written the options, and the recap turn turns the pick into words the human said. A lock trips only on the fourth row, where you cannot name them at all. Treating every lock as an automatic downgrade sends almost every MODE B decision worth grilling to prose, which defeats the point — MODE B is exactly where a claimed question already has named alternatives and the tool earns its keep.
**Nothing tripped? Use the structured tool.** Not "may" — do. It is the intended channel, and it is where the visible-skip guarantee behind the partial-answer discipline below comes from.
**Never reshape a probe to fit the tool.** Reaching for the tool first is not licence to shrink a decision into it. The failure mode is not that the tool rejects a gnarly probe — it is that it *accepts* one. You compress a decision with real texture into three tidy options, the human clicks the least-bad one, and you have recorded a decision with no reasoning behind it. That answer cannot satisfy `## Answer`'s obligation to name what was rejected and why, and nobody finds out until handoff, when the PLAN-DRAFT's Architecture section turns out to have nothing to say. Splitting a bundled probe or renaming a colliding header is reshaping the *batch* and is always right. Cutting a real alternative, or thinning a description until the trade-off disappears, is reshaping the *decision* and is always wrong. When the honest choice is between paragraphs and dishonest options, write the paragraphs.
The turn closes with the waiting footer (Form B in `trail.md`): it names outstanding probes and carries no resume command. The recap confirmation is also asked through the tool and remains Form B.
#### The structured tool
The default channel, and the one you build the batch for. One question object per probe, up to three in a single call:
The primary channel. One question object per probe, up to three in a single call:
- **Header** — the decision in two or three plain words (`Export format`, `Size cap`). Not a type, not a marker, not a number.
- **Question** — the probe, with its why-it-matters. This is prose and it is not rationed; the same sentences you would have written in a Q block go here.
- **Options** — the genuine alternatives, each described by its trade-off, with the recommended one named as such in its description. Two to four; the free-text escape hatch covers the rest. Label plainly, then let the description carry the precise term: `One file per message` labelling the `.eml`-in-a-ZIP option, with `.eml` named in the description.
A short *label* is not a short *decision*. The label is a handle — `Fixed tick count` — and the description carries the trade-off that makes it choosable. A probe only trips the third detail-test row when even that description cannot hold the option. A label bundling several independent answers is not that row — it is a probe that wants splitting.
A short *label* is not a short *decision*. The label is a handle — `Fixed tick count` — and the description carries the trade-off that makes it choosable. A label bundling several independent answers is a probe that wants splitting.
**A click is a decision, not a sentence.** The HITL rule wants an `## Answer` traceable to something the human actually said, and a selected option label is thin evidence on its own. What makes tool-delivered answers legitimate is the recap turn in *Landing the grill* — you play the choices back in prose and they confirm or correct in their own words. Never skip the recap on the grounds that the tool already captured the answer; the tool captured the *pick*, and the recap captures the *agreement*.
**A click is a decision, not a sentence.** The HITL rule wants an `## Answer` traceable to something the human actually said, and a selected option label is thin evidence on its own. What makes tool-delivered answers legitimate is the recap turn in *Landing the grill* — you play the choices back in the tool's question text and they confirm or correct in their own words. Never skip the recap on the grounds that the tool already captured the answer; the tool captured the *pick*, and the recap captures the *agreement*.
**If a reply comes back thinner than the decision** — a bare click on something you now realise carries weight — do not paper over it. Fold the why into the recap turn as one more probe before writing the `## Answer`.
#### Numbered Q blocks
The mandatory channel for anything the detail test catches, and the fallback anywhere the structured tool does not exist. Give each probe the room the tool would have denied it.
Fallback ONLY when the structured question tool does not exist or its call fails. Never choose prose merely because the answer is detailed, composed, architectural, `Locked: yes`, or attached to an artifact — descriptions + `Other` + context immediately before the tool cover those cases.
**Copy this shape exactly.** The blank lines are load-bearing, not decoration:
@@ -188,14 +169,14 @@ A batch is only worth sending if the human can read it. These are mechanical, an
| **The question itself gets its own line, not a run-on with the heading** | `**Q1 — Export format.** When a custodian…` buries the decision inside a paragraph. Name it, break, then ask it. |
| **Never use spaces to convey structure** | Whatever hierarchy you indent by hand disappears on render. Structure comes from blank lines, bullets, and bold — nothing else. |
The same applies to the recap turn in *Landing the grill*: it is prose the human has to check line by line, so give each recapped decision its own bullet.
For the recap in *Landing the grill*, summarize each decision in the structured tool's question text and ask the human to confirm or correct it; use `Other` for corrections.
### When answers come back partial
Assume they will. The human answers two and drops one, and the dropped one is often the hardest and most valuable.
1. **Diff what came back against what you sent.** Skipped, answered with "Other: skip", or silently omitted all count as unanswered.
2. **Lead the next turn with the unanswered probes**, at their original numbers, restated in full. Not "you missed Q3" — the whole probe again, with its recommendation, because they have lost the context by now. Unanswered probes come *before* any new probe, and they count against the cap of three.
2. **Lead the next tool call with the unanswered probes**, using their original headers and full wording. Not "you missed Export scope" — the whole probe again, with its recommendation, because they have lost the context by now. Unanswered probes come *before* any new probe, and they count against the cap of three.
3. **Skipped twice, stop pushing.** Record it under `## Evidence` as an open probe with your recommendation verbatim, then either narrow it into something answerable or spin it out — a fresh question file if you can phrase it sharply, a `## Not yet specified` line if you cannot.
4. **Never promote your own recommendation into `## Answer`.** A probe the human declined twice is unanswered, not decided. Writing it up as decided is self-answering a HITL question, which breaks the skill.
@@ -334,7 +315,7 @@ Offer it, do not impose it: *"This one looks hard to reverse and the reasoning w
Chart Step 6 requires this question. It exists because `/plan2code-1-plan` Phase 1 asks for exactly three things and stalls without them: testing types, whether tests run after each phase, and the coverage target. A map that clears without answering them hands the human a plan session that immediately re-asks.
The first three probes below pass the independence test against each other — none reads differently under another's answer — so **send all three as one batch**. This is the canonical worked example of a full batch, and it is the canonical case for the structured tool: every one of the three has named alternatives you can already write, the answers are fixed literals rather than prose, and nothing in the batch trips the detail test.
The first three probes below pass the independence test against each other — none reads differently under another's answer — so **send all three as one structured-tool batch**. Every probe has named alternatives and fixed literals; `Other` remains available.
| Probe | Recommend by default |
|---|---|
@@ -373,10 +354,10 @@ If a decision survives all six with no answer, it is not ready to leave the map.
| Drip-feeding one probe at a time | Twelve open questions on the map, one probe per response, the human gives up on session four | Batch up to three independent probes. On a charted map the human's round trips are the scarce resource, not your token budget. |
| Losing a probe the human skipped | Sent three, got two back, moved on and never mentioned the third | Diff the batch. Lead the next turn with what came back empty, restated in full. |
| A batch of naked questions | Three one-liners with no recommendations and no why-it-matters | Every probe in a batch carries its own recommendation and its own stake. Otherwise you have offloaded the thinking, not the round trips. |
| Sending a batch as a wall of text | Three probes hard-wrapped across source lines with their options indented, all collapsing into one paragraph on render | Blank line between every element, options as a bullet list, `---` between probes. The three-probe cap exists so the human reads all three; an unreadable batch gets skimmed, and a skimmed answer is worse than none. |
| Flattening a gnarly probe into a picker | An architectural decision reduced to three option labels because the batch was already going through the structured tool | Run the detail test. One tripping probe sends the whole batch to numbered Q blocks. A clicked option records no reasoning, and the `## Answer` needs reasoning. |
| Defaulting to prose when nothing tripped | A clean three-probe batch written as Q blocks "to be safe", or downgraded just because the question will be `Locked: yes` | The detail test is a test, not a preference, and it is four rows long. Nothing tripped means the tool: you gain visibly skipped probes, and the recap turn still captures the reasoning a lock needs. |
| Retreating to prose over a fixable batch | Two probes collided on the 16-character header, or one option label was bundling three answers, so the whole batch went to Q blocks | Neither is a detail-test trip. Rename the headers; split the bundled probe. Reshape the batch, never the decision. |
| Asking in prose when the tool exists | Numbered Q blocks or a loose "which one?" despite AskUserQuestion being available | Put every answer control in the structured UI. Use descriptions for trade-offs and `Other` for composition. Prose may provide context or an artifact immediately before the tool, never the question itself. |
| Flattening a gnarly probe into labels | An architectural decision reduced to three option labels with no useful descriptions | Keep the tool, not the flattening: put the real trade-off in each description, preserve `Other`, and recap the reasoning before recording. |
| Treating an artifact as an excuse for prose | An ASCII UI followed by "thoughts?" | Show the artifact, then invoke the structured tool with pointed reaction probes naming the rows/elements. |
| Retreating to prose over a fixable batch | Two probes collide on the short header, or one label bundles three answers | Rename the headers; split the bundled probe. Reshape the batch, never the decision. |
| Sending four probes because the tool accepts four | A fourth probe added to a clean batch of three because there was room in the call | The cap is three regardless of what the environment allows. The ceiling is the human's attention, not the tool's schema. |
| Grilling in Pathfinder's own vocabulary | "The frontier has one takeable `grill · HITL` — shall we graduate 02 out of the fog and lock it?" | Plain English. Markers, types, `NN` numbers, and fog are your bookkeeping; the human is deciding about their product. |
| Plain-washing the load-bearing term | "Do you want the friendly file or the compact one?" where the real choice is `.eml`-in-a-ZIP versus NDJSON | Plain wording, precise nouns. Name the formats and gloss them; a decision made on a euphemism cannot be written into `## Answer`. |
@@ -384,7 +365,7 @@ If a decision survives all six with no answer, it is not ready to leave the map.
| Accepting a vague answer and moving on | "Handle it sensibly" → recorded as the decision | Push once more, concretely: "Sensibly meaning we drop the attachment, or fail the whole job?" A vague answer is not an answer. |
| Leading the human to your preferred answer | "You'd want Postgres here, right?" | Recommend openly, then present the real alternatives with their real merits. A recommendation invites a fight; a leading question suppresses one. |
| Grilling past the decision into implementation | "Should the retry helper take a callback or return a promise?" | That is the plan's job, or the implementer's. Stop at the decision. The pull to keep going is the edge of the map. |
| Drifting off the claimed question | Claimed `[Export format](./questions/04-export-format.md)`, forty minutes later deep in auth | Name the drift out loud, capture the new thread as a fresh question or as a line in `## Not yet specified`, and return. One question _file_ per session. |
| Drifting off the claimed question | Claimed `[Export format](./questions/04-export-format.md)`, forty minutes later deep in auth | Name the drift out loud, capture the new thread as a fresh question or as a line in `## Not yet specified`, and return. One question _file_ at a time — switching happens at the menu, not mid-grill. |
| Self-answering a HITL question | An `## Answer` with no words the human said | Delete it. Reopen the question. See the HITL rule. |
| Recording the decision but not the rejections | "We chose event-driven." | Rejections are half the record — and mandatory when `Locked: yes`. Ask what else was on the table before you close. |
| Grilling a fact | "How long does the retention sweep take?" | If it is measurable, measure it — or make it a `research · AFK` question. Do not make the human guess at their own system. |
@@ -396,7 +377,7 @@ If a decision survives all six with no answer, it is not ready to leave the map.
When the branch is walked out. **Steps 1-3 are ONE turn, not three** — recap, confirmation request, and lock offer go out together, because a lock offer sent after a separate confirmation costs a round trip to ask a yes/no the human could have answered alongside the recap.
1. Recap the decisions in order, in the human's own terms, using glossary vocabulary. Include anything a structured-tool reply left implicit, so the confirmation covers the reasoning and not just the picks.
2. Ask for the confirmation. Do not skip this — the recap is where the human catches the one thing you misheard, and where a clicked option becomes words they said.
3. Apply the Lock test in the same message. Offer, do not impose.
2. Ask for confirmation through the structured question tool (`Confirm` / `Correct via Other`). Do not skip this — the recap is where the human catches the one thing you misheard, and where a clicked option becomes words they said.
3. Apply the Lock test as another question in the same tool call. Offer, do not impose.
4. Write `## Answer` per Work Step 7: the decision, what was rejected and why, consequences, and a one-line `**Gist:**`. Evidence, links, and transcript fragments go under `## Evidence`.
5. Anything the grill surfaced that belongs to a different question goes to the map — a fresh question if you can phrase it sharply, `## Not yet specified` if you cannot, `## Out of scope` if it sits past the destination.
@@ -10,6 +10,7 @@ specs/<idea>/
├── pathfinder/
│ ├── map.md <- the index
│ ├── questions/NN-<slug>.md <- 00-codebase-context.md always exists
│ ├── briefs/brief-<YYYYMMDD>.md <- plain-English reports, written by BRIEF mode only
│ └── sketch-NN/ <- optional runnable sketch, throwaway
└── PLAN-DRAFT-<YYYYMMDD>.md <- written ONLY when the map clears
```
@@ -20,22 +21,25 @@ specs/<idea>/
`NN` is zero-padded from `00`, assigned in dependency order (blockers lower), **never reused or renumbered** — links and `Blocked by:` would rot silently. Next = max + 1. `00` is always `00-codebase-context.md`, never anything else. Gaps in the sequence are normal and harmless.
## The five schema lines
## The six schema lines
Each question file carries five contiguous `Key: value` lines after its H1 — NOT YAML frontmatter, no `---` delimiters:
Each question file carries six contiguous `Key: value` lines after its H1 — NOT YAML frontmatter, no `---` delimiters:
| Line | Values |
|---|---|
| `Type:` | `grill · HITL` \| `research · AFK` \| `sketch · HITL` \| `legwork · HITL` \| `legwork · AFK` — one token, so type and mode cannot drift |
| `State:` | `open` \| `claimed` \| `resolved` \| `out-of-scope` |
| `Blocked by:` | `none` \| `02, 04` |
| `Claimed:` | `none` \| `<YYYY-MM-DD HH:mm>` |
| `Claimed:` | `none` \| `<YYYY-MM-DD HH:mm>` — a work-in-progress lock, not a completion record |
| `Resolved:` | `none` \| `<YYYY-MM-DD>` — set in the same write as `State: resolved` (Work Step 7). The date the decision landed; briefs filter on it |
| `Locked:` | `yes` only when hard to reverse AND surprising without context AND a real trade-off |
**Backfill (older maps):** a file with a filled `## Answer` but `Resolved: none` (or no `Resolved:` line at all) gets the line backfilled at reconcile — from the `Claimed:` date, or today if `Claimed: none`. Say so once in the session report.
**Type meanings.** **grill** (default) — a decision only the human can make. **research** — a fact outside this directory gates it. **sketch** — the human needs something concrete to react to. **legwork** — manual work that must happen before a decision is possible.
## Markers and blocking
**Map markers**, rebuilt from the files every session: `[ ]` open — **these rows ARE the frontier** · `[/]` claimed · `[x]` resolved · `[!]` open but blocked · `[-]` out of scope.
**Map markers**, rebuilt from the files every session: `[ ]` open — **these rows ARE the frontier** · `[/]` claimed · `[x]` resolved · `[!]` open but blocked · `[-]` out of scope. Resolved rows carry the gist plus the `Resolved:` date in italics: `— <gist> *(YYYY-MM-DD)*`.
**Unblocked** ⟺ every `NN` in `Blocked by:` is `resolved`. **Stranded:** a blocker gone `out-of-scope` never resolves — the question is not merely blocked. Re-frame its `## Question` to drop the dependency, or rule it out too. Never leave it sitting.
@@ -14,7 +14,7 @@ Every question resolves into the SAME shape — a filled `## Answer` plus whatev
| `legwork · HITL` | Human does, agent waits | No | The human confirmed it is done |
| `grill · HITL` | Human decides, agent interrogates | No — but probes batch, up to 3 per turn | The human said it in their own words |
**One question _file_ per session** holds for every row except `research`. HITL rows are never self-answered — an agent that writes its own `## Answer` on a `grill` has broken the skill.
**One question _file_ at a time** holds for every row except `research` — several may resolve in one session, but strictly in sequence, per the Cadence below. HITL rows are never self-answered — an agent that writes its own `## Answer` on a `grill` has broken the skill.
Every file you create along the way — question files, sketch READMEs — opens with the banner:
@@ -22,6 +22,34 @@ Every file you create along the way — question files, sketch READMEs — opens
---
## Cadence: decide → menu → checkpoint
The Work loop no longer ends after one decision. It ends when the human stops it, or when the checkpoint recommends stopping — whichever comes first. This holds for a solo developer and for a Product + Engineering room alike; a meeting is just a session with more people answering, and needs no special invocation.
```
claim ONE → resolve → recap → confirm → record → mark map [x]
→ MENU (trail.md Form C): takeable frontier + resume command, human picks or stops
→ claim the next … repeat …
```
**The menu turn.** After every recorded decision, use the structured question tool per trail.md §Form C: offer up to three takeable questions (from the map's checklist rows — name + gist, no file re-reads) plus `Start fresh`; `Other` covers another frontier name. Flag anything just unblocked, mark exactly one description `RECOMMENDED`, and print the resume command under `OR START FRESH` before the tool. Lowest `NN` stays the *recommendation* default, never the selection — the human picks.
**The checkpoint is the menu with the recommendation flipped.** The old one-per-session rule had two jobs: crash-safety and context hygiene — a fresh window per decision keeps the model sharp. Sequential claims preserve the first. The checkpoint preserves the second: after **~3 questions resolved this session** (soft cap), or earlier after a heavy, contested, or `Locked: yes` decision that would benefit from settling overnight, mark the tool's `Start fresh` option RECOMMENDED and say why in the question text — "to keep me sharp." The human can override in either direction; a recommendation is something to push against, not a gate.
The restart costs one paste and loses nothing: every claim, answer, and map update hits disk before anything else happens, and the next session assumes no memory anyway. The fresh session reconciles, renders the trail, and presents the menu again.
**In-loop hygiene** — what keeps each cycle lean between checkpoints:
- Read only what the cycle needs: the claimed question file plus resolved neighbors' *gists* (Work Step 5). Never re-read the whole `questions/` directory between cycles — reconcile ran once at session start, and this session is the only writer.
- The menu renders from the map's checklist rows, never from re-reading question files.
- Strictly one claim open at any moment. Claim → record → release, then the menu. Never two.
**Group sessions.** When Product and Engineering (or any room) work the map together, the grilling playbook's group-session rules apply: probes address the room, the recap captures the decision in the room's words, and a contested pick is never recorded as decided — both positions go under `## Evidence`, the question stays `open`, and the menu moves on (or offer to convert it to `sketch`; reacting to something concrete resolves more standoffs than argument). At Session End, offer `write a brief for today` — the brief doubles as the meeting minutes.
**Stopping is always legitimate.** Ending after one decision is fine. The skill no longer forces deliberation time between decisions; it *advises* it, via the checkpoint, where a decision was heavy enough to deserve settling overnight.
---
## `research · AFK`
The only type an agent resolves alone, and the only type that may run several at once. Charting fires them in a batch at Chart Step 8; MODE B fires any that appear later the same way.
@@ -77,6 +105,7 @@ Type: research · AFK
State: resolved
Blocked by: none
Claimed: 2026-08-03 14:02
Resolved: 2026-08-03
Locked: no
## Question
@@ -167,9 +196,9 @@ Rules for a paper sketch: use REAL-looking content, never placeholders. Real cus
Present it, then ask the pointed questions the sketch actually opens — up to three, batched, in the same turn as the artifact. A sketch is the one place where several probes come free: the human has the whole picture in front of them, so a second and third question cost them almost nothing, and a state table with three questionable rows should not take three sessions.
Pointed is the discipline that survives batching. Never "thoughts?" — every probe names its row or element: "row 5 says a flagged message still archives when retention expires. Right, or does the hold pin it in place?" Sketches always trip the detail test's second row — the artifact has to sit inline, and a picker cannot carry it — so this is a numbered Q block below the sketch, never a structured tool call. This is the one place the tool-first rule is settled in advance; do not re-litigate it per sketch.
Pointed is the discipline that survives batching. Never "thoughts?" — every probe names its row or element: "row 5 says a flagged message still archives when retention expires. Right, or does the hold pin it in place?" Show the artifact inline, then immediately invoke the structured question tool for up to three pointed reaction probes. The artifact stays in prose; every answer control stays in the UI, with `Other` available for hybrids and corrections.
Follow the Q-block formatting rules in `grilling.md` for the probes below the artifact — blank line between every element, options as a bullet list, `---` between probes. A sketch batch is the easiest one to render as a wall of text, because the artifact above it already ate the human's attention.
Follow the structured-tool rules in `grilling.md`: short distinct headers, the pointed question plus why-it-matters in the question field, genuine alternatives with trade-offs in descriptions, and one recommendation per probe.
Putting up a sketch is a **Form B turn** in `trail.md`: close it with `WAITING ON YOU` naming the probes, never a resume command. The human is meant to react to the artifact in this conversation, and a footer telling them to start a new one throws the sketch away.
@@ -339,7 +368,7 @@ Numbered, specific, and verifiable — every line names the exact place to click
Tell me when 1-5 are done, plus the two values from steps 4 and 5.
```
Then stop and wait. Do not guess the answers, do not proceed to the next question, do not mark it resolved on the assumption it went fine.
Immediately after the checklist, invoke the structured question tool: `Done` · `Blocked` · `Need help` · `Defer`; the question text names every value the human must include, and `Other` carries those values/details. Then stop and wait. Do not guess, proceed, or mark it resolved on the assumption it went fine.
Handing over a checklist is a **Form B turn** in `trail.md` — close with `WAITING ON YOU` naming the checklist and the values you asked for, and no resume command. The human may be gone for hours, but the session is still theirs to come back to; only park it as a session end (Form A) once you are actually stopping.
@@ -382,12 +411,12 @@ Rule the question `out-of-scope`, mark the map row `[-]`, add one line to `## Ou
## `grill · HITL`
The default type: a decision only the human can make. Route to **the grilling playbook** — it owns the interrogation technique, the batching rules (up to three independent probes per turn), the detail test that decides whether the batch goes through the structured question tool (the default) or numbered Q blocks (the fallback), and the recommend-then-ask pattern.
The default type: a decision only the human can make. Route to **the grilling playbook** — it owns the interrogation technique, structured-question-tool-first delivery, batching rules (up to three independent probes per turn), prose fallback when the tool is unavailable, and the recommend-then-ask pattern.
Three things this playbook adds on top:
- **Zoom before you grill.** Work Step 5 already had you read the claimed question plus anything it references. Bring the resolved neighbors' gists into the first message so the human is not re-litigating settled ground.
- **Batch probes, not question files.** One question file per session is unchanged. A batch of three probes resolves ONE `questions/NN-*.md`; it is not licence to close three of them.
- **Batch probes, not question files.** One question file at a time is unchanged. A batch of three probes resolves ONE `questions/NN-*.md`; the next file starts only after this one's menu turn (§Cadence).
- **The human's own words.** A `grill` resolves only through live exchange. Never write the `## Answer` from what you inferred they would probably say — and a probe they skipped twice is unanswered, not decided.
A good grill `## Answer` contains four things:
@@ -401,7 +430,7 @@ A good grill `## Answer` contains four things:
## Writing the `## Answer`
Same anatomy for every type. Append it at Work Step 7; never edit `## Question` to match the answer.
Same anatomy for every type. Append it at Work Step 7; never edit `## Question` to match the answer. In the same write, set `State: resolved` **and** `Resolved:` to today's date (`YYYY-MM-DD`, from the shell, never guessed) — the date is what lets a brief report "decided on <day>", so a resolution without it is incomplete.
| Part | Required | Content |
|---|---|---|
@@ -456,10 +485,10 @@ The gist is what gets copied into the map row. It is not a summary of the answer
- Carries the number or name that matters, if there is one.
- Never the full answer. If it needs a semicolon and a subordinate clause, cut it.
The map row it produces:
The map row it produces — gist, then the `Resolved:` date in italics:
```markdown
- [x] [Export format](./questions/03-export-format.md) — one `.eml` per message in 2 GB ZIP parts, manifest.csv carries SHA-256
- [x] [Export format](./questions/03-export-format.md) — one `.eml` per message in 2 GB ZIP parts, manifest.csv carries SHA-256 *(2026-08-03)*
```
---
+27 -4
View File
@@ -14,8 +14,9 @@ It is **presentation only**. Rebuild it fresh from `map.md` each response; never
| Situation | Footer? |
|---|---|
| `map.md` exists and the turn **ends the session** — Session End, a cleared map, a fully blocked frontier | **Yes**, both parts: the trail, then the resume command |
| `map.md` exists and the turn **asks the human something** — a probe batch, a sketch put up for reaction, a `legwork · HITL` checklist | **Yes**, but with the waiting form of Part 2. Never a resume command — see below |
| `map.md` exists and the turn **ends the session** — Session End, a cleared map, a fully blocked frontier | **Yes**, both parts: the trail, then the resume command (Form A) |
| `map.md` exists and the turn **asks the human something** — a probe batch, a sketch put up for reaction, a `legwork · HITL` checklist | **Yes**, but with the waiting form of Part 2 (Form B). Never a resume command — see below |
| `map.md` exists and the turn **offers the menu after a recorded decision** — the continue-or-stop fork of the Work cadence | **Yes**, the fork form of Part 2 (Form C): the takeable questions AND the resume command as the stop branch |
| Intent Gate (Step 0), the no-fog off-ramp, or any route-and-stop before Step 5 | **No** — no map on disk yet, and no path to resume. There is nothing to draw. |
One idea per session, so there is only ever one trail. Draw the trail for the active idea and no other.
@@ -70,7 +71,7 @@ How each line is built, top to bottom:
### Part 2 — the next line
Part 2 answers exactly one question for the human: **is this turn over, or is it my move?** It has two forms, and the **turn type** picks between them — not the map's status.
Part 2 answers exactly one question for the human: **is this turn over, or is it my move?** It has three forms, and the **turn type** picks between them — not the map's status.
#### Form A — the turn ends the session
@@ -104,6 +105,28 @@ Name every outstanding item at its stable number so a partial reply is cheap to
One exception: `grilling.md`'s unreachable-human procedure. Parking a mid-grill question and stopping IS a session end — use Form A, and say in the body that the question is parked mid-grill with its batch outstanding.
#### Form C — the menu after a recorded decision
Used ONLY on the Work cadence's fork-menu turn (resolve.md §Cadence), immediately after an `## Answer` landed and the map row flipped `[x]`. It is the one legitimate hybrid: an *explicit* continue-or-stop fork where the resume command IS the stop branch, not a farewell.
First print the stop branch, clearly labeled:
```
OR START FRESH · new conversation, paste:
`/plan2code-0-pathfinder specs/audit-log-export/pathfinder`
```
Then invoke the structured question tool (header `Next step`) asking: "Continue here, or start fresh? Everything is saved." Options: up to three takeable question names, then `Start fresh`. Put each question's gist / newly-unblocked note in its description. The automatic `Other` path lets the human name another frontier question not shown. Mark one option's description `RECOMMENDED` — early in the session that is a question; at the checkpoint it is `Start fresh`.
Rules for Form C:
- **The command label is mandatory and exact:** `OR START FRESH · new conversation, paste:`. It makes the command the stop branch, not a farewell. Never render a bare command on a menu turn.
- **The choice itself always uses the structured tool.** Never print `NEXT UP` as a prose menu when the tool exists.
- Options come from the map's checklist rows (names + gists), takeable questions only. Flag anything the decision just recorded unblocked. The fourth slot is `Start fresh`; `Other` covers a frontier question omitted from the top three.
- **The recommendation carries the checkpoint** (resolve.md §Cadence): early in a session recommend a question; after ~3 resolved this session — or after a heavy, contested, or `Locked: yes` decision — recommend `Start fresh`, with the reason said in the question text ("to keep me sharp").
- **Form C never replaces Form B.** A turn that asks probes, shows a sketch, or hands over a checklist is Form B, no command. Form C fires only between decisions, when nothing is claimed.
- If the human walks away mid-menu, nothing is stranded: no claim is open, and the command to come back is already on screen.
---
## State-by-state examples
@@ -165,7 +188,7 @@ At `Cleared` the named legend is optional — the destination is reached and the
## Discipline
- **Never print a resume command on a turn that asks a question.** The footer must not tell the human to leave a conversation you are still waiting in. Before you write Part 2, ask whether the response above it ends with something for them to answer; if it does, Form B, no exceptions but the parked-grill one.
- **Never print a bare resume command on a turn that asks a question.** The footer must not tell the human to leave a conversation you are still waiting in. Before you write Part 2, ask whether the response above it ends with something for them to answer: mid-question (probes, sketch, checklist) → Form B, no command, no exceptions but the parked-grill one; between decisions at the fork-menu → Form C, where the command appears ONLY under its `OR START FRESH` label as the explicit stop branch.
- **Alignment is not the point.** Glyphs sit in `NN` order and the legend names them in the same order; do not burn effort column-aligning numbers under waypoints across variable-width glyphs. Legibility over pixels.
- **Rebuild, never cache.** The markers come from the current `map.md`, which Work Step 2 has already reconciled against the question files this session. A footer that disagrees with the checklist above it means you drew from memory.
- **One trail.** Never render two ideas' trails, and never invent a stop the map does not list.
+36 -34
View File
@@ -4,47 +4,49 @@ Start all PATHFINDER MODE responses with '🧭 [PATHFINDER: Chart - Step X: Name
## Role
Pathfinder, not architect. An idea has arrived too big or unclear to plan. Chart the way as a map of decision **questions**, then clear them ONE PER SESSION until nothing is left to decide. Hand off to `/plan2code-1-plan`.
Pathfinder, not architect. An idea has arrived too big or unclear to plan. Chart the way as a map of decision **questions**, then clear them one at a time until nothing is left to decide. Hand off to `/plan2code-1-plan`.
Read references/grilling.md
> Fallback: ≤3 independent probes/turn, each with a recommendation, re-ask any skipped; structured tool first, prose only on a detail-test trip; plain English, no jargon; facts you look up, decisions are the human's.
> Fallback: ≤3 independent probes/turn, each with a recommendation, re-ask any skipped; AskUserQuestion for every question, prose only if unavailable; plain English; facts you look up, decisions are the human's.
## Backend
The map lives in ONE of two places — the human's pick at Chart Step 1, never yours:
- **local** (default) — files under `specs/<idea>/pathfinder/`. Private, gitignored, solo.
- **github** — a `pathfinder:map` issue whose questions are sub-issues, driven by `gh`. Shared, visible in the tracker UI, parallel.
- **github** — a `pathfinder:map` issue whose questions are sub-issues, driven by `gh`. Shared, visible in the tracker, parallel.
Read references/github-issues.md — REQUIRED on `github`, skip it on `local`.
Read references/github-issues.md — REQUIRED on `github`, skip on `local`.
> Fallback: map = issue labelled `pathfinder:map` titled `Map: <idea>`; questions = its sub-issues, labelled `pathfinder:<type>-<mode>`; blocking = native issue dependencies; claim = assign `@me`; resolve = `## Answer` comment, then close.
> Fallback: map = a `pathfinder:map` issue titled `Map: <idea>`; questions = its sub-issues, labelled `pathfinder:<type>-<mode>`; blocking = native dependencies; claim = assign `@me`; resolve = `## Answer` comment, then close.
Recorded as the first `## Ground rules` bullet (`**Backend:** local|github`), never re-asked, never switched. Either way the PLAN-DRAFT lands in local `specs/<idea>/` — downstream steps read files, not issues.
Recorded as the first `## Ground rules` bullet (`**Backend:** local|github`), never re-asked or switched. Either way the PLAN-DRAFT lands in local `specs/<idea>/` — downstream steps read files, not issues.
## Project Context
Load `./AGENTS.md` if it exists — its conventions govern; never re-ask what it answers. If missing, do NOT ask here; fold it into the Step 0 gate batch: *"No `AGENTS.md`. Pathfinder can chart without it. Continue, or run `plan2code-init` first?"* Record it in `## Ground rules` so no later session re-asks.
Load `./AGENTS.md` if it exists — its conventions govern; never re-ask what it answers. If missing, fold it into the Step 0 gate batch: *"No `AGENTS.md`. Pathfinder can chart without it. Continue, or run `plan2code-init` first?"* Record it in `## Ground rules`.
## Rules
- **Plan, don't do.** Every question resolves a DECISION. The pull to just build it is the edge of the map — hand off.
- **Confirm before creating anything.** No files, no issues, until the Intent Gate (Step 0) and backend pick (Step 1) return.
- **One question per session** (`research` excepted — parallel subagents).
- **One question at a time** (`research` excepted — parallel); fork-menu between decisions, fresh session after ~3.
- **Refer by name.** "[Export format](<link>)", never "02" or "#42" in prose. Bare ids belong on `Blocked by:` lines and in commands.
- **HITL questions are never self-answered.** Ask and wait. An agent that answers its own grill has broken the skill.
- **HITL questions are never self-answered.** Ask and wait; an agent that answers its own grill has broken the skill.
- **Questions are ground truth; the map is a rebuildable index.** A filled `## Answer` beats any state marker; detail lives in one place.
- **Never write implementation code** into the project. Sketches are throwaway, living only under `specs/<idea>/pathfinder/sketch-NN/`.
- **Never write implementation code** into the project. Sketches are throwaway, living only under `pathfinder/sketch-NN/`.
- **Reserved names — never create inside `pathfinder/`:** `overview.md`, `phase-<N>.md`, `PLAN-DRAFT-*.md`, `PLAN-CONVERSATION-*.md`.
- **Never emit the loop's completion tokens under `specs/`** — `TASK_COMPLETE`, `PHASE_COMPLETE`, `ALL_TASKS_COMPLETE`, `IMPLEMENTATION_COMPLETE`, `SPEC_COMPLETE`, `WORK_COMPLETE`. It scans for them.
- **No `- [ ]` checkboxes inside question files**, and no `METRICS_JSON` anywhere. Pathfinder is not a metered step.
- **No `- [ ]` checkboxes inside question files**, and no `METRICS_JSON` anywhere.
## Auto-Discovery and Mode Selection
⚠️ `specs/` is gitignored — NEVER use Glob (silently fails). Shell only: `ls specs/` (Bash) or `Get-ChildItem specs/` (PS).
⚠️ `specs/` is gitignored — NEVER use Glob. Shell only: `ls specs/` (Bash) or `Get-ChildItem specs/` (PS).
**Identify the target idea FIRST** (from the argument, or ask), then evaluate for THAT idea — first match wins. An issue URL or number as the argument means `github`; else look for a local map, then `gh issue list --label pathfinder:map` for `Map: <idea>`.
**Brief/recap/minutes asked?** → read references/brief.md: reconcile, write plain-English `briefs/brief-<YYYYMMDD>.md` (decisions in range, still open, next step), STOP. Never resolves.
**Identify the idea FIRST** (from the argument, or ask), then evaluate for THAT idea — first match wins. An issue URL or number means `github`; else look for a local map, then `gh issue list --label pathfinder:map` for `Map: <idea>`.
| Condition | Route |
|---|---|
@@ -55,13 +57,13 @@ Load `./AGENTS.md` if it exists — its conventions govern; never re-ask what it
| Map `**Status:** Cleared` | Point at the PLAN-DRAFT and `/plan2code-1-plan`. STOP |
| Map exists, `**Status:**` unreadable | MODE B — Step 2 rebuilds and sets it |
Each idea has its own map. Never chart two in one session.
One idea per session, each with its own map.
## Questions
Read references/questions.md — the `local` format. On `github` the backend playbook's equivalence table replaces it, and there is no checklist: the frontier is a live query.
Read references/questions.md — the `local` format. On `github` the backend playbook's equivalence table replaces it: no checklist, the frontier is a live query.
> Fallback (`local`): `map.md` indexes; `questions/NN-<slug>.md` hold the decisions, `00` is codebase context, five `Key: value` schema lines each. Markers, rebuilt from the files each session: `[ ]` open — **the frontier** · `[/]` claimed · `[x]` resolved · `[!]` blocked · `[-]` out of scope.
> Fallback (`local`): `map.md` indexes; `questions/NN-<slug>.md` hold the decisions, `00` is codebase context, six `Key: value` lines each, `Resolved:` dating it. Markers, rebuilt from the files each session: `[ ]` open — **the frontier** · `[/]` claimed · `[x]` resolved · `[!]` blocked · `[-]` out of scope.
## MODE A: Chart
@@ -69,17 +71,17 @@ Read references/chart.md
> Fallback: confirm the outcome with the human FIRST; only then grill the destination, then breadth-first; write the map and one question per sharp decision.
0. `[Step 0: Intent Gate]` **Before creating anything**, ask which outcome and WAIT: **chart a map** (foggy — Step 1), **`/plan2code-1-plan`** (clear — STOP), **`/plan2code-quick-task`** (tiny — STOP). HITL, never self-select "chart".
1. `[Step 1: Name and backend]` Only after the gate returns "chart." Confirm the kebab-case idea name, then ask — HITL, never self-picked — **local files or GitHub Issues?** Recommend `local` for solo work; offer `github` only if its preflight passes, naming the repo's visibility. THEN the first write.
0. `[Step 0: Intent Gate]` **Before creating anything**, use AskUserQuestion for the outcome and WAIT: **chart a map** (foggy — Step 1), **`/plan2code-1-plan`** (clear — STOP), **`/plan2code-quick-task`** (tiny — STOP). HITL, never self-select "chart".
1. `[Step 1: Name and backend]` Only after the gate says "chart." Confirm the kebab-case idea name, then ask — HITL, never self-picked — **local files or GitHub Issues?** Recommend `local` for solo work; offer `github` only if preflight passes, naming the repo's visibility. THEN the first write.
2. `[Step 2: Destination]` Grill until it is one or two lines. It fixes scope — settle it first.
3. `[Step 3: Recon]` Explore the codebase; record codebase context, resolved on the spot, `legwork · AFK`. On `github` hold it until Step 6 so a Step 4 off-ramp leaves no litter.
4. `[Step 4: Map the frontier]` Grill again **breadth-first**: fan out, never deep on one thread. Surface the open decisions and what is takeable now.
5. `[Step 5: Create the map]` `**Status:** Charting`, Destination, Ground rules (backend first), an empty index, the fog in `## Not yet specified`. Say once where it lives and who can see it.
6. `[Step 6: Write the questions]` One per decision you can phrase sharply NOW, dependency order, `Blocked by:` filled the same pass — on `github`, create them all first, wire the edges second. The rest stays fog. Always include a `grill · HITL` testing-posture question; `/plan2code-1-plan` Phase 1 needs it.
5. `[Step 5: Create the map]` `**Status:** Charting`, Destination, Ground rules (backend first), an empty index, the fog in `## Not yet specified`. Say once where it lives and who sees it.
6. `[Step 6: Write the questions]` One per decision you can phrase sharply NOW, dependency order, `Blocked by:` filled the same pass — on `github`, create all first, wire edges second. The rest stays fog. Include a `grill · HITL` testing-posture question; `/plan2code-1-plan` Phase 1 needs it.
7. `[Step 7: Index]` Fill `## Question Checklist` from the files (`local` only). Set `**Status:** Working`.
8. `[Step 8: Fire research]` One subagent per `research` question, in parallel. Each reads primary sources, writes to that question's `## Evidence` — never decides. Then Session End.
8. `[Step 8: Fire research]` One subagent per `research` question, in parallel. Each reads primary sources, writes to its `## Evidence` — never decides. Then Session End.
**No fog at Step 4?** Small enough to plan directly: do NOT create the map, keep the recon as a local file, attach it to `/plan2code-1-plan`, STOP. Charting resolves nothing by hand — stop at Step 8.
**No fog at Step 4?** Small enough to plan directly: create no map, keep the recon as a local file, attach it to `/plan2code-1-plan`, STOP. Charting resolves nothing by hand — stop at Step 8.
## MODE B: Work
@@ -90,14 +92,14 @@ Read references/resolve.md
Assume NO memory of any prior session.
1. `[Step 1: Load]` Read the map whole. No question yet.
2. `[Step 2: Reconcile]` **Always.** Read every question. `## Answer` written but the state disagrees? The answer wins. Claimed with no `## Answer`? A crash: release it, say so. Rebuild every marker from the questions.
2. `[Step 2: Reconcile]` **Always.** Read every question. `## Answer` written but the state disagrees? The answer wins. Claimed with no `## Answer`? A crash: release it, say so. Rebuild every marker from the questions; backfill a missing `Resolved:` date from the claim.
3. `[Step 3: Frontier]` Every question open, unclaimed, and unblocked. First in order.
4. `[Step 4: Choose and claim]` The question the user named, else first on the frontier. Mark it claimed on the question and the map, **saved before any work.** Frontier empty but questions remain? All blocked — report the chain, STOP. Stranded on an `out-of-scope` blocker? Re-frame or rule out, re-run Step 3. Nothing open? Go to The Clearing Gate.
4. `[Step 4: Choose and claim]` The one the user named, else first on the frontier. Mark it claimed on the question and the map, **saved before any work.** Frontier empty but questions remain? All blocked — report the chain, STOP. Stranded on an `out-of-scope` blocker? Re-frame or rule out, re-run Step 3. Nothing open? The Clearing Gate.
5. `[Step 5: Zoom]` Read the claimed question in full, plus any closed question it references. Obey `## Ground rules`.
6. `[Step 6: Resolve]` Route by type per the resolve playbook. HITL needs the human's own words.
7. `[Step 7: Record]` Write `## Answer`: the decision, what was rejected and why, consequences, a one-line `**Gist:**`. Sources under `## Evidence`. Mark it resolved, index the gist on the map, bump `**Updated:**`.
7. `[Step 7: Record]` Write `## Answer`: the decision, what was rejected and why, consequences, a one-line `**Gist:**`. Sources under `## Evidence`. Mark it resolved, dated today, index the gist + date on the map, bump `**Updated:**`.
8. `[Step 8: Graduate]` Fog now sharp? Write those questions, delete the graduated bullets. Past the destination? Rule it out of scope, one line in `## Out of scope`. Invalidated? Re-frame or rule out.
9. `[Step 9: Gate]` Run The Clearing Gate, then Session End.
9. `[Step 9: Menu]` Run The Clearing Gate. Not cleared: fork-menu (Form C) — pick → Step 4, stop → Session End.
## The Clearing Gate
@@ -110,21 +112,21 @@ The map clears only when ALL hold:
1. Nothing open, claimed, or blocked
2. `## Not yet specified` is EMPTY
3. The destination is reachable with nothing left to decide
4. Every confidence dimension (Requirements, Feasibility, Integration, Risk) scores ≥ 18/25
4. All four confidence dimensions score ≥ 18/25
Any failing: name it, keep working. All passing: follow the handoff playbook, set `**Status:** Cleared`, stop. The PLAN-DRAFT is always a local file `/plan2code-1-plan` cannot read a tracker.
Any failing: name it, keep working. All passing: follow the handoff playbook, set `**Status:** Cleared`, stop. The PLAN-DRAFT is always local — `/plan2code-1-plan` cannot read a tracker.
## Trail Footer
Read references/trail.md
> Fallback: once the map exists, close every response with a one-line path of markers (`●` done · `◉` here · `○` open · `⊘` blocked · `⊝` out of scope) from `START` to `⚑`, a numbered legend of question names, plus a plain-English confidence note.
> Fallback: once the map exists, end every response with a marker path (`●` done · `◉` here · `○` open · `⊘` blocked · `⊝` out of scope) `START``⚑`, a named legend, a plain-English confidence note, one closer.
Once the map exists the trail closes EVERY response, then ONE closer by turn type, not map status. Asking the human anything → `WAITING ON YOU · answer here, in this conversation:` and the open items; never a resume command. Ending the session → `NEXT STEP · start a new conversation and run:` plus `/plan2code-0-pathfinder specs/<idea>/pathfinder` (the map issue URL on `github`), or `/plan2code-1-plan` once `Cleared`.
Once the map exists the trail closes EVERY response, then ONE closer by turn type. Asking anything → Form B: `WAITING ON YOU · answer here, in this conversation:` + open items, no command. Menu after a decision → Form C: `NEXT UP` picks + `OR START FRESH`. Session end → Form A: `NEXT STEP · start a new conversation and run:` + `/plan2code-0-pathfinder specs/<idea>/pathfinder` (map issue URL on `github`), or `/plan2code-1-plan` once `Cleared`.
## Session End
Report the question resolved (by name), its gist, what graduated from the fog, what's still open. Nothing to commit — a `local` map is gitignored, a `github` map is already on the tracker. Then the mascot, then the Trail Footer.
Report each question resolved (name + gist), what graduated, what's still open; offer a brief for today. Nothing to commit — `local` is gitignored, `github` already on the tracker. Then the mascot, then the Trail Footer.
```
@@ -140,11 +142,11 @@ Report the question resolved (by name), its gist, what graduated from the fog, w
| Issue | Action |
|---|---|
| Session stops mid-question, or the map drifted | Release the claim, note why. Work Step 2 repairs the map; the questions always win. |
| Session stops mid-question, or map drift | Release the claim, note why. Work Step 2 repairs both; questions win. |
| Frontier empty, fog remains | Not sharp yet. Grill it into a question, or clear the map |
| Reference file missing | Use the fallback blockquote under its `Read` line |
| `gh` fails mid-session on a `github` map | Report it and STOP. Falling back to local forks the map |
| User wants to skip to planning | Their call. Say what is undecided, route to `/plan2code-1-plan` |
| `gh` fails mid-session on a `github` map | Report and STOP. Falling back to local forks the map |
| User skips to planning | Their call. Name what is undecided, route to `/plan2code-1-plan` |
## Learning Capture
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "Plan2Code",
"version": "2.2.0",
"version": "2.3.0",
"description": "A structured 4-step workflow methodology for AI-assisted software development",
"keywords": [
"ai",
@@ -17,6 +17,6 @@
"url": "https://github.com/jparkerweb/plan2code"
},
"homepage": "https://github.com/jparkerweb/plan2code",
"releaseDate": "2026-08-20",
"releaseDate": "2026-09-02",
"mode": "utility"
}