chore(cleanup): R-b R3 — profiles, phase signals and the effort dialog removed, one fixed path per command

The four profiles, the resolver, the profile validator and docs/profiles.md go;
/trekbrief Phase 3.5 and the brief's phase_signals checks go (an older brief's
key is ignored); MANIFEST_PROFILE_DRIFT and profile_used go. Every Profile,
Composition rule, Sequencing gate and High-effort section leaves the commands.
Decision 209: /trekresearch runs the full swarm with contrarian-researcher as
wave 2 every run; /trekreview and the coordinator run all four passes with no
high-effort normalization. Voyage agents are spawned with no model (their own
model: opus applies); the two built-in spawns pass model "opus". --profile
stays in the parser as a retired flag that swallows its value. §Model & effort
moves to docs/architecture.md; the sequencing-gate eval case goes.

Files removed: 44 (43 from the R3 list + tests/commands/trekreview.test.mjs,
whose every test pinned removed text). Files edited: 43.
Tests: 2467 (2466 pass / 0 fail / 1 skipped) before, 2309 (2309 pass / 0 fail /
0 skipped) after. Durable check: all three groups green, none pending.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-11-07 21:12:57 +01:00
commit 2a35d067d9
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
87 changed files with 225 additions and 4967 deletions

View file

@ -184,9 +184,9 @@ Put the task in one of three size classes. In doubt, take the heaviest that fits
| Class | Typical task | What the pipeline does |
|---|---|---|
| `small` | one change in one place, no new dependency, no interface change, easy to undo | one round, no follow-up; brief-reviewer runs once and its gaps become written assumptions, not questions, written after the review stamp (Step 4e, passed gate, step 4); Phase 3.5 is skipped |
| `bounded` | several files or one module behind a clear boundary, no architecture decision | the round + at most one follow-up; at most one brief-review follow-up; Phase 3.5 asks one question for all four phases |
| `architectural` | a new module, interface, dependency, data model or migration; anything hard to undo | follow-up rounds while answers open new branches; the full brief-review loop; Phase 3.5 asks per phase |
| `small` | one change in one place, no new dependency, no interface change, easy to undo | one round, no follow-up; brief-reviewer runs once and its gaps become written assumptions, not questions, written after the review stamp (Step 4e, passed gate, step 4) |
| `bounded` | several files or one module behind a clear boundary, no architecture decision | the round + at most one follow-up; at most one brief-review follow-up |
| `architectural` | a new module, interface, dependency, data model or migration; anything hard to undo | follow-up rounds while answers open new branches; the full brief-review loop |
- **Said aloud.** State the class and why in one line *before* the round
("This reads as `small`: one setting on one screen, no new dependency."),
@ -445,135 +445,6 @@ Stored: {in git | only on this machine}
Proceeding to draft and review.
```
## Phase 3.5 — Per-phase effort dialog
Phase 3.5 is the v5.1 entry-point for **adaptive-depth execution**. After
Phase 3 has gathered intent / goal / success criteria / research plan, the
operator commits an effort level and (optional) model per downstream phase
(`research`, `plan`, `execute`, `review`). The committed signals are written
to brief frontmatter as a `phase_signals:` list that the four downstream
commands read via their `## Composition rule (v5.1)` section.
### State requirements
Before entering Phase 3.5 the following must be populated:
- `state.intent` — the Phase 3 Intent answer (1+ paragraph)
- `state.goal` — the Phase 3 Goal answer
- `state.success_criteria` — at least one falsifiable SC
- `state.research_plan.topics` — list (may be empty)
If any are absent: skip Phase 3.5 entirely and write `phase_signals_partial:
true` to the draft frontmatter. Do not block.
### By size class (and --quick)
- `small` (and `--quick` while the class stays `small`): skip Phase 3.5
entirely and auto-write `phase_signals_partial: true` to draft frontmatter.
The brief satisfies the v5.1 sequencing gate without the dialog, and the
downstream commands fall back to the profile.
- `bounded`: ask ONE question in the Step 3c round — the tier for all four
phases, with 4 options from the mapping below — and write the same tier
for `research`, `plan`, `execute` and `review`.
- `architectural`: the per-phase dialog below, as one `AskUserQuestion` call
carrying four questions (one per phase).
### Default-derivation heuristic (LLM judgment, not algorithmic)
Before each phase question, propose a default tier marked `(default)`. Use
these signals — they are weak heuristics, not rules:
- `research_topics_count` → high (`high`), low (`low`), absent (`low`)
- `sc_count` (count of falsifiable SCs) → high (≥6 ⇒ `high`), low (≤2 ⇒ `low`)
- Goal complexity: keywords like "rewrite", "migration", "refactor across",
"new platform" ⇒ `high`; "typo", "small bugfix", "docs touch-up" ⇒ `low`
- Otherwise: `standard`
Mix these into one proposed default per phase. Document the proposed tier
in the question body so the operator sees why it was picked.
### The dialog — one call, one tier-coupled question per phase
For `[research, plan, execute, review]`, ask one question each, all four in
one `AskUserQuestion` call, each question with 4 options:
| Option | Maps to phase_signals entry |
|--------|----------------------------|
| **Low effort** | `{phase: <name>, effort: low, model: sonnet}` |
| **Standard (default)** | `{phase: <name>, effort: standard}` *(model omitted — composition falls through to profile)* |
| **High effort** | `{phase: <name>, effort: high, model: opus}` |
| **Fable (max quality)** | `{phase: <name>, effort: high, model: fable}` |
The proposed tier per phase (from the default-derivation heuristic) MUST be
labelled `(default)` and listed first so the operator can one-click
accept. Commit the chosen tiers to an in-memory `effort_state` dict as the
answers come back — no bulk summary-before-commit. A hollow or empty answer
for a phase leaves that phase uncommitted (the force-stop path below).
The mapping table is canonical:
- `low → {effort: low, model: sonnet}` (force sonnet for the low-cost path)
- `standard → {effort: standard}` (model omitted; composition rule resolves via profile)
- `high → {effort: high, model: opus}` (force opus for the high-confidence path)
- `fable → {effort: high, model: fable}` (force Fable 5.1 for the max-quality path)
The fable tier reuses `effort: high` semantics — full swarm, contrarian
always-on; `EFFORT_LEVELS` is unchanged (Voyage effort is orchestration
shape, not model reasoning effort). Model reasoning effort is inherited from
the session: Fable 5.1's default effort is `high`, NOT xhigh. To run xhigh, the
operator chooses it explicitly via `/effort xhigh`, `--effort xhigh`, or
`CLAUDE_CODE_EFFORT_LEVEL` — Claude Code saves effort per model, so a level
saved for one model does not carry to another.
### Force-stop handling
If in answer to the dialog the operator says "stop",
"skip", "enough", "just write it", or similar, do NOT exit silently — apply
the Phase 4f force-stop pattern verbatim:
```
You stopped before committing per-phase signals. Remaining phases:
- {list of phases not yet answered}
The brief will still be valid (v5.1 supports `phase_signals_partial: true`
as a force-stop record). Downstream commands will fall back to the profile
resolver for the un-committed phases.
Continue anyway?
```
Then `AskUserQuestion`:
| Option | Action |
|--------|--------|
| **Answer one more phase** | Return to the next un-answered phase question. |
| **Stop now (record partial)** | Drop any in-progress `effort_state` and set `phase_signals_partial: true` in draft frontmatter. Mutually exclusive with `phase_signals`. Break Phase 3.5. |
This pattern matches Step 4f (line 436-458) so the force-stop UX is
identical across both surfaces.
### Hand-off to Phase 4a
If `effort_state` is fully populated (4 commits, no force-stop): write a
`phase_signals:` block to draft frontmatter — one entry per phase,
preserving the canonical-mapping form above. Omit `model:` for standard
tier (composition falls through to profile).
If `phase_signals_partial: true` was set: write that single line to draft
frontmatter and skip the `phase_signals:` block (mutually exclusive per
validator).
Phase 4a (Step 4a — Draft in memory) reads from `effort_state` /
`phase_signals_partial` and incorporates the appropriate frontmatter block
into the draft brief.
### Sequencing gate (downstream)
`brief_version: 2.1` activates the validator's sequencing gate. If the
final brief reaches `/trekplan`, `/trekresearch`, `/trekexecute`, or
`/trekreview` WITHOUT `phase_signals` and WITHOUT `phase_signals_partial:
true`, the validator emits `BRIEF_V51_MISSING_SIGNALS` and the command
halts with a friendly hint pointing back to `/trekbrief`.
## Phase 4 — Draft, review, and revise
Phase 4 runs a **draft → brief-reviewer → revise** loop. The draft is
@ -1127,22 +998,6 @@ Or:
/trekexecute --validate --project {PROJECT_DIR} # schema check
```
## Profile (v4.1)
Accepts `--profile <name>` where `<name>` is one of `economy`, `balanced`,
`premium`, `fable`, or a custom profile under `voyage-profiles/`. Default: `premium`.
Resolution order (per `lib/profiles/resolver.mjs`):
1. `--profile` flag (source: `flag`)
2. `VOYAGE_PROFILE` environment variable (source: `env`)
3. `premium` default (source: `default`)
Examples:
```
/trekbrief --profile economy
VOYAGE_PROFILE=balanced /trekbrief
```
## Hard rules
1. **Interactive only.** This command requires user input. There is no

View file

@ -268,34 +268,6 @@ If the brief file does not exist (validator emits a warning but does not
fail), print: `Warning: next_session_brief_path "{path}" does not exist on
disk. Cannot continue automatically.` and exit. Do not guess.
## Profile (v4.1) — inheritance from plan-frontmatter
Accepts `--profile <name>` where `<name>` is `economy`, `balanced`, `premium`,
or a custom profile under `voyage-profiles/`. Default: `premium`.
Unlike the other voyage commands, `/trekcontinue` defaults to **inheritance**
from the resumed plan's frontmatter `profile:` field rather than to `premium`.
This keeps a multi-session run consistent across resumptions.
Resolution order (per `lib/profiles/resolver.mjs` `resolveTrekcontinueProfile`):
1. `--profile` flag (source: `flag`) — explicit override, emits stderr advisory
`[voyage] profile inheritance overridden by --profile flag: <plan-profile> → <flag-profile>`
2. `VOYAGE_PROFILE` env-var (source: `env`)
3. Plan-frontmatter `profile:` field (source: `inheritance`) — typical case
4. `premium` default for v4.0-style plans without `profile:` (source: `default`)
The inherited profile drives `phase_models.continue` for the next session's
orchestration. Operators who explicitly want to switch profiles mid-run pass
`--profile <name>` and accept the advisory (e.g. drop from `premium` to
`balanced` mid-run to save cost on later sessions).
Examples:
```
/trekcontinue # inherits from plan.md
/trekcontinue --profile balanced # explicit override + advisory
VOYAGE_PROFILE=economy /trekcontinue # env-var override
```
## Hard rules
- **Idempotent.** Running `/trekcontinue` twice in the same Claude session

View file

@ -1,7 +1,7 @@
---
name: trekexecute
description: Disciplined plan executor — single-session, or multi-session through session orders the user starts, with failure recovery
argument-hint: "[--project <dir>] [--profile <name>] [--gates [true|false|closed|open]] [--fg | --resume | --dry-run | --validate | --step N | --session N] [plan.md]"
argument-hint: "[--project <dir>] [--gates [true|false|closed|open]] [--fg | --resume | --dry-run | --validate | --step N | --session N] [plan.md]"
allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion, Agent, Skill
disallowed-tools: TeamCreate
---
@ -49,21 +49,14 @@ Parse `$ARGUMENTS` for mode flags:
recovery session spec inside the project).
- Continue parsing remaining flags (they combine with `--project`).
- Brief check, once every flag below is parsed: when `{dir}/brief.md`
exists, run the two lines `/trekplan` runs on it (its Phase 1), for the
execute phase; append `--profile {profile}` when the operator passed
`--profile`:
exists, run the line `/trekplan` runs on it (its Phase 1):
```bash
node ${CLAUDE_PLUGIN_ROOT}/lib/validators/brief-validator.mjs --soft --json "{dir}/brief.md"
node ${CLAUDE_PLUGIN_ROOT}/lib/profiles/resolver.mjs --resolve-phase-model --phase execute --brief-path "{dir}/brief.md" [--profile {profile}] --json
```
The validator exits 1 when its `errors` are not empty; read its JSON
either way. Halt only when the validator's `errors` hold
`BRIEF_V51_MISSING_SIGNALS`, with the message from "Sequencing gate
surface" below. Any other error is printed in one line and the run
continues. A validator or resolver that cannot run (no JSON) is "not
measured" in one line, and the run continues. Capture the resolver's
JSON as `phase_signal_result` (Composition rule below). No
`{dir}/brief.md`: skip both lines.
either way. Any error is printed in one line and the run continues. A
validator that cannot run (no JSON) is "not measured" in one line, and
the run continues. No `{dir}/brief.md`: skip the line.
2. If arguments contain `--fg`: extract the file path. Set **mode = foreground**.
3. If arguments contain `--resume`: extract the file path. Set **mode = resume**.
4. If arguments contain `--dry-run`: extract the file path. Set **mode = dry-run**.
@ -95,8 +88,7 @@ Parse `$ARGUMENTS` for mode flags:
(operator decision 2026-10-08: two questions for one merge became one). The
MAIN_MERGE_GATE in Phase 8 is always on, regardless of `gates_mode`: it is
a lock, and the guard's question is the one question.
9. If arguments contain `--profile <name>`: set `profile = {name}`; strip both tokens.
10. Otherwise: the arguments left after every flag above is stripped are the file path.
9. Otherwise: the arguments left after every flag above is stripped are the file path.
Set **mode = execute**.
If no path is provided (and `--project` was not used to derive one), output
@ -111,7 +103,6 @@ Usage: /trekexecute <plan.md>
/trekexecute --validate <plan.md>
/trekexecute --step N <plan.md>
/trekexecute --session N <plan.md>
/trekexecute --profile <name> <plan.md>
/trekexecute --project <dir> --resume
/trekexecute --project <dir> --session N
@ -125,7 +116,6 @@ Modes:
--validate Schema-only check — parse steps + manifests, no security scan, no execution
--step N Execute only step N (foreground)
--session N Execute only session N from the plan's Execution Strategy
--profile Profile for this run's resolver; the step helper and the controller stay on opus
--gates Accepted, pauses on nothing: bare, true or closed = on; false or open = off
Examples:
@ -465,7 +455,6 @@ Determine how to execute this plan:
- `--step N` mode
- `--resume` mode
- `--session N` mode (runs only that session's steps, foreground)
- `phase_signal_result.effort == 'low'` → one session, steps in order, unless a wave is in flight: when `.claude/trekplan-sessions/{slug}/orders/wave.json` exists in the main checkout (the first entry of `git worktree list`), this bullet does not apply and the multi-session path below collects the wave. The check only reads the file and never stops the run.
- Plan has no `## Execution Strategy` section
- Plan has Execution Strategy with only 1 session
@ -2565,7 +2554,7 @@ Default **25** is an independent value from the cap research (practitioner range
10–50; OWASP Agentic ASI08 financial-DoS), tuned down from the research ~50
starting point for a tighter backstop. Operators may override:
`TREKEXECUTE_MAX_RECOVERY_ITERATIONS=10 /trekexecute --project ...`. The
`effort=='low'` single-foreground-loop path and the wave path are both subject to
single-foreground-loop path and the wave path are both subject to
this aggregate ceiling; it is an execution-spec ceiling (enforced via the
`iterations_remaining` counter), not a code-loop edit.
@ -2974,80 +2963,6 @@ run resumes at the lowest wave not yet merged, or re-runs Step 4 and returns to
the gate, and the `clear` command in Step 0 starts the plan over from its first
wave instead.
## Profile (v4.1)
Accepts `--profile <name>` where `<name>` is `economy`, `balanced`, `premium`,
`fable`, or a custom profile under `voyage-profiles/`. Default: `premium`.
Resolution order (per `lib/profiles/resolver.mjs`):
1. `--profile` flag (source: `flag`)
2. `VOYAGE_PROFILE` env-var (source: `env`)
3. Inherited from `plan.md` frontmatter `profile:` field (source: `inheritance`)
4. `premium` default for v4.0-style plans without `profile:` (source: `default`)
The selected profile goes to the resolver. It changes no model here: the step helper and the
controller run opus (Composition rule below), and nothing in this command reads `parallel_agents`.
Examples:
```
/trekexecute --profile economy --project .claude/projects/2026-05-09-add-auth
VOYAGE_PROFILE=balanced /trekexecute --project ...
```
## Composition rule (v5.1)
Independent of the profile system. When `brief.md` carries
`phase_signals` (brief_version ≥ 2.1), each downstream phase resolves
effort + model as:
```
effort_for_phase = brief.phase_signals[<phase>]?.effort ?? 'standard'
model_for_phase = brief.phase_signals[<phase>]?.model ?? profile.phase_models[<phase>]
```
The brief signal wins per-phase when present; the profile fills any
gaps. Both fields are mechanically resolved by the single composed CLI,
invoked in Phase 1 alongside the sequencing-gate brief-validator call:
```bash
# v5.9 — composed phase-model resolution (brief > profile > default) for the
# execute 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.
# Append --profile {profile} when the operator passed --profile.
node ${CLAUDE_PLUGIN_ROOT}/lib/profiles/resolver.mjs --resolve-phase-model --phase execute --brief-path "{dir}/brief.md" [--profile {profile}] --json
```
`phase_signal_result.effort` (absent = `standard`) is consumed when picking the execution
strategy (the parallel-wave choice, Phase 2.5). The resolver does NOT control the orchestrator's own
model — that is fixed at invocation time (command frontmatter omits
`model:`, so it follows the session model) and cannot be switched mid-turn.
`/trekexecute` spawns no swarm: one step helper at a time and one controller
(Hard Rule 10), and both run `opus` — the step agent's pin and the
controller's `model: "opus"` — so `phase_signal_result.model` still has no
spawn site here; it is returned for cross-command uniformity.
For `/trekexecute` specifically: `effort == 'low'` runs the plan as one
session, step after step (Phase 2.5). `effort == 'standard'` (or absent) →
no change (default execution strategy applies). `effort == 'high'`: see
`### High-effort behavior (v5.1.1)` below.
### Sequencing gate surface
When `/trekexecute --project <dir>` is invoked, ALWAYS run
`brief-validator.mjs --soft --json` against `{dir}/brief.md`. If
`BRIEF_V51_MISSING_SIGNALS` appears in `errors` (brief_version ≥ 2.1
without `phase_signals` or `phase_signals_partial: true`), halt with:
`Brief is brief_version 2.1 but does not carry phase_signals — re-run
/trekbrief to commit them (Phase 3.5).` Enforcement is validator-only;
commands surface, don't re-enforce.
### High-effort behavior (v5.1.1)
High effort changes nothing in `/trekexecute`: the step helper and the
controller already run opus, and every gate already runs. No `gates_mode` is
set from the effort.
## Hard rules
1. **No AskUserQuestion for execution decisions.** All execution decisions come

View file

@ -74,14 +74,6 @@ Parse `$ARGUMENTS` for mode flags. Order of precedence:
# 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
@ -325,9 +317,7 @@ Determine the output directory from the plan slug:
Launch the **session-decomposer** agent:
Phase 1 runs the model resolver only for `--project`, so `--decompose` has no
resolved model: this spawn passes no `model:`, and the agent's own `model:`
applies.
This spawn passes no `model:`: the agent's own `model: opus` applies.
```
Plan file: {plan path}
@ -468,9 +458,7 @@ 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.
This spawn passes no `model:`: the agent's own `model: opus` applies.
Handle the verdict:
- **PROCEED** — continue to Phase 5.
@ -529,9 +517,7 @@ research-scout's web search is not a local read; the line above bounds its local
### 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.
This spawn passes no `model:`: the agent's own `model: opus` applies.
**architecture-mapper** — full codebase structure, tech stack, patterns, anti-patterns.
Prompt: "Analyze the architecture of this codebase. The task being planned is: {task}.
@ -570,7 +556,7 @@ Read local files only inside the repo under exploration, plus paths this prompt
### 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)
**Convention Scanner** — use the `convention-scanner` plugin agent (no `model:`; its own `model: opus` applies)
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."
@ -588,9 +574,7 @@ 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.
This spawn passes no `model:`: the agent's own `model: opus` 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.
@ -611,9 +595,9 @@ Common reasons for deep-dives:
- 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
For each significant gap, spawn a targeted deep-dive agent (subagent_type:
"Explore", Claude Code's built-in agent) with a narrow, specific brief.
Spawn it with `model: "opus"`: a built-in agent has no Voyage pin. 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).
@ -986,9 +970,7 @@ Both reviewers are asked for `voyage:writing-criteria` and
writing-criteria rule in one sentence in its prompt, for the brief's criteria
it traces into `## Verification`.
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.
This spawn passes no `model:`: the agent's own `model: opus` applies.
**plan-critic** — adversarial review of the plan.
Prompt: "Review this implementation plan for the task: {task}.
@ -1301,97 +1283,6 @@ one step helper per step and the review.
There is no team path. Print the same `/trekexecute` line; parallel work is `--decompose` followed by `/trekexecute`'s session orders.
## Profile (v4.1)
Accepts `--profile <name>` where `<name>` is `economy`, `balanced`, `premium`, `fable`,
or a custom profile under `voyage-profiles/`. Default: `premium`.
Resolution order (per `lib/profiles/resolver.mjs`):
1. `--profile` flag (source: `flag`)
2. `VOYAGE_PROFILE` env-var (source: `env`)
3. `premium` default (source: `default`)
The selected profile drives `phase_models.plan` (model used for the planning
LLM), `parallel_agents_min`/`max` (the exploration swarm size), and is
recorded in `plan.md` frontmatter so `/trekexecute` and `/trekcontinue` can
inherit it across the pipeline.
Examples:
```
/trekplan --profile economy --project .claude/projects/2026-05-09-add-auth
/trekplan --profile balanced --brief brief.md
VOYAGE_PROFILE=balanced /trekplan --project ...
```
## Composition rule (v5.1)
Independent of the profile system. When `brief.md` carries
`phase_signals` (brief_version ≥ 2.1), each downstream phase resolves
effort + model as:
```
effort_for_phase = brief.phase_signals[<phase>]?.effort ?? 'standard'
model_for_phase = brief.phase_signals[<phase>]?.model ?? profile.phase_models[<phase>]
```
The brief signal wins per-phase when present; the profile fills any
gaps. Both fields are mechanically resolved by the single composed CLI
`node ${CLAUDE_PLUGIN_ROOT}/lib/profiles/resolver.mjs --resolve-phase-model`
invoked in Phase 1; the resolved JSON is `{model, source}`, plus
`effort` only when the brief's phase signal sets one (without it the
phase runs at effort `standard`: no change). It is captured as
`phase_signal_result` and passed to `Agent` tool calls explicitly. The
resolver controls the `model` parameter at Agent-spawn sites only — the
orchestrator's own model is fixed at invocation time (command frontmatter
omits `model:`, so it follows the session model) and cannot be switched
mid-turn. Sub-agents fall back to `model:` in their own `agents/*.md`
frontmatter when no spawn-site injection happens.
For `/trekplan` specifically: `effort == 'low'` activates the existing
`--quick`-equivalent code-path (skip Phase 5 agent swarm — plan directly
without exploration agents). `effort == 'standard'` (or absent) → no
change. `effort == 'high'` activates the high-effort behavior documented
under `### High-effort behavior (v5.1.1)` below.
### Sequencing gate surface
Phase 1 already calls `brief-validator.mjs --soft`. If the validator
returns `BRIEF_V51_MISSING_SIGNALS` in `errors` (brief_version ≥ 2.1
without `phase_signals` or `phase_signals_partial: true`), halt with a
one-line message: `Brief is brief_version 2.1 but does not carry phase_signals
— re-run /trekbrief to commit them (Phase 3.5).` Enforcement is
validator-only; this surface just makes the friendly hint readable.
### High-effort behavior (v5.1.1)
When `phase_signal_result.effort == 'high'` for the `plan` phase, the
additional adversarial Pass 2 on the post-revision plan is
**unavailable, skipped**. Append the section header to plan.md before
the trailing JSON block with exactly that status, so a reader can tell
a deliberately dropped pass from one that failed:
```
## Adversarial Pass 2 (v5.1.1 high-effort)
**Status:** unavailable, skipped — the third-party bridge agent that
ran this pass was dropped in v5.10.1 by operator directive. No
substitute is wired. Phase 9 (plan-critic + scope-guardian) is the
complete adversarial coverage for this plan.
```
Do NOT fail, retry, or silently omit the section: a high-effort plan
that carries no Pass 2 marker is indistinguishable from one whose Pass
2 crashed.
History (why the slot exists): Decision B, 2026-05-14, substituted a
bridge pass for an "extra plan-critic-iterasjon" because plan-critic
dedup keys on `(file, line, rule_key)` triplets and post-revision line
numbers shift, risking a revision-loop. Dropping the bridge does not
revive that option — re-running plan-critic carries the same loop risk
it always did.
Standard and low effort: do NOT emit the section at all.
## Hard rules
- **Brief-driven**: Every plan decision must trace back to a section of the
@ -1404,11 +1295,6 @@ Standard and low effort: do NOT emit the section at all.
own requirements.
- **Scope**: Only explore the current working directory and its subdirectories.
Never read files outside the repo (no ~/.env, no credentials, no other repos).
- **Cost**: Model resolution at Agent-spawn sites is a three-layer fallback:
brief `phase_signals[<phase>].model` > `profile.phase_models[<phase>]` >
agent frontmatter `model:`. The composed resolver returns the first two
layers as `phase_signal_result.model`; spawn sites inject it, and agent
frontmatter is the fallback when no injection happens.
- **Privacy**: Never log, store, or repeat file contents that look like
secrets, tokens, or credentials. Never log prompt text.
- **No premature execution**: Do not modify any project files until the user

View file

@ -54,22 +54,12 @@ Supported flags:
Create `{dir}/research/` if it does not already exist.
When `{dir}/brief.md` exists, ALWAYS run the brief-validator (soft mode)
AND the composed phase-model resolver for this command's phase before
continuing. The resolver's JSON output (brief signal > profile > default)
is `{model, source}`, plus
`effort` only when the brief's phase signal sets one (without it the
phase runs at effort `standard`: no change). It is captured as
`phase_signal_result` and used at Agent-spawn sites in Phase 4 and Phase 5 to inject
the resolved model:
before continuing:
```bash
# When --min-brief-version was passed, append --min-version {min_brief_version}
# so an older brief raises BRIEF_VERSION_BELOW_MINIMUM (warn, never block).
node ${CLAUDE_PLUGIN_ROOT}/lib/validators/brief-validator.mjs --soft --json [--min-version {min_brief_version}] "{dir}/brief.md"
# v5.9 — composed resolver: ONE call returns {model, source}, plus
# effort only when the brief's phase signal sets one (without it: standard).
# Append --profile {profile} when the operator passed --profile.
node ${CLAUDE_PLUGIN_ROOT}/lib/profiles/resolver.mjs --resolve-phase-model --phase research --brief-path "{dir}/brief.md" [--profile {profile}] --json
```
6. `--gates` — autonomy control. `--gates` takes the next token as its
@ -280,6 +270,11 @@ Skip to Phase 8 after writing the brief.
**Determine which agents to launch based on scope:**
Every run launches the FULL swarm for its scope: all 5 local agents and all 4
external agents, and `contrarian-researcher` runs every time, as wave 2 (see
Launch rules), so the final brief always carries an adversarial
counter-evidence pass.
### Local agents (scope = both or local)
Reuse existing plugin agents with research-focused prompts. These agents are
@ -336,7 +331,7 @@ ticket IDs) already removed: the agents search with the words they are given.
- Launch in two waves, both in Phase 4.
- **Wave 1:** ALL selected agents except `contrarian-researcher` **in parallel**
in a single message.
- **Wave 2:** `contrarian-researcher`, when selected, after wave 1 returns, in a
- **Wave 2:** `contrarian-researcher`, after wave 1 returns, in a
message of its own. Give it a conclusion to attack: the leading answer (one or
two sentences), the claims for it and the alternatives wave 1 dismissed,
taken from wave 1's external findings only, never from the local agents'
@ -346,9 +341,8 @@ ticket IDs) already removed: the agents search with the words they are given.
local file name or project term may be in them. When wave 1's external
findings hold no leading answer, say so and give it the research question
alone, stripped the same way.
- Inject the resolved model at every spawn: `phase_signal_result.model` (brief
signal > profile), with the agent's frontmatter `model:` as the fallback — see
Hard rules → Cost. The orchestrator itself follows the session model.
- Pass no model at a Voyage agent's spawn: the agent's own frontmatter
`model: opus` applies. The orchestrator itself follows the session model.
- **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"`
@ -361,17 +355,16 @@ ticket IDs) already removed: the agents search with the words they are given.
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`.
- convention-scanner: medium+ codebases only (50+ files)
## Phase 5 — Targeted follow-ups
Review all agent results. Identify knowledge gaps — dimensions where findings
are thin, contradictory, or missing (**under-illuminated dimensions**).
For each significant gap, launch a targeted follow-up agent (model: phase_signal_result.model, else opus — a
follow-up may be one of Claude Code's built-in agents, which have no Voyage
frontmatter to fall back to; see Launch rules) with a narrow, specific
brief; a follow-up that searches the web names the `researching-sources` skill
For each significant gap, launch a targeted follow-up agent with a narrow,
specific brief. A follow-up may be one of Claude Code's built-in agents:
Spawn it with `model: "opus"`: a built-in agent has no Voyage pin.
A follow-up that searches the web names the `researching-sources` skill
in its prompt, as above. Maximum 2 follow-ups. If no gaps exist, skip: "Initial research
sufficient — no follow-ups needed." Then go to Phase 6.
@ -456,86 +449,6 @@ You can:
- Ask follow-up questions about specific findings
```
## Profile (v4.1)
Accepts `--profile <name>` where `<name>` is `economy`, `balanced`, `premium`, `fable`,
or a custom profile under `voyage-profiles/`. Default: `premium`.
Resolution order (per `lib/profiles/resolver.mjs`):
1. `--profile` flag (source: `flag`)
2. `VOYAGE_PROFILE` env-var (source: `env`)
3. `premium` default (source: `default`)
The profile dictates `phase_models.research`, `parallel_agents`, and
`external_research_enabled`. `economy` and `balanced` profiles auto-disable
the external research swarm regardless of `--external` flag (operator
override deferred to v4.2).
Examples:
```
/trekresearch --profile economy --project .claude/projects/2026-05-09-add-auth
VOYAGE_PROFILE=balanced /trekresearch
```
## Composition rule (v5.1)
Independent of the profile system. When `brief.md` carries
`phase_signals` (brief_version ≥ 2.1), each downstream phase resolves
effort + model as:
```
effort_for_phase = brief.phase_signals[<phase>]?.effort ?? 'standard'
model_for_phase = brief.phase_signals[<phase>]?.model ?? profile.phase_models[<phase>]
```
The brief signal wins per-phase when present; the profile fills any
gaps. Both fields are mechanically resolved by the single composed CLI
`node ${CLAUDE_PLUGIN_ROOT}/lib/profiles/resolver.mjs --resolve-phase-model`
invoked in Phase 1; the resolved JSON is `{model, source}`, plus
`effort` only when the brief's phase signal sets one (without it the
phase runs at effort `standard`: no change). It is captured as
`phase_signal_result` and passed to `Agent` tool calls explicitly. The
resolver controls the `model` parameter at Agent-spawn sites only — the
orchestrator's own model is fixed at invocation time (command frontmatter
omits `model:`, so it follows the session model) and cannot be switched
mid-turn. Sub-agents fall back to `model:` in their own `agents/*.md`
frontmatter when no spawn-site injection happens.
For `/trekresearch` specifically: `effort == 'low'` activates the
existing `--quick`-equivalent code-path (inline research, no agent swarm).
`effort == 'standard'` (or absent) → no change. `effort == 'high'`
activates the high-effort behavior documented under `### High-effort
behavior (v5.1.1)` below.
### Sequencing gate surface
When `/trekresearch --project <dir>` is invoked and `{dir}/brief.md`
exists, ALWAYS run `brief-validator.mjs --soft --json` against it.
If `BRIEF_V51_MISSING_SIGNALS` appears in `errors` (brief_version ≥ 2.1
without `phase_signals` or `phase_signals_partial: true`), halt with:
`Brief is brief_version 2.1 but does not carry phase_signals — re-run
/trekbrief to commit them (Phase 3.5).` Enforcement is validator-only;
commands surface, don't re-enforce.
### High-effort behavior (v5.1.1)
When `phase_signal_result.effort == 'high'` for the `research` phase,
run the FULL swarm regardless of normal selection rules: 5 local
agents + 4 external agents, AND force `contrarian-researcher` to
always-on: in high-effort mode `contrarian-researcher` runs
unconditionally, as wave 2 (see Launch rules), so the final brief
always carries an adversarial counter-evidence pass.
The former third-party second-opinion bridge pass is **unavailable,
skipped** (dropped in v5.10.1 by operator directive). High effort no
longer has a bridge arm.
Standard effort (or absent): the selected agents run as in Phase 4, and
`contrarian-researcher`, when selected, runs as wave 2 after the other
agents return (see Launch rules).
Low effort: inline research only, no agent swarm (existing
`--quick`-equivalent code-path).
## Hard rules
- **No planning:** This command produces research briefs, not implementation plans.
@ -546,11 +459,6 @@ Low effort: inline research only, no agent swarm (existing
Triangulate AFTER independent research.
- **Graceful degradation:** If MCP tools are unavailable (Tavily, MS Learn),
proceed with available tools and note limitations in brief metadata.
- **Cost:** Model resolution at Agent-spawn sites is a three-layer fallback:
brief `phase_signals[<phase>].model` > `profile.phase_models[<phase>]` >
agent frontmatter `model:`. The composed resolver returns the first two
layers as `phase_signal_result.model`; spawn sites inject it, and agent
frontmatter is the fallback when no injection happens.
- **Privacy:** Never log secrets, tokens, or credentials.
- **Honesty:** If the question is trivially answerable, say so. Don't inflate research.
- **Scope of codebase:** Only analyze the current working directory for local research.

View file

@ -98,15 +98,6 @@ as the file is parseable:
```bash
node ${CLAUDE_PLUGIN_ROOT}/lib/validators/brief-validator.mjs --soft --json "{brief_path}"
# v5.9 — composed phase-model resolution (brief > profile > default) for the
# review 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 used in Phase 7 at the reviewer-launch site to
# inject the resolved model. Append --profile {profile} when the operator
# passed --profile.
node ${CLAUDE_PLUGIN_ROOT}/lib/profiles/resolver.mjs --resolve-phase-model --phase review --brief-path "{brief_path}" [--profile {profile}] --json
```
Read the JSON output. If `valid: false` AND any error has code
@ -568,9 +559,7 @@ The coordinator runs the 4-pass process documented in
`rule_key` is not in `RULE_CATALOGUE` (`unknown-rule_key`) or whose file
cannot be checked (`file-existence:indeterminate`) to `unverified`, which
forbids `ALLOW`; reset a severity that does not match its catalogue tier.
Skipped at high effort too, where an unknown `rule_key` is normalized to
`PLAN_EXECUTE_DRIFT` instead (`### High-effort behavior (v5.1.1)` below);
the brief-conflict rule still applies in every mode.
The brief-conflict rule still applies in every mode.
4. **Verdict** — BLOCK / WARN / ALLOW per the threshold table.
**Fail-closed.** Every removal in Pass 2 and Pass 3 is either
@ -931,85 +920,6 @@ Per **Handover 6**, BLOCKER and MAJOR findings are consumed by
review's frontmatter `findings:` list and the trailing JSON block are
the contract for that handover (see `docs/HANDOVER-CONTRACTS.md`).
## Profile (v4.1)
Accepts `--profile <name>` where `<name>` is `economy`, `balanced`, `premium`, `fable`,
or a custom profile under `voyage-profiles/`. Default: `premium`.
Resolution order (per `lib/profiles/resolver.mjs`):
1. `--profile` flag (source: `flag`)
2. `VOYAGE_PROFILE` env-var (source: `env`)
3. `premium` default (source: `default`)
The selected profile drives `phase_models.review` — `economy` uses sonnet
for the brief-conformance + code-correctness reviewers; `balanced` and
`premium` use opus (review benefits from deeper reasoning).
Examples:
```
/trekreview --profile balanced --project .claude/projects/2026-05-09-add-auth
VOYAGE_PROFILE=premium /trekreview --project ...
```
## Composition rule (v5.1)
Independent of the profile system. When `brief.md` carries
`phase_signals` (brief_version ≥ 2.1), each downstream phase resolves
effort + model as:
```
effort_for_phase = brief.phase_signals[<phase>]?.effort ?? 'standard'
model_for_phase = brief.phase_signals[<phase>]?.model ?? profile.phase_models[<phase>]
```
The brief signal wins per-phase when present; the profile fills any
gaps. Both fields are mechanically resolved by the single composed CLI
`node ${CLAUDE_PLUGIN_ROOT}/lib/profiles/resolver.mjs --resolve-phase-model`
invoked in Phase 2; the resolved JSON is `{model, source}`, plus
`effort` only when the brief's phase signal sets one (without it the
phase runs at effort `standard`: no change). It is captured as
`phase_signal_result` and passed to `Agent` tool calls explicitly. The
resolver controls the `model` parameter at Agent-spawn sites only — the
orchestrator's own model is fixed at invocation time (command frontmatter
omits `model:`, so it follows the session model) and cannot be switched
mid-turn. Sub-agents fall back to `model:` in their own `agents/*.md`
frontmatter when no spawn-site injection happens.
For `/trekreview` specifically: `effort == 'low'` activates the existing
`--quick`-equivalent code-path (skip the brief-conformance reviewer; run
correctness-only). `effort == 'standard'` (or absent) → no change.
`effort == 'high'` activates the high-effort behavior documented under
`### High-effort behavior (v5.1.1)` below.
### Sequencing gate surface
Phase 1 already calls `brief-validator.mjs --soft` against `{brief_path}`.
If the validator returns `BRIEF_V51_MISSING_SIGNALS` in `errors`
(brief_version ≥ 2.1 without `phase_signals` or `phase_signals_partial:
true`), halt with: `Brief is brief_version 2.1 but does not carry
phase_signals — re-run /trekbrief to commit them (Phase 3.5).`
Enforcement is validator-only; this surface just makes the friendly hint
readable.
### High-effort behavior (v5.1.1)
When `phase_signal_result.effort == 'high'` for the `review` phase,
skip Pass 3 (Cloudflare reasonableness filter) in `agents/review-coordinator.md`, except the brief-conflict rule, which applies in every mode.
Passes 1, 2, and 4 still run.
Rationale: high-effort review trusts the operator to weigh borderline
findings rather than have the coordinator drop them. To prevent
unknown `rule_key` values from polluting downstream remediation plans
(Handover 6), the coordinator applies its v5.1.1 high-effort
normalization rule — substituting unknown `rule_key` values with the
literal string `PLAN_EXECUTE_DRIFT` (the most general drift category
in the catalogue) and preserving the original in
`original_rule_key`. See `agents/review-coordinator.md` § Pass 3
"High-effort normalization (v5.1.1)" for the full normalization spec.
Standard effort (or absent): run all 4 passes as usual.
Low effort: skip the brief-conformance reviewer entirely (existing
`--quick`-equivalent code-path).
## Hard rules
- **Brief is the contract.** Every finding in the review traces to a
@ -1030,11 +940,6 @@ Low effort: skip the brief-conformance reviewer entirely (existing
`findings:\n - a\n - b`.
- **Refuse-with-suggestion above 100 files / 100K tokens.** Never run
blind on a giant diff. Use AskUserQuestion to surface the gate.
- **Cost.** Model resolution at Agent-spawn sites is a three-layer fallback:
brief `phase_signals[<phase>].model` > `profile.phase_models[<phase>]` >
agent frontmatter `model:`. The composed resolver returns the first two
layers as `phase_signal_result.model`; spawn sites inject it, and agent
frontmatter is the fallback when no injection happens.
- **Privacy.** Never log secrets, tokens, or credentials in review.md.
Findings citing files with secret-like content must redact the secret
in the `detail` field.