Use the Sandbox
A sandbox is an isolated Linux machine. An automation can use it to run shell commands, Git, the GitHub CLI, and scripts, and to keep files between runs.
| Automation | Sandbox |
|---|---|
| Instruction automation | The managed agent has its own sandbox. It runs commands, reads and writes files, and runs skill scripts as part of the run. Ask for this work in the instructions. |
| Code automation | Each automation has one sandbox. Your code calls it with ctx.tools.call and the managed-sandbox service. |
The rest of this page is about the sandbox of a code automation.
Sandbox tools for code
Section titled “Sandbox tools for code”Code automations run in a QuickJS VM with no shell. For shell work, call these managed-sandbox tools:
| Tool | Use it to |
|---|---|
exec_command | Run a short shell command and get its output. |
start_background_command | Start a long command that keeps running after the call returns. |
read_file, write_file, edit_file | Read and change text files. |
list_directory, list_working_directories | Find files and folders. |
Run a command
Section titled “Run a command”export default class { async check(ctx: AutomationContext, event: RecurringEvent) { const result = await ctx.tools.call( { service: "managed-sandbox", name: "exec_command", arguments: { command: "printf automation-ready" }, }, { automationEffectKey: `workspace-check:${event.scheduledAt}` }, ); if (result.isErr()) return err(result.error); if (result.value.isError) return err(new TypeApiError("Command failed", "invalid_response")); const text = result.value.content .filter((block) => block.type === "text") .map((block) => block.text) .join("\n"); return ctx.setOutput({ text }); }}- Each sandbox call needs an
automationEffectKey, also for reads. exec_commandreturns text content. It does not return{ stdout, exitCode }. CheckisError, then read the text.- To return structured data, print a marker and JSON, for example
printf 'JSON:%s\n' "$out", then parse the line in code.
How the sandbox works
Section titled “How the sandbox works”- The first sandbox call in a run starts the sandbox. The sandbox folder is
/tmp/type-automation. - Each automation has its own sandbox. Type keeps it between runs for speed, but it can replace it at any time.
- Files can stay between runs. Treat them as a cache. Make setup steps safe to run again.
- Agent checkouts and environment variables from threads are not copied into the sandbox.
- Commands get no Type credential.
Use the GitHub CLI
Section titled “Use the GitHub CLI”The sandbox has gh and jq. Type gives fresh GitHub credentials for the GitHub connections of the Space. The credentials belong to the automation’s creator.
TYPE_GITHUB_CONNECTIONS is a JSON list. Each item has fullName, organizationIntegrationId, and tokenEnv, the name of the environment variable that holds the token.
const repo = "acme/project"; // a fixed value, never event textconst command = [ `t=$(printf %s "$TYPE_GITHUB_CONNECTIONS" | jq -er 'first(.[] | select(.fullName == "${repo}") | .tokenEnv)') || { echo "No GitHub connection covers ${repo}" >&2; exit 1; }`, `out=$(GH_TOKEN=$(printenv "$t") gh api 'repos/${repo}/pulls?per_page=1' --jq 'map({number, title})') || exit 1`, `printf 'JSON:%s\\n' "$out"`,].join("\n");Access rules
Section titled “Access rules”- Sandbox commands run only in live runs. In fixtures, give the result in
toolResponses. A test never starts the sandbox. - For GitHub, the connection must be in the Space with full automation access. If there is none, the deploy fails.
- A shell cannot enforce read-only access. A command with a full-access token can change data.
Retries and effects
Section titled “Retries and effects”An effect key identifies the call. It does not stop a command from running again if a run fails part of the way. Make commands safe to repeat. For example, check if a branch exists before you create it.
Limits
Section titled “Limits”- One sandbox call can take up to 170 seconds.
exec_commandreturns at most 16 KiB of output. Filter output in the command, for example withjqorhead.- Each sandbox call counts toward the 128 requests in a run.
- The run deadline still applies. See Limits.