Skip to content

Agent App API

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 internals/env-vars.md — “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 app-API RPC surface

Section titled “Two layers: MCP tools vs. the app-API 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, …) documented in the next section. This is the intentionally small surface most agents use.
  • The app-API 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 app-API 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 (see agentmux-srv/src/server/app_api.rs, agentmux-srv/src/server/agent_handlers.rs, and the command-name constants in agentmux-srv/src/backend/rpc_types.rs) and dispatched over the WebSocket JSON-RPC transport described at the bottom of this page.

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).
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.
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:digestProduce a digest/summary of a session.
session:archiveArchive a session.
session:restoreRestore a previously archived session.
session:exportExport a session.
session:activity_summaryPer-turn live activity summary (writes term:activity).

Agent-anchored session zone (agent_handlers.rs)

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

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.

Broader agent_handlers.rs surface (grouped)

Section titled “Broader agent_handlers.rs surface (grouped)”

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 agentmux-srv/src/backend/rpc_types.rs.

GroupCommands
Agent-definition CRUDlistagents, createagent, updateagent, deleteagent, forkagentdefinition, forkagentdefinitionsuggest, agentdefcreatefromtemplate, agentdefhide, agentdefunhide, agentdeflisthiddentemplates
Agent contentgetagentcontent, setagentcontent, getallagentcontentsetagentcontent 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
Identity bundleslistidentitybundles, getidentitybundle, upsertidentitybundle, deleteidentitybundle, bindidentityaccount, unbindidentityaccount, listidentitybindings
Memory bundles (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 App API namespaces

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

Five higher-level, agent-scoped namespaces wrap the low-level handlers above behind the App API permission boundary. All are registered in agentmux-srv/src/server/app_api/mod.rs today — none of these are “planned,” despite earlier drafts of this page saying so.

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 the “Brain” primitive — see Memory bundles → Native memory and the Armory. 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 (Armory-level, 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 Memory bundles — the page name predates this rename, the content is current):

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 the same storage as the older preset.* commands (agentmux-srv/src/backend/storage/memory_bundles.rs, table db_memory_bundles) — preset.* still works today as a compatibility alias registered against the identical handlers, but new code should use bundle.*.

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. All providers that support MCP (Claude Code, Codex, Gemini, OpenClaw, Kimi) get them automatically. Each maps to a REST endpoint (see the REST API table), which in turn drives an app-API RPC command from the catalog above.

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 }.


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.


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.


Every MCP tool has an equivalent REST endpoint 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

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. The Agent App API is the curated surface across that boundary — scoped, reversible operations.

What the curated MCP tool surface allows today: open panes, rename UI elements, navigate, discover and message peers, manage shells. The broader app-API 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: delete arbitrary panes belonging to other agents, access other agents’ file systems, or call raw dispatch_service destructive commands. 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.