open-standards/sandbox/spec/environment-manifest.md
Transaction Science e526133f21 Sandbox + JCP: long-horizon agent execution
Add a coherent set of long-running-agent capabilities, each as a spec
section + reference implementation + conformance class, every one metered,
attested, and receipt-chained.

Sandbox:
- §13 Durable run records (C6): the receipt chain IS the resumable run;
  execute/suspend/resume segments hash-chained; idle energy metered across
  parks. (sandbox-attest::runrecord)
- §14 Environment manifest (C7): devcontainer.json declarative-subset
  ingestion -> canonical, content-addressed, signed manifest;
  command/widening and unknown fields refused. (sandbox-attest::manifest)
- §5.5 Content-addressed process control (C8): exec allow/deny by BLAKE3 of
  the binary; denylist absolute, survives rename/move/wrapper.
- §15 Warm pools (C9): a claim attributes accrued idle energy to the run
  (a fast start has a visible joule price); evictions record overhead, not
  zero. (sandbox-attest::warmpool)
- §16 Fleet records (C10): merkle aggregate receipt over per-item runs;
  log-size membership proofs. (sandbox-attest::fleet)
- durable.json cross-impl wire vectors + file-backed verify.

JCP:
- §4.6 Standing grants (C20): a signed mint policy turns a held grant into
  bounded, rate-limited, event-triggered children via the attenuation path.
  (jcp-grant::standing)
- §4.7 Checkpoints + amendments (C21): mid-run steering under separation of
  duties — the agent checkpoints its own state, only the issuer (a distinct
  principal) may amend, and only to tighten. (jcp-grant::checkpoint)
- standing.json cross-impl vectors.

Both workspaces green; conformance harnesses pass with no skips; clippy clean.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-12 23:14:59 -04:00

3 KiB

The environment manifest

A receipt says what a unit cost; an attestation says who ran it, where, at what tier. Neither says in what environment — which base image, which tool features, which variables and mounts. For short runs that gap is tolerable. For durable runs (§13) it is not: a run suspended on one host and resumed on another is only the same run if it resumes into the same toolchain, and "same" must be checkable by hash, not asserted by trust.

The environment manifest closes the gap: one canonical object whose BLAKE3 content address stands for the whole declared environment.

Ingestion: the devcontainer format

Environments are declared in the open Development Containers specification (devcontainer.json) — already the common declaration format across the industry. This standard ingests its declarative subset:

accepted meaning
image base image reference; a @sha256: digest marks the manifest pinned
features tool features, normalized to (id, JCS-canonical options), sorted
containerEnv environment variables, sorted
mounts string or object form, normalized to (source, target, kind), sorted by target
remoteUser the user the unit runs as

Cosmetic and editor-facing fields (name, customizations, …) are accepted and excluded from identity. Networking fields (forwardPorts, appPort, …) are likewise excluded: the network surface is governed by the capability grant (§5), never by the environment declaration.

Refused fields. Anything that executes commands or widens the sandbox is refused with an error, not skipped: build, dockerFile, dockerComposeFile, the five lifecycle *Command hooks, runArgs, privileged, capAdd, securityOpt. Lifecycle automation belongs to the unit and its grants, where it is metered and attested — not smuggled into an identity object. Unknown fields are also refused: silently dropping a field a future devcontainer revision makes execution-relevant would mint a false identity.

Canonical form, address, signature

The manifest core (schema: "sandbox.env-manifest/1") is JCS-canonicalized; its BLAKE3 address is the environment's identity; it is signed Ed25519 over the canonical bytes, mirroring the attestation convention (§7.3). Key order and whitespace in the source document do not affect the address.

A manifest without an image digest is unpinned: its address identifies a declaration, not bytes. Hosts SHOULD treat unpinned manifests the way the energy receipt treats estimates — usable, but labelled, and never the basis for a "same environment" claim across hosts.

Use in durable runs

SnapshotRef.manifest (§13) records the manifest address at suspension. Resumption MUST be refused when the offered environment's manifest address differs — same filesystem plus a drifted toolchain is a different snapshot. Conformance class C7 exercises ingestion determinism, the refusals, and this linkage.

The reference implementation is sandbox_attest::manifest.