Sign in

Run Claude Managed Agents in Prized Sandboxes

Run each Claude Managed Agents session's tools in a Prized sandbox of its own: a self-hosted environment, a spawn script for Anthropic's worker, and the limits.

On this page9

Claude Managed Agents can run an agent's tools on machines you control, through a self-hosted environment. This guide gives each session its own sandbox: Claude runs on Anthropic's side, and the sandbox runs the agent's tool calls and holds its files.

How it works

  1. You start a session on a self-hosted environment, and Anthropic queues it.
  2. ant beta:worker poll, on a machine you keep running, claims the session and runs spawn.sh.
  3. spawn.sh creates a sandbox, installs Anthropic's ant CLI in it without root, and starts ant beta:worker run, which runs the session's tool calls.
  4. A minute after the session goes idle, the worker exits, and spawn.sh saves the output and deletes the sandbox.
  5. A message that wakes the session again starts the cycle over, in a new sandbox that gets the session's files back.

Nothing connects in: the poller and the worker call out to api.anthropic.com over HTTPS.

Before you start

  • An agent and a self-hosted environment. Create an agent with Anthropic's quickstart. In the Claude Console, choose Environments → New → Self-hosted, then Generate environment key on the environment's page.
  • A Prized API key with Full access, or Custom with Sandboxes: Write (Sandboxes: Quickstart).
  • A poller machine that stays on, Linux or macOS, with ant, jq, and prized v0.21.0 or later (CLI).

1. Set the keys

On the poller machine:

export ANTHROPIC_ENVIRONMENT_ID=env_…
export ANTHROPIC_ENVIRONMENT_KEY=sk-ant-oat01-…
export PRIZED_API_KEY=dcp_…

The poller needs the environment key, never your Claude API key.

2. Save the spawn script

Save this as spawn.sh in the folder you run the poller from, and run chmod +x spawn.sh.

spawn.sh
#!/bin/bash
# spawn.sh: `ant beta:worker poll --on-work ./spawn.sh` runs this once per work item (a session's run until it goes idle), with the session's ids and the environment key in ANTHROPIC_* variables and the work item as JSON on stdin.
set -euo pipefail
ANT_VERSION=1.40.0
MAX_MIN=60  # the sandbox's lifetime in minutes: up to 1440 after a top-up or a plan
ANTHROPIC_WORK_SECRET=$(jq -r '.secret // empty')
DIR="sessions/$ANTHROPIC_SESSION_ID"  # the session's working directory as work.tgz, and a log per work item
OUT="$DIR/$ANTHROPIC_WORK_ID"
mkdir -p "$DIR"

# Run the session in the background, so the poller can claim the next one now.
(
  # One run of a session at a time, so a follow-up starts from the files the run before it saved.
  # A run ends with its sandbox, so a lock older than that was left by a run that was killed.
  until mkdir "$DIR/lock" 2>/dev/null; do
    find "$DIR/lock" -maxdepth 0 -mmin +$((MAX_MIN + 10)) -exec rmdir {} \; 2>/dev/null || true
    sleep 5
  done
  trap 'rmdir "$DIR/lock"' EXIT

  SECONDS=0  # from here, the sandbox's lifetime
  SBX=$(prized sandbox create --no-wait --template prized-base-v1 --max-runtime "$MAX_MIN" --label "anthropic-session=$ANTHROPIC_SESSION_ID")
  echo "sandbox: $SBX"
  trap 'prized sandbox rm "$SBX" || true; rmdir "$DIR/lock"' EXIT  # until the session is over, a failed step deletes the sandbox

  # Hand the worker its keys in a file, through stdin: other users of this machine can read a command line.
  for v in ANTHROPIC_ENVIRONMENT_ID ANTHROPIC_ENVIRONMENT_KEY ANTHROPIC_SESSION_ID ANTHROPIC_WORK_ID ANTHROPIC_WORK_SECRET; do printf 'export %s=%q\n' "$v" "${!v}"; done |
    prized sandbox cp - "$SBX:~/worker.env"

  # A session that went idle and woke again carries on with its files.
  if [ -e "$DIR/work.tgz" ]; then
    prized sandbox cp "$DIR/work.tgz" "$SBX:~/work.tgz"
    prized sandbox exec "$SBX" -- 'tar xzf ~/work.tgz -C ~/work'
  fi

  # Install the ant CLI without root, and start the worker. It stops 5 minutes before the sandbox's lifetime ends, to leave time to save its output.
  prized sandbox exec "$SBX" -- "mkdir -p ~/.local/bin && curl -fsSL https://github.com/anthropics/anthropic-cli/releases/download/v$ANT_VERSION/ant_${ANT_VERSION}_linux_amd64.tar.gz | tar -xz -C ~/.local/bin ant"
  prized sandbox exec "$SBX" -- "nohup bash -c '. ~/worker.env; timeout $((MAX_MIN * 60 - 300 - SECONDS)) ~/.local/bin/ant beta:worker run --workdir /home/prized/work; touch ~/worker.done' > ~/worker.log 2>&1 &"

  # The worker exits a minute after the session goes idle, and leaves ~/worker.done behind. Check every 30 seconds.
  until prized sandbox exec "$SBX" -- 'test -e ~/worker.done' || [ "$SECONDS" -ge $((MAX_MIN * 60 - 240)) ]; do sleep 30; done

  # Save the working directory and the worker's log, then delete the sandbox. If saving fails, the sandbox and the session's lock stay until its lifetime ends.
  trap - EXIT
  prized sandbox exec "$SBX" -- 'tar czf ~/work.tgz -C ~/work .'
  prized sandbox cp "$SBX:~/work.tgz" "$DIR/work.tgz"
  prized sandbox cp "$SBX:~/worker.log" "$OUT.worker.log"
  prized sandbox rm "$SBX" || true
  rmdir "$DIR/lock"  # after the delete, so a follow-up's create finds the sandbox's slot free
) > "$OUT.log" 2>&1 < /dev/null &
  • MAX_MIN is each sandbox's lifetime in minutes: 60, the most the free tier allows. After a top-up or a plan, it can be up to 1,440 (24 hours). The worker is stopped 5 minutes before the end, so its output can still be saved.
  • ANT_VERSION pins the ant release; newer ones are on GitHub.
  • Sessions run side by side, a sandbox each: the script returns at once, so the poller claims the next session while this one runs. A follow-up to one session waits until its previous run has saved.
  • Output goes to sessions/<session id>/: the working directory as work.tgz, replaced whole when a later run of the session saves, and for each work item the script's log as <work id>.log and the worker's as <work id>.worker.log.
  • If saving fails, for example on an archive over the 100 MB a copy takes, the sandbox is kept until its lifetime ends, and the session's next run waits until then: copy what you need with prized sandbox cp, then delete the sandbox and sessions/<session id>/lock. Its id is at the top of the work item's log.

3. Start the poller

ant beta:worker poll --on-work ./spawn.sh

4. Run a session

Start a session on the environment and send it Write the output of "uname -a" to hello.txt in your working directory. While it runs, prized sandbox ls shows its sandbox, labelled anthropic-session=sesn_…. About a minute after the session goes idle, hello.txt is in sessions/sesn_…/work.tgz.

Keys in the sandbox

The environment key and the session's secret reach the sandbox in ~/worker.env, which the worker loads, so the agent's tool calls can read them. The key reaches only its environment's queue: use one environment per trust boundary (Security model). Never pass your Claude API key or your Prized API key into a sandbox.

Limits

LimitIn a sandbox
Working directory/home/prized/work: tools run as the user prized, without root, so there is no /workspace. If the agent uses skills, tell it in its system prompt that they are in /home/prized/work/skills
Memory storesNot supported: they need a writable /mnt/memory
Files and repositoriesAnthropic does not mount them on self-hosted environments; fetch them in spawn.sh before the worker starts (Stage files for a session)
Lifetime24 hours, or 60 minutes on the free tier; a session still running then loses its sandbox
At once4 sandboxes of up to 2 vCPU and 4 GB on the free tier; paid quotas are on Limits
NetworkOutbound internet, with no allow or deny lists yet
Regionus-west-2 (Oregon)

Prized Sandboxes and Claude Managed Agents are both in beta.

Troubleshooting

SymptomFix
The poller exits with 401 Unauthorized and OAuth access token is invalidThe environment key is wrong, revoked, or for another environment than ANTHROPIC_ENVIRONMENT_ID: generate a new one
The poller exits with on-work script "./spawn.sh" is unrunnableRun chmod +x spawn.sh, and start the poller in the script's folder
A session stays queuedStart the poller. From your own machine, with your Claude API key, ant beta:environments:work stats --environment-id env_… then shows workers_polling of 1 or more
A follow-up waits, and its log stays emptyThe session's previous run is still going, or its save failed (If saving fails above). A lock left by a run that was killed, for example by a reboot, clears itself a little over MAX_MIN + 10 minutes after that run started
A session's log starts with a prized: errorPrized refused the sandbox, so that session has none; the ↳ line says what to change. MAX_MIN above 60 needs a top-up or a plan. An error after the sandbox: line while saving keeps the sandbox: see If saving fails above
A session goes idle at once, and its log says cannot create the memory store's folderStart the session without memory stores