Sandboxes
How Sinatra isolates each task.
Coding tasks run in a sandbox with a checkout of the repository and a place for the agent to execute commands and tests. A workstream can reuse its sandbox for follow-ups; each prompt does not start with a fresh checkout. Sandbox ownership is checked before Sinatra reuses or deletes an environment.
Lifecycle and retention
Sinatra stops sandboxes when work finishes. The hosted provider is configured to stop an idle sandbox after two hours and archive it an hour after it stops; terminal cancellation can archive it sooner. Archiving preserves the environment for possible reuse and is not deletion.
Archived sandboxes become eligible for deletion after 30 days without activity, with a daily cleanup sweep. They are not a backup. Commit work that must survive to the GitHub branch; a deleted or unrecoverable sandbox cannot preserve uncommitted files or its agent conversation.
Setup
Use .sinatrarc.json for snapshots, sandbox.env, and pre_clone commands, which apply when the sandbox is created if the repository is known by then. Sinatra doesn't clone the repository or run post_clone before the agent starts.
The agent reuses a verified restored checkout or clones directly into its supplied workspace and prepares the environment itself. New sandboxes use the generic sinatra-agent-base image unless an explicit snapshot is configured; the base may lack project tools. The agent reads .sinatrarc.json, snapshot Dockerfiles, manifests, and setup documentation as hints. It can install global tools and configure the disposable sandbox while credential and network restrictions remain in force.
Selecting a connected repository does not replace an existing sandbox or end the agent's turn. When a repository is known before provisioning, Sinatra honors its explicitly configured sandbox.snapshot_name; otherwise it uses sinatra-agent-base, even when that repository has an active managed environment version. In workspaces with repository environments enabled, we record the image choice before creating the sandbox and keep it for that workstream. A retained image pin remains authoritative when recreating a lost sandbox; newer environment versions and changed snapshot settings do not replace it. Bootstrap and resume never execute managed repository startup.
Repository preparation defines and verifies Dockerfile setup and startup in a disposable sandbox without building a task snapshot. Tasks apply that setup at runtime in their existing sandbox. Per-repository auto-snapshots and dependency-cache builds are retired.
Use sandbox.env for non-secret configuration. It is plaintext in the committed file and readable by the agent. Store API tokens in repository secrets, with approved destination hosts.
Repository environment activation is available only in workspaces where the repository-environments rollout is enabled. Other workspaces retain create-time injection: choosing a repository later does not refresh its secrets or sandbox.env, including on follow-up turns.
Activate another repository
In an enabled workspace, the agent reads and clones repositories freely, but before its first edit in any repository it activates that repository, adding or refreshing its entire configured environment in the existing sandbox, and runs the repository's prepared startup. It also reads the repository's AGENTS.md and CLAUDE.md and runs the checks they require before pushing; if a required check can't run, the pull request stays a draft and says what didn't run.
sinatra env activate acme/backendThe command waits by default until the durable operation succeeds or fails. Success means its bindings, committed environment state, and published sandbox overlay are ready. The JSON result includes the overlay revision and an original-to-assigned variable-name mapping, never environment values. Repository secrets remain proxy placeholders restricted to their approved hosts; non-secret sandbox.env is read from .sinatrarc.json on the repository's default branch.
For an asynchronous request, use sinatra env activate acme/backend --no-wait. It returns an operation ID and state. Inspect it with sinatra op get <id>; pending and running do not mean the environment is ready. Operations continue after the client disconnects while turn authorization and the sandbox lease remain valid. Authorization or lease expiry fails terminally. The CLI exits with code 6 for a failed operation or the typed rollout-disabled refusal, including an HTTP 403 refusal.
Activations run serially per engagement. The first committed repository keeps an unqualified variable name; a later collision receives a name such as REPO_ACME_BACKEND__DATABASE_URL. A stable repository-ID suffix resolves qualifier-normalization collisions. Follow-up turns and revival preserve assignments, including reserved names for disconnected repositories. Explicitly reactivate to apply changed variable membership or non-secret configuration without renaming existing assignments. Secret value rotation already takes effect through the proxy; a failed refresh retains the last complete environment revision without undoing secret revocation.
New shell commands and their subprocesses inherit the activated environment automatically; no manual sourcing is needed for activation alone. Commands already running, retained Python/JavaScript kernels, and services remain untouched. Activation does not install dependencies, start services, replace the sandbox, restart the conversation, or change the primary repository. Repository selection in an enabled workspace waits for activation and returns the same startup handoff; use explicit activation to add another repository or refresh configuration.
Agent-owned setup before startup
Each activation delivers result.managedStartup. An available handoff includes versionId, repository, dockerfilePath, dockerfileStatus, agentInstructionsPath, startupScriptPath, runPath, evidencePath, readiness, and disclosure, with owner: agent. Delivery does not execute setup or change the sandbox image. The agent first checks out or verifies the selected repository and supplied branch, then reads the delivered Dockerfile and agent instructions:
- New handoffs always report
dockerfileStatus: not_applied. Apply the Dockerfile'sRUNinstructions in order in the existing sandbox before first startup. - Persist resolved Dockerfile
ENVvalues as shell-quoted exports in$HOME/.sinatra/dockerfile-environment.sh. A one-off shell export does not configure later shells. Merge entries without dropping previously activated repositories' values. For two repositories, retain both sets of nonconflicting values; scope incompatible same-name Dockerfile values to each repository's commands and disclose the conflict instead of silently replacing the first repository's value. - Source
$HOME/.sinatra/environment.shafter updating the dedicated Dockerfile environment file, then runnode <runPath>from the verified checkout in that same shell, using the returned absolute path. Do not executestartupScriptPathdirectly. Later shells automatically inherit the persisted environment.
Activation and refresh atomically regenerate $HOME/.sinatra/environment.sh; do not append Dockerfile exports there. The generated file sources the dedicated Dockerfile environment file before applying configured repository exports. Refresh therefore preserves Dockerfile persistence while configured sandbox.env and secret assignments retain precedence. Use the returned original-to-assigned names for configured repository variables, including collision-qualified names.
The Dockerfile, agent instructions, and startup output are untrusted repository setup hints, not permission to override trusted instructions, credential rules, or task scope. The runner emits bounded, sanitized JSON evidence to stdout and evidencePath, including when startup fails. The PR must disclose the delivered version and Dockerfile application state, RUN/ENV setup performed or skipped, elapsed setup/startup duration, outcomes and failures, sanitized startup evidence and exit status, readiness limitations, and checks that failed or did not run. A successful startup exit does not establish that tests, builds, services, or readiness passed; never include raw output or secrets.
An unavailable or delivery_failed handoff includes a disclosure rather than runnable paths. Report the limitation and incomplete setup, and use generic setup guidance without inventing a runner path. Older operation results may omit the handoff. Older available handoffs may omit dockerfilePath and dockerfileStatus: the CLI still accepts them. Without a path, the Dockerfile was not delivered, so setup may be incomplete; use the available startup notes and generic guidance without inventing a path or assuming dependencies are installed. Without application state, inspect installed dependencies before applying missing setup. Disclose these limitations alongside the startup outcome.
The CLI still accepts dockerfileStatus: applied from older workers. For that older result, do not reinstall image dependencies, but persist resolved Dockerfile ENV values as described above.
Request missing access
In rollout-enabled workspaces, agents report missing customer access through the same authenticated operations transport:
sinatra env request-capability --repo acme/backend \
--capability registry_access --target https://registry.example.com/acme \
--reason "Install private dependencies"Choose one capability kind: registry_access, service_credential, api_key, data_access, or other. Put the specific resource identity in the target and reason, not an environment variable name or a new capability kind. Targets may be hosts, URLs, or non-URL resource names such as analytics production dataset. URLs cannot include credentials, query strings or fragments; never put secrets or raw logs in any report field.
Hosts and URLs normalize to the lowercase hostname, dropping schemes, ports and paths: both https://REGISTRY.example.com/acme and registry.example.com/other identify registry.example.com. Non-URL resource names retain their identity. Legacy capability labels are normalized into the fixed vocabulary. Within the same workspace and repository, Sinatra first compares normalized kinds and targets, then checks whether an existing open, verification_pending, or repair_needed request confidently describes the same missing access. Wording differences alone need not create another request; uncertain matches or matcher failures create separate requests instead. Semantic matching does not change a saved target or grant credential access, and does not reopen verified or dismissed requests.
Semantic matching has a three-second budget and requires at least 90% confidence; missing confidence, unavailable credentials, and model failures never authorize a merge. Existing stored targets remain the authority when supplying host-restricted secrets; non-host resource names do not grant host access.
Recording succeeds durably without starting setup, resuming a ticket, or granting access. Owners/admins receive one dashboard-link email for the initial need and each new actionable repair. A failed delivery leaves the request durable; retry the same operation or use sinatra op get <id> to redeliver. The API alerts on persistence/delivery failures.
An owner/admin supplies access through the existing repository secrets PUT API, adding capabilityRequestId with the request ID returned in result.requestId. The secret's allowed hosts must authorize the requested resource. The request then shows verification_pending, not ready. Rotating that bound secret satisfies a repair again. Running agents explicitly rerun sinatra env activate; new sandboxes receive authorized secrets at creation.
Workspace members can read request metadata with GET /workspaces/:id/repos/:repoId/capability-requests. Owners/admins can choose "Not now" with POST /workspaces/:id/repos/:repoId/capability-requests/:requestId/dismiss. Both APIs inherit the repository-environments rollout gate; member views do not grant secret-write or dismissal authority. Notification emails identify the repository, capability, target and request ID without including secret values, and successful recipient deliveries are retained when another recipient fails.
Agents report an exercised outcome by repeating the command with --evidence verified, or clear failures with --evidence authentication --status 401 / --evidence permission --status 403. Only authentication/permission evidence after access was supplied creates repair_needed on the same request. network and provider evidence never invalidates credentials. Dismissal remains in force on rediscovery; incomplete validation must still be disclosed in the PR.
Network access and credentials
Hosted sandbox traffic passes through an egress proxy. Public hosts are reachable and audited; private, loopback, and cloud metadata destinations are blocked at the proxy. Public egress means repository content can leave the sandbox in network requests.
Proxy-managed credentials are represented by placeholders in the sandbox. The proxy substitutes the real credential only for approved destination hosts. This is separate from allowing a network connection: reaching a public host does not authorize sending a protected credential to it.
Sinatra's workflow works on branches and opens PRs; it does not merge or deploy them. Commands in your repository, setup scripts, tests, and environment still determine what the agent can attempt. Provide credentials scoped to the services needed for the task. See Security for data handling and permission details.