Skip to content

jcfrancisco/opencode-advisor

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 

Repository files navigation

advisor

An opencode plugin that implements the advisor pattern: a cheaper/faster executor model consults a stronger planner model mid-generation for strategic guidance, then continues the task informed by the advice.

This is a client-side reimplementation of Anthropic's advisor tool, which is server-side and Claude-only. This plugin works with any executor model opencode supports and lets you pick the advisor model from several providers.

How it works

  1. The plugin registers an advisor tool with the executor.
  2. When the executor calls advisor, optionally with a short focus, the plugin fetches the full conversation transcript via the opencode SDK, serializes it, and sends it to a configured advisor model (Claude, GPT, etc.).
  3. The advisor's guidance returns to the executor as the tool result, and the executor continues.

The executor decides when to call the advisor (like any tool). Models not tuned for this pattern (e.g. GLM, Haiku) may need a nudge in your agent prompt or a mid-conversation reminder to call it.

Design goals, and how this compares

This isn't the only opencode adaptation of the advisor pattern. A quick search will turn up several others, and some are better engineered than this one in real ways (per-session call budgets, secret redaction, actual test suites). Several of those gaps are acknowledged in Future work.

What this plugin optimizes for, in order:

  1. Fidelity to the documented pattern's behavioral core. The advisor is a single tool-less inference call that returns advice text only, capped at the docs' recommended 2048 output tokens. It is not a research subagent with its own tool loop. The full transcript is attached automatically; the executor's only job is a short focus.
  2. Anthropic's call-timing guidance, taken seriously. The docs' eval data suggests most of the pattern's gains come from when the executor calls the advisor: early, before the approach crystallizes, plus once before declaring done. It also suggests that "use sparingly / only when stuck" framing gives most of the value back. AGENTS.md ships the docs' suggested timing prompt nearly word-for-word instead of a rewrite.
  3. Freedom in choosing the advisor. Any Anthropic- or OpenAI-protocol model can advise, with reasoning effort passed through. Picking a stronger planner than your executor is the whole point of doing this client-side.

When I did a brief search online (July 2026), those were the strengths that set this one apart: the alternatives I found variously gave the advisor its own tool loop, told the executor to hold back on calling it, or fixed the advisor to a single provider. By the time you read this, someone may well have built one that's better even by these criteria. If you find it, use it (and tell me).

Installation

Option A: Agent-assisted (recommended)

In an opencode session, ask your agent to integrate the plugin for you:

Integrate the opencode-advisor plugin from https://github.com/jcfrancisco/opencode-advisor into this project.

The agent will read the repo, create .opencode/plugins/advisor.ts, .opencode/package.json, and .opencode/advisor.config.json in your project, and tell you how to configure it. It should also append the executor guidance from AGENTS.md to your project's AGENTS.md (creating one if it doesn't exist) so the executor calls advisor at the right moments.

Option B: Manual

Copy .opencode/plugins/advisor.ts, .opencode/package.json, and .opencode/advisor.config.json from the repo into your project's .opencode/ directory. opencode auto-loads plugins from .opencode/plugins/ and runs bun install for package.json deps at startup.

Not on npm yet. Holding off for now — this file structure is easier to test locally, and installing via agent is seamless enough anyway.

Setup

Configuration lives in JSON, not environment variables. The plugin reads two files and merges them, with the second taking priority:

  1. Project default.opencode/advisor.config.json, shipped with the plugin and committed to your repo.
  2. Personal override$XDG_CONFIG_HOME/opencode-advisor/config.json (defaults to ~/.config/opencode-advisor/config.json), for a per-machine choice you don't want to commit (e.g. a provider only you have a key for).

Either file may set any subset of keys; unset keys fall through to the other file, then to built-in defaults. Example personal override:

{
  "provider": "zen-anthropic",
  "model": "claude-opus-4-8",
  "effort": "xhigh"
}

You still need an API key for your chosen provider — set it via environment variable, or sign in via opencode auth login (see API keys below).

Add the suggested text from AGENTS.md to your executor agent's prompt (the body of .opencode/agent/<name>.md, or the prompt field under agent in opencode.json) so the executor calls advisor at the right moments. If your project doesn't already have an AGENTS.md, the agent-assisted install below will create one.

Restart opencode.

Config file

.opencode/advisor.config.json (and the personal override) accept:

Key Default Description
provider anthropic Which provider/protocol to use for the advisor. See table below.
model provider-specific The advisor model ID. See table below.
effort null (unset = provider default) Effort/reasoning level, passed through verbatim. See table below.
maxTokens 2048 Cap on the advisor's response length.

API keys

provider Required env var
anthropic ANTHROPIC_API_KEY
openai OPENAI_API_KEY
zen-anthropic, zen-openai ZEN_API_KEY

If the env var isn't set, the plugin falls back to opencode's own ~/.local/share/opencode/auth.json (written when you sign in via opencode). API keys are never read from the config JSON.

Providers

provider API used Key env var Wire param for effort
anthropic (default) Anthropic Messages ANTHROPIC_API_KEY output_config.effort
openai OpenAI Chat Completions OPENAI_API_KEY reasoning_effort
zen-anthropic Zen → Anthropic /v1/messages ZEN_API_KEY output_config.effort
zen-openai Zen → OpenAI /v1/responses ZEN_API_KEY reasoning.effort

Models

Pick model from the column for your provider. Defaults are marked.

Provider Default Example model IDs
anthropic claude-sonnet-4-6 claude-opus-4-8, claude-opus-4-7, claude-sonnet-5, claude-sonnet-4-6, claude-haiku-4-5
openai gpt-5.5 gpt-5.5, gpt-5.5-pro, gpt-5.4, gpt-5.4-mini, gpt-5.3-codex
zen-anthropic claude-sonnet-4-6 claude-fable-5, claude-opus-4-8, claude-opus-4-7, claude-opus-4-6, claude-opus-4-5, claude-sonnet-5, claude-sonnet-4-6, claude-sonnet-4-5, claude-haiku-4-5, qwen3.7-max, qwen3.7-plus, qwen3.6-plus, qwen3.5-plus
zen-openai gpt-5.5 gpt-5.5, gpt-5.5-pro, gpt-5.4, gpt-5.4-mini, gpt-5.4-nano, gpt-5.3-codex, gpt-5.3-codex-spark, gpt-5.2, gpt-5.1, gpt-5, gpt-5-nano

Zen's Gemini and OpenAI-compatible models (GLM, Kimi, DeepSeek, MiniMax, Grok) are not supported as advisors yet — only the Anthropic-protocol and OpenAI-protocol models above.

Effort levels

effort is passed through verbatim per provider — no mapping. Unset = omit the param (provider default). Invalid values for your model will be rejected by the API with a 400, which surfaces to the executor as a tool error.

Provider Param location Valid levels (model-dependent)
anthropic, zen-anthropic output_config.effort low, medium, high (default), xhigh, max
openai reasoning_effort (top-level) none, minimal, low, medium, high, xhigh
zen-openai reasoning.effort none, minimal, low, medium, high, xhigh

Notes:

  • Anthropic effort is supported on Fable 5, Mythos 5, Opus 4.8/4.7/4.6, Sonnet 5/4.6, and Opus 4.5 — not Haiku 4.5 or older. high is equivalent to omitting it.
  • OpenAI effort levels are model-dependent ("some models support only a subset"). gpt-5.5 defaults to medium.
  • The vocabularies differ between providers (Anthropic has max with no OpenAI equivalent; OpenAI has none/minimal with no Anthropic equivalent), so values are not normalized — pick one valid for your provider/model.

Caveats vs. Anthropic's built-in advisor

This is a client-side approximation. Differences from Anthropic's server-side advisor tool:

  • Transcript timing: the advisor sees messages up to the last completed one, not the in-progress partial of the current turn.
  • No single-request illusion: each advisor call is a genuine extra round trip from your machine.
  • No advisor-side prompt caching across calls within a conversation.
  • No max_uses cap, no usage.iterations cost breakdown, no redacted/encrypted result variants.
  • Timing is not tuned: the executor decides when to call the advisor. Models not trained for this (GLM, Haiku) may not call it reliably without a nudge — add language to your agent's prompt ("consult the advisor for non-obvious design decisions") or inject a mid-conversation reminder.

Files

.opencode/
  package.json          # declares @opencode-ai/plugin, @anthropic-ai/sdk, openai deps
  advisor.config.json    # shipped default config (provider, model, effort, maxTokens)
  plugins/
    advisor.ts          # the plugin: registers the `advisor` tool

Future work

Features from Anthropic's advisor tool docs that are reasonable to reproduce client-side but aren't implemented yet. Each notes the doc section it comes from and a starting point in this plugin's architecture.

  • Automate the mid-conversation nudge. Inject a reminder to consult the advisor if an under-calling executor (Haiku, GLM) hasn't called it by turn N. Today this is manual prose in AGENTS.md. Docs: Mid-conversation nudge for under-calling executors (NUDGE_TURN / NUDGE_TEXT). Approach: count assistant turns and whether advisor fired via the chat.message / tool.execute.after hooks, then append the nudge as a user message through experimental.chat.messages.transform. Gate on a config key (e.g. nudgeTurn).

  • Call caps (max_uses + conversation-level). Cap how many times the advisor runs so a chatty executor can't rack up cost. Docs: Tool parameters (max_uses) and Cost control. Approach: a module-level Map<sessionID, count> incremented in execute; past maxUses return a short "advisor limit reached" string instead of calling the model.

  • Graceful error results. An advisor failure (network, bad effort, prompt_too_long) currently throws raw. Anthropic's design is that the executor sees an error result and continues; the turn doesn't fail. Docs: Error results. Approach: wrap the provider call in try/catch and return "(advisor unavailable: …)" so the executor proceeds.

  • Advisor usage/cost reporting. Surface advisor token counts so the extra spend is visible. Docs: Usage and billing (usage.iterations). Approach: read resp.usage from each provider response and report it via the tool context's metadata({ metadata: { … } }).

  • Advisor-side prompt caching (stretch, Anthropic only). Cache the advisor's transcript prefix across calls in a conversation. Lower ROI here since each call is stateless and the payoff only appears at ~3+ calls per conversation. Docs: Advisor prompt caching. Approach: add a cache_control breakpoint on the transcript block in the Anthropic/zen-anthropic branch; OpenAI providers cache automatically with no knob.

About

OpenCode plugin to apply Claude's "advisor" pattern

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors