Skip to Content
Connect an AgentBring your own agent

Bring your own agent

Autonomy doesn’t require Claude Code or Codex specifically. Because the integration point is “an MCP client,” anything that can hold an MCP connection over stdio and call tools — a custom agent you’ve built, a different vendor’s CLI, an internal automation host — can connect to the same daemon the default agent uses, see the same tool catalog, and be held to the same consent rules.

This matters because Autonomy’s actual product is the accessibility layer, not an agent. If Autonomy only worked with one blessed CLI, every disabled user stuck with a different agent would be locked out of consent-aware, accessibility-native computer use. The bring-your-own path is what keeps Autonomy a runtime other agents plug into, rather than another agent competing with the ones people already use.

This page covers the two things a BYO integration needs: the MCP connection itself, and — if you want your agent to appear in the in-app Agent Conversation panel rather than just calling tools ad hoc — the agent_conversation_* sequence that claims, narrates in, and releases that panel.

What the daemon does and doesn’t spawn

Nothing about connecting a BYO agent causes Autonomy to spawn a process for it. Your agent already exists as its own process, with its own model and its own loop; it becomes an MCP client of a7y-mcp, which runs as one local daemon reachable over stdio (JSON-RPC 2.0). Autonomy hosts the tool surface, the consent ledger, and — if you use it — the conversation event log. It does not host, supervise, or restart your agent process.

This is a deliberate contrast with the retired nightgram path, where the app spawned a codex exec subprocess and parsed its stdout. That subprocess had no MCP connection and none of Autonomy’s tools. A BYO agent under the current model is the opposite: it’s a full MCP peer from the first message.

Connecting over stdio

The minimum viable connection is any mcpServers entry pointed at the daemon, the same shape used by the shared plugin config:

{ "mcpServers": { "autonomy": { "command": "/Applications/autonomy (a7y).app/Contents/Resources/bin/a7y-cli", "args": ["daemon", "proxy"] } } }

Once connected, a tools/list call returns the full catalog (see MCP tool catalog) unless your host was configured against a domain-filtered proxy invocation, in which case it returns only that domain’s tools plus a small cross-cutting set (consent, action ledger, readiness). Either way, it’s ordinary MCP — no Autonomy-specific handshake beyond standard tools/list / tools/call.

Driving the Agent Conversation panel

If your agent should show up in Autonomy’s own conversation panel — the surface a screen-off user reads or hears from — it participates through four tools instead of owning any UI itself:

Claim

Claim the conversation with a stable session id, your provider id, and a display name:

{ "sessionId": "conversation-claude-1", "providerId": "anthropic", "providerDisplayName": "Claude", "modelId": "claude-sonnet", "actorId": "claude-worker", "reason": "Handle the persistent screen-off conversation" }

Call this as agent_conversation_session_claim. Claiming does not hand you exclusive control of the UI, transcript, VoiceOver output, or consent — Autonomy keeps ownership of all four. It just tells Autonomy which external agent is currently the one narrating.

Append

Append transcript content as you go, with role set to user, agent, status, or failure, and redactionApplied: true asserting the text is safe user-visible panel content:

{ "sessionId": "conversation-claude-1", "actorId": "claude-worker", "role": "status", "text": "Checking Autonomy readiness before making changes.", "redactionApplied": true }

Release

Release the claim when you’re done (agent_conversation_session_release) — this doesn’t close the panel, it just marks the session released so another agent (or the same one, later) can claim it cleanly.

Under the hood, claim/append/release don’t mutate shared in-memory session state — they publish events onto a local, durable agent.conversation topic. Any process can call agent_conversation_session_get at any time and get the same reconstructed session state by replaying those events, which is also what the macOS app’s own event poller does to render the panel and speak through the VoiceOver transport.

Regardless of how you built your agent, once it calls a tool in Autonomy’s elevated or critical safety band, the daemon’s consent gate applies the same way it would to the default agent. See Consent & safety for the request/resolve flow — a BYO agent gets no shortcut around it, and shouldn’t want one: it’s the boundary that makes an unfamiliar agent safe to run against a real person’s Mac.

Pitfalls

  • A Claude Code subagent tools: allowlist is not context isolation. If you’re building a domain-scoped specialist rather than one general agent, know that in Claude Code a subagent’s tools: list only restricts which tools it may call — every tool’s schema still lands in its context unless you also declare an inline mcpServers: block requesting a domain-filtered proxy. Plugin-defined subagents can’t declare that block at all, which is why Autonomy’s own specialists are launched via claude -p --agents with inline mcpServers, not shipped as plugin subagents.
  • redactionApplied: true is a promise, not a formality. agent_conversation_append rejects redactionApplied: false outright — the tool exists to keep hidden raw source content and secrets out of a transcript a screen-reader user relies on, not to be toggled off when convenient.
  • The root *.mcp.json files in this repo aren’t Autonomy config. cursor.mcp.json, windsurf.mcp.json, and gemini.mcp.json all point at an unrelated development-only Agent Mail coordination server; codex.mcp.json is just an empty {"mcpServers": {}} stub. Don’t copy any of those thinking they wire up Autonomy — use plugins/autonomy/.mcp.json as the template.
  • A successful tool call is not confirmation the user heard or saw anything. Treat delivery evidence (voiceover_direct_requested, tts_fallback_used, user_heard_unverified, …) as exactly what it says, and say so in your own agent’s status output too.
Last updated on