/code-review high on main..HEAD: the four commands that parse their own arguments in prose (/trekbrief, /trekplan, /trekresearch, /trekexecute) lost their --profile handling, and /trekresearch its --engine, so a typed value became the path or the question. Each now strips a retired flag with its value; the arg parser retires --profile only for the commands that had it (not /trekendsession) and --engine for /trekresearch, seen red first. Stale lines R-b left: architecture's hook row (9 scripts) and bridge agent, the gap row's removed event ledger, README's contrarian marker, and a dangling "also" in /trekexecute Phase 8. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
20 KiB
Voyage — Architecture, project layout, state, terminology
Imported from CLAUDE.md via pointer.
Quality infrastructure (v3.4.0)
lib/ contains zero-dep validators, parsers, and autonomy primitives wired into the four commands:
lib/util/{frontmatter,result,atomic-write,autonomy-gate}.mjs— shared YAML-frontmatter parser + Result helpers +atomicWriteJson(path, obj)for tmp+rename writes +--gatesflag parser (v3.4.0)lib/parsers/{plan-schema,manifest-yaml,arg-parser,jaccard,finding-id}.mjs— pure parsers (no I/O), unit-tested.manifest-yamlextended in v3.4.0 with additiveskip_commit_check+memory_writeflags (forward-compat: unknown keys ignored)lib/review/{rule-catalogue,plan-review-dedup}.mjs— version-pinned rule catalogue (17 keys) + Phase 9 inline dedup helpers (v3.4.0)lib/review/{verdict-gate,engine-findings,recurrence}.mjs— the review gate (K7: 0 ALLOW, or WARN with every counting MAJOR answered · 1 BLOCK · 2 never green), Claude Code/code-review+/security-reviewfindings → reviewer payload, recurring finding classes → operator-approved project-memory lines (review_version 1.2);lib/review/fill-finding-ids.mjscomputes the coordinator's@@ID_<n>@@placeholders over(file, line, rule_key);lib/validators/brief-review-stamp.mjslets/trekplanskip a brief review/trekbriefalready ran on the same textlib/validators/{brief,research,plan,progress,session-state}-validator.mjs— schema validators with CLI shims (node lib/validators/X.mjs --json <path>)lib/validators/architecture-discovery.mjs— drift-WARN external-contract discovery forarchitecture/overview.mdlib/validators/query-privacy-gate.mjs— gates an outbound research query before it leaves the machine (no command calls it now: its callers were the removed STORM steps); the hard-block tier (secret-shaped strings) is not operator-overridable, so a query that trips it must be reformulated rather than forced through. CLI shim:node lib/validators/query-privacy-gate.mjs "<query>"
Wiring points (replaces previous prose-grep instructions):
/trekbriefPhase 4g →brief-validator(post-write sanity check)/trekplanPhase 1 →brief-validator --soft,research-validator --dir,architecture-discovery/trekplanPhase 8 →plan-validator --strict(replaces 3grep -cEcalls)/trekexecute --validate→plan-validator --strict+progress-validator
Tests under tests/**/*.test.mjs (~290 tests, 0 deps). npm test is the fork-readiness gate. v3.4.0 adds: hook baseline regression pins (tests/hooks/{path-guard,bash-guard}.test.mjs exercising pre-write-executor.mjs + pre-bash-executor.mjs denylist BLOCK paths).
Doc-consistency test at tests/lib/doc-consistency.test.mjs pins agent-table count, command-table coverage, plan_version invariant, Handover 7 presence, and session-state-validator CLI shim.
docs/HANDOVER-CONTRACTS.md is the single source of truth for the 7 pipeline handovers (brief→research, research→plan, architecture→plan EXTERNAL, plan→execute, progress.json resume, review→plan, .session-state.local.json). Read it before changing any artifact format.
hooks/scripts/pre-compact-flush.mjs (PreCompact event, CC v2.1.105+) fixes a documented P0: keeps progress.json in sync with git history before context compaction so --resume works after long conversations. Atomic write, monotonic only, never blocks compaction.
hooks/scripts/session-title.mjs (UserPromptSubmit, CC v2.1.94+) sets sessionTitle to voyage:<command>:<slug> for voyage-command invocations. Helps parallel sessions identify themselves in process lists.
hooks/scripts/post-compact-flush.mjs (PostCompact event, v3.4.0) re-injects .session-state.local.json after context compaction so multi-session work survives a compaction boundary. Companion to pre-compact-flush.mjs (which writes the state file before compaction); together they form the rehydrate cycle that keeps /trekcontinue reliable across long-running multi-session work.
Architecture
Brief: 7-phase workflow: Parse mode → Create project dir → Phase 3 completeness loop (section-driven, no question cap) → Phase 4 draft/review/revise with brief-reviewer as stop-gate (max 3 iterations; gate = all dimensions ≥ 4 and research plan = 5) → Finalize (brief.md on pass, or brief_quality: partial on cap/force-stop) → Manual/auto opt-in. Always interactive. Auto mode runs research + plan inline in the main context (v2.4.0).
Research: Foreground workflow (v2.4.0): Parse mode → Interview → Parallel research swarm (5 local + 4 external, spawned from main context) → Follow-ups → Triangulation → Synthesis + brief. With --project, writes to {dir}/research/NN-slug.md.
Plan: Foreground workflow (v2.4.0): Parse mode (validate brief input) → Codebase sizing → Brief review (brief-reviewer) → Parallel exploration (6-8 agents, spawned from main context) → Deep-dives → Synthesis (with architecture-note cross-reference if present) → Planning → Adversarial review (plan-critic + scope-guardian) → Present/refine → Handoff. With --project, writes to {dir}/plan.md and auto-detects {dir}/architecture/overview.md (produced by an opt-in upstream architect plugin if installed; not bundled).
Decompose: Parse plan → Analyze step dependencies → Group into sessions → Identify parallel waves → Generate session specs + dependency graph + orders.md (one starter line per session).
Execute: Parse plan → Security scan (Phase 2.4) → Detect Execution Strategy → Single-session (step loop) or multi-session (one wave at a time: a worktree plus a session order and starter per session; the user opens every session, and a re-run merges the wave — Voyage never starts a session) → Phase 7.5 manifest audit → Phase 7.6 bounded recovery (if partial) → Phase 8 atomically writes progress.json + .session-state.local.json (Handover 7) → Report. With --project, reads {dir}/plan.md. Phase 2.55 (pre-flight stop) and Phase 4 (entry-condition stop) also write .session-state.local.json so /trekcontinue can surface the stop and prompt for next steps.
Continue: /trekcontinue reads {dir}/.session-state.local.json (Handover 7), validates schema-v1 via session-state-validator, narrates a 3-line summary (project / next-session-label / brief-path), and immediately begins executing the next session. Auto-discovers active project state files under .claude/projects/*/.session-state.local.json if no explicit <project-dir> argument. Operator-invoked only — never auto-loaded via SessionStart. The /trekendsession helper is the informal-flow producer: writes the same state file for ad-hoc multi-session handovers that don't run through /trekexecute.
Delegate the engine, keep the policy (cross-cutting; audited S32, 2026-06-20). Every swarm and interview in the pipeline rides a native Claude Code primitive and re-implements no engine of its own: parallel sub-agent fan-out is a single-message multi-Agent-call dispatch (research swarm, exploration swarm, reviewer swarm), and interview turn-taking is AskUserQuestion (brief Phase 3, the research interview, the trekplan research-status gate, the trekreview scope gate). Voyage's value is the policy layered on top — never the scheduler, concurrency loop, or menu loop underneath: typed agent roles + effort defaults + codebase-size scaling (exploration); 4-angle decomposition (docs/community/security/contrarian) + per-source schemas + triangulation (research); the 17-key rule catalogue + no-cross-feed isolation + deterministic dedup/verdict (review); the section-driven completeness loop + framing gate (brief). Concretely: the brief's Phase-3 "selection rule" picks which question to ask (policy); AskUserQuestion does the asking (engine). The V01/V07/V08/V11/V24 balance-analysis audit confirmed all five already delegate natively — no engine re-implementation found; the doc-consistency test (tests/lib/doc-consistency.test.mjs § S32) pins the native-delegation prose so a hand-rolled engine cannot creep back in.
Operator-UX guarantee (since v5.0.2): /trekbrief, /trekplan, and /trekreview MUST always emit (a) a plain file://<abs path> URL AND (b) a copy-pasteable open file://<abs path> command in the final report block. The file:// URL must use an ABSOLUTE path (not relative or ~/-prefixed) so terminals with cmd+click support (Ghostty, iTerm2, modern Terminal.app) can resolve it without shell interpretation. This is a non-negotiable operator-UX contract — the doc-consistency test pins both forms in all three commands' final report blocks.
Operator-annotation HTML (v5.0.3): the last step of /trekbrief, /trekplan, and /trekreview runs scripts/annotate.mjs against the just-written .md and prints the resulting file://<abs path> link. The HTML is self-contained (zero npm deps, zero external network, design-system-styled, light + dark + print) and modelled on an existing annotation surface the operator pointed at. The operator opens the file, the document renders as a proper article (headings / paragraphs / lists / tables / code / quotes — every element gets a stable data-anchor-id). In annotation mode (default ON, pencil-toggle in topbar), the operator can select any text or click any element → a form popover opens at the cursor with: section context auto-detected from nearest h1/h2, the anchored snippet (selection if any, else element text), three intent buttons (Fix / Change / Question), comment textarea, Save/Cancel. The sidebar (Show annotations button) lists every annotation grouped by section with intent badge + snippet + comment + delete; clicking a card scrolls to and flashes the source element. Copy Prompt assembles a structured markdown (### N. [Intent] Section: <…> + Quote: «…» + Comment: …) and copies to clipboard. Persistence: localStorage keyed on absolute artifact path (voyage-annotate:v2:<abs path>). v5.0.0 removed the v4.2/v4.3 bespoke playground SPA + /trekrevise + Handover 8; v5.0.1 pointed at /playground document-critique (Claude-leads, wrong direction); v5.0.2 was operator-led but too thin (line-click + freeform note, no intents); v5.0.3 matches the annotation reference the operator first pointed at, with pencil-toggle / selection capture / intent categories / popover form / structured export. See CHANGELOG.md § v5.0.3.
Security: 3-layer defense-in-depth: plugin hooks (pre-bash-executor, pre-write-executor), prompt-level denylist (holds even if a hook does not fire), pre-execution plan scan (Phase 2.4). Hard Rules 14-16 enforce verify command security, repo-boundary writes, and sensitive path protection.
Pipeline: /trekbrief produces the task brief. /trekresearch --project <dir> fills in {dir}/research/. /trekplan --project <dir> reads brief + research to produce {dir}/plan.md (and auto-discovers {dir}/architecture/overview.md if an opt-in upstream architect plugin produced one). /trekexecute --project <dir> executes and writes {dir}/progress.json. /trekreview --project <dir> produces {dir}/review.md. /trekbrief, /trekplan, and /trekreview each end by running scripts/annotate.mjs on the just-written artifact, producing {dir}/{artifact}.html — a self-contained operator-annotation surface — and printing the file:// link. The operator opens it, clicks lines, writes their own notes, copies a structured prompt, pastes back, Claude revises the .md. All artifacts live in one project directory.
Project-directory contract (v3.0.0): trekplan owns the directory layout below. The architecture/ subdirectory is opt-in and produced by an opt-in upstream architect plugin (not bundled) — the architect plugin is no longer publicly distributed, but the architecture/overview.md slot remains available for any compatible producer.
.claude/projects/{YYYY-MM-DD}-{slug}/
brief.md ← trekbrief writes; everyone reads
brief.html ← trekbrief annotates (operator-annotation HTML, gitignored, re-buildable from brief.md)
research/*.md ← trekresearch writes; plan + architect read
architecture/ ← OPT-IN, owned by an opt-in upstream architect plugin (not bundled)
overview.md
gaps.md
plan.md ← trekplan writes; trekexecute reads
plan.html ← trekplan annotates
progress.json ← trekexecute writes
review.md ← trekreview writes; trekplan reads (Handover 6)
review.html ← trekreview annotates
The .html files (brief.html, plan.html, review.html) are produced by scripts/annotate.mjs and live alongside their .md siblings in the project directory. They are re-buildable from the .md source at any time (deterministic, byte-identical output on re-run), so they are conventionally gitignored along with the rest of .claude/projects/. Operator annotations live in browser localStorage keyed on the absolute artifact path — they survive refresh and browser-close, but are local to the operator's machine.
No code-level dependency between plugins — the contract is filesystem-level only.
Primitives per step (decision matrix)
Which native Claude Code primitive each pipeline step runs on today, and the alternatives that were considered and where they landed. Companion to Delegate the engine, keep the policy above. The orchestration runs inline in the session, not in a delegated orchestrator agent, because the swarm's results end in the main context anyway (the orchestrator reference docs are removed).
| Step | Primitive today (production) | Alternatives considered (status) |
|---|---|---|
| brief | Inline interview loop → brief.md (framing gate) |
AskUserQuestion as the Q&A engine (recommended, not yet wired); Skill/Workflow auto-orchestration (rejected — one-shot, can't span slash-command/handover boundaries) |
| research | Inline spawns a foreground swarm; MCP per agent¹ | Delegated synthesis-agent (PoC measured Δ main-context ≈ 0 → removed) |
| plan | Inline: parallel explorer swarm → synthesis → adversarial plan-critic |
Delegated orchestrator via nested sub-agents (CC-26 → lean NO, not wired) |
| execute | Inline step loop; multi-session via git worktree + session orders the user runs, wave by wave; deterministic manifest audit |
CC TaskCreate/TodoWrite for progress/resume (insufficient — carries no step status / attempts / SHA / drift → own typed progress.json contract) |
| review | Inline parallel reviewers (no cross-feed) → review-coordinator Judge |
Workflow substrate for Phase 5–6 (bake-off POSITIVE: +4.4 % tokens / +54 % wall-time → shipped opt-in, since removed; wholesale substrate swap declined) |
| continue | Inline reads .session-state.local.json → zero-confirm resume |
CC --resume (transcript replay, not typed work-state → insufficient) |
| cross-cutting | 9 hook scripts: pre-bash + pre-write guards, pre-plan-gate, session-title, post-approval-log, post-edit-check, pre-/post-compact flush, stop-test-lock |
— |
¹ MCP per research agent: docs-researcher → Microsoft Learn + Tavily · community-/security-/contrarian-researcher → Tavily (+ WebSearch/WebFetch). Graceful degradation when an MCP server is absent.
Legend: production = wired and active · not wired = considered, deferred (delegated orchestrator, the AskUserQuestion brief engine).
Model & effort
opus, sonnet, and fable are model aliases, not pinned ids. On the
Anthropic API (verified 2026-10-02 against the Claude Code model-config docs)
the opus alias resolves to Opus 5.5 and sonnet to Sonnet 5.5, both
with default reasoning effort medium; fable resolves to Fable 5.1
(the most capable model in Claude Code), whose default reasoning effort is
high. Other providers resolve opus and sonnet to other versions.
Reasoning effort inherits from the session. Fable 5.1's default reasoning
effort is high, NOT xhigh, and Claude Code saves effort per model, so a level
saved for one model does not carry to another. To run Fable 5.1 at xhigh,
choose it explicitly: /effort xhigh, --effort xhigh, or
CLAUDE_CODE_EFFORT_LEVEL.
Native effort: on agents. Voyage sets the reasoning axis statically on
selected agents, overriding the session level:
- Nine agents pin
high: the retrieval agentstask-finder,git-historian,dependency-tracer,architecture-mapper, the adversarial-reasoning agentsplan-critic,risk-assessor,contrarian-researcher,review-coordinator, and/trekexecute's step helperstep-implementer. No agent pins belowhigh(operator rule, 2026-10-05: standard is Opus 5.5 at effort High). - All other agents: unset → inherits the session's effort level (a session
that nothing sets runs at its model's default —
mediumon Opus 5.5).
Every agent is pinned model: opus. The pin is set in each agent's
frontmatter (operator decision, commit 40d8742). The operator wants Opus on
all Voyage work and accepted the roughly fivefold sub-agent cost against
Sonnet. The glue, mechanical, retrieval and dormant roles were reconsidered
for a Sonnet downgrade (operator, 2026-06-20) and kept on Opus: the pin stays
firm.
Native-effort precedence (harness): env CLAUDE_CODE_EFFORT_LEVEL > frontmatter
effort: > session setting > model default, and a maxEffortLevel setting or
an organization effort cap still limits the result. MAX_THINKING_TOKENS=0 has
no effect on Opus 5.5, Sonnet 5.5 or the Fable models: thinking cannot be turned
off there. availableModels restricts which models can be selected — it does
not bound effort.
State
All artifacts in one project directory (default):
- Project root:
.claude/projects/{YYYY-MM-DD}-{slug}/brief.md+brief.html(task brief from/trekbrief;.htmlis the operator-annotation surface fromscripts/annotate.mjs)research/{NN}-{slug}.md(research briefs from/trekresearch --project)architecture/overview.md+architecture/gaps.md(opt-in, produced by an opt-in upstream architect plugin, not bundled)plan.md+plan.html(from/trekplan --project)sessions/session-*.md(from--decompose)progress.json(from/trekexecute --project)review.md+review.html(from/trekreview --project).session-state.local.json(Handover 7 — gitignored via*.local.json; written by/trekexecutePhase 8/2.55/4 or/trekendsession; read by/trekcontinue)
Legacy paths (still work without --project):
- Research briefs:
.claude/research/trekresearch-{date}-{slug}.md - Plans:
.claude/plans/trekplan-{date}-{slug}.md - Sessions:
.claude/trekplan-sessions/{slug}/session-*.md - Session orders:
.claude/trekplan-sessions/{slug}/orders.md(--decompose) andorders/(/trekexecutePhase 2.6: one order per session,wave.jsonwhile a wave awaits its sessions,merged-waves.json, and each session's archivedwave-W-session-N.progress.json) - Progress:
{plan-dir}/.trekexecute-progress-{slug}.json
Terminology
- Task brief — produced by
/trekbrief. Declares intent, goal, and research plan. Drives planning. - Research brief — produced by
/trekresearch. Answers a specific research question. Feeds planning. - Architecture note — opt-in, produced by an opt-in upstream architect plugin (not bundled; the architect plugin is no longer publicly distributed, but the
architecture/overview.mdfilesystem slot remains available for any compatible producer). Proposes which Claude Code features fit the task with brief-anchored rationale + explicit gaps. When present, enriches planning. - Review — produced by
/trekreview. Independent post-hoc review of delivered code against the task brief. Handover 6 (review → plan) routes BLOCKER + MAJOR findings into/trekplan --brief review.mdfor a remediation plan. The plan's optionalsource_findings:frontmatter list is the audit trail back to the consumed findings. MINOR + SUGGESTION are skipped for v1.0 plan-input. - Session state —
.session-state.local.jsonper project. Handover 7 — produced by any session-end mechanism (/trekexecutePhase 8/2.55/4,/trekendsessionhelper, future graceful-handoff v2.2). Consumed by/trekcontinueto resume the next session in a fresh chat. Schema v1 is forward-compat (unknown top-level keys ignored). Never committed (gitignored via*.local.json).
A project typically has 1 task brief, 0–N research briefs, 0 or 1 architecture note, 0–N reviews (one per review iteration), and 0 or 1 session-state file (overwritten on every session-end).