@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
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. ThenACPAgent.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:
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.
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/*orterminal/*are answered with an error and never reach your client.
Lifecycle
agent.stop()sends EOF to the agent and kills it if it has not exited within 5 seconds of the call (timeoutMsin JavaScript,timeoutin Python). Messages the agent sends afterstop()are not delivered. In JavaScript, closing the connection withagent.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. PassonStderr(on_stderrin 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 sandboxtimeoutMs/timeoutfor the longest task you expect. - A single message from the agent can be up to 32 MiB. Change it with
maxMessageBytes(max_message_bytesin Python).
Related guides
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