Red while an agent works.
Amber when one needs you.
Green when they're all free.
One Chrome toolbar lamp for every coding agent on your machine: Claude Code, Codex CLI, GitHub Copilot CLI and Antigravity CLI, plus opencode, Goose and Qwen Code on the free tier. Optional desktop notifications. It works on macOS, Ubuntu and Windows.
perturbation (n.): in physics and astronomy, a small disturbance of a system by an outside influence, stated without any judgement of whether the disturbance is welcome.
One lamp, four states
Only one lamp is ever lit, and the fill pattern carries the meaning without colour: solid, dotted, ring, dashed.
Perturbed
At least one agent is working. The badge counts the busy sessions.
Needs you
Nothing is working, but a session waits for a permission or an answer.
Unperturbed
Every watched agent is free.
Not connected
The local helper isn't running, or no agent is watched. Run the installer.
What you get
Small, local, and with no dependencies beyond Python 3.
- One button for every agentThe four earlier projects (Claudication, Codexalgia, Copilonidal, Antigravalgia) become one host, one extension, one lamp. The installer removes the old ones for you.
- A count, not a colourThe badge shows how many sessions are busy across every agent, so the lamp answers "how much" and not only "whether".
- Needs you, separatelyAmber is its own state, so an agent blocked on a permission never hides behind one that is still working.
- A popup you can shapeOne row per agent, a mute switch each, and drag rows into the order you want.
- Three platformsmacOS, Ubuntu/Linux and Windows. The installer detects which one you're on and which agents you have.
- Stays out of the wayHooks that always exit 0 and print nothing, merged into files that stay yours and are backed up first.
- Fully localNothing leaves your machine. The status goes from each agent's hooks to Chrome over native messaging.
Install
Requires Python 3.9 or newer and Google Chrome.
git clone https://github.com/Tpojka/perturbation.git
cd perturbation
./install.shsudo apt install python3 libnotify-bin # notify-send, for the notifier
git clone https://github.com/Tpojka/perturbation.git
cd perturbation
./install.shwinget install Python.Python.3.12 # if Python isn't installed
git clone https://github.com/Tpojka/perturbation.git
cd perturbation
install.cmdChoose what to watch and what to install
Which agents should be watched?
[x] 1) Claude Code found ~/.claude
[x] 2) Codex CLI found ~/.codex
[ ] 3) GitHub Copilot CLI not found
[x] 4) Antigravity CLI found ~/.gemini/antigravity-cli
[x] 5) opencode found ~/.config/opencode
[ ] 6) Goose not found
[ ] 7) Qwen Code not found
Space or 1-7 toggles, ↑/↓ moves, a: all, n: none, Enter confirms:
What should be installed?
1) Chrome extension
2) Chrome extension + OS notifier
3) Nothing (exit)
Choose 1, 2 or 3: 2
Play a sound with notifications? [Y/n]:
Let Antigravity show "needs you" alerts? This sets its status line command. [y/N]:
Finish in Chrome (once)
- Open
chrome://extensionsand turn on Developer mode. - Click Load unpacked and pick the
extensionfolder the installer printed. - Pin Perturbation to the toolbar.
- Restart any running agent sessions so they load the hooks. In Codex, run
/hooksand trust the new hooks.
Had Claudication, Codexalgia, Copilonidal or Antigravalgia installed? The installer lists what they left behind and offers to remove it, keeps your notification settings, and prints the old extension IDs to remove at chrome://extensions.
OS notifier
You get a notification when an agent finishes a turn and when it needs you. The title names the agent and the project.
| When | Title | Text |
|---|---|---|
| An agent finishes a turn | Claude is ready · project | the first line of its last message, or "Task finished" |
| An agent needs a permission or an answer | Codex needs you · project | the prompt, or what it wants to run |
| A turn ends with an error | Claude stopped · project | the error type |
Notifications are sent only when a session's state actually changes, never for a reminder that repeats a finished turn, and each agent can be muted in the popup.
Change settings any time
Run these from the repository. They take effect at once, with no restart:
python3 -m perturbation.install set agents claude,codex # watch exactly these
python3 -m perturbation.install set sound off
python3 -m perturbation.install set notifications off
python3 -m perturbation.install mute codex on # silence one agent, keep its lamp
python3 -m perturbation.install statusline antigravity on # "needs you" alerts for Antigravity
python3 -m perturbation.install status
python3 -m perturbation.install doctorOn Windows, use py -3 instead of python3.
How it works
Each agent's hooks write its sessions' state. One small local helper sends the sum to Chrome.
Claude Code ──hook──┐
Codex CLI ──hook──┤
Copilot CLI ──hook──┼──► perturbation.pyz hook <agent> ──► sessions/<agent>/<session> (busy | waiting | ready)
Antigravity ──hook──┘ └──► desktop notification (optional)
Chrome ──starts──► perturbation.pyz host
watches sessions/, pushes a per-agent summary on change
│ native messaging
▼
extension: lamp + badge + tooltip, popup on clickEach agent is one small adapter that knows its hook file and its events. Everything else is shared: one hook handler, one state tree, one host, one lamp.
| Agent | Busy | Needs you | Ready |
|---|---|---|---|
| Claude Code | prompts, tool calls, compaction | permission prompts, questions | Stop, a manual compaction, an error |
| Codex CLI | prompts, tool calls | permission requests unanswered for 5 s | Stop, Interrupt |
| GitHub Copilot CLI | prompts, tool calls | permission prompts, questions | Stop, an unrecoverable error |
| Antigravity CLI | invocations, tool calls | its status line, when you turn it on | Stop when fully idle |
| opencode | session status, tool calls | permission prompts | session.idle, an error |
| Goose | prompts, tool calls, file and shell steps | never: Goose has no permission event | Stop |
| Qwen Code | prompts, tool calls, compaction | permission prompts and requests | Stop, a manual compaction, an error |
Every hook command exits 0 and prints nothing, even when Python or the app is missing. Copilot denies a tool call when a hook fails, Claude's PreCompact blocks compaction on exit 2, and Antigravity reads a hook's stdout as a decision, so this is what keeps the agents unharmed. A busy session with no activity for 15 minutes counts as ready, and one waiting for an hour does too, for the agents that never say goodbye.