--- name: trekplan description: Deep implementation planning from a task brief. Requires --brief or --project. Runs parallel specialized agents, optional external research, and adversarial review. argument-hint: "--brief | --project [--fg | --quick | --research | --decompose | --export headless ]" allowed-tools: Agent, Read, Glob, Grep, Write, Edit, Bash, AskUserQuestion --- # Voyage Local v2.0 Deep, multi-phase implementation planning driven by a **task brief**. Planning consumes the brief (produced by `/trekbrief`) and any research briefs referenced in it, then runs specialized exploration agents, synthesis, and adversarial review to produce an executable plan. **v2.0 is a breaking release.** The interview phase has been extracted into `/trekbrief`. This command no longer accepts free-text task descriptions — it requires either `--brief ` or `--project `. Pipeline position: ``` /trekbrief → brief.md /trekresearch → research/*.md /trekplan → plan.md (this command) /trekexecute → execution ``` ## Phase 1 — Parse mode and validate input Parse `$ARGUMENTS` for mode flags. Order of precedence: 1. **`--export headless `** — extract `{format}` (first token after `--export`) and `{plan-path}` (remainder). `headless` is the only export format; it is a backwards-compatible **alias for `--decompose`**. Set **mode = decompose** and run the decomposition pipeline (Phase 1.5). The PR / issue / markdown export variants were removed — Claude Code reformats a plan into a PR body, issue comment, or stripped markdown ad-hoc on request, so a dedicated export path added maintenance without value. If `{format}` is anything other than `headless`: ``` Error: export format '{format}' is not supported. The only export is 'headless' (an alias for --decompose). For PR / issue / markdown output, ask Claude to reformat the plan directly. ``` If the plan file does not exist: ``` Error: plan file not found: {path} ``` 2. **`--decompose `** — extract the plan path. Set **mode = decompose**. If the plan file does not exist: ``` Error: plan file not found: {path} ``` 3. **`--project `** — extract the project directory path. - Resolve `{dir}` (trim trailing slash). - Derive implicit flags: - `--brief {dir}/brief.md` - Plan destination: `{dir}/plan.md` - Research briefs auto-discovered from `{dir}/research/*.md` (sorted). - If `{dir}` does not exist or `{dir}/brief.md` is missing: ``` Error: project directory not initialized. Run /trekbrief to create it. Missing: {dir}/brief.md ``` - Set **project_dir = {dir}**, **brief_path = {dir}/brief.md**. - **Validate inputs** (soft mode — warnings do not block, errors do): ```bash # Brief schema sanity check (frontmatter + state machine, soft on body sections). # When --min-brief-version was passed, append --min-version {min_brief_version} # so the validator emits BRIEF_VERSION_BELOW_MINIMUM (warn, never block) for an # older brief that sidesteps framing enforcement. node ${CLAUDE_PLUGIN_ROOT}/lib/validators/brief-validator.mjs --soft --json [--min-version {min_brief_version}] "{dir}/brief.md" # v5.9 — composed phase-model resolution (brief > profile > default) for # the plan phase. ONE call returns {model, source}, plus # effort only when the brief's phase signal sets one; without it the # phase runs at effort `standard` (no change). Captured as # phase_signal_result and injected at Agent-spawn sites below. # Append --profile {profile} when the operator passed --profile. node ${CLAUDE_PLUGIN_ROOT}/lib/profiles/resolver.mjs --resolve-phase-model --phase plan --brief-path "{dir}/brief.md" [--profile {profile}] --json # Research briefs (if any) — drift-warn only, none of these block the run [ -d "{dir}/research" ] && \ node ${CLAUDE_PLUGIN_ROOT}/lib/validators/research-validator.mjs --soft --dir "{dir}/research" --json # Architecture note discovery (EXTERNAL CONTRACT — drift-WARN, never drift-FAIL) node ${CLAUDE_PLUGIN_ROOT}/lib/validators/architecture-discovery.mjs --json "{dir}" ``` Each call exits 0 on success or with a structured JSON error report on stderr. Surface any warnings in the user-facing summary at Phase 3, but do not abort. - Set **has_research_brief = true** if `{dir}/research/*.md` matches ≥ 1 file. - Read the architecture-discovery JSON output: set **has_architecture_note = true** if `found == true`. The discovery module emits warnings if the file lives at a non-canonical path (e.g. `architecture-overview.md`); preserve them for the user-facing summary. If set, **architecture_note_path = {result.overview}**. Produced by an external opt-in architect plugin (no longer publicly distributed; the filesystem slot remains available for any compatible producer). Missing file is fine — additive discovery, not required. 4. **`--brief `** — extract the brief path. If the file does not exist: ``` Error: brief file not found: {path} ``` Set **brief_path = {path}**. Plan destination will be derived in Phase 3 from the brief's slug and date (see Phase 3). 5. **`--research [brief2.md] [brief3.md]`** — collect paths after `--research` until the next `--` flag or a token that does not look like a file path. Maximum 3 briefs. Set **has_research_brief = true**. Validate each path exists — if any is missing: ``` Error: research brief not found: {path} ``` `--research` combines with `--brief`, `--project`, `--fg`, and `--quick`. When combined with `--project`, the explicit `--research` briefs are appended to the auto-discovered ones (deduplicated by path). 6. **`--fg`** — accepted as a no-op alias for backwards compatibility. All phases always run in the main session as of v2.4.0. 7. **`--quick`** — set **mode = quick**. Skip agent swarm; use lightweight Glob/Grep scan and go directly to planning + adversarial review. 8. **`--gates`** — autonomy control. When present, set `gates_mode = true`. Pause for operator confirmation after Phase 5 (exploration), Phase 7 (synthesis), and Phase 9 (adversarial review). Default `gates_mode = false` lets phases flow continuously. The flag is consumed by the autonomy-gate state machine via the CLI shim: `node ${CLAUDE_PLUGIN_ROOT}/lib/util/autonomy-gate.mjs --state X --event Y --gates {true|false}`. 9. **`--min-brief-version `** — (optional) version floor. Set **min_brief_version = {ver}** (e.g. `2.2`). Forwarded to the brief-validator as `--min-version {ver}`; when the brief declares an older version it emits a `BRIEF_VERSION_BELOW_MINIMUM` **warning** (never blocks) — framing enforcement only fires at `≥ 2.2`, so an older brief sidesteps the framing-alignment defense silently. Absent → no version check. See `docs/HANDOVER-CONTRACTS.md` §Handover 1 for the pre-2.2 enforcement hole this guards. 10. If neither `--brief` nor `--project` is present after flag parsing, output usage and stop: ``` Usage: /trekplan --brief /trekplan --project /trekplan --brief --research /trekplan --project --fg /trekplan --project --quick /trekplan --export headless /trekplan --decompose A brief is required. Produce one with /trekbrief first. Modes: --brief Plan from a brief file (foreground, v2.4.0+) --project Plan from a project directory (brief.md + research/ auto-resolved) --research Add up to 3 extra research briefs as planning context --fg No-op alias (foreground is the only mode as of v2.4.0) --quick Skip exploration agent swarm; plan directly --min-brief-version Warn (never block) if the brief is older than (e.g. 2.2) --export headless Legacy alias for --decompose (the only remaining export format) --decompose Split an existing plan into self-contained headless sessions Examples: /trekplan --project .claude/projects/2026-04-18-jwt-auth /trekplan --brief .claude/projects/2026-04-18-jwt-auth/brief.md /trekplan --project .claude/projects/2026-04-18-jwt-auth --research extra.md /trekplan --project .claude/projects/2026-04-18-jwt-auth --fg /trekplan --export headless .claude/plans/trekplan-2026-04-06-rate-limiting.md /trekplan --decompose .claude/plans/trekplan-2026-04-06-rate-limiting.md Migrating from v1.x? See MIGRATION.md in this plugin. The old --spec flag and free-text interview mode were removed in v2.0. ``` Do not continue past this step if no brief was provided. ### Read the brief **Intent approval gate (veikart steg 1).** Before anything is read for planning, check that the operator approved THIS brief's intent. Runs for `--brief` and `--project` alike; `--quick` does not skip it and there is no override flag: ```bash node ${CLAUDE_PLUGIN_ROOT}/lib/validators/intent-approval.mjs --check --json "{brief_path}" ``` Exit 0 → continue. Any other exit → **halt** — do not read further, spawn no agent, write no plan. Print each error's `message` and `hint`, then stop: | Code | Meaning | What the operator does | |------|---------|------------------------| | `BRIEF_INTENT_NOT_APPROVED` | No approval marker (`intent_approved_hash`) in the brief | `/trekbrief --approve {brief_path}` — read `## Intent` + `## Goal`, answer "Approve" | | `BRIEF_INTENT_APPROVAL_STALE` | `## Intent` or `## Goal` changed after approval | Same command — the approval covers the old text, not this one | | `BRIEF_INTENT_APPROVAL_INVALID` | Marker malformed, or `## Intent` / `## Goal` missing, empty or present more than once | Fix the brief, then the same command | If the command does not print the JSON report (module not found, node missing, an unresolved `${CLAUDE_PLUGIN_ROOT}`), **halt** as well and show the raw error: an approval check that could not run is never a pass. `trekreview` briefs are exempt (the check returns exit 0 for them). The exemption is read from the brief's own frontmatter, so a brief relabelled `type: trekreview` walks past this gate. That is the same trust class as self-stamping. What the marker does NOT prove — it is a trace that the approval step ran against this text, not a signature: see the header of `lib/validators/intent-approval.mjs`. **Approval log gate (K2).** The marker passed; now check that the approval is in the target repo's approval log, the chain is intact, and the logged approval covers this intent. `{intent_approved_hash}` is the brief's frontmatter value (the check above just confirmed it is current). Same scope as the check above: both brief modes, `--quick` included, no override flag; `trekreview` briefs skip it (they carry no intent hash). ```bash node ${CLAUDE_PLUGIN_ROOT}/lib/util/approval-log.mjs verify --json --kind intent --subject "{brief_path}" --sha256 "{intent_approved_hash}" ``` Exit 0 (`approved`) → continue; if `uncommitted` is above 0, say in one line that N approvals are in the log but not committed yet. Exit 1 → **halt** — no agent, no plan — print `status` and `detail`: | `status` | Meaning | What the operator does | |----------|---------|------------------------| | `broken` | A record in `.claude/voyage/approvals.jsonl` was edited, removed or reordered | Restore the log from git (`git checkout -- .claude/voyage/approvals.jsonl`), then re-run | | `diverged` | The committed log is no longer the start of the file: committed approvals were rewritten | Same: restore from git; the rewrite shows in `git diff` | | `not-logged` | No intent approval for this brief in the log (approved before the log existed, or the log step failed) | `/trekbrief --approve {brief_path}` | | `mismatch` | The latest logged approval covers other intent text | `/trekbrief --approve {brief_path}` | Exit 2, or no JSON at all → **halt** and show the raw error: a log check that could not run is never a pass. Read the brief file and parse its frontmatter. Extract: - `task` — one-line task description - `slug` — slug for plan filenames - `project_dir` — if present, overrides derived project path (optional) - `research_topics` — N (used as a sanity check) - `research_status` — `pending | in_progress | complete | skipped` - `ceremony` — size class (K1) `small | bounded | architectural`; absent = `architectural` (heaviest in doubt) - `artifact_store` — `git | local`, where Phase 11 keeps the plan; absent = `local` If `research_status == pending` and `research_topics > 0`: - Warn the user: "Brief declares {N} research topics but research is still pending. Plan confidence will be lower. Continue anyway?" - `AskUserQuestion`: **Continue with low confidence** / **Cancel — run research first**. - If cancel: print the research invocations from the brief's "How to continue" section and stop. Report the detected mode: ``` Mode: {foreground | quick | decompose} Brief: {brief_path} Project: {project_dir or "-"} Research: {N local briefs, M extra via --research} Class: {small | bounded | architectural} {(absent → architectural)} ``` ### When the input is type:trekreview (Handover 6) The brief input may be a `review.md` produced by `/trekreview` instead of a `brief.md` produced by `/trekbrief`. Both files share the same handover slot — `type` is the discriminator. If `fm.type === 'trekreview'`: 1. Skip the `research_status` gate above (review.md has no `research_topics` and no Research Plan section). 2. Extract the `findings` array from the frontmatter — this is the list of 40-char hex finding-IDs the review surfaced. 3. Read the body's last fenced ```json``` block to recover the full finding objects (the frontmatter only has IDs; the JSON has the `severity`, `file`, `line`, `rule_key`, `title`, `detail`, `recommended_action` payload). 4. Filter findings to severity ∈ `{BLOCKER, MAJOR}`. MINOR and SUGGESTION are skipped for v1.0 plan-input — they are advisory only and would inflate the plan with low-priority churn. 5. Treat each remaining finding as a plan goal: - `recommended_action` → step intent - `file` → primary `Files:` target - `id` → goes into the plan's `source_findings:` frontmatter list 6. When writing `plan.md`, populate the frontmatter field `source_findings: [, , ...]` containing exactly the IDs of the BLOCKER + MAJOR findings consumed. The list provides the audit trail back to `review.md`. 7. Use **block-style YAML** for the `source_findings:` list. The frontmatter parser at `lib/util/frontmatter.mjs` does not support flow-style arrays; `source_findings: [a, b]` is broken — use: ```yaml source_findings: - 0123456789abcdef0123456789abcdef01234567 - fedcba9876543210fedcba9876543210fedcba98 ``` `source_findings:` is **additive and optional** — plans produced from a `type: brief` input simply omit the field. No `plan_version` bump is required for this addition (backwards compatible). ## Phase 1.5 — Decompose (runs only when mode = decompose) **Skip this phase entirely unless mode = decompose.** (`--export headless` is a backwards-compatible alias that sets mode = decompose, so it lands here too.) Read the plan file. Verify it contains an Implementation Plan section with numbered steps. If no steps are found, report and stop: ``` Error: plan has no implementation steps. Run /trekplan first to generate a plan. ``` Determine the output directory from the plan slug: - Extract the slug from the plan filename (e.g., `trekplan-2026-04-06-auth-refactor` → `auth-refactor`) - Output directory: `.claude/trekplan-sessions/{slug}/` Launch the **session-decomposer** agent: Pass `model: {phase_signal_result.model}` at this spawn; without it (the `--brief` branch, where the resolver does not run, or a resolver that printed nothing) the agent's own `model:` applies. ``` Plan file: {plan path} Plugin root: ${CLAUDE_PLUGIN_ROOT} Output directory: .claude/trekplan-sessions/{slug}/ ``` The session-decomposer will: 1. Parse the plan's steps and their file dependencies 2. Build a dependency graph between steps 3. Group steps into sessions of 3–5 steps each 4. Identify which sessions can run in parallel (waves) 5. Generate one session spec file per session 6. Generate a dependency diagram (mermaid) 7. Write the session orders (`orders.md`): one starter line per session, wave by wave When the session-decomposer completes, present the summary to the user: ``` ## Decomposition Complete **Master plan:** {plan path} **Sessions:** {N} across {W} waves **Output:** .claude/trekplan-sessions/{slug}/ ### Sessions | # | Title | Steps | Wave | Parallel | |---|-------|-------|------|----------| {session table from decomposer} ### Files generated - Session specs: .claude/trekplan-sessions/{slug}/session-*.md - Dependency graph: .claude/trekplan-sessions/{slug}/dependency-graph.md - Session orders: .claude/trekplan-sessions/{slug}/orders.md You can: - Review individual session specs before running - Run the sessions yourself, wave by wave: open a Claude Code session per spec and give it the starter line from orders.md (`/trekexecute `). Run the sessions of one wave in parallel only in separate git worktrees. ``` Voyage does not start these sessions. Then **stop**. Do not continue to any subsequent phase. ## Phase 2 — (removed in v2.0) The interview phase has moved to `/trekbrief`. This command no longer asks the user any requirements questions — the brief is the authoritative input. ## Phase 3 — Destination and context recap (foreground) Determine the plan destination path: - If `project_dir` is set (from `--project` or the brief's `project_dir` frontmatter field): **plan destination = {project_dir}/plan.md**. - Otherwise: derive slug and date — if the brief has frontmatter `slug` and `created`, use them; otherwise extract from the brief filename. Destination: `.claude/plans/trekplan-{YYYY-MM-DD}-{slug}.md`. Collect all research briefs (from `--research` flag and auto-discovered `{project_dir}/research/*.md`). Report to the user: ``` Planning pipeline running in foreground. Brief: {brief_path} Project: {project_dir or "-"} Plan: {plan destination} Research briefs: {N} Architecture note: {present | none} ``` Then continue to the next phase inline. > **Why foreground (for now)?** The planning-orchestrator was moved out of > background mode in v2.4.0 because, before Claude Code 2.1.172, the harness > did not expose the Agent tool to sub-agents, so an orchestrator launched > with `run_in_background: true` could not spawn the documented exploration > swarm (`architecture-mapper`, `task-finder`, `plan-critic`, etc.) and > silently degraded to single-context reasoning. As of CC 2.1.172 sub-agents > can spawn sub-agents (up to 5 levels deep), so that block no longer holds — > a delegated redesign is under evaluation (see > `docs/cc-upgrade-2.1.181-decision-matrix.md`, W1/CC-26). Until then, running > the phases inline in main context keeps the swarm intact. --- **All remaining phases run inline in the main command context.** --- ## Phase 4 — Codebase sizing Determine codebase scale to decide whether convention-scanner runs. Run via Bash: ``` find . -type f \( -name "*.ts" -o -name "*.tsx" -o -name "*.mts" -o -name "*.cts" -o -name "*.js" -o -name "*.jsx" -o -name "*.mjs" -o -name "*.cjs" -o -name "*.py" -o -name "*.go" -o -name "*.rs" -o -name "*.java" -o -name "*.rb" -o -name "*.c" -o -name "*.cpp" -o -name "*.h" -o -name "*.cs" -o -name "*.swift" -o -name "*.kt" -o -name "*.sh" -o -name "*.md" \) -not -path "*/node_modules/*" -not -path "*/.git/*" -not -path "*/vendor/*" -not -path "*/dist/*" -not -path "*/build/*" | wc -l ``` Classify: - **Small** (< 50 files) - **Medium** (50–500 files) - **Large** (> 500 files) Report: ``` Codebase: {N} source files ({scale}). Deploying exploration agents. ``` ## Phase 4b — Brief review First check whether `/trekbrief` already reviewed exactly this text: ```bash node ${CLAUDE_PLUGIN_ROOT}/lib/validators/brief-review-stamp.mjs --check "{brief_path}" ``` Exit 0 (`current`): the body is unchanged since `/trekbrief`'s brief-reviewer gate passed. Skip the review, say so in one line ("Brief review: skipped — unchanged since /trekbrief's review"), and continue to Phase 5. Exit 1 (`stale`: edited after that review; `absent`: no stamp — a gate that did not pass, or a brief from another producer) or 2 (could not run): review it as below (operator decision 2026-10-08). Launch the **brief-reviewer** agent. It has `voyage:writing-criteria` and `voyage:reviewing-adversarially` preloaded through its `skills:` line; name both in the prompt anyway, so the rules hold even where preloading did not happen. Prompt: "Review this task brief for quality: {brief_path}. Check completeness, consistency, testability, scope clarity, and research-plan validity. Follow the writing-criteria skill (each success criterion is one command the criteria runner accepts, and it can go red) and the reviewing-adversarially skill. Read local files only inside the repo under exploration, plus paths this prompt gives you (the brief, the plan, and templates it names)." Pass `model: {phase_signal_result.model}` at this spawn; without it (the `--brief` branch, where the resolver does not run, or a resolver that printed nothing) the agent's own `model:` applies. Handle the verdict: - **PROCEED** — continue to Phase 5. - **PROCEED_WITH_RISKS** — continue, carry flagged risks as `[ASSUMPTION]` in the plan. - **REVISE** — present findings and ask the user for clarification (foreground is the only mode). If the user force-stops, carry outstanding findings as `[ASSUMPTION]` entries. ## Phase 5 — Parallel exploration (specialized agents + research) **If mode = quick:** Do NOT launch any exploration agents. Instead, run a lightweight file check: - `Glob` for files matching key terms from the brief's task/intent (up to 3 patterns) - `Grep` for function/type definitions matching key terms (up to 3 patterns) Report findings as: ``` Quick scan: {N} potentially relevant files found via Glob/Grep. No agent swarm — proceeding directly to planning. ``` Then skip Phase 6 (deep-dives) and proceed to Phase 7 (Synthesis) with only the quick-scan results. --- **All other modes:** Launch exploration agents **in parallel** (all in a single message). Use the specialized agents from the `agents/` directory. > **Never pass the Agent tool's `name` parameter — at this or any other spawn > site in this command.** `name` does not label a subagent, it changes its kind: > the spawn is recorded as `taskKind: "in_process_teammate"` (`spawnDepth: 0`) > instead of a subagent (`spawnDepth: 1`). A teammate's final assistant text is > not a return value — it reaches the orchestrator only if the teammate itself > calls `SendMessage(to: "main")`, and every agent in `agents/` declares a > `tools:` allowlist without SendMessage. The agent still runs and still > produces correct output; the result is simply never delivered, so the phase > presents as a hung agent that no re-prompting can revive. Measured > 2026-08-17: named 0/5 returned, unnamed 3/3. Mechanism, denominators, and the > on-disk recovery path: `docs/agent-return-channel-defect.md`. **All agents run for all codebase sizes.** | Agent | Small | Medium | Large | Purpose | |-------|-------|--------|-------|---------| | `architecture-mapper` | Yes | Yes | Yes | Codebase structure, patterns, anti-patterns | | `dependency-tracer` | Yes | Yes | Yes | Module connections, data flow, side effects | | `risk-assessor` | Yes | Yes | Yes | Risks, edge cases, failure modes | | `task-finder` | Yes | Yes | Yes | Task-relevant files, functions, types, reuse candidates | | `test-strategist` | Yes | Yes | Yes | Test patterns, coverage gaps, strategy | | `git-historian` | Yes | Yes | Yes | Recent changes, ownership, hot files, active branches | | `research-scout` | Conditional | Conditional | Conditional | External docs (only when unfamiliar tech detected AND no research brief covers it) | | `convention-scanner` | No | Yes | Yes | Coding conventions, naming, style, test patterns | research-scout's web search is not a local read; the line above bounds its local reads only. The session decomposer (`--decompose`) is not an exploring or reviewing agent and does not carry the line. ### Always launch (all codebase sizes): Pass `model: {phase_signal_result.model}` at this spawn; without it (the `--brief` branch, where the resolver does not run, or a resolver that printed nothing) the agent's own `model:` applies. **architecture-mapper** — full codebase structure, tech stack, patterns, anti-patterns. Prompt: "Analyze the architecture of this codebase. The task being planned is: {task}. Brief file: {brief_path} — read it first. Read local files only inside the repo under exploration, plus paths this prompt gives you (the brief, the plan, and templates it names)." **dependency-tracer** — module connections, data flow, side effects for task-relevant code. Prompt: "Trace dependencies and data flow relevant to this task: {task}. Focus on modules that will be affected by the implementation. Brief file: {brief_path} — read it first. Read local files only inside the repo under exploration, plus paths this prompt gives you (the brief, the plan, and templates it names)." **risk-assessor** — risks, edge cases, failure modes, technical debt near task area. Prompt: "Assess risks and failure modes for implementing this task: {task}. Check for complexity hotspots, security boundaries, and technical debt in the relevant code. Brief file: {brief_path} — read it first. Read local files only inside the repo under exploration, plus paths this prompt gives you (the brief, the plan, and templates it names)." **task-finder** — all files, functions, types, and interfaces directly related to the task. Prompt: "Find all code relevant to this task: {task}. Include existing implementations that solve similar problems, API boundaries, database models, configuration files. Report file paths and line numbers for every finding. Brief file: {brief_path} — read it first. Read local files only inside the repo under exploration, plus paths this prompt gives you (the brief, the plan, and templates it names)." **test-strategist** — existing test patterns, coverage gaps, test strategy. Prompt: "Analyze the test infrastructure and design a test strategy for this task: {task}. Discover existing patterns and identify coverage gaps. Brief file: {brief_path} — read it first. Read local files only inside the repo under exploration, plus paths this prompt gives you (the brief, the plan, and templates it names)." **git-historian** — recent changes, code ownership, hot files, active branches. Prompt: "Analyze git history relevant to this task: {task}. Brief file: {brief_path} — read its Constraints and Non-Goals for files it keeps unchanged, and never recommend changing one. Report recent changes, ownership, hot files, and active branches that may affect planning. Name the remote as `git remote -v` shows it. Read local files only inside the repo under exploration, plus paths this prompt gives you (the brief, the plan, and templates it names)." ### Launch for medium+ codebases (50+ files): **Convention Scanner** — use the `convention-scanner` plugin agent (model: phase_signal_result.model, the agent's frontmatter as the fallback) for medium+ codebases only. Prompt: "Discover the coding conventions relevant to this task: {task}. Brief file: {brief_path} — read it first. Read local files only inside the repo under exploration, plus paths this prompt gives you (the brief, the plan, and templates it names). Provide concrete examples from the codebase, not generic advice." ### Conditional: External research After reading the brief, determine if the task involves technologies, APIs, or libraries that are: - Not clearly present in the codebase - Being upgraded to a new major version - Being used in an unfamiliar way **Skip research-scout** for any topic already answered by an attached research brief. If the brief's `research_status == complete` and all `Research Plan` topics have corresponding research files, skip research-scout entirely. If yes (and not covered by attached briefs): launch **research-scout** in parallel with the other agents. Pass `model: {phase_signal_result.model}` at this spawn; without it (the `--brief` branch, where the resolver does not run, or a resolver that printed nothing) the agent's own `model:` applies. Prompt: "Research the following technologies for this task: {task}. Specific questions: {list specific questions about the technology}. Technologies to research: {list}. Brief file: {brief_path} — read it first. Read local files only inside the repo under exploration, plus paths this prompt gives you (the brief, the plan, and templates it names)." If no external technology is involved or all topics are covered by briefs: skip research-scout and note: "No external research needed — covered by research briefs / well-represented in codebase." ## Phase 6 — Targeted deep-dives After all Phase 5 agents complete, review their results and identify **knowledge gaps** — areas where exploration was too shallow to plan confidently. Common reasons for deep-dives: - A critical function was found but its implementation details are unclear - A dependency chain needs tracing to understand side effects - A test pattern was identified but the test infrastructure needs more detail - A risk was flagged but the actual impact needs verification For each significant gap, spawn a targeted deep-dive agent (model: phase_signal_result.model, else opus — Explore is Claude Code's built-in agent and has no Voyage frontmatter to fall back to, subagent_type: "Explore") with a narrow, specific brief. Each deep-dive prompt carries these two lines: Brief file: {brief_path} — read it first. Read local files only inside the repo under exploration, plus paths this prompt gives you (the brief, the plan, and templates it names). Launch up to 3 deep-dive agents in parallel. If no gaps exist, skip this phase and note: "Initial exploration was sufficient — no deep-dives needed." ## Phase 7 — Synthesis After all agents complete (initial + deep-dives + research), synthesize: 1. Read all agent results carefully 2. Identify overlaps and contradictions between agents 3. Build a mental model of the codebase architecture 4. Catalog reusable code: existing functions, utilities, patterns 5. Integrate research findings with codebase analysis 6. Note remaining gaps — things you cannot determine from code or research (these become assumptions in the plan, marked explicitly) 7. For each finding, track whether it came from **codebase analysis** or **external research** — the plan must distinguish these sources Do NOT write this synthesis to disk. It is internal working context only. ## Phase 8 — Deep planning > **Schema-drift defense (sealed inline so this contract survives even when > `agents/planning-orchestrator.md` is not implicitly loaded by the session model).** > > The plan you write MUST satisfy these regexes. The executor parses with > strict regex matching; any deviation breaks parsing and forces a re-plan. > > ``` > STEP_HEADING_REGEX = /^### Step (\d+):\s+(.+?)\s*$/m > FORBIDDEN_HEADING_REGEX = /^(?:##|###) (?:Fase|Phase|Stage|Steg) \d+/m > ``` > > **FORBIDDEN headings** (parser rejects these — do not emit them under > Implementation Plan): > - `## Fase 1`, `### Fase 1` — Norwegian narrative format > - `## Phase 1`, `### Phase 1` — narrative phase format > - `## Stage 1`, `### Stage 1` — narrative stage format > - `## Steg 1`, `### Steg 1` — Norwegian step word > - `### 1.` or `### 1)` — numbered without "Step" > - `### Step 1 —` (em-dash instead of colon) > - Any heading that doesn't match `STEP_HEADING_REGEX` > > **REQUIRED step shape** — copy this canonical example verbatim, substituting > file paths, descriptions, and patterns. Preserve the exact heading format, > bullet field names, and Manifest YAML structure. Do not invent new field > names. Do not skip fields. Do not nest steps under sub-headings. > > ````markdown > ### Step 1: Add JWT verification middleware > > - **Files:** `src/middleware/jwt.ts` > - **Changes:** Create new middleware function `verifyJWT(req, res, next)` that reads `Authorization: Bearer ` header, verifies signature with `process.env.JWT_SECRET`, attaches decoded payload to `req.user`, and returns 401 on invalid/missing token. (new file) > - **Reuses:** `jsonwebtoken.verify()` (already in package.json), pattern from `src/middleware/cors.ts` > - **Interface out:** `verifyJWT(req, res, next)`; sets `req.user = {id, roles}` — read by Step 2 > - **Review focus:** an expired token and a token signed with another key — pinned by `src/middleware/jwt.test.ts` > - **Test first:** > - File: `src/middleware/jwt.test.ts` (new) > - Verifies: valid token attaches user; invalid token returns 401; missing header returns 401 > - Pattern: `src/middleware/cors.test.ts` (follow this style) > - **Verify:** `npm test -- jwt.test.ts` → expected: `3 passing` > - **Regression:** `npm test` → expected: exit 0 > - **On failure:** revert — `git checkout -- src/middleware/jwt.ts src/middleware/jwt.test.ts` > - **Checkpoint:** `git add src/middleware/jwt.ts src/middleware/jwt.test.ts && git commit -m "feat(auth): add JWT verification middleware"` > - **Manifest:** > ```yaml > manifest: > expected_paths: > - src/middleware/jwt.ts > - src/middleware/jwt.test.ts > min_file_count: 2 > commit_message_pattern: "^feat\\(auth\\): add JWT verification middleware$" > bash_syntax_check: [] > forbidden_paths: > - src/middleware/cors.ts > must_contain: > - path: src/middleware/jwt.ts > pattern: "verifyJWT" > ``` > ```` > > **plan_version 1.8 or later additions** (the validator enforces them; 1.7 plans stay > valid): `Test first:` with `File:` and `Verifies:` on EVERY step; exactly the > optional fields `Interface in:`, `Interface out:`, `Review focus:` (never > empty when present), plus `Regression:` below; at least one step with `End-to-end:` and a backticked > command — the "run the thing" step; the header line carries > `` `plan_version: 1.9` · `ceremony: ` ``; an architectural plan carries > `## Design` (see "Design part" below); and every check the run executes can > run — each `## Verification` criterion, the first backticked span of each > `Verify:` (the step's test command) and each `End-to-end:` command pass the > criteria runner's allowlist, and each `End-to-end:` command also stands under > `## Verification` (`PLAN_VERIFICATION_NOT_RUNNABLE`, > `PLAN_STEP_VERIFY_NOT_RUNNABLE`, `PLAN_END_TO_END_NOT_RUNNABLE`, > `PLAN_END_TO_END_NOT_VERIFIED`). > > **plan_version 1.9 additions** (the validator enforces them on a 1.9 plan; > 1.8 and 1.7 plans are read as before, with the warning > `PLAN_STEP_PATH_UNTICKED` for a path outside backticks): the file first on > every line. Each `Files:` entry (the field's first line and each list item) > and each `Test first:` `File:` line opens with its backticked path(s), > separated only by commas or spaces; everything from the first other text on > is description and is never read. So every path stands before any annotation: > `` `src/a.mjs`, `src/b.mjs` (new) ``, never `` `src/a.mjs` (new), `src/b.mjs` `` > (the second path would be description); two test files share one line, > `` File: `a.test.mjs`, `b.test.mjs` (new) ``. A line that is no list item > continues the entry above it, so a list wrapped after a comma keeps its paths (`` `src/a.mjs`, `` with > `` `src/b.mjs` `` on the next line names both) and a wrapped description stays description: once the > entry so far does not end with a comma, a wrapped line is description even when it opens with a backticked > span (operator decision 29), and a `File:` line with nothing after it takes its first wrapped line. The > `File:` line may open with `-`, `*`, `+`, `1.` or `1)`, and any list item (the `Verifies:` line too) ends it. > A 1.9 step always names a file: an entry that does not open with a backticked path, the bare word none > (written without backticks), or an empty > `Files:` is `PLAN_STEP_PATH_NOT_FIRST`; a leading span that is no path (a > call, an option, a URL) is `PLAN_STEP_PATH_NOT_A_PATH`. > So is a backticked placeholder (`` `none` ``, `` `TBD` ``, `` `TODO` ``, > `` `TBA` ``, `` `N/A` ``, `` `NA` ``, `` `...` ``) and a mixed-case bare name such as > `` `Parser` `` (no `.` or `/`, neither in capitals like `LICENSE` nor a build > file like `Makefile`), by operator decision 22: write `./Name` for such a > file. The canonical step above already opens each line with its path. > > **Two step rules at every plan_version** (no version bump; a plan without > the field is unchanged): the optional `Regression:` field (K10) holds ONE > backticked command the criteria runner accepts (`voyage:writing-criteria`) — > usually `npm test`, the suite the step must not break. `Verify:` stays the > step's own test, the one that is red first; `Regression:` is what the > executor runs green before the checkpoint, so a step whose red test is a > script can still keep the frozen suite green. Write it on a step that can > break existing tests; leave it out otherwise. A `Regression:` that can never > run is `PLAN_STEP_REGRESSION_NOT_RUNNABLE`. And `On failure:` (K11) opens with > one of `revert`, `retry`, `skip`, `escalate` — the words `/trekexecute` > reads — then the specifics; any other opening is the warning > `PLAN_STEP_ON_FAILURE_UNKNOWN`. A step whose `Files:` are all tests is the > warning `PLAN_STEP_TESTS_ONLY`: the test for a behaviour belongs in the step > that builds it (see "Steps are vertical slices" below). > > **Validator self-check (mandatory after writing `plan.md`):** run > `node ${CLAUDE_PLUGIN_ROOT}/lib/validators/plan-validator.mjs --strict --json {plan_path}` > and re-revise the plan if it fails. The validator is the source of truth for > heading shape, manifest presence, and required-field coverage. If > `${CLAUDE_PLUGIN_ROOT}` is unset (rare in practice), fall back to the > equivalent path under your validators cache or the repo's `lib/validators/`. Read the brief file (from `--brief` or `--project`). Read the plan template: @${CLAUDE_PLUGIN_ROOT}/templates/plan-template.md **Ceremony.** Read `ceremony:` from the brief's frontmatter: `small`, `bounded` or `architectural`. Absent means `architectural` (heaviest on doubt). Write it into the plan's header line. Only `architectural` gets the design part. Write the plan following the template structure. The plan MUST include: ### Required sections 1. **Context** — Why this change is needed. Use the brief's **Intent** verbatim or tightly paraphrased. The plan's motivation must trace directly to the brief. **Global Constraints** follows it: the brief's Constraints and NFRs that bind more than one step, quoted verbatim (exact values, never paraphrased). **Design** follows that, for `ceremony: architectural` only — see "Design part" below. 2. **Codebase Analysis** — Tech stack, patterns, relevant files, reusable code, external tech researched. Every file path must be real (verified during exploration). 3. **Research Sources** — If any research briefs or research-scout was used: table of technologies, sources, findings, and confidence levels. Omit if none. 4. **Implementation Plan** — Ordered steps. Each step specifies: - Exact files to modify or create (with paths) - What changes to make and why - Which existing code to reuse - Dependencies on other steps - Whether the step is based on codebase analysis or external research - **Test first:** — the test file and what it verifies, on EVERY step, written in the step that builds the behaviour it tests - **Interface in:** / **Interface out:** — what the step consumes (and which earlier step or existing code produces it) and what it produces for later steps. Write them whenever a step hands something to another step; a step's `Interface in:` must match an earlier `Interface out:`. - **Review focus:** — inputs the brief implies but no test exercises yet, each pinned to a test; and any Global Constraint the step could break, quoted verbatim. - **Regression:** (optional, K10) — the one suite command run green before the checkpoint, on a step that can break existing tests - **On failure:** — opens with the recovery action (`revert`, `retry`, `skip` or `escalate`, K11), then the specifics - **Checkpoint:** — `git add` of the step's Files and test files, then the git commit, after success Steps are vertical slices: each cuts a narrow but complete path through the layers it touches and is verifiable on its own. Never "all the tests, then all the code". Preparatory refactoring comes first as its own steps; a wide change goes expand → migrate → contract. **The test for a behaviour belongs in the step that builds it.** A step cannot consist of only tests for behaviour an earlier step delivered: at its start point that behaviour already exists, so its tests pass there and it can never be proven red — `/trekexecute` stops on it (`not-red-at-base`, stop class 4). The voyage-lekerepo trial (2026-10-09) lost a run that way to a step that only added `tests/e2e.sh` and a guard script for step 1's behaviour. Put such tests in the step that builds the behaviour; the validator warns on a step whose `Files:` are all tests (`PLAN_STEP_TESTS_ONLY`). **The "run the thing" step.** At least one step carries `End-to-end: \`\` → expected: `: the product run the way a user runs it (the CLI, the server and a request, the app; for iOS, the simulator). Without it the result is "not verified end to end", never green. To see and drive the app, use Claude Code's built-in `run` skill; the verdict is still the `End-to-end:` command, because `run` gives no exit code. The command passes the criteria runner's allowlist — the product's own binary does not, so the run is wrapped in a script: `End-to-end: \`bash tests/e2e.sh\``. The same command is also listed under `## Verification`: Phase 7 of `/trekexecute` runs that section, and a passed criterion that runs the step's `End-to-end:` command is what verifies the run end to end. `End-to-end:` rides on the last step that builds behaviour, with `tests/e2e.sh` in that step's `Files:`: a step of its own that only adds the script is a step of only tests, and it can never be proven red. 10. **Execution Strategy** — For plans with > 5 steps: group steps into sessions (3–5 steps each), organize sessions into waves (parallel where independent), specify scope fences per session. Omit for plans with ≤ 5 steps. 5. **Alternatives Considered** — At least one alternative approach with pros/cons and reason for rejection. 6. **Risks and Mitigations** — From the risk-assessor findings and the brief's open questions. What could go wrong and how to handle it. 7. **Test Strategy** — From the test-strategist findings (if available). What tests to write and which patterns to follow. 8. **Verification** — Reuse the brief's **Success Criteria** as the baseline. Each criterion must be an executable command or observable condition. The heading is **exactly `## Verification`** and the criteria are written in one of two forms. This is not style: `lib/verification/criteria-runner.mjs` is what runs this section in trekexecute Phase 7, and it reads those two forms and nothing else — `## Verification (acceptance)`, `### Verification`, an untagged fence or a table all parse to zero criteria, which fells the run without verifying anything. - a bullet whose FIRST backticked span is the command: ```markdown - [ ] `npm test` -> expected: exit 0 ``` - or a shell-tagged fence, one command per line: ```bash npm test node --test tests/lib/x.test.mjs ``` Each command is written by the `voyage:writing-criteria` skill (use it by name before you write this section and the steps' `Verify:`, `Regression:` and `End-to-end:` lines): one command the criteria runner accepts, in plain words, a script under `tests/` (`bash tests/