Skip to content

Claude Code Advisor

Advisor pairs a cheap main model (Sonnet/Haiku) doing headless work with a stronger reviewer model (Opus) that gets consulted automatically at decision points: before committing to an approach, after a repeated error, and before the agent declares a task done. It rides on the --advisor <model> CLI flag (or the advisorModel settings key), requires Claude Code v2.1.98+, and only works on Anthropic-API auth. Rolled out 2026-07-09.

Design intent: Advisor runs ONLY on unattended cheap-model surfaces, headless claude -p work with nobody watching in real time. Interactive sessions and any run already on Opus/Fable get nothing, there's no stronger reviewer to pair an already-top-tier model with (and pairing Opus with Opus just doubles cost for no benefit).

The central knob

One environment variable, FORGE_CLAUDE_ADVISOR, is the single source of truth. It names the reviewer model (default opus). Set it empty to disable Advisor everywhere that reads it; unset it to fall back to the default.

Two thin accessors read that variable so no call site hand-rolls the enable/skip logic:

  • Python: scripts/forge_advisor_config.pyadvisor.advisor_args(model) returns ["--advisor", "opus"] or [].
  • Bash: scripts/forge_advisor_config.shsource it, then forge_advisor_flags "$MODEL" prints --advisor opus or nothing (use read -r -a ARR <<< "$(forge_advisor_flags "$MODEL")" to get an array-safe arg list).

Both skip automatically when model contains opus or fable (case insensitive), so callers never need their own model-tier branch, they can unconditionally splice the accessor's output into the claude -p argv.

To disable Advisor at the Claude Code engine level regardless of any --advisor flag already baked into a call site (e.g. mid-incident kill switch), export CLAUDE_CODE_DISABLE_ADVISOR_TOOL=1 in the process environment. That's the CLI's own escape hatch, separate from the forge-level knob above.

Wired surfaces (2026-07-09)

Surface File Model(s) Notes
Dispatcher workers scripts/forge_dispatcher.sh sonnet (default) / haiku / opus resolve_model() picks the id; advisor args computed once in spawn_worker(). No-op when task requests opus.
Autoagent shared runner autoagent/core/_claude_runner.py sonnet (specialist default) / opus (manager) Single shared runner used by every tick script (manager, specialist). Manager's MANAGER_MODEL=claude-opus-4-8 auto-skips.
Followup jobs scripts/forge_followup.py haiku / sonnet (default) / opus per job /followup skill schedules these; fired by forge-followup-dispatcher.timer.
/spawn, warm pool, coordinator spawn tool scripts/forge_spawn_session.sh sonnet (default) / haiku / opus / fable Canonical implementation shared by the /spawn skill, forge_spawn_pool.sh, and tool_spawn_remote_session in the coordinator bot. Opus/fable spawns unaffected.
Spawn-headless-agent skill .claude/skills/spawn-headless-agent/SKILL.md sonnet (default) / haiku / opus Template snippet now sources forge_advisor_config.sh before the nohup claude -p line.
Telegram remote bridge /ask scripts/forge_telegram_remote_bridge.py (run_claude_ask) user-selected (default sonnet) Escape-hatch one-shot chat command; skipped when user picks opus/fable.
Telegram remote bridge routing brain scripts/forge_telegram_remote_bridge.py (_call_brain_sonnet) claude-sonnet-5 (fixed) Classifies free-text Telegram messages into actions; always qualifies.

Restarted after edit: forge-dispatcher.service, forge-remote-bridge.service (both are long-running processes that hold the old code in memory). forge_followup.py, forge_spawn_session.sh, and _claude_runner.py are invoked fresh per call (timer-fired oneshots or ad hoc subprocesses), no service restart needed, next invocation reads the edited file.

Tested

End-to-end: dropped a real trivial haiku task into tasks/pending/, watched the restarted dispatcher pick it up. Confirmed via ps that the live worker process argv included --model claude-haiku-4-5-20251001 --advisor opus --dangerously-skip-permissions --no-session-persistence, and the task completed normally with the expected result file. Cleaned up after confirming.

Boundary: raw Anthropic API callers get nothing

Advisor is a Claude Code CLI feature. Anything that talks to the Anthropic Messages API directly instead of shelling out to claude -p cannot use it, there's no CLI process to attach the flag to. This includes scripts/forge_brain_server.py (the warm in-process brain server that most Telegram bot brains prefer, falling back to cold claude -p subprocess only on failure) and any other direct-SDK integration. Do not attempt to hack Advisor onto the raw-API path, the intended failover here is the cold claude -p subprocess call, which DOES get Advisor once/if that fallback path is wired (see "Not yet wired" below).

Not yet wired (found via grep, left for a follow-up pass)

These are all secondary cold-claude -p-subprocess fallback paths behind a primary raw-API brain-server call (see boundary above), always Sonnet, always unattended. Wiring them is a 3-line change each (import forge_advisor_config, splice advisor.advisor_args(model) into the existing subprocess argv) once there's budget to test them individually:

  • scripts/forge_telegram_brain.py (call_brain, subprocess fallback branch)
  • scripts/forge_telegram_inbox_brain.py (_call_sonnet, subprocess fallback branch)
  • scripts/forge_food_lookup.py (lookup_sonnet)

Explicitly NOT touched: scripts/forge_session_launcher_api.py

Out of scope for this pass, it carries Justin's uncommitted WIP. It has three headless claude -p call sites that would benefit:

  • _curate_prompt() (~line 1005): Sonnet, headless "curate a worker briefing" pass, a clean decision-point candidate.
  • _name_from_prompt() (~line 1583): Haiku, trivial slug generation, low value for Advisor (matches the CLI's own "skip on short reactive tasks" guidance) but harmless to wire.
  • chat_turn() /api/chat (~line 1971): model is caller-selected (MODEL_IDS[req.model]), backs a live chat UI (chat.justinsforge.com) where a human is reading the reply turn by turn, judgment call whether that counts as "unattended."

Exact edit needed (once the WIP lands and this file is unblocked): add import forge_advisor_config as advisor near the top (module already sits in scripts/, plain import works), then splice *advisor.advisor_args(model) into each of the three cmd/argv lists shown above, mirroring the pattern used in this same file's sibling scripts (forge_followup.py, forge_telegram_remote_bridge.py).

Disabling

  • One surface: prepend FORGE_CLAUDE_ADVISOR= (empty) to that process's environment (systemd unit Environment= line, or the shell that launches it).
  • Everywhere: export FORGE_CLAUDE_ADVISOR= in the environment every wired systemd unit and the dispatcher shares, or set CLAUDE_CODE_DISABLE_ADVISOR_TOOL=1 for the engine-level kill switch.