View source on GitHub
start-sandbox, which shows the bare
sandbox lifecycle. Read that one first if the sandbox/agent-server split is new
to you.
How It Works
Steps 1–2 use the Cloud app server (auth headerX-Session-API-Key: <OH_API_KEY>).
Steps 3–4 use the sandbox’s agent server (auth header
X-Session-API-Key: <session_api_key>, returned by the create call). Step 5 is
back on the Cloud app server. See start-sandbox for more
on the two-server split.
Where does setup.sh live?
In the repository, at .openhands/setup.sh. That is the exact location
OpenHands itself runs every time it starts working with a repo — see
Repository Customization.
This example runs that same file so the sandbox you hand off is set up the way
the agent would expect. If a repo has no .openhands/setup.sh, the step is
skipped with a note. (This repo ships a tiny one so the default run does
something visible.)
Attaching is asynchronous
POST /api/v1/app-conversations returns a start task, not the conversation
itself. Poll GET /api/v1/app-conversations/start-tasks?ids=<task_id> until it
reports an app_conversation_id, then open
https://app.all-hands.dev/conversations/<app_conversation_id>.
Run It
Why Would I Do This?
Normally you start a conversation and OpenHands clones your selected repository for you. Sometimes you want more control before the agent gets involved:- pre-warm an environment so the agent starts instantly on an expensive setup,
- check out a specific commit, tag, or a sub-path of a monorepo,
- clone from a mirror or run custom bootstrapping the default flow doesn’t do,
- reuse one prepared sandbox for several scripted conversations.
POST /api/v1/app-conversations accepts a
sandbox_id. Pass the id of a sandbox you already prepared and the new
conversation attaches to it instead of creating a fresh one.
Point It at Your Own Repo
Every input is a flag with an environment-variable fallback, so the script is safe to drop into your own automation unchanged:Cloning a private repo? Start the sandbox with the appropriate git credentials available (e.g. via sandbox secrets) or clone over an authenticated URL. This example targets public repositories to stay simple.
Cleanup
The sandbox is intentionally left running because a live conversation is now attached to it — deleting the sandbox ends that conversation. Delete it from the conversation UI, or via the API (the id goes in both the path and a requiredsandbox_id query parameter):
APIs Used
Related
start-sandbox
The bare sandbox lifecycle and the sandbox/agent-server split
Repository Customization
Where .openhands/setup.sh lives

