Skip to main content
The Agent Client Protocol (ACP) is an open protocol between coding agents and the clients that drive them. With the E2B ACP package (@e2b/acp for JavaScript, e2b-acp for Python), the agent runs inside an E2B sandbox and your application is the ACP client: it starts sessions, sends prompts, receives the agent’s messages and tool calls, and answers permission requests. The same client code works for all three agents below. Only the sandbox template and the command that starts the agent change. Other ACP agents can run the same way once they are installed in a custom template.

Install

Set E2B_API_KEY to your E2B API key, and the provider key for the agent you run.

Run an agent

Your code creates a sandbox from a template that already has the agent installed. Then ACPAgent.start() (AsyncACPAgent.start() in Python) runs the agent inside that sandbox and connects your ACP client to it over the agent’s stdin and stdout. The agent process runs in the sandbox, not on your machine:
Use agent.connection to initialize the agent, create sessions and send prompts. In JavaScript, your client is a client() app from @agentclientprotocol/sdk, and requests to the agent go through agent.connection.agent. In Python, client is an ACP client object, or a function that takes the connection and returns one.
The agent writes and runs fizzbuzz.py in the sandbox, so the file is there afterwards for sandbox.files.read() or sandbox.commands.run(). OpenCode takes its model from its config. Pass it in the OPENCODE_CONFIG_CONTENT environment variable, as the TypeScript cookbook example does with {"model": "openai/gpt-5.6-luna"}. The ACP Python SDK is asynchronous, so use it with AsyncSandbox.

Where the agent’s tools run

ACP lets an agent ask its client to read and write files or run terminal commands on the client’s machine. The E2B ACP package keeps that work in the sandbox:
  • In initialize, the client filesystem and terminal capabilities are always turned off, whatever your client sends.
  • Agent requests for fs/* or terminal/* are answered with an error and never reach your client.
The agent uses its own tools instead, so files it edits and commands it runs stay in the sandbox even if your client also works as an editor. The package does not restrict the agent’s network access or the MCP servers you pass to it: an MCP server you pass with a command is started by the agent in the sandbox, while a remote MCP server is reached over the network. Your client still receives permission requests. Whether an agent asks before a tool call depends on the agent’s own settings.

Lifecycle

  • agent.stop() sends EOF to the agent and kills it if it has not exited within 5 seconds of the call (timeoutMs in JavaScript, timeout in Python). Messages the agent sends after stop() are not delivered. In JavaScript, closing the connection with agent.connection.close() also stops the agent, in the background.
  • agent.wait() returns the exit code once the agent exits. If the agent exits with an error, pending requests fail with the exit code and the end of the agent’s stderr in JavaScript, and with a connection error in Python. Pass onStderr (on_stderr in Python) to receive the agent’s logs.
  • The agent runs as long as the sandbox does. If your application exits without calling stop(), the agent keeps running until the sandbox times out, so set the sandbox timeoutMs/timeout for the longest task you expect.
  • A single message from the agent can be up to 32 MiB. Change it with maxMessageBytes (max_message_bytes in Python).

ACP agents in TypeScript

One client for goose, OpenCode and Claude Code

ACP agents in Python

The Python version of the same example, built on agent-client-protocol

OpenCode

Run OpenCode headless or with its own HTTP server

Claude Code

Run Claude Code headless with structured output and sessions