Versioned code across a credential boundary

A workspace is a multi-file tree whose exact digest can be authorized, executed and audited. A trusted host holds the agent's run; jailed code receives no credential and can only propose bounded operations. Workspaces are an extension over Radia's public API.

Why workspaces exist

Code generation often produces a project rather than one source file. The files must persist between iterations, preserve their version history and materialize as a directory for tools that expect a filesystem.

Radia stores each tree version durably while using temporary directories only for execution. The record model remains the source of identity, provenance and authorization.

A workspace moves from durable tree to isolated run and back to a new version A durable workspace manifest points to content-addressed file artifacts. A host materializes the exact tree digest as a read-only input to jailed code. The code writes to a separate output directory, which the host captures as a new workspace version. workspace v7 tree t1:9f2c… index.html style.css cat.png materialize isolated run read-only input exact tree t1:9f2c… separate output capture workspace v8 based on v7 index.html style.css · changed cat.png the input never changes; every run produces a successor
Durable versions stay immutable. Execution reads one exact tree, writes somewhere else and returns that output as a successor version, so concurrent runs cannot alter one another's code or input.

An extension over runtime primitives

The runtime has no workspace, file, path or directory abstraction.

The workspace extension combines a manifest record, artifact records for file contents and a latest-version projection. It uses the same public API as an external application.

application a chat agent, a code reviewer, your own worker examples/ extension: workspace, sandbox, git clone and push imports the SDK only. Never the runtime extensions/ runtime: records, artifacts, leases, grants, taint knows nothing about files src/
Shared conventions live in extensions/. Application-specific behavior stays in the application, and the runtime remains limited to records, leases, grants and artifacts.

Structural tests prevent extensions from importing runtime internals. The Git export and the Git server are therefore ordinary clients, not privileged server operations: a push writes versions under the pusher's own permissions.

Tree digests and path validation are normative. Their exact algorithms cross a trust boundary and are covered by extension conformance tests.

Workspace representation

A manifest record contains a name, tree digest, base version and file list. Each file entry contains a validated path, mode, content digest and artifact id.

A workspace manifest names paths while artifacts hold file bytes One immutable workspace manifest contains validated paths and content digests. Each entry points to a content-addressed artifact holding the bytes. A successor manifest reuses unchanged artifacts and points only changed files at new artifacts. workspace manifest immutable record name landing-page tree digest t1:9f2c… index.html sha256:4b1e… style.css sha256:c70a… cat.png sha256:8ee3… artifact sha256:4b1e… bytes for index.html artifact sha256:c70a… bytes for style.css artifact sha256:8ee3… bytes for cat.png paths and hashes stay in the record; file bytes live in erasable artifacts
The manifest gives the tree its identity and history. Artifacts hold the bytes, so unchanged files are shared between versions and a payload can be destroyed without rewriting every descendant record.
a workspace record
{ "name": "landing-page",
  "treeDigest": "t1:9f2c...ade1",
  "basedOn": "01JB2Q7X4KJ8ZN0R5V3M9WPHTC",
  "files": [
    { "path": "index.html", "mode": "100644", "digest": "sha256:4b1e...", "artifactId": "01JB2..." },
    { "path": "style.css",  "mode": "100644", "digest": "sha256:c70a...", "artifactId": "01JB2..." },
    { "path": "cat.png",    "mode": "100644", "digest": "sha256:8ee3...", "artifactId": "01JB2..." }
  ] }

Editing writes a new manifest linked to its base version. File bytes are content-addressed, so unchanged files are shared across versions. Concurrent edits from the same base create visible successor branches.

Existing artifacts can be attached without copying their bytes. Attached artifacts become data parents of the manifest, propagating their provenance labels.

radia workspaces
NAME          FILES  VERSIONS  TREE            OWNER
landing-page      3         7  t1:9f2cade1a4…  human:alice
scraper           9        22  t1:07b3e5c918…  human:alice

Paths are validated when a manifest is written and again during materialization. The materializer verifies that every resolved file remains within the destination directory.

Sandboxed execution

Radia ships a Deno permission jail for JavaScript, a bubblewrap backend on Linux for available host interpreters, a Seatbelt backend for macOS Python, and a Web Worker backend for a browser tab. Sandbox records describe the guarantees of each backend.

A worker probes a sandbox before advertising it. A backend is available only when the probe confirms the guarantees claimed by its record.

Successful probes determine which execution tools the worker publishes. A host that cannot provide the required isolation does not advertise that runner.

The sandbox and the broker enforce different boundaries. The sandbox restricts ambient host access such as files, processes, storage and network. The broker ensures that code inside the sandbox never possesses a reusable Radia credential and cannot choose the identity, provenance or idempotency of committed operations.

The untrusted process holds no Radia credential. The host performs permitted operations on its behalf and supplies authoritative metadata that the child cannot choose.

Deno permissions alone do not confine module loading. Filesystem confinement therefore uses a mount namespace on Linux and a Seatbelt profile on macOS. Sandbox records state whether this additional boundary is active.

A run writes files into a separate output directory. When execution finishes, the host captures that directory as a new workspace version. The input tree remains immutable and may be shared by concurrent runs.

A promoted workspace runs across a credential boundary A binding and a promotion grant must name the same workspace digest. A trusted host holds the agent run credential and launches untrusted code without a credential. The code writes to a separate directory, which the host captures as a successor workspace. binding agent:scraper → digest t1:07b3… promotion grant prod may claim with t1:07b3… digest agrees otherwise refuse trusted host holds the agent's run credential adds parents, labels and identity sandbox boundary untrusted code · no credential separate output tree successor workspace host captures the code tree is immutable; every run writes somewhere new
The binding chooses the code, the grant pins what may claim work, and the host requires the digests to agree. Only the host holds a credential; executed code receives a confined tree.

Promotion and agent bindings

A binding record associates an agent with a workspace digest. The generic host materializes that version, executes it in the selected jail and claims work through the agent's run.

Promotion rotates grants that are pinned to the workspace digest. The claim permission and executable code version are therefore checked together.

A binding and promotion grant form two locks on execution The binding says agent scraper should execute workspace digest B. The production grant permits digest A to claim work. When the digests differ the host refuses and releases the claim. After promotion makes both name digest B, the host may execute it under the agent's credential. before promotion: the locks disagree binding run digest B production grant claim as digest A A ≠ B refuse + release promote B both locks name B binding selects B grant permits B host may execute claim authority and executable identity change together rollback is the same operation with an earlier approved digest
A binding alone cannot authorize code, and a grant alone cannot select code. The host runs a workspace only when both independently managed records agree on its digest.
what is prod running, answered from the enforcement path
$ radia promote t1:07b3e5c918… --tier prod --pin agent:scraper:take,ack
$ radia pins agent:scraper --tier prod
agent:scraper on 'prod': t1:07b3e5c918…

A host refuses a binding whose digest disagrees with the active grant pin. Rollback promotes a previous digest through the same mechanism. The jail bounds host access, the binding selects code and the grant limits the records that code may process and produce.

Bindings declare which request fields identify input artifacts. The host fetches those artifacts under the agent's authority and places them in the run directory. Outputs name the inputs as parents so their labels propagate.

The analysis example uses promoted workspace stages through one generic host. View the analysis example →

Serving and exporting workspaces

Serve a tree to a browser

The extension converts a manifest into a path-to-artifact index and mints a short-lived capability over the complete tree. Scriptable content is served from an isolated origin.

Requests match entries in the fixed index and never resolve against a filesystem. Artifact access is authorized when the capability is minted, and the URL expires with that capability.

Git: export, clone and push

radia workspace-git
$ radia workspace-git landing-page --dir /tmp/landing.git
landing-page: 7 versions, 34 objects -> /tmp/landing.git
$ git clone /tmp/landing.git && cd landing && git log --oneline
9c1e4a2 attempt 7: fix the header overlap
04b7f30 attempt 6: add the illustration
…

The same projection can be served over Git HTTP, for clone and for push:

radia git-serve
$ radia git-serve
git server on http://127.0.0.1:7790  (reading http://127.0.0.1:7788)

$ git config --global credential.http://127.0.0.1:7790.helper '!radia git-credential'
$ git clone http://127.0.0.1:7790/landing-page.git
$ cd landing-page && $EDITOR index.html
$ git commit -am "tighten the hero copy" && git push
To http://127.0.0.1:7790/landing-page.git
   9c1e4a2..d41f2b7  main -> main
$ radia workspaces
NAME          FILES  VERSIONS  TREE             OWNER
landing-page  9      8         a41c7f0e2b9d31…  human:oidc-alice

Git authenticates as you: the credential helper hands git the login this machine already holds, from radia login --sso or radia login, and the server applies that principal's Radia permissions. Revocation stops the next fetch or push.

Push is accepted fast-forward only. Each pushed commit becomes the next version, written under the pusher's own workspace: put grant, and the commit keeps its id, so a fetch after a push changes nothing. A force-push, a merge commit, a new or deleted branch, a symlink or a commit that changes no file is refused with the reason on git's own ! [remote rejected] line. There is no merge: rebase onto the branch and push again.

Each manifest version becomes a commit, version links become commit parents and trailers refer back to the source record. The exporter writes Git objects directly without invoking Git.

A push imports trees, never history. Each pushed commit's files become a version and its commit id is recomputed from the bytes; Git object identity and rewritable history are not accepted as workspace identity, and Radia records and SHA-256 tree digests remain authoritative.

Capabilities and limits

Anyone who has purged a leaked credential from a repository knows what it costs: every downstream hash changes, every fork force-pushes, every clone is invalidated, signed tags die. Here a file is an artifact, so one payload can be destroyed while the tree digest still verifies and the history still reads.

The guarantee is narrower than it sounds. The manifest keeps the path and the hash of the erased file, in a record body that has no erasure path of its own. So credentials/prod-db.txt outlives its own contents, and anyone holding a candidate secret can hash it and confirm that exact value was in that tree. A destroyed build output or document is gone in every practical sense. A destroyed credential is unreadable and still confirmable, and its filename is plaintext forever. What this removes is the blast radius, not the disclosure.

Past that: every file version is attributable to a specific run, the dependency set is inside the record rather than claimed by a lockfile, a grant can scope which workspace an agent may touch at all, and labels track whether a file descends from something untrusted. Branch protection has been approximating that last set for years, and a git hook dies to --no-verify.

What it does not buy: incremental builds, editor feedback, merge, blame. Git does the storage model better and has thirty years of tooling around it. A workspace is instead a working tree whose every state is a record the runtime can authorize, attest and erase.

What the system can tell you about all this →