Skip to content

MuxAPI

MuxAPI (formerly the Agent App API) is what makes AgentMux an operating environment, not just a workspace. Every agent running inside a pane has access to a typed API that lets it drive the environment itself: open new panes, rename tabs and windows, navigate between tabs, discover and message peer agents. No human in the loop required.

The API has two equivalent surfaces — MCP tools (for agents that use MCP-capable providers) and a REST API (direct HTTP, for any language). Both authenticate with the same key and express the same capabilities. The MCP tools are what most agents will reach for; the REST endpoints are there for scripts, webhooks, and advanced use.

When AgentMux launches an agent, the sidecar injects three environment variables into the agent’s PTY:

Env varValuePurpose
AGENTMUX_LOCAL_URLhttp://127.0.0.1:<port>Sidecar base URL
AGENTMUX_BLOCKID<pane UUID>The pane this agent lives in — used as self-context default
AGENTMUX_AGENT_ID<agent name>Agent’s registered name — used by SendMessage routing

AGENTMUX_AUTH_KEY is not classified as a PTY env var (see Environment variables — “Available In Pane? No”). The sidecar strips it from its own process environment at startup (security PR #801) and re-injects it per spawn only for internal tooling that requires it (agentmux-bashwrap, the streaming bash runner). agentmux-mcp receives it through its own spawn configuration, not from the agent’s PTY environment.

Agent CLI (claude / codex / gemini / …)
└─ spawns agentmux-mcp (MCP stdio server)
├─ receives AGENTMUX_LOCAL_URL + AGENTMUX_AUTH_KEY + AGENTMUX_BLOCKID
└─ advertises a curated set of MCP tools → routes each to the REST API

Agents using MCP tools never touch X-AuthKey directly — the MCP sidecar handles it. The REST API is for scripts or tooling that run with explicit access to the auth key (e.g. inside the sidecar itself, or a trusted subprocess you spawn with the key explicitly).

Two layers: MCP tools vs. the MuxAPI RPC surface

Section titled “Two layers: MCP tools vs. the MuxAPI RPC surface”

It helps to keep two layers separate:

  • MCP tools — the curated, agent-facing verbs that agentmux-mcp advertises and maps onto REST endpoints. These are the high-level “operate your workspace” actions (WhoAmI, Layout, SetName, OpenEditor, Shell, SendMessage, …) listed in MCP tools below. This is the curated surface most agents use.
  • The MuxAPI RPC surface — the full set of JSON-RPC commands the backend (agentmux-srv) registers over its WebSocket transport. The frontend and internal tooling drive AgentMux through these. They include agent lifecycle, process management, session/blockfile persistence, agent-definition CRUD, identity, memory, drones, and more. The MCP tools are a thin, curated slice of this larger surface.

The catalog below documents the MuxAPI RPC commands by group, with each command’s exact name verified against source. This is the current surface and grows actively — treat it as a snapshot, not a frozen contract.

These commands are registered in agentmux-srv: the MuxAPI handlers are split by domain into the files of crates/srv/src/server/app_api/ (registered from crates/srv/src/server/app_api/mod.rs), the agent-management handlers into crates/srv/src/server/agent_handlers/ (registered from crates/srv/src/server/agent_handlers/mod.rs), and the command-name constants are in crates/srv/src/backend/rpc_types/commands.rs. They are exposed and dispatched over the WebSocket JSON-RPC transport described at the bottom of this page.

Agent lifecycle (agent_open.rs, agent_io.rs, agent_define.rs in app_api/)

Section titled “Agent lifecycle (agent_open.rs, agent_io.rs, agent_define.rs in app_api/)”
CommandPurpose
agent.openOpen (or idempotently reattach) an agent pane in a tab from an agent definition. Routes through the reducer/CreateBlock for saga consistency (PR #1681).
agent.sendSend a message/turn to a running agent (host subprocess, persistent, or container).
agent.stopStop a running agent’s controller (graceful or SIGKILL/SIGTERM).
agent.statusRead one agent block’s status, provider, controller type, session id.
agent.listList all agent blocks across tabs with status + session id.
agent.outputRead paginated persisted output lines for an agent block.
agent.defineCreate or upsert an agent definition (broadcasts agents:changed).

Agent process management (agent_io.rs in app_api/)

Section titled “Agent process management (agent_io.rs in app_api/)”
CommandPurpose
agent.process-listList OS processes tracked for an agent block, with tracking confidence.
agent.tracked-blocksList every block currently tracked (swarm aggregate view).
agent.kill-processTerminate a single tracked PID within a block’s process tree.
agent.kill-treeTerminate a block’s entire process tree (job object / cgroup / killpg).
CommandPurpose
pane.openOpen a non-agent pane (editor / term / browser / sysinfo / help), docked or floating. Like agent.open, routes through the reducer/CreateBlock for saga consistency (PR #1681). This is what the OpenEditor MCP tool calls.

Blockfile pagination (blockfile.rs in app_api/)

Section titled “Blockfile pagination (blockfile.rs in app_api/)”
CommandPurpose
blockfile:line_countCount lines in a block’s transcript file.
blockfile:read_rangeRead a line range from a block’s transcript file.
blockfile:read_stateRead a block’s persisted state JSON.
blockfile:write_stateWrite a block’s persisted state JSON.
CommandPurpose
session:resume_preflightBefore a pane opens, answer whether its conversation will resume or start new, without spawning anything.
session:archiveArchive a session.
session:restoreRestore a previously archived session.
session:exportExport a session.
session:activity_summaryPer-turn live activity summary (writes term:ambient_summary).
session:next_prompt_suggestionPer-turn ghost-text suggestion for the next prompt (writes term:next_prompt_suggestion).

Agent-anchored session zone (session.rs in agent_handlers/)

Section titled “Agent-anchored session zone (session.rs in agent_handlers/)”

A session zone is bound to the agent definition (definition_id), so every block of the same agent shares it.

CommandPurpose
agent:session:readRead the agent definition’s current session zone.
agent:session:write_stateWrite state into the agent’s session zone.
agent:session:append_outputAppend output to the agent’s session zone.
agent:session:archiveSnapshot the agent’s session zone to an archive.
agent:session:list_archivesList the agent’s session-zone archives.
CommandPurpose
agent:memory:listList an agent’s native memory files.
agent:memory:read_fileRead one native memory file.
agent:memory:write_fileWrite one native memory file.

The backend also registers a large set of management RPCs that the frontend (and tooling) use. These are grouped here rather than exhaustively expanded; names are verified against crates/srv/src/backend/rpc_types/commands.rs.

GroupCommands
Agent-definition CRUDlistagents, createagent, updateagent, deleteagent, forkagentdefinition, forkagentdefinitionsuggest, agentdefcreatefromtemplate, agentdefhide, agentdefunhide, agentdeflisthiddentemplates
Agent contentgetagentcontent, setagentcontent, getallagentcontent — setagentcontent persists per-agent content (e.g. ui:zoom, env) keyed to the agent definition
Skills CRUDlistagentskills, createagentskill, updateagentskill, deleteagentskill
Historyappendagenthistory, listagenthistory, searchagenthistory
Import / export / seedimportagentfromclaw, importagents, exportagents, reseedagents
Identity accountslistidentityaccounts, getidentityaccount, upsertidentityaccount, deleteidentityaccount, account.key.verify, account.oauth.start, account.oauth.poll, account.oauth.cancel
Agent ↔ identity junctionlinkagentidentity, unlinkagentidentity, listagentidentities
Bundles (formerly presets)listmemories, getmemory, upsertmemory, deletememory, reorderglobalbrain
Agent instanceslistagentinstances, getagentinstance, createagentinstance, updateagentinstance, deleteagentinstance, listnamedagents, hidenamedagent, listrecentsessions
Container runtimecontainerruntimeavailable
Droneslistdrones, getdrone, upsertdrone, deletedrone, rundrone, listdroneruns

Identity, Memory (native), MCP, Skill & Bundle — shipped MuxAPI namespaces

Section titled “Identity, Memory (native), MCP, Skill & Bundle — shipped MuxAPI namespaces”

Five higher-level, agent-scoped namespaces wrap the low-level handlers above behind MuxAPI’s permission boundary. All are registered today, from crates/srv/src/server/app_api/ (identity.rs, memory.rs, mcp.rs, skill.rs and bundle/).

CommandPurposeParams
identity.self.accountsList the calling agent’s linked accounts (secrets masked)agent_id
identity.account.upsertStore/rotate a credential in the OS keychain, upsert the IdentityAccount row, and (re)link it to the agent for that provideragent_id, provider, name, kind?, secret, validate?, account_id?
identity.account.validateValidate a stored account (by account_id) or an ad-hoc provider+secret pair (WS-only, not exposed over REST/MCP)account_id+agent_id, or provider+secret
identity.self.unlinkUnlink an account from a provider for this agentagent_id, provider
CommandPurposeParams
memory.listList .md files in the agent’s native-memory dir, with preview + frontmatter typeagent_id
memory.readRead one file’s contentagent_id, filename
memory.writeWrite/overwrite one file (atomic tmp+rename), 10 MB capagent_id, filename, content

This is Personal Memory (stored as “native memory”, once labelled “Brain”) — see Memory → Personal. It’s distinct from a Bundle (below).

CommandPurposeParams
mcp.listList an agent’s accessible MCP serversagent_id
mcp.getFetch one server (accessibility-checked)agent_id, id
mcp.upsertCreate/update a private (non-global) server, name-unique per agentagent_id, id?, name, transport? (default "stdio"), config? (JSON string, default "{}")
mcp.deleteDelete a server bound to the agent (forbidden if global)agent_id, id
mcp.bindBind an agent to an existing global (or already-bound) serveragent_id, mcp_id
mcp.unbindUnbindagent_id, mcp_id
mcp.catalog.listList all global servers (the Connectors → MCP servers catalog, no agent scoping)—
mcp.catalog.upsertCreate/edit a global server (cannot promote a private one)id?, name, transport?, config?
mcp.catalog.deleteDelete a global server (cannot delete a private one via the catalog)id

Same shape as mcp.*:

CommandPurposeParams
skill.listList agent’s accessible skillsagent_id
skill.getFetch one skillagent_id, id
skill.upsertCreate/update a private skillagent_id, id?, name, trigger?, skill_type? (default "prompt"), description?, content?
skill.deleteDelete (forbidden if global)agent_id, id
skill.bindBind to a global (or already-bound) skillagent_id, skill_id
skill.unbindUnbindagent_id, skill_id
skill.catalog.listList all global skills—
skill.catalog.upsertCreate/edit a global skillid?, name, trigger?, skill_type?, description?, content?
skill.catalog.deleteDelete a global skillid

The reusable agent-definition primitive (see Bundles):

CommandPurposeParams
bundle.listList all bundles—
bundle.getFetch one bundle by id or nameid or name
bundle.upsertCreate/update a bundle (the Memory row shape — provider, model, instructions, context_files, mcp_servers, skills)bundle fields
bundle.deleteDelete a bundleid
bundle.self.getResolve the calling agent’s currently-bound bundle (or the blank singleton)agent_id

bundle.* is backed by crates/srv/src/backend/storage/bundles.rs (table db_bundles). The old WebSocket preset.* aliases are retired; the PresetList and PresetGet MCP tools still reach bundles through the REST routes /api/v1/agent/preset/list and /api/v1/agent/preset/get.

Prerequisite these all share: RpcContext carries an agent_id field populated from bus_agent_id in websocket.rs, enforcing per-agent scope (an agent can only read/write its own links, private primitives, and bindings — not another agent’s).

Recent additions for widget panes that run a local HTTP server (PR #1689). The frontend passes a per-widget port so a widget can override the default and AgentMux still reaches it:

CommandPurpose
widget.healthLiveness probe a widget’s local server ({ port, health_check_path, health_check_body_contains? } → { healthy, status_code }).
widget.apiHTTP proxy to a widget’s local server, bypassing browser CORS ({ port, path, method?, headers?, body? } → { ok, status_code, body, error? }). Agents use it to call e.g. ComfyUI /prompt or Grafana /api/query.

These are the high-level tools registered by agentmux-mcp. Most providers that support MCP get them automatically. Claude Code, Codex, Gemini and Kimi read them from the agent’s configuration files. The ACP harnesses (OpenClaw, GitHub Copilot CLI, Pi, Kilo Code CLI, Cline CLI, OpenCode, goose, Grok Build and DeepSeek Harness) get the agentmux server, with the agent’s other MCP servers, in the mcpServers of ACP’s session/new or session/load. The terminal-tier harnesses (Aider, Crush and Muse Code) don’t get them. Each one calls the sidecar over HTTP; the REST API table lists the endpoints behind the core tools.

Resolve the calling agent’s position in the UI tree — pane, tab, window, workspace.

// Returns:
{
"block_id": "uuid",
"block_title": "pane title",
"tab_id": "uuid",
"tab_name": "Tab Label",
"window_id": "uuid",
"window_name": "Window Title",
"workspace_id": "uuid",
"workspace_name": "Workspace Name"
}

No parameters. Call this before any navigation verb to get a stable reference to your own context.


Read the AgentMux UI structure. Single tool with a query discriminator.

queryReturns
"layout" (default)Full hierarchical tree: Windows → Workspaces → Tabs → Panes
"windows"Flat list of all windows
"workspaces"Flat list of all workspaces
"tabs"Tabs in the calling agent’s workspace
// Layout("layout") returns:
{
"windows": [
{
"window_id": "uuid",
"window_name": "AgentMux",
"workspaces": [
{
"workspace_id": "uuid",
"workspace_name": "Main",
"tabs": [
{
"tab_id": "uuid",
"tab_name": "Tab 1",
"active": true,
"panes": [
{ "block_id": "uuid", "view": "agent", "title": "claude" }
]
}
]
}
]
}
]
}

Rename any UI element. Self-defaults: omit the explicit target ID and the agent’s own context is used.

targetWhat it renamesChar limit
"pane"The agent’s own pane header title128
"tab"The current tab label128
"window"The OS window title bar64
"workspace"The workspace name128

Parameters: target (required), name (required).

// Rename own pane
SetName(target="pane", name="Research")
// Rename the current tab
SetName(target="tab", name="Build pipeline")
// Rename the window
SetName(target="window", name="Project Athena")

Switch the active tab within the current workspace.

Parameters: tab_id (required, from Layout("tabs")).

Create a new tab in the current workspace.

Parameters: name (optional string).

Bring an AgentMux window to the OS foreground.

Parameters: window_id (optional — defaults to the calling agent’s own window).


Open a file in an editor pane.

ParameterTypeDefaultDescription
filestring (required)—Absolute path to the file
titlestringfile nameTab/pane title
split"right" | "left" | "down" | "up""right"Split direction relative to the calling pane
collapse_treebooleanfalseOpen with the file-tree sidebar collapsed
floatingbooleanfalseOpen in a floating overlay window instead of a docked split

Returns { block_id, tab_id, view, created }.

ToolWhat it does
OpenMediaOpen an image, video or audio file (absolute host path) in a media pane next to the conversation.
OpenFilesOpen a folder in a Files pane next to the conversation, optionally with some entries selected. Navigation only; it changes nothing on disk. Takes connection for a folder on an SSH host.
OpenAgentLaunch an agent from My Agents (by name or definition id) into a new pane in the target tab. Idempotent: an agent already open in that tab returns its existing pane. Templates are refused.
ClosePaneClose a pane. With a block_id it closes any pane, logged with your verified identity; another agent’s pane waits 15 seconds for its user to keep it. With no arguments it closes your own pane after the same window.
QuitSelfEnd your own session and close your own tab, only when the user has told you to in this conversation. Unless the user’s own message started the current turn, the user gets a 15-second window to keep you running.
RegisterDevServerContainer agents only: register a dev server running in your own container with AgentMux’s reverse proxy, at http://<project>-<agent-id>.localhost:8090.

See Build a widget for the package format.

ToolWhat it does
WidgetListList installed widgets: id, name, version, kind, state, permissions, folder and the views each adds.
WidgetInstallInstall a widget package you built (a folder, its widget.json, or a .zip) and ask the user to approve it. Returns installed, declined, pending, or the validation error. You can’t approve it yourself.
OpenWidgetOpen a view of an installed, approved widget (ext:<id>/<pane>) next to the conversation, optionally setting keys of its pane state.

UIScreenshot, UIQuery and UIClick reach your own pane and the shared app chrome (status bar, menus, window controls), never another pane or agent’s UI; pass pane (from OpenBrowser) to act on a browser pane you opened. The shortcut tools act in the window that holds your pane.

ToolWhat it does
UIScreenshotScreenshot your own pane, clipped to it. Returns a file path.
UIQueryFind elements matching a CSS selector: tag, text, attributes, bounding rect and focus state.
UIClickClick an element with a real synthesized mouse click. Refused on a pane you opened with OpenBrowser; use BrowserClick there.
ListShortcutsList the keyboard shortcuts as the Help pane shows them, with the user’s remaps: command id, label, keys, context and the pane that handles each.
RunCommandRun a shortcut’s command by id (from ListShortcuts) in your own window, optionally focusing a target pane first. Commands keep the user’s protections: tab:close asks first, and permanent deletes are refused.
PressKeysPress a shortcut from the table as real key events in your own window and report which command it resolved to. Keys bound to permanent delete or pane:close are refused.
CaptureWindowScreenshot a top-level window on this machine (another AgentMux instance, your own floating windows, or another application) by pid or title. Windows owned by another OS user are withheld; every call is audited.
DiscoverWindowsList top-level windows (pid, title, executable, whether each can be captured) to pick a CaptureWindow target. Other applications are listed only with include_foreign.

OpenBrowser opens a browser pane next to yours and makes you its owner. The other tools take that pane’s id as pane; without it they act on your own pane, if it is a browser pane. You can drive only browser panes you opened, and page content is untrusted.

ToolWhat it does
OpenBrowserOpen a browser pane at an http(s) URL. allowed_origins keeps it on the sites the task needs; a page that tries to leave them is stopped and the user is asked.
BrowserSnapshotRead the page as an accessibility snapshot, one line per element, with a ref on each one you can act on.
BrowserClickClick an element by ref with a real mouse click. A click that submits a form, or is named like Submit, Send, Pay or Delete, waits for the user to approve it.
BrowserFillReplace a text field’s value by ref, as typed input, and read it back. Refuses password, one-time-code and card fields.
BrowserSelectChoose an option of a <select> by ref and the option’s label or value.
BrowserCheckSet a checkbox, radio button or switch by ref.
BrowserSetFilesPut files from your own workspace into a file input by ref, up to 25 MB in all. Every upload is logged.
BrowserWaitForWait until the page shows some text, its URL contains something, or an element is gone.
BrowserHandoffHand the pane to the user for something you must not do (signing in, two-factor codes, payment details) and wait for Done or Cancel.
BrowserNavigateNavigate to a URL.
BrowserBack / BrowserForward / BrowserReloadWalk history back or forward, or reload the page.
BrowserEvalRun JavaScript in the page and return the result. Refused on a pane you opened with OpenBrowser.
BrowserDispatchKeyType text or a named key into whatever has focus in the pane, optionally focusing a selector first. Enter and Space are refused on a pane you opened with OpenBrowser.
BrowserFocusElementCall .focus() on the first element matching a CSS selector.
BrowserFocusInfoReport the currently focused element, in UIQuery’s shape.

Start a persistent background shell process pinned to the activity dock.

ParameterTypeDescription
cmdstring (required)Shell command to run
cwdstringWorking directory (defaults to agent’s working dir)
titlestringLabel shown in the activity dock
envobjectExtra env vars for the shell process

Returns { shell_id }. The shell process stays alive until ShellStop is called or the pane closes. Use it for long-running background processes.

Stop a running shell by ID.

Parameters: shell_id (required, from Shell response).

Write to the stdin of a running shell started by Shell. Only works if that shell was created with capture_stdin=true — otherwise its stdin is /dev/null and the write is discarded (the tool tells you so).

Parameters: shell_id (required), text (required — a newline is appended automatically).

Returns a plain-text status string, e.g. "wrote to shell <shell_id>", or an explanation of why the write was discarded (StdinNotCaptured, shell already exited, etc.).

Query whether a shell started by Shell is still running.

Parameters: shell_id (required).

Returns a plain-text summary: running state, exit code (if exited), and total output line count so far.

PtyShell attaches to the pane’s one interactive shell: the same real terminal the user sees in the shell drawer, so programs that need a PTY (password prompts, sudo, ssh, REPLs) work. While you type into it, the user’s own keyboard input to it is locked out for a few seconds.

ToolWhat it does
PtyShellAttach to (or create) the pane’s interactive shell; returns a shell_id. Takes connection to run in WSL or on an SSH host.
PtyShellInputWrite raw text, exactly as typed: no newline is appended, and \u0003 is Ctrl+C.
PtyShellReadRead back the output tail as text (default the last 200 lines).
PtyShellResizeResize the terminal (default 25 rows by 200 columns).
PtyShellStatusWhether the shell is still running, and its exit code once it ended.
PtyShellStopRelease your keyboard lock at once. It doesn’t stop the shell.
ConnListList the connections Shell and PtyShell can take as connection: this machine, each WSL distribution, the user’s ssh config hosts, and their status. An SSH host asks the user to allow you the first time.

Repeatedly inject a prompt to an agent on a fixed interval, from inside the current MCP session.

ParameterTypeDefaultDescription
promptstring (required)—Text to inject each fire
intervalstring"10m" (min "10s")Fire interval, e.g. "5m", "30s"
tostringselfTarget agent name
immediatebooleanfalseFire once immediately, then on the interval
max_iterationsintegerunlimitedAuto-stop after this many fires (equivalent to calling LoopStop once reached)

Returns a plain-text confirmation naming the loop (e.g. loop-3) and how to stop it. Loops are session-scoped — they live only as long as the current MCP process/agent session and do not survive a restart.

Stop a running loop by ID (e.g. loop-3, from the Loop response).

List every loop running in the current agent session — id, prompt preview, target, interval, fire count, and remaining cap if any. No parameters.

Create a durable, DB-persisted scheduled job — unlike Loop, a cron job survives agentmux-srv restarts and isn’t tied to any one agent session.

ParameterTypeDescription
namestring (required)Job name
expressionstring (required)5-field UTC cron expression, e.g. "0 9 * * 1-5"
promptstring (required)Text to inject on each fire
tostring (required)Target agent id
max_firesinteger (optional)Auto-disable after N fires; omit for unlimited

Returns the created job’s id, schedule, and next fire time.

Permanently delete a cron job by id and cancel its scheduled task.

List every persistent cron job (enabled and paused), with schedule, next fire time, and fire count. No parameters.

Pause or resume a cron job by id. A paused job’s definition stays in the database but doesn’t fire until resumed.


List reachable agents across the MuxBus tiers (Host / LAN / WAN).

No parameters. Returns:

{
"host": {
"addressable": [
{ "agent_id": "claude", "block_id": "uuid", "provider": "claude" }
],
"agents": [ /* full agent records */ ]
},
"lan": [ { "host": "peer-machine", "agents": [ /* … */ ] } ],
"wan": { "subscribed_agents": [ /* … */ ] }
}

Use the addressable list to find agents you can SendMessage to.

Send a message to another agent by name. Routes through the MuxBus.

Parameters: to (target agent name, required), message (string, required).

Returns { success, error? }. The message is delivered to the target agent’s pane as if a user typed it — the agent picks it up on its next turn.

ToolWhat it does
GetAgentTranscriptRead the tail of another agent’s transcript by name, and whether it has a turn in flight. Reaches agents on this host, including other channels; not LAN or WAN.
ListConversationsEvery agent’s latest activity across host, other channels, LAN and WAN in one call. Host and cross-channel entries carry a preview line and what the agent is working on; LAN and WAN entries are liveness only.
SearchHistorySearch your own past conversations, including ended or compacted sessions, by text or by tool call. Only complete: true with no hits means it didn’t happen.
WhoIsWorkingOnWhich other agents are working on a file, folder, repository, branch, topic or open PR. Informational; nothing is locked.
ClaimWorkSay what you’re working on (a path, branch or topic, with a note) so other agents see it in WhoIsWorkingOn and get a note if they edit inside it. Lapses after ttl_minutes (default 120).
ReleaseWorkRelease one of your claims by id, or all of them.
SupervisorNudgeFor a Warden Supervisor watcher: record a decision about an agent that ended its turn. nudge sends a fixed, server-owned continuation message; decline only logs.
FleetListList every reachable agent with the target ids FleetBroadcast and FleetBulkStop take.
FleetBroadcastSend the same message to many agents, each delivered and signed as SendMessage would.
FleetBulkStopStop many agent panes at once, optionally in stages that abort on a high failure rate. Stopping an agent you don’t own waits 15 seconds for its user to keep it.

SendMessage is push, addressed, immediate: it names a recipient and delivers now. Muxqueue is pull and deferred — work is enqueued, and an agent takes it when it asks, rather than being handed it.

By default an item is also unaddressed: it names nobody, and whichever agent claims next gets it. That is the common case and the reason the queue exists. It is optionally addressable though — target_agent restricts an item to one agent, target_group to the members of an agent group, and a restricted item is simply invisible to everyone else’s WorkClaim. Targeting narrows who may claim; it never changes when — the item still waits to be claimed rather than being delivered.

Reach for it when you don’t need a specific agent, or need something done eventually rather than now: “someone should repro this”, “this PR needs review when a reviewer frees up”. Items survive pane closes, app restarts, and version/channel changes, and are visible to every agent on the machine.

Instead ofUse
A specific agent, right nowSendMessage
On a scheduleCronCreate
Anyone, when they’re freeWorkEnqueue
A specific agent, but whenever they get to itWorkEnqueue with target_agent

WorkClaim grants a time-limited lease (default 2 minutes). Heartbeat during long work, then complete or release. An expired lease is what stops a crashed agent from blocking an item forever — but two details matter, and both are easy to assume wrong:

  • Reaping is lazy. Nothing sweeps in the background. An expired item stays claimed until the next time some agent calls WorkClaim, which is when the reaper runs. So a queue can show items as claimed with nobody working them; muxspect work flags exactly that.
  • An expired item does not always come back. It returns to the pool only if it has attempts left. If the expired claim consumed the item’s final permitted attempt, it is parked as failed and never offered again — the same rule that makes a release on the final attempt terminal.

So “the agent crashed, it’ll be retried” holds until the attempts run out, and not after.

The claim response includes an attempt number that every later call must echo back. It fences one claim instance from another: because agent_id is stable across claims, a delayed call left over from an expired claim would otherwise operate on a newer claim of the same item by the same agent. A stale fence gets HTTP 409, and the only recovery is to claim again.

ParameterTypeDescription
titlestring (required)Short human-scannable summary
payloadstring (required)The full instruction injected into whoever claims it. Write it standalone — the claimant has none of your context
kindstring (optional)Free-form tag for filtering claims (review, repro, …)
target_agentstring (optional)Restrict to one agent id. Mutually exclusive with target_group
target_groupstring (optional)Restrict to an agent-group id. Mutually exclusive with target_agent
priorityinteger (optional)Higher claims first; ties break oldest-first. Default 0
not_beforeinteger (optional)Unix ms; not claimable before this
max_attemptsinteger (optional)Claims before the item is parked as failed. Default 3

Take the next eligible item and become its holder. Returns {claimed: false} when nothing is available — a normal answer, not an error, so it’s safe to call speculatively.

ParameterTypeDescription
kindstring (optional)Only claim items with this tag
lease_msinteger (optional)Lease length. Default 120000

If a previous agent handed the item back, their reason is included — read it before repeating their approach.

WorkHeartbeat / WorkComplete / WorkRelease

Section titled “WorkHeartbeat / WorkComplete / WorkRelease”

All three take id and the attempt fence from your claim.

  • WorkHeartbeat — extend the lease while still working.
  • WorkComplete — finish. result is required: once an item is done, it’s the only record the work happened.
  • WorkRelease — hand back with a reason. Prefer this over letting a lease lapse; it frees the item immediately and records why. A release still consumes an attempt, and releasing on the final attempt parks the item as failed rather than reopening it — work nobody can do should stop circulating.

The shared backlog. Filter by state (open, claimed, done, failed, cancelled) and limit. Read-only — useful before enqueueing, to avoid duplicates.

For a richer view from a terminal, including stuck-lease detection, see muxspect work.


Personal memory is the calling agent’s own native memory files; Global Memory is the workspace-wide list every agent gets at launch. Every write keeps a version. See Memory.

ToolWhat it does
MemoryListList your own memory files: filename, whether it is the index, type, size and modified time.
MemoryReadRead one of your memory files.
MemoryWriteCreate or overwrite one of your memory files, atomically.
MemoryHistoryList a memory file’s recorded versions, newest first, with who wrote each.
MemoryDiffLine diff between two versions of a memory file.
MemoryRevertRestore a memory file to an earlier version, recorded as a new version.
GlobalMemoryListList Global Memory entries (id, name, updated, system). AgentMux’s own system entries are listed but can’t be read, changed or removed here.
GlobalMemoryReadRead one Global Memory entry.
GlobalMemoryWriteCreate an entry, or update one by id. Changes what every agent gets at its next launch.
GlobalMemoryRemoveTake an entry off the Global Memory list (the entry itself isn’t deleted).
GlobalMemoryHistoryList an entry’s recorded versions, newest first.
GlobalMemoryDiffLine diff between two versions of an entry.
GlobalMemoryRevertRestore an entry to an earlier version, recorded as a new version.

ToolWhat it does
PresetListList the presets (bundles) available to you, summary fields only.
PresetGetFetch a preset by id or name; with neither, your own bound preset.
IdentityAccountsList your own linked accounts: id, provider, name, kind, status and a masked tail. Secrets are never returned.
IdentityValidateCheck one of your linked accounts against its provider with the stored key.

The core MCP tools have these REST endpoints on $AGENTMUX_LOCAL_URL. All requests require X-AuthKey: $AGENTMUX_AUTH_KEY.

MethodEndpointMCP equivalent
GET/api/v1/self?block_id=<id>WhoAmI
GET/api/v1/layoutLayout("layout")
GET/api/v1/windowsLayout("windows")
GET/api/v1/workspacesLayout("workspaces")
GET/api/v1/tabs?block_id=<id>Layout("tabs")
POST/api/v1/pane/titleSetName(target="pane")
POST/api/v1/tab/nameSetName(target="tab")
POST/api/v1/window/nameSetName(target="window")
POST/api/v1/workspace/nameSetName(target="workspace")
POST/api/v1/tab/activateSetActiveTab
POST/api/v1/tab/newNewTab
POST/api/v1/window/focusFocusWindow
POST/api/v1/pane/openOpenEditor
POST/api/v1/shell/createShell
POST/api/v1/shell/stopShellStop
POST/api/v1/shell/inputShellInput
GET/api/v1/shell/statusShellStatus
GET/agentmux/discoveryDiscoverAgents
POST/agentmux/reactive/injectSendMessage
POST/agentmux/workWorkEnqueue
GET/agentmux/workWorkList
POST/agentmux/work/claimWorkClaim
POST/agentmux/work/:id/heartbeatWorkHeartbeat
POST/agentmux/work/:id/completeWorkComplete
POST/agentmux/work/:id/releaseWorkRelease
DELETE/agentmux/work/:id(cancel — no MCP tool; operator action)

Example — rename the current tab from a trusted script that has access to the auth key (e.g. an agentmux-mcp subprocess or a sidecar utility, not an agent’s own PTY shell):

Terminal window
curl -s -X POST "$AGENTMUX_LOCAL_URL/api/v1/tab/name" \
-H "X-AuthKey: $AGENTMUX_AUTH_KEY" \
-H "Content-Type: application/json" \
-d "{\"block_id\": \"$AGENTMUX_BLOCKID\", \"name\": \"Done\"}"

The underlying protocol is WebSocket, JSON-RPC 2.0 — the same transport the frontend uses. The MCP tools and REST endpoints are thin wrappers over this. Direct WebSocket access is available for advanced use (streaming events, subscriptions):

  • Protocol: WebSocket, JSON-RPC 2.0
  • Endpoint: ws://127.0.0.1:<port>/ws?authkey=<AGENTMUX_AUTH_KEY>
  • Auth: authkey query param on connect (custom headers not supported by the browser WS API)

The WebSocket connection receives server-pushed JSON-RPC notifications for live agent output and workspace events — use these instead of polling the REST endpoints.

Agents are sub-trusted: they run as the user but do not hold the sidecar’s full auth key at the OS level. MuxAPI is the curated surface across that boundary — scoped, reversible operations.

What the curated MCP tool surface allows today: open panes, browser panes and widgets, rename UI elements, navigate, drive its own pane’s UI, discover and message peers, manage shells, and read and write its own memory and Global Memory. The broader MuxAPI RPC surface (agent lifecycle, sessions, identity, memory, drones) is driven by the frontend and internal tooling over the authenticated WebSocket transport.

What it does not expose: access to other agents’ file systems, or raw dispatch_service destructive commands. An agent can ask to close another agent’s pane (ClosePane with a block_id) or stop it (FleetBulkStop), but that waits 15 seconds for the pane’s user to keep it running. A finer-grained per-agent permission model (allow-lists, scoped capabilities) is on the roadmap.

Practical advice: don’t inject AGENTMUX_AUTH_KEY into agent instructions when running less-trusted agents. The API is designed for agents you authored or trust, not for arbitrary model output from external sources.