Agent status detection
tmux agent status: see if Claude Code, Codex or any agent in a pane is working, blocked, done or idle, from hooks, a self-report or a screen fallback.
Agent detection gives every tmux pane an agent status: tmux-ide knows whether each agent is working, blocked, done or idle. It has two layers. tmux-ide trusts an agent's own report first. When there is none, it reads the pane's process and screen, and shows you exactly how it decided.
The same states appear on Home, in the sidebar and pane headers, and in the tmux chrome.
How detection works
The four states are blocked, working, done, and idle (plus unknown when there's no signal at all). A fresh self-report decides the state; without one, tmux-ide infers it from the pane's process and screen.
Systems / Agent detection
Two layers, one status.
- %3A tmux pane
- @agent_stateSelf-report · pane option
a. Ground truth. A fresh @agent_state stamp from Claude Code hooks or any agent always wins and goes straight to the status.
- pane_pid → agentProcess tree↓ no fresh stamp
b. Inference. With no stamp, or one older than 10 minutes, tmux-ide finds the real agent and reads its screen.
- rule set per agentScreen manifests
Infers working, blocked or done
- working · blocked · done · idleAgent status
c. Everywhere. The same status drives Home, pane headers, the chrome and team --json.
explain any panetmux-ide agent explain <pane>
Fig 1.A pane's status comes from its own fresh self-report when there is one; otherwise from its process tree and visible output, matched against per-agent manifests.
How agents report their own state
The first layer is the agent's own report. An agent stamps its pane with a tmux option, and tmux-ide trusts it while it is fresh.
The Claude Code integration
tmux-ide integration install claudeThis command writes a small POSIX hook script and registers it in
~/.claude/settings.json for the Claude Code lifecycle events that map to
agent states:
| Claude event | Reported state |
|---|---|
UserPromptSubmit, PreToolUse | working |
Notification | blocked |
Stop | done |
SessionEnd | idle |
Each hook invocation stamps the current pane:
@agent_state "<working|blocked|done|idle>:<unix epoch>"
@agent_session_id the Claude session idThe session id lets tmux-ide restore --resume-agents
bring the conversation back after a crash.
Install and uninstall touch only tmux-ide's entries: they are tagged by the
hook-script path, and a one-time backup is written next to settings.json. Hooks are read at session start, so the
integration takes effect for new Claude Code sessions.
The self-report contract
You don't need the integration to report state. Any agent or script can write the same pane option:
tmux set-option -p @agent_state "working:$(date +%s)" # working | blocked | done | idleThe value is <state>:<unix epoch>. A working or blocked report older than
10 minutes is treated as stale, and detection falls back to reading the screen,
so long-running agents should re-stamp periodically.
Two optional options add context while the state report is fresh:
tmux set-option -p @agent_display_name "reviewer" # name shown for the agent
tmux set-option -p @agent_status_text "refactoring auth" # one-line statusBoth are cleaned of control characters and cut to 32 characters. The display
name labels the agent in the app, and both appear in tmux-ide team --json.
Detection without a self-report
Without a fresh self-report, the detector works in two steps. First it finds the agent from the pane's process tree, the command actually running in the pane. Then it matches the last lines of the screen against that agent's manifest, a rule set for recognizing working, blocked and done.
This layer is deterministic, you can inspect it, and you can override it.
Which agents are detected?
tmux-ide ships a manifest for each of these agent commands. Tuned manifests were built from real captured screens or the agent's own source strings. Conservative manifests report a state only on strong evidence, such as an explicit prompt or a spinner; anything they miss shows as unknown.
| Manifest id | Agent | Fallback |
|---|---|---|
claude | Claude Code | tuned |
codex | Codex | tuned |
aider | Aider | tuned |
opencode, gemini, copilot, cursor, goose, amp, devin, kimi, pi, grok, kiro, cline, droid, kilo | Other agent CLIs | conservative |
Any agent, listed or not, can report its own state,
and you can add or replace a manifest.
Claude Code also has the hooks integration above.
tmux-ide integration install opencode captures opencode session ids so
restore can resume those conversations; it does not
report state.
Debug a wrong state with agent explain
To see exactly how a pane was classified, ask:
tmux-ide agent explain %3 # a pane id
tmux-ide agent explain %3 --jsonIt's read-only — it captures and inspects, never sends keys — and prints everything the detector reasoned over:
- the pane's command and pid;
- the
@agent_stateauthority option (raw value, parsed verdict, staleness); - the
@agent_hintoverride option; - which manifest resolved and by which path (hint / fast / tree);
- each state's rule and whether it matched;
- the winning classification;
- the bottom screen lines it judged.
Override detection for a tool
If the fallback ever guesses wrong for a particular tool, pin the manifest with
the @agent_hint pane option — agent explain reports whether a hint is
applied and which manifest it forced:
tmux set-option -p @agent_hint claudeTo tune detection for a tool, drop a manifest into
~/.tmux-ide/agent-detection/ — one JSON file per agent:
{
"id": "my-agent",
"commands": ["my-agent", "my-agent-cli"],
"states": {
"working": { "any": [{ "contains": "esc to interrupt", "caseInsensitive": true }] },
"blocked": { "any": [{ "contains": "(y/n)", "caseInsensitive": true }] }
}
}A file whose id matches a bundled manifest replaces it; a new id adds one.
Invalid files are skipped with a warning. Your files always win over the
bundled set and over the optional manifest pack fetched by
tmux-ide update --manifests. For authoritative control, prefer the
self-report contract above: a fresh @agent_state
always wins.
Read agent states as JSON
Whatever the detector resolves is exposed programmatically. tmux-ide team --json
carries a per-pane agents[] array on each session — one entry per pane that
classified to a real agent, flat across the session's windows:
| Field | What it is |
|---|---|
paneId | tmux pane id, e.g. %5 |
windowIndex | the window (tab) the pane lives in |
session | owning session name (repeated per entry so a flat list stays keyed) |
kind | resolved agent — the manifest id (claude, codex, …) |
state | final status (blocked / working / done / idle) |
confidence | the manifest's evidence confidence |
since | authority-state epoch stamp, or null for a scraped/tracked pane |
title | pane_title |
command | pane_current_command — the immediate process (often node/bun/sh) |
dir | pane_current_path — the pane's working directory |
The app's Home roster, sidebar and pane headers show the same agent states. See App tour.
Common questions
Do I need the Claude Code integration?
No. Without it, tmux-ide still detects Claude Code from its process and screen. The integration makes the state exact and records the session id for restore.
Why does an agent still show working after it stopped?
A working or blocked report expires after 10 minutes; until then tmux-ide
trusts it. If a hook did not fire, run tmux-ide agent explain <pane> to see
the stamp and its age, and tmux-ide integration status to check the hooks.
Does detection send keys to my panes?
No. Detection only reads pane options, the process tree and the visible screen.
agent explain is read-only too.
See also
- App tour — where agent states appear in the app
- tmux chrome — status-bar glyphs and pane chips in plain tmux
- Notifications and events — reacting to state transitions
- Multi-agent teams — message and wait on other agents
- Claude Code agent teams — teammate panes and their status
- Restore and resume — resume conversations after a crash
Remote machines over SSH
Run coding agents on remote machines over SSH with tmux-ide: start the remote daemon, open its sessions from your app, and keep agents running.
Configuration
Reference for the optional .tmux-ide/workspace.yml layout file and the global ~/.tmux-ide/config.json settings file, with every field and default.