{"slug": "tmux-agent-status-quiet-keyboard-first-control-of-coding-agents", "title": "Tmux-agent-status – Quiet, keyboard-first control of coding agents", "summary": "Developer gs released tmux-agent-status, an open-source tmux plugin that shows coding agents' status only when they need attention, supporting Claude Code, Codex, opencode and pi. The plugin requires tmux ≥ 3.2 and bash ≥ 4.2, displays a `⚠N` marker when an agent is blocked on a permission and a `✓N` marker when it finishes, and installs via TPM with `set -g @plugin 'gs/tmux-agent-status'` followed by `install.sh all`.", "body_md": "**The anti-dashboard for AI coding agents in tmux.** No sidebar, no live feed of prompts and tool\ncalls, no desktop notifications, no daemon. For Claude Code, Codex, opencode and pi: nothing is\nshown while an agent works. When one needs you — blocked on a permission, or just finished — you\nget a small marker in the bar, plus a searchable popup to jump straight to it. **It lives entirely\ninside tmux.**\n\nThree states, and only two of them ever show up. Working is deliberately invisible.\n\n| state | meaning | bar / window marker | banner (optional) | \n|---|---|---|---|\n| working | agent busy | nothing | never | \n| waiting | blocked on a permission or a question | `⚠N` /`⚠` | yes, unless you're already looking at it | \n| done | finished, you haven't looked yet | `✓N` /`✓` | never | \n\nThe bar at three moments: five agents working (nothing shown), `codex` finishing (a quiet `✓`), and\n`claude` blocking on a permission prompt in another session (`⚠`). The `✓` clears the moment you\nfocus that pane, with nothing to dismiss.\n\nThe `⚠` stays in the bar until you deal with it. If you want a nudge as well, turn on the banner\n(`set -g @agent-status-banner on`): for a few seconds the status line of every attached client shows\nwhich agent is blocked and where. It never shows if you're already looking at that pane, and never\ntwice within 10 seconds for the same one.\n\nA popup lists every agent in every session: needs-you first, then done, then working, then agents\nthat haven't reported yet (`○`, found by process name). The preview shows the selected pane's\nlatest output, here the exact command it is asking permission for.\n\nType to filter by agent, session or window. Enter jumps.\n\nEnter switches session, window and pane.\n\nAnswer it and the warning clears itself. The finished agent's `✓` waits for you.\n\n| need | why | notes | \n|---|---|---|\n| **tmux ≥ 3.2** | `display-popup` , array hooks | required | \n| **bash ≥ 4.2** | associative arrays | required. macOS ships 3.2: `brew install bash` | \n| **git** | clone / TPM | to install | \n| **procps** (`ps` ) | knows when an agent has really exited | required in practice; without it the plugin falls back to the foreground command name, which is less reliable for wrapper scripts | \n| **coreutils, sed, awk, util-linux** (`readlink -f` ,`sort` ,`flock` ) | ordinary plumbing | present on any normal Linux; `flock` is optional | \n| **fzf** | the searchable popup | optional. Without it `prefix a` opens a plain numbered tmux menu | \n| **jq** | `install.sh` editing your agents' JSON configs | needed to run `install.sh` ; the hooks themselves work without it | \n\nDebian/Ubuntu: `sudo apt install tmux git jq fzf` (the rest is normally preinstalled).\nArch: `sudo pacman -S tmux git jq fzf`.\n\nLinux is what it's developed and tested on. Nothing here is desktop-specific, so macOS should work with a newer bash, but it is untested. The pi and opencode adapters run inside those agents' own runtimes (Node), so they need nothing extra.\n\n**Quick start (TPM):** needs [TPM](https://github.com/tmux-plugins/tpm) installed first.\n\n```\n# ~/.tmux.conf\nset -g @plugin 'gs/tmux-agent-status'\ntmux source ~/.tmux.conf   # then press prefix + I to fetch the plugin\n~/.tmux/plugins/tmux-agent-status/install.sh all   # wire up every installed agent\n```\n\nThat's it — two commands, no binary to download, no config to hand-edit. `install.sh all` is\nidempotent and safe to re-run; add `--uninstall` to undo it.\n\n**Without TPM**, add to `tmux.conf`, *after* your status-bar options (use the path you cloned this\nrepo into):\n\n```\nrun-shell /path/to/tmux-agent-status/agent-status.tmux\n```\n\nThe plugin prepends `#{@agent_summary}` to `status-right` and appends a marker to the window formats.\nSet `@agent-status-modify-status off` / `@agent-status-modify-window-format off` to place\n`#{@agent_summary}` / `#{@agent_mark}` yourself.\n\nThen connect the agents — this is the same step the TPM quick start above already ran for you via\n`install.sh all`; run it yourself if you installed without TPM, or to wire up individual agents (each\nstep is optional, idempotent and reversible with `--uninstall`):\n\n```\n./install.sh all            # or: claude | codex | opencode | pi\n```\n\n| agent | how it reports | notes | \n|---|---|---|\n| Claude Code | hooks in `~/.claude/settings.json` (existing hooks are kept) | working / waiting / done | \n| Codex | hooks in `~/.codex/hooks.json` | approve the new hooks once with `/hooks` | \n| opencode | plugin symlinked into `~/.config/opencode/plugin/` | sub-agent sessions are ignored | \n| pi | extension symlinked into `~/.pi/agent/extensions/` | working / done only (pi has no permission prompts) | \n\nVerified so far: **pi** (live), **Claude Code** (live: a real `claude -p` run goes working → done → cleared;\nthe permission `waiting` path is covered by payload-shape tests, not a live prompt). **Codex** and\n**opencode** adapters are written against their documented events but **not yet run live**: please\nreport what you see.\n\nAgents that were already running when you installed keep running without reporting: restart them\n(in pi, `/reload`). They still appear in the list as `○` because they are found by process name.\n\n| key | action | \n|---|---|\n| `prefix a` /`prefix A` | searchable agent list, enter jumps ( `Esc` closes); a plain menu if fzf isn't installed | \n| `@agent-status-key-next` (unbound by default) | one key: jump to the oldest agent that needs you | \n\nA short message on the status line when an agent starts **waiting** (not when it finishes). It is the\nonly \"notification\" the plugin has, and it stays inside tmux: nothing is sent to your desktop, so it\nalso works over SSH and on machines with no notification daemon.\n\n- Skipped when you're looking at that pane; repeats for the same pane within `debounce` seconds are dropped.\n- Enable: `set -g @agent-status-banner on` . Length:`@agent-status-banner-ms` (default 5000).\n\n`set -g @agent-status-<name> <value>`\n\n| option | default |  | \n|---|---|---|\n| `key-pick` | `a A` | keys for the popup; `\"\"` to skip | \n| `key-next` | none | key for jump-to-oldest-waiting | \n| `agents` | `pi claude codex opencode` | process names listed before they report | \n| `banner` | `off` | status-line banner when an agent starts waiting | \n| `banner-ms` | `5000` | how long the banner stays | \n| `debounce` | `10` | min seconds between banners per pane | \n| `icon-waiting` /`icon-done` | `⚠` /`✓` | bar and window markers | \n| `color-waiting` /`color-done` | `yellow` /`green` |  | \n| `modify-status` /`modify-window-format` | `on` | let the plugin edit `status-right` / window formats | \n\nAgents push their state through hooks: `agent-status set working|waiting|done`. The state is one small\nfile per pane in `$XDG_RUNTIME_DIR/agent-status-$UID/`. Every change recomputes two tmux options,\n`@agent_summary` and `@agent_mark`, so the bar updates instantly and nothing polls.\n\n- Records of closed panes, or panes with no process left except a shell, are dropped automatically\n(decided from the pane's process tree, so wrappers like `sh -c \"agent; …\"` are fine).\n- A `done` that arrives while you are watching that pane is never recorded.\n- Everything is a silent no-op outside tmux, and hooks never fail or slow the agent.\n\n```\nagent-status set <working|waiting|done> [--agent NAME] [--msg TEXT]\nagent-status clear | seen [PANE] | refresh | list\nagent-status pick [CLIENT]                 # the fzf popup\nagent-status jump next [CLIENT] [PANE]     # oldest agent that needs you\nagent-status jump pane PANE [CLIENT]       # used by the fzf-less menu\nagent-status open | menu [CLIENT]          # what the key runs / the plain tmux menu\n```\n\nEverything is local: no network, no telemetry. State is a few bytes per pane in your runtime directory\n(`$XDG_RUNTIME_DIR`, mode 700; the `/tmp` fallback is only used if it is owned by you). Agent-supplied\ntext (messages, names) is stripped of control characters and `#` is escaped before it reaches tmux.\n`install.sh` edits `~/.claude/settings.json` and `~/.codex/hooks.json` (backed up next to them as\n`*.bak.tmux-agent-status`) and only ever adds or removes its own entries.\n\n```\ntests/run.sh          # runs against a private tmux server\nshellcheck -x -S warning bin/agent-status adapters/hook.sh agent-status.tmux install.sh\n```\n\nCI ([status](https://github.com/gs/tmux-agent-status/actions)) runs both on every push.\n\n[MIT](https://github.com/gs/tmux-agent-status/blob/main/LICENSE). Copy it, change it, sell it — just keep the copyright notice.", "url": "https://wpnews.pro/news/tmux-agent-status-quiet-keyboard-first-control-of-coding-agents", "canonical_source": "https://github.com/gs/tmux-agent-status", "published_at": "2026-10-05 06:53:36+00:00", "updated_at": "2026-10-05 07:19:31.622157+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools"], "entities": ["tmux-agent-status", "tmux", "Claude Code", "Codex", "opencode", "pi", "gs", "TPM"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/tmux-agent-status-quiet-keyboard-first-control-of-coding-agents", "markdown": "https://wpnews.pro/news/tmux-agent-status-quiet-keyboard-first-control-of-coding-agents.md", "text": "https://wpnews.pro/news/tmux-agent-status-quiet-keyboard-first-control-of-coding-agents.txt", "jsonld": "https://wpnews.pro/news/tmux-agent-status-quiet-keyboard-first-control-of-coding-agents.jsonld"}}