A Claude Code plugin that keeps your best model in the seat you talk to, and pushes the grunt work — editing files, running tests, searching the codebase — into separate throwaway agent sessions. Your main conversation stays clean.
MIT licensed; house rules in CONTRIBUTING.md, chiefly the honesty policy.
Add the marketplace once, then install:
/plugin marketplace add analogproblems/Opulent # or a local /path/to/Opulent
/plugin install opulent@opulent
Or try it without installing:
claude --plugin-dir /path/to/Opulent
After editing commands, agents, hooks, or manifests, run /reload-plugins or
restart.
Two timing gotchas worth knowing up front:
- Enable/disable takes effect at session start, not mid-session. Enabling a plugin inside a running session registers neither its hooks nor its agents — the session keeps behaving as if the plugin were absent, with no error to tell you so. Start a new session after toggling.
- Updating is two steps.
claude plugin marketplace update opulentrefreshes only the marketplace cache; the installed copy moves when you follow it withclaude plugin update opulent@opulent(then restart).
The problem. In a long session, the conversation you're actually having fills up with things you never needed to read: whole file bodies, test output, search results. The model you're talking to spends its context on clutter.
What it does. Your best coding model — Opus 5 by default — stays in the architect seat: the one you talk to, the one that designs, reviews, and orchestrates. Everything else happens in a delegated agent with its own disposable context. The bulk lands there and is thrown away, so the architect's window stays lean deep into a long session. That's the claim: context hygiene.
The secondary bet — that routing execution to cheaper lanes also slows your
quota drain — is plausible but yours to verify. The routing log
(~/.claude/opulent-log.jsonl) records every delegation and denial, and
/usage shows the spend, so you can check what routing actually did rather
than take our word for it.
How it's enforced. Not by instructions the model can talk itself out of: a hook denies every ordinary path to writing code, running tests, or delegating to catch-all agents from the main loop. See What enforcement is — and isn't for the honest boundary.
Top-shelf reasoning models (Fable) sit outside this system by default. Their usage draws disproportionately on the shared weekly pool, so reserve them — manually, in their own session — for the rare problem the architect genuinely can't crack.
Or seat one as the architect. An official optional mode, for operators
with Fable access: the old rationale assumed Fable would do the work, and
under opulent it only leads. Implementation, tests, docs and exploration all
execute in pinned lanes whose bulk is thrown away, so the architect seat draws
few tokens by construction — the model whose usage you most want to conserve
is precisely the one this architecture protects. Per token the draw is still
disproportionate, so the mode stands entirely on the seat staying lean, and
that is measurable rather than assumable: a fresh Fable session states which
model it is, so the transcript records which brain led, and
~/.claude/opulent-log.jsonl with /usage says whether the seat stayed lean.
A week of Fable-led operation sits behind this. Opus stays the recommended
default.
| Work | Agent | Model |
|---|---|---|
| Architecture, review, conversation, orchestration | main loop | Opus 5 (recommended session model); Fable optionally, same seat |
| Problems Opus can't crack | you, manually | Fable, in its own session — outside this plugin |
| Complex implementation | opulent:coder |
Opus, effort max |
Complex implementation, eco mode (OPULENT_ECO=1) |
opulent:coder-eco |
Opus, effort xhigh |
| Routine edits, boilerplate | opulent:mechanic |
Sonnet |
| Tests, builds, linters, typechecks | opulent:test-runner |
Sonnet (read-only tools) |
| UI verification, screenshots, console errors | opulent:ui-checker |
Sonnet + browser tools |
| Documentation (READMEs, ADRs, guides, release notes) | opulent:scribe |
Opus, effort xhigh |
| Locating code and structure — never analysis or judgment | opulent:scout |
Haiku |
In a Fable-led session the escalation row is moot: the model you would escalate to already holds the seat.
The tiering principle: task fit, not cost. Judgment and complexity go to Opus lanes (effort max; xhigh for scribe); bounded mechanical execution and verification go to Sonnet (effort xhigh); locating goes to Haiku, which is never asked to interpret what it finds. Effort is pinned per lane, not inherited from the session — deterministic like everything else here.
Eco mode. OPULENT_ECO=1 in the environment runs complex implementation
one effort rung down for that session: the session-start policy names
opulent:coder-eco as the implementation lane, and the routing hook denies
opulent:coder with a redirect to the twin — same Opus model, same charter,
effort: xhigh instead of max. The cut is coder-only by design: the routing
log shows the rare judgment lanes barely firing, so eco-ing them would save
nothing, while coder is the high-volume Opus spend. Unset, nothing changes —
and the twin stays spawnable either way, since voluntarily spending less is
never a routing violation. Presence is truth, exactly as with OPULENT_OFF:
any non-empty value turns eco on, so OPULENT_ECO=0 is still eco mode and
unsetting the variable is what turns it off. A tests/ci_checks.py assertion holds
agents/coder-eco.md byte-identical to
agents/coder.md outside name, description and effort,
so the duplication cannot drift silently.
Three built-in Claude Code mechanisms, nothing else:
- Agents (agents/) pin
model:andeffort:in frontmatter — deterministic once delegation happens. - A PreToolUse hook (hooks/route-models.py) guards the control plane and records the rest. Hook payloads include an
agent_idfield only when the call originates inside a subagent, so the hook can tell main-loop work from delegated work. Main-loop edits and test runs are allowed and logged; only the control plane is refused. Calls to the built-inExploreagent are redirected toopulent:scout(plugins can't shadow built-in agents, so the hook redirects instead). - A SessionStart hook (hooks/session-start.py) injects the routing policy as context, so the model delegates proactively instead of bouncing off denials.
Design details:
- Fail-open. Any payload the hook can't parse is allowed. A Claude Code update can never brick your sessions.
- Command-position matching. Test tools are only recorded when actually invoked (
pytest -x,CI=1 pytest,npx jest,./gradlew test,python -m pytest) — not when merely mentioned (echo pytest,grep -r pytest .,git commit -m 'fix eslint config'). - Bash writes seen too. Beyond the Edit/Write tools, the hook tokenizes Bash commands (via
shlex, so quoted strings likegit commit -m "a > b"never false-positive) and sees file redirects (>,>>,>|,&>),tee,cp/mv/touch,patch,git apply, andsed/perlin-place edits. It reads every target in a command, not the first, so a compound that writes/dev/nulland thensettings.jsonis judged on the half that matters. - Catch-all delegation denied. Delegating to
general-purposeorclaudewould satisfy "delegation" while defeating "routing" (full tools, session model) — the hook denies those in the main loop and points at the lanes. Purpose-defined agents from other plugins are untouched. - The control plane, and only it. Refused from the main loop: anything under a
.claudedirectory'shooks/,agents/,commands/orplugins/, asettings*.jsonbeside them, and any.env*— the user's and the project's alike, because both govern the session that is running. A plugin's source repo is ordinary code and is freely editable: it changes nothing until it is installed, and treating it as sacred is what made plugin development expensive. Paths are normalized per-platform, so this holds on Windows and macOS, not just Linux. - Scratch is quiet. The system temp dir and
~/.claude/{plans,projects,todos}are writable and not logged — an audit trail of temp files buries the project edits it exists to surface. - Escape hatch.
OPULENT_OFF=1in the environment disables enforcement for that session — a dial, not a binary, so tuning doesn't require uninstalling. - Telemetry. Main-loop edits (
"event": "edit"), test runs ("test"), delegations ("delegate") and denials ("deny") each append a line to~/.claude/opulent-log.jsonl(override withOPULENT_LOG), and each session opens with a one-line activity summary. The record is the point: what the main loop touched stays visible whether or not it was refused. The doctor's own canary write is still denied, but logged as"event": "probe"so health checks don't skew denial telemetry; the eco redirect is logged as"event": "eco"for the same reason.
Honesty section. As of 0.9.0 the hook denies far less than it used to, and
that is deliberate. It refuses three things from the main loop: the control
plane (settings, hooks, agent and command definitions, the installed plugin
tree, .env*), the built-in Explore agent, and the
general-purpose/claude catch-alls. Everything else — edits, Bash writes,
test runs — is allowed and written to the log.
Why the retreat. Until 0.9.0 every main-loop write was denied to force delegation. Measured against a real session, that cost a subagent round trip per one-line comment and per status stamp, and the protection was mostly redundant: the thing worth having was never the refusal, it was knowing what the main loop touched, and that is a log line. Routing is a judgment the model can make; the control plane is the one place where a silent change would remove the ability to notice later, so that is the one place still refused.
It is not a security boundary. A model determined to edit the control plane from the main loop can still do it (an inline interpreter one-liner, a script it executes, an exotic utility we didn't pattern-match). We deliberately stop short of blocking those, because closing every avenue means blocking Bash itself. Treat the hook as a seatbelt with an audit trail: it makes the recorded path the path of least resistance and makes writes, bypasses and denials visible — in the transcript and in the routing log — rather than making bypass impossible.
Two further honest limits. The main-loop/subagent distinction rests on the
agent_id field in hook payloads — an observed harness behavior, not a
documented contract, and the hook fails open if it ever breaks. Day to day the
drift alarm is the doctor's canary: a hook that stopped telling main loop from
subagent reports as not enforcing, in your own session. The live e2e that
proves the same thing end to end runs by manual dispatch from the private
companion's CI, fired when the harness or the CLI updates — the event that
would actually break this, rather than a date on a calendar. And lane choice
among the opulent agents (coder vs mechanic, scribe vs scout) remains
policy-steered, not hook-enforced — what the hook guarantees is that work
leaves the main loop and lands in a purpose-defined, model-pinned agent.
Run /opulent:doctor. It probes its own installation with real tool
calls: installed version, agents registered, policy injected, enforcement
liveness (a canary write that should bounce), and the telemetry log — then
gives a one-line verdict (LIVE / OFF / PARTIAL / DEAD) with remediation.
"Installed" and "enforcing" are different states, and the difference is
silent; the doctor exists to make it loud.
Run it in a session started after the plugin was enabled — a mid-session enable registers nothing (see the install gotchas), so every probe would report dead when the fix is simply a fresh session.
Manual spot-checks, if you prefer: ask Claude to edit a file directly — the
tool call should be denied with a message pointing at opulent:coder /
opulent:mechanic. To confirm an agent's pinned model from the outside,
grep "model" in its transcript under
~/.claude/projects/<project>/<session-id>/subagents/agent-*.jsonl.
Usage-limit exhaustion hard-blocks the affected model — there is no automatic fallback, and no hook fires that tooling could react to.
- Model-specific cap (e.g. Opus, the architect): switch the session with
/model sonnetand keep working. The agents keep their pinned models and enforcement continues unchanged — the architecture is main-model-agnostic by design, so a Sonnet-led session still routes exactly the same way — as does a Fable-led one; the agnosticism runs upward as well as down. - Shared session/weekly cap: everything waits for the reset shown in the
limit message, subagents included.
/usageshows what's draining the pool, and~/.claude/opulent-log.jsonlrecords what routing actually did — measure before trusting any savings claim, including ours.
lens-master is a separately-shipped private plugin — the steering layer (which perspective, when) to opulent's enforcement layer (which model, where). It is not served by this marketplace and is not required: opulent behaves identically without it.
The two ship from separate repos and neither imports the other, but four couplings are real, and each one breaks quietly if either side moves.
- The doctor's probe string.
/opulent:doctorconfirms lens-master's Secret Keeper hook is live by running exactlygit push --dry-run, and expects the danger log to record that command as verdictproberather thandeny— so repeated health checks do not inflate the near-miss record the log exists to build. The probe is conditional: with lens-master absent the doctor skips it and says so. A skipped probe is never an error and never a failed verdict. Recognition on the far side is exact, so anything beyond the bare command still logs asdeny. - The routing log. lens-master's session steering reads opulent's routing
log at
~/.claude/opulent-log.jsonl(OPULENT_LOGto override) and reports how often its own lanes were actually delegated to. That path is a runtime contract rather than an implementation detail: change it and the companion goes blind. It is a soft read on their side — an absent log is silence, not an error — which is exactly why a move would be silent here too. - The implementation lanes, reciprocally. Any new agent lane in this repo
with unrestricted tools — or a tools allowlist naming
Edit/Write— needs a matching entry in lens-master's delegation-bridgeIMPL_LANESin the same release window. A lane it does not know is a lane whose briefs skip the contract check silently, which reads as green rather than as a gap. Its CI drift-guards that set against this repo's public main, so the failure surfaces over there — the wrong place to learn it, and the reason the rule is written down on this side too. - The live e2e tier runs from over there.
tests/validate_plugins.pyandtests/e2e_smoke.pylive in this repo, beside what they test, but nothing in this repo's CI runs them: they need an authenticatedclaudeCLI, and no self-hosted runner serves a public repository. lens-master's CI clones our main and runs both, by manual dispatch only — the honest trigger is a CLI or harness update on that machine, not a calendar. Renaming or moving either script is a change to a workflow in the other repo, and this side's CI stays green while it breaks.
python3 tests/hook_selftest.py # routing hook payload cases
python3 tests/ci_checks.py # marketplace manifests + session-start JSON
python3 tests/gate_selftest.py # the gate finds planted terms, and never prints them
python3 tests/public_gate.py # no private residue in the object database
python3 tests/validate_plugins.py # claude CLI structure validation (needs claude on PATH)
ci_checks.py and validate_plugins.py both derive their member roster from
marketplace.json — a member sourced from another repo is skipped with a
notice rather than failing, since its manifest and CI live in its own tree.
- Change a lane's model or effort: edit the frontmatter in agents/.
- Add/remove recorded test runners: edit
TEST_REin hooks/route-models.py. - Change what counts as the control plane:
_CONTROL_SUBDIRS/_SETTINGS_RE; change what stays out of the log:_SCRATCH_DIRS, in the same file. - Disable opulent for a session:
OPULENT_OFF=1. Run implementation one effort rung down:OPULENT_ECO=1. Redirect telemetry:OPULENT_LOG=<path>.