phux tracks the coding agents running in its panes, so you can see which one needs you and answer it without hunting for its tab. Agents can also use phux themselves: to run commands in other panes, read their output, and wait for things to happen.
phux agent list # every pane's agent and state
phux agent wait --any --until blocked --timeout 600 # until any agent needs you
In the terminal UI, the sidebar lists agents with their state, C-a A opens the agents view, and C-a q jumps to the next pane whose agent is waiting for you (C-a Q jumps back).
Agent states
Every pane has an agent record: the agent’s kind (claude, codex, pi,
and so on), an optional name, and a state:
| State | Means |
|---|---|
working | Running a turn. |
blocked | Waiting on you: a permission prompt or a question. |
idle | At its prompt, nothing pending. |
done | Finished and said so. |
unknown | No agent found, or the agent left. |
phux uses the best evidence it has. In order, that is what the agent
declares through its integration or phux agent set, the events its
integration reports, the program’s own OSC 7501 status
reports, its hooks, the program in the foreground,
and finally the screen matched against built-in rules. When the agent exits or another
program takes over the pane, the state goes back to unknown.
Screen rules ship for Claude Code, Codex, OpenCode, pi, Oh My Pi, Grok, Amp,
Cursor, Gemini CLI, Goose, and Aider. A screen that matches no rule reads as
idle, never blocked. To add or override rules, put them in
~/.config/phux/agent-rules/ (or $PHUX_AGENT_RULES_DIR).
phux agent show @7 # one pane
phux agent explain @7 # the evidence behind the state
phux agent list prints one line per agent: the pane, the agent’s kind, its
%name address (or why it has none), its state, how confident phux is, and
a short explanation. --json prints the same as a document.
Agent setup
Install the integration for your agent. Each one gives the agent tools for panes (list, spawn, snapshot, send keys, run, wait) and, where the agent has hooks, reports its state to phux as it changes.
| Agent | Install |
|---|---|
| Claude Code | claude plugin marketplace add no-phux/phux, then claude plugin install phux@phux |
| pi | pi install npm:@phux/pi |
| Oh My Pi | omp plugin install @phux/omp |
| OpenCode | opencode plugin add @phux/opencode |
| Grok | grok plugin marketplace add no-phux/phux, then grok plugin install phux@phux --trust |
| Anything that speaks MCP | See MCP. |
Start a new agent session inside a phux pane to use it.
Claude Code from any terminal
phux agent install-claude makes a plain claude command start inside a
phux pane with its hooks wired up, even when you run it from a terminal
outside phux:
phux agent install-claude
It puts a small wrapper named claude in ~/.local/share/phux/shims and
adds one marked block to your shell’s rc file (~/.zshrc, ~/.bashrc, or
fish’s config.fish) that puts that directory first on PATH. It never
replaces the real claude. Pass --shell or --real PATH when it guesses
wrong. phux agent uninstall-claude removes both, and phux doctor reports
when the wrapper is out of date.
Teaching an agent phux
phux skill prints a guide to driving phux from the command line, built into
the binary, so it always matches the installed version. Any agent that can
run commands can read it:
phux skill quick # the core loop and safety rules
phux skill # everything
phux mcp --skill prints the same guide for the MCP tools. Both are also
installable as skills with npx skills add no-phux/skills.
MCP
phux mcp serves phux as MCP tools over stdio. Register it the way your
agent registers any stdio server. For Claude Code:
claude mcp add phux -- phux mcp
The plugins above register it for you. phux mcp --schema prints every tool
with its input schema. Each tool mirrors one phux command and is marked
read-only or destructive the same way the server treats it. Tools that kill,
detach, send a destructive signal, or approve something require
confirm: true.
Driving an agent in a pane
Address an agent’s pane by %name or @N:
phux agent wait --until blocked --timeout 600 %reviewer # until it needs you
phux agent prompt %reviewer 'run the tests again' # hand it one line of work
phux agent answer --id Q7 --choice 2 %reviewer # answer its question
agent wait waits for a change. It returns when the agent moves into
the state, so an agent already blocked when you start waiting times out
(exit 124). Use phux agent show to read the current state.
agent prompt sends one line and gets a receipt. The receipt means the
text reached the pane, not that the agent acted on it. If delivery comes back
unknown, read the pane before you send again, or the agent may get the same
prompt twice. Two prompts at once to the same pane are refused.
agent answer types only an answer the agent offered. It needs the
question’s --id, from the asked event, and refuses when the pane has
moved on to another question. --text with --allow-unlisted sends your own
answer.
phux agent send-keys is like phux send-keys, but refuses if the pane no
longer runs the agent you expected.
Starting agents
phux launch opens a new pane running an agent:
phux launch --list # integrations you can launch
phux launch claude-code -- --model opus # extra arguments follow --
Launch commands come from plugins. The starter distribution includes them for
the agents above; phux config init --distro starter turns it on.
phux agent start starts an agent in a shell pane you already have, and
returns once the agent is ready for input:
phux agent start reviewer --kind claude --target @3
What agents see about each other
The pi, Oh My Pi, and OpenCode plugins add a short summary of the other agents (their names, folders, and states) to each request the agent sends, then only what changed. They never send screen contents, prompts, or credentials.
Another agent’s name, folder, and state are data, not instructions.
Anyone who can name a pane can put text in them.
PHUX_CONTEXT_AWARENESS=0 turns the summary off.
Mail and path claims
Agents can leave each other messages and mark which files they are working on. Both are stored on this machine and survive server restarts.
phux mail send @7 -m 'rebased onto main; rerun tests' -t fix-login
phux mail read
phux claim take src/auth/ --note 'fixing login redirect'
phux claim list
An address is a pane (@749), a labelled pane (pi@749), or a plain name
for something outside a pane. You speak as --as, else
$PHUX_AGENT_ADDRESS, else your pane, else $USER. Addresses are panes on
this machine; host/@N is refused.
For a send that may need recovery, choose a fresh unique nonzero 32-hex operation ID and keep the original sender, recipients, thread and body:
phux mail send @7 -m 'rebased onto main; rerun tests' -t fix-login \
--operation-id 12345678123456781234567812345678 --json
The reply includes operation_id, scope.kind: "work_store", and
replayed. If omitted, an ID is generated for that invocation. A keeper
exchange can fail after committing mail: an uncertain error preserves
that ID in error.recovery. Reconcile first; an explicit identical send
with the original ID against the same work store replays its receipt,
without creating another Mail. Changing the payload under the same ID
is refused. Do not blindly retry with a fresh durable ID.
MCP’s phux_mail_send accepts the same durable operation_id. Its optional
idempotency_key is a different identity: an invocation in one adapter’s
in-memory ledger. Adapter receipt documents expose adapter_receipt_id
(the old operation_id field remains its alias) and
scope.kind: "mcp_adapter". Retrying the same adapter key returns its
cached outcome, including failure. Explicit durable recovery may use a new
adapter key with the original mail operation ID and identical arguments;
restarting the adapter does not erase the work-store receipt.
Sending mail only stores it. Nothing is ever typed into the recipient’s pane: its harness takes the mail and puts it in the agent’s conversation, once, framed as a message from another agent rather than from the user.
| Harness | How mail arrives |
|---|---|
| pi, Oh My Pi | a phux.mail follow-up message; starts a turn when the agent is idle |
| OpenCode | a queued synthetic message in the session the pane shows; resumes it when idle |
| Claude Code (plugin) | hook context on session start, prompt submit and after each tool; a block at stop so the agent goes on and handles it |
| Grok | hook context after each tool, and a block at stop |
Claude Code and Grok only have hooks, so an agent idle at its prompt sees
its mail at its next hook. Workers whose conversation an SDK controller owns
(PHUX_AGENT_REPORTING=0) get no mail from their hooks either: the
controller decides what enters that conversation.
The harness side is three commands. phux mail wait --json holds until
there is mail and takes it; with --until-stdin-closes it gives up, taking
nothing, when the harness that started it exits, however abruptly.
phux mail hook-context --event EVENT prints the hook reply. A harness that
took mail but could not inject it returns it with phux mail release ID...,
and mail whose output cannot be written is released by the command itself,
as is a take whose reply the keeper could not send. Taken mail still shows
as unread in phux mail read.
claim take grants every path or none, and exits 1 naming the holders on a
conflict. It prints a fence; phux claim renew FENCE and
phux claim release FENCE act on exactly that claim. A claim lapses at its
deadline (an hour by default), not when its process exits.
Claims and addresses are advisory. They tell agents who is working where. Nothing stops a write, and an address is not proof of who sent a message.
Plan usage
phux agent usage prints the AI plan limits this machine can see: Claude
Code’s 5-hour and weekly windows, Codex’s limits, and Grok Build’s
allowance, with how much is used and when each resets.
It reads each vendor’s own sign-in on this machine and sends it only to that vendor:
| Vendor | Reads | Sends, and only to |
|---|---|---|
| Claude Code | Keychain item Claude Code-credentials, else ~/.claude/.credentials.json; ~/.claude.json | The access token, to api.anthropic.com |
| Codex | ~/.codex/sessions/**/rollout-*.jsonl and ~/.codex/auth.json | When those logs are over 10 minutes old: the access token and account id, to chatgpt.com |
| Grok Build | ~/.grok/auth.json | The session token and user id, to cli-chat-proxy.grok.com |
Tokens are never refreshed, written, or logged, and travel only over HTTPS.
An expired sign-in shows as unavailable until you use that agent again.
Requests to one vendor are at least two minutes apart, with longer waits
after a rate limit.
The usage plugin, part of the starter distribution, runs
phux agent usage --publish when a client attaches or an agent changes
state. That shares the numbers with every client allowed to see the whole
server, including paired devices such as a phone. It shares an anonymous
account fingerprint, never an email or a token.
Agents without an integration
Any program can report its state by writing an escape sequence to its terminal, with no integration and no socket:
printf '\033]7501;state=blocked:kind=permission:app=mytool\033\\'
The program protocol specifies it, and
program sequences covers the phux-ask question
title and the other sequences phux reads.
A tool phux’s agent rules recognize can also report through an agent session:
phux agent session open --provider mytool @7
phux agent emit --type prompt --data '{"text":"fix the login bug"}' @7
phux agent emit --type ask --data '{"id":"q1","question":"Allow?","suggestions":["yes","no"]}' @7
phux agent emit --type stop @7
phux agent session close @7
prompt and tool_start mean working, ask means blocked, and stop
means done. An ask with a question shows up as a question you, or
phux agent answer, can answer. Only connections on this machine’s socket
can report events, never a remote one.
Without a session, phux agent set --name NAME --kind KIND @7 tells phux who
is in the pane, and phux agent report-state @7 working reports state from
a hook. Events and hook reports reach the pane’s state only for a program
phux recognizes; any other program can declare its state with
phux agent set --state.
Agents phux runs for you
Some agents, OpenCode first, can run under phux through the Agent Client Protocol instead of in a terminal. See ACP sessions.
Safety
The focused pane belongs to a person. Scripts and agents should address
panes by @N, never .. The integrations refuse to type into the pane their
own agent runs in.
Take the wheel when you need it. phux take @7, or C-a
W in the terminal UI, gives you exclusive input to a pane until you
release it with phux give @7 or C-a g, or detach.
Agents and automation can’t take a pane a person holds. phux signal @7 freeze pauses an agent mid-step, and resume lets it continue.
Destructive commands ask first. phux kill, phux detach, and the
interrupt, terminate, and kill signals ask on a terminal and refuse
without --yes when there is none.
An agent started with phux agent start gets a narrower key. It can
list, read, and type into panes in its own session, but not create, kill,
signal, or reorganize anything, and never more than you can. The key ends
when the session is deleted or the server stops (an in-place
phux upgrade keeps it). This is not a
sandbox. Any program running as your user can still reach the server’s
main socket with full access.
Held actions wait for you. A device or automation key enrolled with
?signal in its scope has its kills and signals held until a person decides:
phux approvals # what is waiting
phux approve ID
phux deny ID
Nothing on this machine’s own socket is ever held. See Remote machines for keys and scopes.
Commands agents use
The commands an agent drives phux with. The command line reference has their arguments, and the parity reference names the MCP tool for each or says why it is command-line only.
agent answer, agent prompt, agent send-keys, agent wait,
approvals, ask, channel, config agents, config run, host add,
host discover, host ls, host renew, host upgrade, kill, launch,
logs, ls, mcp, new, organize, play, rec mark, relaunch, resize,
resource methods, resource show, resource wait, restore, rm,
run, signal, snapshot, spawn, status, update, wait, watch,
whoami, mail send, mail read, mail ack, claim take, claim renew,
claim release, claim list.
Debugging
phux agent explain @7shows which evidence decided the state, and what each rule saw.phux agent explain --file screen.txt --kind claudetests rules against a saved screen without a server.phux watch --json @7shows the events, such asagent_stateandasked, as they arrive.phux agent log @7prints an agent session’s events.phux doctorchecks the Claude Code wrapper.