A Claude Code plugin that changes the reasoning effort level from the keyboard, per agent, without leaving a row in the transcript:
- Alt+E steps the effort up: low → medium → high → xhigh → max, stopping at max.
- Alt+Shift+E steps it down, stopping at low.
- The keys change the agent in view: the main thread, or the subagent whose transcript you opened from the tasks list. Every other agent keeps its level.
- The footer shows that agent's model and level as they change, as a meter colored
cool to hot (gray, green, yellow, orange, red, by theme color), the blocks a
press fills or empties lit for a moment:
Opus 5.5 ▰▰▰▱▱ high. A press past either end lights the level's word. At max the model name turns red too, and while Claude works a light sweeps across the bar. In a subagent's transcript the meter is that agent's, led by its type:Explore · Opus 5.5 ▰▰▱▱▱ medium. - A line under each Agent call in the transcript shows the level of the agent it started.
- With one setting (see Levels in the tasks list),
each subagent's row in the tasks list under the prompt shows its level too:
Fix the parser · ‹▰▰▰▱▱› high · Reading the failing test.
Each agent's level is its own and applies to that agent's next model requests.
A subagent starts at the level Claude Code gives it (its definition's
effort, else the main thread's), which the plugin reads off the subagent's
first model request; until then its meter is empty (—), and a press leaves
it and says wait. Changing effort Claude Code's way (/effort, the Alt+P
picker) takes over again from the next request, for the main thread and for
any subagent whose level Claude Code changes with it.
With the session also open on another surface over Remote Control (Claude Code Desktop), each surface follows its own view: the keys step the agent that surface is viewing.
What it hooks: each model request, the main thread's and every subagent's, to
read its effort level and set the one picked for that agent; each subagent's
start, to tie the Agent call to the agent it started; the /effort and
/model commands, which it lets run unchanged and only watches afterwards to
drop its own level and redraw the footer; the footer itself, to draw the
meter; the Agent calls' rows, to add the line under them; and the band above
the prompt, which says whose transcript is in view and where two hidden
buttons take the keys, leaving whatever other plugins and Claude Code show
there in place. It reads your settings and the session's list of agents and
nothing else, sends nothing anywhere, and keeps its state in the session, save
the levels it leaves for the tasks list's rows when you turn that on.
Mods (plugins of function hooks) are an early-access Claude Code API that changes between releases. This one is built and tested against Claude Code 2.1.289.
-
Install it from the anerco marketplace, in Claude Code:
/plugin marketplace add Anerco/plugins /plugin install effort-cycle@anercoOr, to work on it, clone the repo and load the folder with
claude --plugin-dir <folder>, or in every session throughCLAUDE_CODE_PLUGIN_DIRSin theenvblock of~/.claude/settings.json. -
Bind the keys in
~/.claude/keybindings.json:{ "bindings": [ { "context": "Global", "bindings": { "meta+e": "strip:jump9", "meta+shift+e": "strip:jump8" } } ] }A mod cannot own a key. It can only borrow one of Claude Code's own keybinding actions, so the mod listens for
strip:jump9(up) andstrip:jump8(down). Any modified key or chord works; a bare letter does not.On macOS, Option+E types an accent unless the terminal sends Option as Meta: in Terminal.app turn on Use Option as Meta key (Settings → Profiles → Keyboard), in iTerm2 set Left Option key to Esc+ (Settings → Profiles → Keys), in Ghostty set
macos-option-as-alt = true. Or bind a ctrl chord instead.
A plugin cannot draw in the tasks list, but Claude Code draws its subagent
rows from a command's output when ~/.claude/settings.json names one as
subagentStatusLine. This repo has one, subagent-rows/rows.py (it needs
Python 3). Copy it somewhere of its own, outside the plugin, and name it in
settings:
mkdir -p ~/.claude/subagent-rows
curl -fsSL https://raw.githubusercontent.com/Anerco/claude-code-effort-cycle/main/subagent-rows/rows.py -o ~/.claude/subagent-rows/rows.py"subagentStatusLine": { "type": "command", "command": "python3 ~/.claude/subagent-rows/rows.py" }Each row then reads the Agent call's description, the agent's level, what it is doing, and, dim, how long it has run and its tokens, as Claude Code's own row shows them:
◯ Fix the parser · ‹▰▰▰▱▱› high · Reading failing note test · 53m 11s · ↓ 499.8k tokens
A row too wide for the list drops its tokens, then its time, then is cut in its activity. The time shows only while the agent runs: the command is told when an agent started, not when it ended. Claude Code runs the command every five seconds while there are subagents, so a row follows an Alt+E press within that. The main thread has no row there, and its level stays in the footer.
While the setting is there, the plugin writes each subagent's level to
~/.claude/subagent-rows/sessions/<session id>/effort-cycle.json as
{"order": 10, "agents": {"<agent id>": "<text>"}}. The script joins every
file in a session's folder by order, so another plugin can add its own part
of the rows the same way, and it deletes a session's folder once nothing in it
has changed for a week.
/config lists five toggles, Effort keys: include low through include
max, all on by default. The keys step only through the levels that are on,
for every model.
The values are stored in ~/.claude/settings.json under pluginConfigs,
under the plugin's key (effort-cycle@anerco when installed from the
marketplace).
- The spinner can show a different level from the footer (#1). The footer is the level the requests go out with; the spinner reads Claude Code's own state, which a mod cannot change.
- The level is not kept after a restart. An Alt+E pick lasts for the session. A mod cannot write settings, so it cannot save the level the way the Alt+P picker does.
- A subagent's level shows once it has made a model request. Neither the
session's list of agents nor a subagent's start says what effort it runs at,
so the plugin learns it from the agent's first request, a moment after it
starts. An agent started before the plugin loaded shows
—until its next request. - The tasks list shows the levels only through a command. The plugin API
draws no part of it, so its rows need the
subagentStatusLinesetting (Levels in the tasks list), and follow a press within five seconds. - The keys change only the agent in view. To step another agent, open its transcript from the tasks list.
- Ultracode is not a step. It is a separate on/off switch that works at
any level (
/effort ultracode on), and the plugin API exposes no way to switch it.
claude plugin validate .
claude plugin test .
tsc -p .Claude Code writes the API declarations an editor and tsc type the mod
against into .claude-plugin/types each time it loads the folder. They are
generated per Claude Code build and are not committed.
effort-cycle collects no personal data. It reads Claude Code's own settings
and the session's model and agents, keeps each agent's effort level in session state
on your machine, and sends nothing to any server: no telemetry, no network
requests. With the subagentStatusLine setting it also writes each subagent's
level to a file under ~/.claude/subagent-rows, which the script deletes a week
after the session last wrote it; otherwise nothing is kept after the session
ends.
MIT
