Operator rule (2026-10-05): standard is Opus 5.5 at reasoning effort High. Four retrieval agents (architecture-mapper, dependency-tracer, git-historian, task-finder) pinned effort: medium in frontmatter, which overrides the session level, so every /trekplan exploration ran part of its swarm below the floor. They came fromfdd3ad8on the premise that unpinned agents inherit high;e4e37f9corrected that (unpinned inherits the session; Opus 5.5 defaults to medium), so the reason for medium was already gone. All four now pin high; the other agents keep following the session (operator's choice). docs/profiles.md (one bullet for the eight pinned agents), CLAUDE.md and README.md updated; the model-default sentence stays. Dated decision records and CHANGELOG untouched. Red: 4 of 5 new tests fail on the pre-fix files - effort floor over all agents (offenders: the four), the four pin exactly high, no live doc says retrieval runs at medium (hits docs/profiles.md:76, CLAUDE.md:85, README.md:806), profiles.md names the four as high. Known-positive control green on arrival. Verify 153/153 (agent-frontmatter, doc-consistency). SC9 probe: npm test green under a scratch HOME with CLAUDE_PLUGIN_DATA empty, nothing under its plugin data dir. Suite 1393 (1391/0/2). The change is repo-true, not installed-true, until a release. Voyage order 20261005T104513Z-1250514346, plan step 5/5. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
11 KiB
Profile system — voyage v4.1
This document describes the model profile system: built-in tiers, lookup precedence, custom-profile authoring, drift detection, and cost estimation (with disclaimer).
Built-in profiles
Four pre-defined tiers ship with the plugin (fable added in v5.9), located at
lib/profiles/{economy,balanced,premium,fable}.yaml.
| Profile | Brief | Research | Plan | Execute | Review | Continue | Use case |
|---|---|---|---|---|---|---|---|
economy |
sonnet | sonnet | sonnet | sonnet | sonnet | sonnet | ⚠ Experimental (uncalibrated Jaccard floor) — lowest cost; small-scope tasks where you have high confidence the brief is right |
balanced |
sonnet | sonnet | opus | sonnet | opus | sonnet | Mixed — opus where reasoning depth pays off (plan synthesis + adversarial review); opt-in via --profile balanced |
premium (default) |
opus | opus | opus | opus | opus | opus | Maximum quality — Opus on every phase + external research on (default since the 2026-05-13 operator decision) |
fable |
fable | fable | fable | fable | fable | fable | Max quality — Fable 5.1 (the most capable model in Claude Code) on every phase; opt-in via --profile fable; reasoning effort inherits from the session (see Model & effort axes) |
premium is the default tier — set by the 2026-05-13 operator decision and
matched by the hardcoded resolver default in lib/profiles/resolver.mjs. It
runs opus on every phase and turns external research on: maximum quality, at
roughly 5× the sub-agent cost of an all-sonnet run, accepted as a deliberate
trade-off. Drop to --profile balanced (opus only on the two phases where
quality matters most — Plan synthesis + Review — and sonnet everywhere else)
or --profile economy (sonnet everywhere) when cost or latency matters more
than depth. Step up to --profile fable (Fable 5.1 on every phase) when
maximum quality is wanted end-to-end and cost is not a constraint.
economy is strictly experimental in v4.1, and says so in the profile
data itself: lib/profiles/economy.yaml carries experimental: true. The
cross-tier Jaccard floor (0.55) is grounded in parked-synthetic fixtures, not
empirical runs (Step 17 calibration was deferred — see
tests/synthetic/profile-jaccard-calibration.md). The flag is pinned: it must
stay true while the calibration status is parked-synthetic, and must be
dropped in the same change that lands empirical calibration
(status: empirical). If you observe economy-plan quality regressions, fall
back to balanced.
Model & effort axes
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. The
profile table above selects which alias runs each phase — it does not touch
reasoning effort.
Reasoning effort inherits from the session. Voyage effort (orchestration
shape — which agents/passes run) and model reasoning effort are different
axes. 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 the fable tier at xhigh, choose it explicitly: /effort xhigh,
--effort xhigh, or CLAUDE_CODE_EFFORT_LEVEL.
Two different things share the word "effort" in Voyage. They are orthogonal axes — same name, different mechanism:
| Orchestration effort | Reasoning effort (native) | |
|---|---|---|
| Where | brief phase_signals.effort, consumed by command prose |
native Claude Code effort: in agent frontmatter |
| Values | low / standard / high |
low / medium / high / xhigh / max |
| Controls | which agents/passes/gates run (swarm cardinality, gate strictness, sequential-vs-parallel) | per-spawn reasoning-token budget the harness gives one agent |
low means |
"run fewer agents" (the --quick-equivalent code-path) |
"think with a smaller budget" |
| Applied by | Voyage command logic | the harness, at spawn time |
The phase-signal-resolver.mjs helper only reads the orchestration axis
(phase_signals.effort, gated against low/standard/high) plus the optional
per-phase model (gated against ['sonnet','opus','fable']). It never emits
native effort:.
Native effort: on agents. Voyage sets the reasoning axis statically on
selected agents, overriding the session level:
- Eight agents pin
high: the retrieval agentstask-finder,git-historian,dependency-tracer,architecture-mapper, and the adversarial-reasoning agentsplan-critic,risk-assessor,contrarian-researcher,review-coordinator. 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).
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.
Decision tree
Are you uncertain whether the brief is correctly framed?
└── Yes → premium (opus on brief + plan + review)
└── No → continue
↓
Is the change small (≤ 5 steps in the plan)?
└── Yes → economy (sonnet everywhere)
└── No → balanced (opus on plan + review)
Special cases:
- Critical-infrastructure plan → premium
- Migration with rollback risk → premium
- Research-heavy task (≥ 4 dimensions) → balanced (research-stage benefits)
- Bug fix with clear reproducer → economy
- Documentation-only PR → economy
Lookup order
Voyage resolves the profile in this priority order:
- Explicit
--profile <name>flag — passed to the command - Plan-file frontmatter
profile:— when resuming via/trekexecute --resumeor/trekcontinue VOYAGE_PROFILEenvironment variable — useful for headless CI- Default
premium— final fallback
The resolved value is recorded in two places:
- Plan-file frontmatter
profile: <name>andphase_models: [...] - Stats stream
${CLAUDE_PLUGIN_DATA}/trek*-stats.jsonl—profile,profile_source,phase_models,model_used,phase_models_resolvedfields
profile_source distinguishes how the profile was resolved (flag /
plan_frontmatter / env / default), so dashboards can surface
unexpected env-var inheritance in CI.
Custom profiles
Drop a YAML file at lib/profiles/<name>.yaml to define a new tier.
The validator (lib/validators/profile-validator.mjs) enforces:
- Every
phase_models[].phasemust be a known phase enum:brief/research/plan/execute/review/continue - Every
phase_models[].modelmust exactly match an entry inBASE_ALLOWED_MODELS(['sonnet', 'opus', 'fable']inlib/validators/profile-validator.mjs;haikuonly withVOYAGE_ALLOW_HAIKU=1) - All six phases must be present (no partial profiles)
The four built-in names (economy, balanced, premium, fable) resolve to their
bundled yaml first — findProfilePath() returns the built-in before consulting
voyage-profiles/, so a same-named custom file is ignored and cannot shadow a
built-in. To customize, give your profile a new name and reference it via
--profile <new-name> or VOYAGE_PROFILE=<new-name>.
Example custom profile
# lib/profiles/critical.yaml — opus everywhere except continue
phase_models:
- phase: brief
model: opus
- phase: research
model: opus
- phase: plan
model: opus
- phase: execute
model: opus
- phase: review
model: opus
- phase: continue
model: sonnet
Validate with: node lib/validators/profile-validator.mjs --json lib/profiles/critical.yaml
Drift detection
In --strict mode, plan-validator.mjs emits a MANIFEST_PROFILE_DRIFT
warning when the plan-level profile: differs from any step manifest's
profile_used. The warning is a signal, not a failure — the plan
remains valid: true. This catches:
- Manual edits where an operator changed a single step's profile
- Resume from a partial run where the previous session used a different tier
- Copy-paste errors when stitching plan fragments
To suppress the warning intentionally (e.g. when a critical step
genuinely needs a higher tier), document the override in the step's
prose and re-run with --soft to validate without strict-mode warnings.
Cost estimation
Disclaimer: the table below is an anslag, not a contractual SLA. Real cost depends on context size, agent-swarm cardinality, tool-use density, and Claude Code billing schedule. Treat these as rough order-of-magnitude.
| Profile | Brief | Research | Plan | Execute | Review | Total |
|---|---|---|---|---|---|---|
economy |
$0.10–0.50 | $0.50–2.00 | $0.50–2.00 | $1.00–5.00 | $0.20–1.00 | $2–10 |
balanced |
$0.10–0.50 | $0.50–2.00 | $1.00–4.00 | $1.00–5.00 | $0.50–2.00 | $3–14 |
premium |
$0.50–2.00 | $0.50–2.00 | $1.00–4.00 | $1.00–5.00 | $0.50–2.00 | $4–15 |
Numbers are per full pipeline run (brief + research + plan + execute + review) on a moderate-complexity task. Numbers scale roughly linearly with the size of the resulting plan (10 steps ≈ baseline; 30 steps ≈ 3× the execute column).
Per-profile actuals are emitted to JSONL stats — pipe them through the
OTel export (docs/observability.md) to get real cost-attribution
graphs in Grafana. Replace the table above with your own measured
numbers after ≥ 3 runs of each profile.
Deferred to v4.2
balanced.external_research_enabledoperator-override — v4.1 omits this per scope-guardian SG2. v4.2 may add an opt-in flag to enable external research agents in the balanced tier without forcing premium.- Empirical Jaccard re-calibration — parked-synthetic fixtures in v4.1 use a 0.55 conservative starting threshold. v4.2 plans an empirical re-run with $60-120 LLM budget to derive a calibrated threshold from real economy-vs-premium plan pairs.
- ROUGE-L + char-4gram MinHash as primary/secondary cross-tier gates per research/02 Recommendation #7. Jaccard remains the gate in v4.1; v4.2 may layer ROUGE-L on top.
See also
README.md§ Profile system — top-level overviewCLAUDE.md§ Profile system — internal referencedocs/observability.md— JSONL → OTel pipelinetests/synthetic/profile-jaccard-calibration.md— calibration status and threshold rationalelib/profiles/— built-in profile YAMLslib/validators/profile-validator.mjs— schema validator with CLI shim