Automation with ACP

An Oda process can serve a program of yours instead of a person: the automation profile speaks the Agent Client Protocol (ACP) over standard input and output, and your client manages persistent Oda sessions through it. Use this page when you build or debug such a client; Automation clients covers the serving profiles, and the Oda SDK overview and The Oda Remote API cover the other ways a program can drive Oda.

Set up the connection

  1. Start the automation profile for your client. It serves one client per process and runs until that client disconnects; the profile can also name a default provider and model for its sessions.
  2. Send initialize. The answer names the protocol version the server speaks and the server's name and version. If your client requests a version the server does not support, the handshake still succeeds and the answer names the version the server speaks.
  3. Send authenticate. It succeeds immediately: the server requires no authentication and advertises no authentication methods.
Note

Standard output carries protocol messages only. Keep anything else, such as a logger, off that stream.

What the server advertises

The initialize answer tells your client what the connection supports:

The calls

Your client drives the server with these calls:

CallWhat it does
initializeOpens the connection; names the protocol version and the server.
authenticateSucceeds immediately; no authentication is required.
session/newCreates a session. It needs an absolute working folder, and the MCP servers are declared here. An empty session is stored before the call returns.
session/promptSends one prompt. One prompt can be in flight per session, and several sessions can run over one connection.
session/cancel ($/cancel_request)Cancels the prompt in flight; it settles as cancelled. With nothing in flight, it cancels autonomous work, and an unknown session id is a no-op.
session/listLists the sessions that can be resumed, newest first, with a cursor for the next page.
session/resumeReopens a stored session: it verifies the working folder, restores the latest model route and reconnects the declared MCP servers.
session/set_config_optionChanges the Model or the Reasoning effort for the next turn.
session/closeCloses the session. After a close, the session can be listed and resumed again.

The server also sends messages of its own:

MessageWhat it carries
session/updateWhat the session is doing while it works, as the updates section describes.
session/request_permissionA request to allow or reject one action; see Permissions.

Sessions

Permissions

Prompts and images

MCP servers

Updates and how a prompt settles

The turn endsYour client is told
Completedend_turn
At its token limitmax_tokens
Cancelled by your clientcancelled
Interruptedcancelled
Blocked or failedend_turn
Aborted by a hook or another ownerend_turn

Model and effort settings

Limits and unsupported surfaces

Questions, answered

What does initialize answer with?

The protocol version the server speaks, the server's name and version, and what the connection supports: HTTP MCP, image prompts when the runtime has them, session close, list and resume, and no authentication methods. A request for a version the server does not support still gets an answer naming the server's version.

Does the server require authentication?

No. authenticate succeeds immediately, and the server advertises no authentication methods. The connection is trusted: the server adds no authentication of its own.

Can I run several sessions on one connection?

Yes. Sessions are independent of each other, and each runs one prompt at a time; a second prompt for the same session is refused until the first settles: a prompt is already in flight for this session.

How do I stop a prompt that is running?

Send session/cancel (or $/cancel_request); the prompt settles as cancelled. With nothing in flight, the same call cancels autonomous work, and an unknown session id makes it a no-op.

Why was my session not resumed?

Three common reasons: it is active elsewhere (session is already active: <id>), it is not a stored root session (session is not resumable: <id>), or the folder you gave differs from the session's (session cwd does not match: <cwd>). Subagent and forked sessions cannot be resumed.

Why is my session missing from session/list?

The list leaves out sessions that are live in the process, subagent sessions, forked sessions, and sessions with a missing or relative folder. Only sessions that can be resumed are listed, newest first, one page at a time.

What happens to running work when I close a session?

Closing cancels the prompt in flight first, then lets updates and subagent work drain, flushes what is stored and disposes the session; a failure in that sequence is reported (session close failed: <detail>). New work during the close is refused with session is closing: <id>, and afterwards the session can still be listed and resumed.

Which images can a prompt carry?

PNG, JPEG, WebP or GIF, as canonical base64, and only when the connection advertised image support and the selected model accepts image input. Otherwise the prompt is refused with inline image prompts were not advertised by this connection or model "<model>" does not declare image input.

How does a model or effort change take effect?

It applies to the next turn. The turn that is running keeps the model and effort it started with, so one turn never mixes routes. An unknown value is refused, for example unknown model option: <value>.

What does my client receive while a prompt runs?

session/update messages: thought chunks, message chunks, tool calls and their completions, and a usage update when usage can be measured. The prompt then settles with a reason such as end_turn, max_tokens or cancelled.

Why did session/new fail?

Most often because the working folder is not absolute (cwd must be an absolute path: <cwd>), because the request carried additional directories (additionalDirectories is not supported), or because one MCP declaration was invalid; declarations are checked before the session starts, so nothing is left behind.