Skip to main content

Reasoning effort

Reasoning effort is the --effort level a coding-agent harness launches at (Claude Code’s low/medium/high/xhigh/max, and the nearest equivalent on every other harness). Overdeck resolves it through one function, resolveEffort() (src/lib/agents/resolve-effort.ts), on top of one enum, EFFORT_LEVELS (packages/contracts/src/effort.ts) — instead of the ad hoc effort ?? 'high' fallbacks and copied 'low' | 'medium' | 'high' unions scattered through earlier code.

Levels

xhigh was added in Opus 4.7 (between high and max); max predates it (Opus 4.6+/Sonnet 4.6). The default is high — nothing resolves to xhigh or max unless something explicitly asked for it.

Where effort comes from

resolveEffort() walks a fixed precedence chain and returns the first layer that supplies a valid level, plus which layer won: An invalid explicit value throws InvalidEffortError. An invalid item, plan, or project value is skipped silently (a project value also adds a warning) and resolution falls through to the next layer — configuration typos degrade rather than crash a spawn.

Config keys

Clamping

Once a level is resolved, clampEffort() checks it against what the target model and harness actually support (supportedEffortLevels() intersects the model’s effortLevels from model-capabilities.ts with the harness’s effortLevels from harness-behavior.ts; either side being unrestricted contributes all five levels):
  • If the resolved level is supported, it’s used as-is.
  • If not, the highest supported level below it is used instead (max requested on a harness with no max falls to xhigh).
  • If nothing supported ranks below it, the lowest supported level is used (low requested against a model that only supports high/max becomes high).
  • If the model and harness restrictions don’t overlap at all, the requested level is kept as-is and flagged with a warning rather than dropped.
Pi (ohmypi) and Muse Code never accept max — their effortLevels stop at xhigh. Config validation rejects; a resolved flag clamps. Setting an unsupported level in config.yaml (roles.<role>.effort, roles.<role>.sub.<name>.effort, or tiered_execution.tiers.<name>.effort) fails config load with effortConfigErrors()’s is not supported by <model> message — you have to fix the file. An explicit --effort flag or a resolved runtime value that turns out unsupported is clamped instead, with a warning printed to stderr — a spawn never hard-fails over it.

What honors it today

  • pan start <id> for work-agent spawns.
  • Definition-less role runs (review sub-roles, the standing supervisor) and their codex/omp launcher fields (getRoleRuntimeBaseCommand, getCodexLauncherFields, getOhmypiLauncherFields in src/lib/agents/runtime-command.ts).
Everything else — conversations, specialist/review-parent/test/worker launches, the Flywheel orchestrator, remote Fly workspaces, per-slot tier staffing, planning, and dashboard-wide display — still resolves effort ad hoc and is tracked in sibling issues: