Skip to content

Epic: SandboxTransport — language-neutral remote sandbox exec over gRPC #89

Description

@pdettori

Epic: SandboxTransport — language-neutral remote sandbox exec over gRPC

Tracks the work in the SandboxTransport spec (Status: Design — approved for planning) and ADR-0024 (Accepted). Landed via #78.

Origin

Today the harness runs every Pi tool call (read/write/bash/grep) inside a sandbox pod via kubectl exec — the harness dials into the pod through the kube API. That only works when the harness can reach the sandbox's API server, which rules out sandboxes behind NAT, on-prem, on a laptop, or in another cloud — and blocks the top driver: bring-your-own (untrusted 3rd-party) sandboxes (spec §1).

Target architecture

Invert connectivity: the sandbox dials out to a broker the harness also talks to, over a language-neutral, firewall-friendly protocol (one outbound TLS connection, HTTP/2 on :443), without changing the Pi loop, session backend, or leaf queue (spec §2–§3).

Sandbox (laptop / on-prem / other cloud / same cluster)
  worker (Go static binary) — SandboxWorker.Attach client
     │ outbound only, TLS :443, HTTP/2  (WorkerFrame ↑ / ServerFrame ↓)
     ▼
Kubernetes
  relay (Deployment, 1 replica)  — parks Attach streams; mirrors presence → Redis pool
     │ in-cluster gRPC (SandboxExec.Exec/Abort)
     ▼
  Harness (central brain: Pi loop + LLM)      Redis sandbox pool
     SandboxTransport.exec(...)  ← the ONE seam
       ├─ [local]  KubectlTransport    (existing kubectl-exec, renamed)
       └─ [remote] GrpcRelayTransport  (new; calls the relay)
     select-sandbox → leases pod OR remote record → returns a transport

Key decisions (locked) — see ADR-0024

  • Brain stays central. The Pi loop + LLM key never leave the harness; an untrusted sandbox only ever receives commands and returns bytes (trust-correct for driver harness: tsc fails on cli.ts gateway-header cast (x-api-key: null → Record<string, string>) #1).
  • Contract is a Protobuf IDL (sandbox/v1), not a TypeScript interface. Any gRPC-capable language can host a worker; TS is just one generated client (§4).
  • gRPC-native over HTTP/2 on :443, not Connect — full-duplex bidi needs HTTP/2 regardless, so Connect adds a second toolchain for no gain on the streaming core (§5).
  • Single-replica, presence-only relay — no matchmaking, no presence glue beyond mirroring workers into the existing Redis pool; select-sandbox matches unchanged (§6).
  • One Go reference worker — the honest proof the contract is genuinely language-neutral (§7).
  • Per-sandbox bearer token at the edge day-one; SPIFFE/mTLS upgrades into the same Attach seam later (§9).

What does NOT change

The Pi orchestration loop, run-turn, the session backend (RedisSessionBackend), the leaf queue (@sh/work-queue), and the sandbox pool/lease logic. The change slots strictly below the current ExecInPod call sites (spec §3).

Two tracks (build in parallel off the shared contract)

The worker build is separated from the backend and coded by a different contributor; per the repo's lifecycle conventions, implementation plans are local-only (docs/plans/, gitignored) and per-contributor — one for the backend, one for the worker.

Phases (dependency-ordered)

Deferred / follow-up (spec §13.4, ADR-0024) — not scheduled here

  • Untrusted-BYO isolation → SPIFFE/SPIRE mTLS per-connection identity on the same Attach endpoint.
  • Multi-replica relay / HA (adds a presence map — K8s API or Redis pub/sub).
  • Private-mesh reachability (Headscale / WireGuard) for fleets refusing a public endpoint.
  • Additional-language workers (e.g. Python) — the proto already permits them.
  • HTTP/1.1-only proxy traversal — the Connect / split-stream variant of §5.

Working conventions

  • Spec: docs/specs/2026-07-08-sandbox-transport-grpc-design.md + registry row (docs/specs/README.md). Decision: docs/adrs/0024-sandbox-transport-remote-exec.md.
  • Plans live in docs/plans/ (local-only, gitignored), named for the spec, deleted once coded.
  • DCO: git commit -s; attribution trailer Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com> (never Co-authored-by).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions