sand-boxer/docs/meta-framework.md
tegwick b6655d8859
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Add bounded stdin to owner execution
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a06def-6490-7033-8448-2eab2d12ed44
2026-09-04 22:30:11 +02:00

9.1 KiB

sand-boxer meta-framework specification

Version 0.1 — derived from research/03-meta-framework-synthesis.md and INTENT.md.

sand-boxer is the sandbox establishment service: one API for consumers, many extension backends. It provisions where and how code runs; sibling projects own agent harnessing, validation, and code generation.


Resource model

Resource Description
Profile Named, versioned sandbox recipe: extension binding, isolation, network, TTL, placement
Extension Backend adapter implementing provision / wait_ready / teardown
Host Registered placement target for self-hosted extensions; read-only telemetry via profile.sandbox-canary (see docs/host-telemetry.md)
Sandbox Running instance of a profile
Snapshot Point-in-time workspace checkpoint (sandboxer snapshot / restore)
Route Extension selection policy when multiple backends qualify
Meter Usage record for payments layer (SaaS extensions — SAND-WP-0006)

Lifecycle states

requested → provisioning → ready → active → { expired | failed } → destroying → destroyed
State Meaning
requested Create accepted; not yet handed to extension
provisioning Extension running provision + wait_ready
ready Reachability confirmed; consumer may attach
active Consumer has marked sandbox in use (optional transition)
expired TTL elapsed before explicit destroy
failed Provision or readiness failed
destroying Teardown in progress
destroyed Resources released; record retained for audit

State Hub event mapping

Each transition emits a State Hub progress event (or dedicated registration API when available):

Transition event_type Required fields
requested note sandbox_id, profile_id, consumer
provisioning note extension_id, host
ready milestone reachability descriptor
active note actor_type, timestamps
failed note error summary
destroying note
destroyed milestone duration_s, cleanup report

Event detail payload (JSON):

{
  "sandbox_id": "abc12345",
  "profile_id": "profile.compose-e2e",
  "extension_id": "ext.compose-ssh",
  "host": "coulombcore",
  "consumer": {"actor": "atm", "project": "wise-validator", "run_id": "..."},
  "actor_type": "atm",
  "state": "ready",
  "reachability": {
    "ssh": "root@coulombcore",
    "remote_dir": "/tmp/sandboxer/abc12345",
    "tunnel": "localhost:12222",
    "tunnel_via": "ops-bridge",
    "identity": "ops-warden"
  },
  "timestamps": {"created_at": "...", "ready_at": "..."}
}

Extends the build-agent self-register pattern: generic sandbox identities carry profile_id + extension_id instead of build-machine metadata.


Core API operations (v0)

Operation Description v0 scope
create Provision from profile + inputs Yes
get Inspect sandbox status Yes
list List sandboxes (filter by consumer optional) Yes
extend_ttl Extend time-to-live Yes
recreate Destroy and reprovision from stored seed Yes
destroy Idempotent teardown Yes
snapshot / restore Checkpoint workspace Yes (compose-ssh, saas-stub)
exec Owner-mediated command in a local bwrap sandbox Yes (ext.bwrap only)

HTTP surface (optional v0; CLI calls core library directly):

  • POST /v1/sandboxes — create
  • GET /v1/sandboxes/{id} — get
  • GET /v1/sandboxes — list
  • DELETE /v1/sandboxes/{id} — destroy
  • POST /v1/sandboxes/{id}/snapshot — checkpoint
  • POST /v1/snapshots/{id}/restore — restore
  • GET /v1/snapshots — list checkpoints
  • POST /v1/sandboxes/{id}/recreate — recreate
  • PATCH /v1/sandboxes/{id}/ttl — extend TTL
  • POST /v1/sandboxes/expire — TTL reap (query apply=true)
  • GET /v1/sandboxes/{id}/reachability — enriched descriptor + SSH one-liner
  • POST /v1/sandboxes/{id}/exec — authenticated owner-mediated bwrap command

Reachability descriptor

When a sandbox reaches ready, sand-boxer emits a reachability block on SandboxStatus, lifecycle events, and sandboxer reachability show <id>.

Field Source Description
ssh Extension SSH target (user@host)
remote_dir Extension Workspace root on remote host
host Extension Placement host name
tunnel Profile + env Local port (localhost:PORT) or VM alias
tunnel_via Profile spec Route owner (default ops-bridge)
identity Profile spec Warden actor hint (default ops-warden)

Tunnel metadata is enriched from profile reachability and environment:

  • SANDBOXER_TUNNEL_PORT / handle tunnel_port or ssh_port
  • SANDBOXER_TUNNEL_ALIAS / handle vm_target
  • SANDBOXER_TUNNEL_VIA (optional override)

sand-boxer does not bring tunnels up. Consumers use ops-bridge (MCP or bridge CLI) to attach SSH routes; the descriptor is a pointer only.

For ext.bwrap, reachability is not an invitation to enter the recorded PID. The report contains execution.mode: owner-mediated; callers use sandboxer exec when running as the sandbox owner or the authenticated HTTP exec endpoint when calling the resident owner service. Direct consumer-side nsenter is not supported.

secret_refs from profile.setup are resolved at the provision boundary and passed to the extension handle — they never appear on SandboxStatus or State Hub events.


Consumer attribution

Every create request carries a consumer block:

consumer:
  actor: adm | agt | atm
  project: <calling-repo-or-service>   # e.g. wise-validator, glas-harness
  session_id: <optional>
  run_id: <optional>
Actor Typical caller
adm Human operator via CLI
agt LLM agent session
atm Deterministic automation (CI, activity-core, wise-validator)

sand-boxer records attribution on every lifecycle event. It does not interpret agent intent or authorize the caller — flex-auth owns authorization when enforced. An exec request must nevertheless repeat this block exactly. Any actor, project, session, or run mismatch is refused before extension dispatch.


Extension interface

Each extension implements:

provision(profile, inputs, placement) → SandboxHandle
wait_ready(handle) → Reachability
teardown(handle) → CleanupReport
supports_execution?() → bool
execute?(handle, argv, credential_route_refs, execution_context, bounds) → CommandResult
estimate_cost?(profile, duration) → MeterQuote   # optional; SaaS only

Registration requirements (validated at load time):

  • id — unique extension identifier (ext.<name>)
  • capabilities — isolation levels, regions, persistence, pricing model
  • handler — Python entry point or built-in registry binding

Extensions are discovered from extensions/*.yaml at repo root and loaded via sandboxer.extensions.registry.


Routing policy vocabulary

When multiple extensions satisfy a profile capability:

Strategy Behavior
prefer-self-hosted Self-hosted extensions first; SaaS fallback (default Coulomb posture)
lowest-cost Cheapest estimate_cost quote wins
lowest-latency Closest region / host wins
explicit Profile names a single extension; no auto-routing

Routing engine v0: sandboxer.routing.resolver — see docs/routing.md.


Security limits

sand-boxer commits to:

  1. Default-deny network unless profile explicitly allows egress
  2. Secrets at provision boundarysecret_refs resolved via ops-warden / OpenBao; never returned to agent context
  3. Blast-radius isolation — dedicated hosts (sandboxer01, CoulombCore) away from Railiance01 production
  4. Observable lifecycle — every transition attributed to adm / agt / atm
  5. Honest limits — allowed tool paths can be abused by compromised agents
  6. Fail-closed local execution — exact identity/state/TTL binding, owner-managed workspace validation, sanitized environment, bounded duration/output, and no host-checkout or alternate-extension fallback

Owner execution also accepts up to 1,000,000 UTF-8 bytes of stdin_text. It is delivered only to the child process and excluded from results and lifecycle events, allowing a harness to create prompt/task files inside the sandbox without putting their content in argv or writing through the host workspace.

sand-boxer does not provide intent-aware egress filtering in v1.


Out of scope (sibling ownership)

Concern Owner
Agent gateway, tools, memory glas-harness
e2e.yml semantics, health checks, test pass/fail wise-validator
Code generation, setup instructions content snuggle-inventor
SSH tunnels ops-bridge
SSH certificates ops-warden
Workstream / task state state-hub

See docs/integrations/ for per-sibling contracts.