Your coding agent runs on a cheap, fast model most of the time, and most of the time that's the right call — it's grinding through edits, running tests, moving quick. The trouble is the handful of moments that actually decide how the thing turns out: the architecture choice, the "should I even build this," the bug it's been circling for twenty minutes. That's where cheap-and-fast quietly makes the wrong call, and you don't catch it until three commits later.
bpx-consult is the smarter, pricier model you keep on the bench for exactly those moments. One advisor for a quick gut-check, a whole council when the call's genuinely hard, two of them arguing it out when it's contentious. Let the cheap model do the typing; pay senior rates only when senior judgment is actually worth it.
The advisor that died right when I needed it
None of this is a new trick for me. I'd already run the same idea — cheap models doing the grunt work, a stronger one taming and steering them — in a private tool of my own, well before I needed it in pi. So when I wanted it here, I knew the pattern worked.
The catch was the advisor extension I tried in pi kept dying on me. It forwarded the entire session to the advisor without ever checking whether the advisor's own context window could hold it. So my second opinion errored out at exactly the moment the session got long enough to need one. An advisor that quits the second the conversation gets interesting isn't an advisor.
It's a liability.
So I built bpx-consult — same pattern, done right for pi. And once you're already paying to call a second model, why stop at one, and why only to review? A council. A debate.
A cheap model driving and an expensive one steering — with a context engine that finally makes it survive a long session, which is the part the old extension never got right.
Four modes, because not every question is the same size
Some calls need a fast sanity check. Some need three senior brains and a referee. bpx-consult ships all four, and the executor can reach for whichever fits:
- solo — one advisor model, one response. Fast, cheap, the second opinion you reach for most days.
- council — several models in parallel, each with a stance and a persona, and a synthesizer that merges their verdicts with a confidence score. For real decisions: architecture, "should I even do this," tricky bugs where one voice isn't enough.
- debate — an advocate proposes, a critic attacks, the advocate rebuts, then a synthesizer issues a verdict. For controversial calls where you want the strongest case on both sides before you commit.
- gut-check — one cheap fast model, terse output. The "does this smell off?" check before you do something you're 90% sure about.
Call it with no arguments and solo runs. Ask for a council when the stakes earn it.
A council that's actually allowed to disagree
This is the part I went past a bugfix for. The default roster seats three personas — an architect who argues for the design, a critic whose whole job is to find the holes, and a simplifier who keeps asking whether you need the thing at all. Each runs on its own model tier and gets a stance baked into its prompt. But the stance only biases what a persona hunts for — never the verdict.
A persona structurally incapable of dissent is theater, and a critic that rubber-stamps is worse than no critic.
Say you ask whether to ship a half-built feature for the next morning's demo. The architect argues ship it and caveat it live. The critic argues a broken demo teaches the room the wrong thing. The synthesizer refuses to average them into mush:
VERDICT — STOP. Demo the pre-recorded flow; ship the real feature once it's tested.
confidence 0.83 (success 1.0 · agreement 0.5 · alignment 1.0)
That agreement 0.5 is the disagreement showing up in the math: two of three held opposing stances, so the confidence dial drops. That's the feature, not the bug. A council that always reports high confidence isn't worth the tokens.
The fix nobody else bothered with
Every consult runs the conversation through a context engine before it reaches the advisor. The first version was blunt about it: keep the first couple of messages, keep the last few, drop the middle. It never overflowed. But "keep recent, drop old" is a lousy proxy for "keep what matters." In a long debugging session the line explaining why you're stuck is usually buried in the middle, and blindly clipping a message shreds the one stack trace the advisor needed.
So now it classifies before it cuts. Every message gets a deterministic tag — directive, diff, failing-output, stack-trace, test, exploration — from what the message is, never from the stuck model's own judgment. Then it fills the window by priority rather than position: your question pinned first, the latest failure and the latest diff kept verbatim, the older exploration path compressed to one-line signals (read x.ts, $ npm test (exit 1)), then dropped. Compress the path, preserve the payload.
And because it now decides what to keep, it can show its work. Every consult comes back with an audit ledger — what got kept whole, compressed, clipped or dropped, plus the token count it fitted into. You can watch a 150k session fold into a 28k advisor and see exactly what survived. A token count alone can't tell you why a consult was bad; the ledger can.
The load-bearing bit: the budget is read per call from that advisor's real context window, never a global constant. Point a small flash-tier advisor at a long session and it fits. Point an 8k CLI advisor at the same session and it still fits. A council fits every member to the smallest window in the roster so the weakest one can't overflow.
This is the plumbing that makes "cheap executor, expensive advisor" actually survive a real session — the whole reason the extension exists.
Triggers, and how the advice gets back to you
Consults don't have to be manual. Two auto-triggers, both off by default: whenStuck fires after a few consecutive tool errors or the same tool call on repeat (it catches loops), and onDone reviews the work when a turn finishes. Auto-fires always run solo — a safety net shouldn't quietly burn three model calls every time you hit a loop. And they never fire in an untrusted project.
When the advice comes back, it can steer the agent mid-run (the default — you get the second opinion without leaving the flow), pipe in as if you typed it, or just show in the UI where only you see it. The advisor unblocks the agent without you having to stop, read, copy, paste, and restart.
Seats you can actually change — and one that can die without taking the room down
None of this lives in a config file you have to hand-edit. Type /consult and you get a menu: default mode, the models for solo and gut-check, the council roster, the auto-triggers, on/off. Pick a setting, choose from a fuzzy-filterable list of the models you've actually got authed, and it saves and reopens so you can set several in one pass.
Adding a council member doesn't mean writing a system prompt either. Describe what you want the advisor to focus on and a model drafts the persona: name, stance, and a lens specific to that focus. The stance vocabulary is the honest kind: against hunts for risks and flaws, for advocates, neutral weighs. Before a model takes a seat it gets probed with that persona's own prompt, so a dead key or a 401 surfaces right there instead of blowing up your first real consult.
Each seat also picks its own backend. A model you've authed in pi runs inline; something you only have as a CLI (codex, claude, opencode, or any custom command you point it at) gets spawned as a subprocess with the fitted prompt piped to its stdin. That's per persona, so two advisors on the same model can reach it different ways, and a single council can mix inline and CLI seats in one run. It spawns rather than blocking, so CLI seats run alongside the inline ones instead of queueing behind them.
Which brings it full circle. The extension I replaced died when one call failed. This one fans the council out so a seat that falls over — rate limit, dead key, provider having a moment — just gets marked as an empty chair while the rest carry on and the synthesizer works with what came back. The exact failure that made me build the thing can't take the whole thing down anymore.
The first room in the house
bpx-consult is the first extension in bpx-mono — a monorepo of small, sharp tools for pi, the minimal terminal coding harness. pi stays lean and does the work; these add the bits I kept wishing it had. Each one installs on its own:
pi install npm:@booplex/bpx-consult
It's built on the same instinct as the rest of the shelf — slopbuster for AI writing tells, pixelslop for visual slop, pixeltamer for images that do what you asked. Tools for people who care whether the machine got it right. Because the advisor that dies when you need it most isn't an advisor — and I'd rather build the one that doesn't.
