Skip to main content

Runner and sandbox configuration

This page is the reference for the agent runner: the service that executes agent code, either inside its own container (local) or in a Daytona cloud sandbox. It lists every operator-facing runner variable, its default, its Helm path, and the errors an invalid value produces.

The runner parses all of its AGENTA_RUNNER_* variables once before it starts listening. An invalid value fails startup with the error shown in Startup validation.

For the model behind these settings, see How agents run. For the general platform variables, see the configuration reference. The local subscription mount variables (PI_CODING_AGENT_DIR and CLAUDE_CONFIG_DIR) are covered by Use your own subscription.

The bundled Compose env examples group these variables under Agenta - Agent runner in the same order as the sections below, so the file and this page mirror each other.

Service

Set on the runner service.

VariableRoleDefaultSecretHelm
AGENTA_RUNNER_HOSTBind interface127.0.0.1noagentRunner.env.AGENTA_RUNNER_HOST
AGENTA_RUNNER_PORTBind port8765noChart-managed (8765)
AGENTA_RUNNER_CONCURRENCY_LIMITMaximum concurrent runs1000noagentRunner.env.AGENTA_RUNNER_CONCURRENCY_LIMIT
AGENTA_RUNNER_LOG_LEVELLog verbositysilentnoagentRunner.logLevel
AGENTA_RUNNER_REPLICA_IDReplica identity for logsGenerated when unsetnoagentRunner.env.AGENTA_RUNNER_REPLICA_ID

Every variable on this page treats an empty value as unset, so leaving a line blank selects the default rather than an empty string.

The code default host is 127.0.0.1. The bundled Compose files set AGENTA_RUNNER_HOST=0.0.0.0 so the Services container can reach the runner across the Compose network. AGENTA_RUNNER_PORT and AGENTA_RUNNER_CONCURRENCY_LIMIT must be positive integers.

Routing and authentication

These locate the runner and authenticate the call. Two of the three are caller-side: the Services API and its SDK read them, not the runner.

VariableRoleRead byDefaultSecretHelm
AGENTA_RUNNER_INTERNAL_URLRunner locatorServices API (caller-side)Compose: http://runner:8765noagentRunner.externalUrl, else derived from agentRunner.enabled
AGENTA_RUNNER_TOKENShared request credentialServices sends it; runner verifies itUnsetyesagentRunner.env.AGENTA_RUNNER_TOKEN
AGENTA_RUNNER_TIMEOUT_SECONDSIdle timeout the caller allows on the run requestServices API and SDK (caller-side)180non/a

AGENTA_RUNNER_TOKEN is the same credential at both ends. It does not belong to a sandbox or a harness. The runner enforces the check only when the value is set, so leaving it unset (the bundled Compose and Helm default) disables it. To turn it on, set the same value on the runner and on the Services API.

AGENTA_RUNNER_TIMEOUT_SECONDS bounds idle time on the caller's streaming transport, not the total run duration, and the runner never reads it. The runner enforces its own deadlines through Run limits. Set the caller timeout above the runner's idle timeout, or the caller gives up on a run the runner still considers healthy.

Sandbox providers

Read by both the runner and the Services API, so the operator sets each value once and hosting templates apply it to both.

VariableRoleDefaultHelm
AGENTA_RUNNER_ENABLED_SANDBOX_PROVIDERSProviders this deployment can uselocalagentRunner.providers.enabled (list, rendered comma-joined)
AGENTA_RUNNER_DEFAULT_SANDBOX_PROVIDERProvider used when a run does not chooselocalagentRunner.providers.default

Rules:

  • Values are lowercase provider ids separated by commas. The known ids are local and daytona.
  • Unset enabled providers means exactly local.
  • An explicitly empty list is invalid, and so is an empty entry inside the list.
  • Unknown ids and duplicate ids are invalid.
  • The default must be one of the enabled providers.
  • A run may select any enabled provider. A run that selects a known but disabled provider fails before any working directory, mount, secret, or sandbox is created. There is no fallback to another provider.

The enabled list applies to the whole deployment, not to a user or a run. It decides what isolation a run can get; see Sandbox isolation and security.

Daytona

Read by the runner service. Required only when daytona is enabled.

VariableRoleDefaultSecretHelm
AGENTA_RUNNER_DAYTONA_API_KEYProvisioning credentialUnsetyesagentRunner.providers.daytona.apiKeySecretRef
AGENTA_RUNNER_DAYTONA_API_URLDaytona API locatorUnsetno...daytona.apiUrl
AGENTA_RUNNER_DAYTONA_TARGETRegion or targetUnsetno...daytona.target
AGENTA_RUNNER_DAYTONA_SNAPSHOTSnapshot to start fromRunner's pinned agenta-agent-sandbox-v1no...daytona.snapshot
AGENTA_RUNNER_DAYTONA_IMAGEImage to start fromUnsetno...daytona.image
AGENTA_RUNNER_DAYTONA_AUTOSTOP_MINUTESIdle minutes before stop15no...daytona.autostopMinutes
AGENTA_RUNNER_DAYTONA_AUTODELETE_MINUTESIdle minutes before delete30no...daytona.autodeleteMinutes

When neither AGENTA_RUNNER_DAYTONA_SNAPSHOT nor AGENTA_RUNNER_DAYTONA_IMAGE is set, the runner starts from its pinned default snapshot agenta-agent-sandbox-v1. The two variables are mutually exclusive. The autostop and autodelete values must be positive integers. See Run agents in a cloud sandbox (Daytona) for the setup flow, and Customize the agent runtime for the CPU, memory, and disk each sandbox gets.

The bare DAYTONA_* variables configure a different sandbox

DAYTONA_API_KEY, DAYTONA_API_URL, DAYTONA_TARGET, DAYTONA_SNAPSHOT, and DAYTONA_SNAPSHOT_CODE configure the code evaluator's sandbox, which runs custom evaluator code. The agent runner reads only the AGENTA_RUNNER_DAYTONA_* names in the table above.

The two may point at the same Daytona account, so the key, the URL, and the target may hold the same values. The snapshot may not: the evaluator's snapshot (for example daytona-small) has no agent harness installed, so an agent booted into it cannot run.

Warm sessions and scale

A session stays warm between turns so a follow-up turn skips a cold start. Both providers pool sessions, but they budget different things: the Daytona pool budgets billed compute, and the local pool budgets host memory inside the runner container. All of these are read by the runner service, and all are safe to leave unset.

Daytona, one warm sandbox per parked session:

VariableRoleDefaultSecretHelm
AGENTA_RUNNER_DAYTONA_SESSION_IDLE_TTL_MSHow long a sandbox stays running with its live session after a clean turn120000 (2 minutes)no...daytona.sessionIdleTtlMs
AGENTA_RUNNER_DAYTONA_SESSION_MAX_WARMHow many idle sandboxes may stay running between turns20no...daytona.sessionMaxWarm

Set AGENTA_RUNNER_DAYTONA_SESSION_IDLE_TTL_MS to 0 to stop a sandbox after each turn. There is no separate enable flag. AGENTA_RUNNER_DAYTONA_SESSION_MAX_WARM bounds idle spend only; it never blocks an active turn. Overflow sandboxes park in the stopped state.

Keep the idle TTL below the autostop window

AGENTA_RUNNER_DAYTONA_SESSION_IDLE_TTL_MS must stay below AGENTA_RUNNER_DAYTONA_AUTOSTOP_MINUTES. Autostop is Daytona's own idle timer, and it does not know about the runner's warm pool. If the TTL is the longer of the two, Daytona stops a sandbox the runner still believes is warm: the next turn takes the cold path anyway, and you paid for the warm window without getting it. The defaults (2 minutes against 15) satisfy this. Raise autostop first whenever you raise the TTL.

Local, one pooled harness process per parked session inside the runner container:

VariableRoleDefaultSecretHelm
AGENTA_RUNNER_SESSION_POOL_MAXHow many local sessions may stay pooled8noagentRunner.env.AGENTA_RUNNER_SESSION_POOL_MAX
AGENTA_RUNNER_SESSION_TTL_MSIdle lifetime of a pooled local session60000 (1 minute)noagentRunner.env.AGENTA_RUNNER_SESSION_TTL_MS
AGENTA_RUNNER_SESSION_APPROVAL_TTL_MSIdle lifetime while a run waits for a human approval300000 (5 minutes)noagentRunner.env.AGENTA_RUNNER_SESSION_APPROVAL_TTL_MS
AGENTA_RUNNER_SESSION_KEEPALIVEWhether local sessions are reused at allEnablednoagentRunner.env.AGENTA_RUNNER_SESSION_KEEPALIVE

Local keep-alive is on by default. Set AGENTA_RUNNER_SESSION_KEEPALIVE=off (0, false, and no also work) to make every local turn take the cold path, which lowers the runner container's memory ceiling and raises the latency of a follow-up turn. The approval TTL applies while a run waits on a human approval, so it does not expire a session that is waiting on a person. These four apply to the local provider only; Daytona ignores them and uses the two variables above.

A Daytona sandbox moves through three states:

StateWhenBilling
RunningWhile a turn executes, and during the warm window after a clean turnCompute and disk
StoppedAfter AGENTA_RUNNER_DAYTONA_AUTOSTOP_MINUTES idle minutesDisk only; restart is cheap and the session reloads on the same instance
DeletedAfter AGENTA_RUNNER_DAYTONA_AUTODELETE_MINUTES idle minutesNone; the next turn creates a fresh sandbox and reloads the working directory from the store

Run limits

Four deadlines bound a single run. Whichever limit trips first aborts the run and releases its sandbox, its mount, and its socket. All four are read by the runner service and apply to every provider.

VariableRoleDefaultSecretHelm
AGENTA_RUNNER_RUN_TOTAL_TIMEOUT_MSHard deadline for one run, measured from the first message2700000 (45 minutes)noagentRunner.env.AGENTA_RUNNER_RUN_TOTAL_TIMEOUT_MS
AGENTA_RUNNER_RUN_IDLE_TIMEOUT_MSLongest gap between two progress events before the run is abandoned300000 (5 minutes)noagentRunner.env.AGENTA_RUNNER_RUN_IDLE_TIMEOUT_MS
AGENTA_RUNNER_RUN_TTFB_TIMEOUT_MSLongest wait for the first response after the run starts120000 (2 minutes)noagentRunner.env.AGENTA_RUNNER_RUN_TTFB_TIMEOUT_MS
AGENTA_RUNNER_TOOL_CALL_TIMEOUT_MSLongest a single tool call may take300000 (5 minutes)noagentRunner.env.AGENTA_RUNNER_TOOL_CALL_TIMEOUT_MS

Three rules govern how they interact:

  • A run paused for a human approval is exempt from all four. The pause freezes every timer.
  • The idle timeout must stay below the total deadline, or it could never fire first. A value at or above the total is clamped to half the total, and the runner logs the clamp rather than failing to start.
  • The TTFB timer only covers the wait for the first response. The first progress event of any kind cancels it and arms the idle timer instead.

An invalid value (not a number, or negative) falls back to the default for that variable. These are the runner's own deadlines and are unrelated to AGENTA_RUNNER_TIMEOUT_SECONDS, which is the caller's idle timeout on the streaming transport.

Callback API

Set on the runner service. It gives the runner the in-network address of the API for session heartbeats, working-directory mount signing, and the trace-export fallback.

VariableRoleDefaultHelm
AGENTA_API_INTERNAL_URLAPI locator for runner callbacksCompose: http://api:8000Wired by the chart

Point this at the API as reached from inside the runner container (its Compose or cluster service name, for example http://api:8000), not the public URL, which does not resolve inside a container. If it is unset, the runner falls back to the public AGENTA_API_URL and then to the base inferred from each request.

Internal settings

The runner reads two more variables that exist for debugging and for custom sandbox images. They are not part of the supported configuration surface and may change without notice. Leave them unset on a normal deployment.

  • AGENTA_RUNNER_DEBUG_TOOLS: when set to any value, the runner logs verbose tool-callback diagnostics to standard error. Unset by default.
  • AGENTA_AGENT_SANDBOX_PI_DIR: where the Pi agent directory lives inside a Daytona sandbox, defaulting to /home/sandbox/.pi/agent. This describes the sandbox image's own layout, not the deployment. Change it only if you build a custom snapshot that puts Pi somewhere else.

Startup validation

The runner fails to start when configuration is invalid, before it listens. The exact messages:

CauseError
Enabled list is set but emptyAGENTA_RUNNER_ENABLED_SANDBOX_PROVIDERS is set but empty; unset it for the default 'local', or list at least one provider.
Empty entry in the enabled listAGENTA_RUNNER_ENABLED_SANDBOX_PROVIDERS has an empty entry in '<list>'.
Unknown provider id in the enabled listAGENTA_RUNNER_ENABLED_SANDBOX_PROVIDERS lists unknown provider '<id>'; known providers: local, daytona.
Duplicate provider idAGENTA_RUNNER_ENABLED_SANDBOX_PROVIDERS lists provider '<id>' more than once.
Default is an unknown providerAGENTA_RUNNER_DEFAULT_SANDBOX_PROVIDER is unknown provider '<id>'; known providers: local, daytona.
Default not in the enabled setAGENTA_RUNNER_DEFAULT_SANDBOX_PROVIDER '<id>' is not in the enabled set [<list>]. Add it to AGENTA_RUNNER_ENABLED_SANDBOX_PROVIDERS or change the default.
Daytona enabled without a keyAGENTA_RUNNER_DAYTONA_API_KEY is required when 'daytona' is in AGENTA_RUNNER_ENABLED_SANDBOX_PROVIDERS.
Snapshot and image both setAGENTA_RUNNER_DAYTONA_SNAPSHOT and AGENTA_RUNNER_DAYTONA_IMAGE are mutually exclusive; set only one.
Non-integer positive value<variable> must be a positive integer, got '<value>'.

The last message covers AGENTA_RUNNER_PORT, AGENTA_RUNNER_CONCURRENCY_LIMIT, AGENTA_RUNNER_DAYTONA_AUTOSTOP_MINUTES, and AGENTA_RUNNER_DAYTONA_AUTODELETE_MINUTES.

On a valid start, the runner logs one redacted summary. No credential value or source path is logged.

runner providers enabled=[local,daytona] default=local
runner daytona target=eu artifact=snapshot:agenta-agent-sandbox-v1

The first line always prints. The second line appears only when daytona is enabled. target reads default when AGENTA_RUNNER_DAYTONA_TARGET is unset, and artifact reads snapshot:agenta-agent-sandbox-v1 (the pinned default), snapshot:<name>, or image:<name> depending on what is set.

Troubleshooting

A run fails with Sandbox provider '<id>' is not enabled on this deployment

Cause: The run requested a provider that is not in AGENTA_RUNNER_ENABLED_SANDBOX_PROVIDERS.

Solution: Add the provider and recreate the runner, or change the run to use an enabled provider.

A run fails with could not find runner CLI at /app/runner/src/cli.ts

Cause: AGENTA_RUNNER_INTERNAL_URL is unset on the Services API. With no runner URL, the SDK falls back to spawning the runner as a subprocess from its own image, which does not ship the runner source.

Solution: Set the locator on the services container and recreate it. On Compose:

AGENTA_RUNNER_INTERNAL_URL=http://runner:8765

The bundled Compose files already default to this value, and the Helm chart derives it from agentRunner.enabled. A hand-written deployment has to set it. Check that the Services container reaches the runner at that address:

docker compose exec services python -c \
"import urllib.request; print(urllib.request.urlopen('http://runner:8765/health').status)"

A 200 confirms the hop.

The API cannot reach the runner, or the runner rejects its calls

Cause: AGENTA_RUNNER_INTERNAL_URL does not point at the runner, or AGENTA_RUNNER_TOKEN is set on only one side.

Solution: Check the URL, and set the same token value on the API and on the runner or on neither.

A self-managed local run fails because the harness has no login

Cause: The subscription mount is missing, or PI_CODING_AGENT_DIR / CLAUDE_CONFIG_DIR does not point at it.

Solution: See Use your own subscription.

A self-managed run that requested Daytona fails

Cause: Personal subscriptions are local-only.

Solution: Run Daytona with a model API key. See Sandbox isolation and security.

The runner fails to start with a Daytona authentication error

Cause: AGENTA_RUNNER_DAYTONA_API_KEY is wrong, or it has no access to the target.

Solution: Check the key and AGENTA_RUNNER_DAYTONA_TARGET.

Working directories do not persist across turns on Daytona

Cause: The sandbox could not reach the store, so it mounted nothing. The runner logs a mount-degradation warning.

Solution: Make the store publicly reachable. See Run agents in a cloud sandbox (Daytona).