Ring
A Ring is one of three in-process enforcement positions.
Rings sit inside the agent's process. Each ring's enforcement depends on what the surrounding sandbox supports. Filled by per-target Providers selected into a Runtime.
Three rings, period. Targets multiply within each ring; rings stay stable. Per ADR 0001 — Rings, not layers.
At a glance
Section titled “At a glance”| What it is | A category of in-process enforcement (3 of them; not 5) |
| Sits | Inside the agent's process |
| Filled by | One Provider per ring, selected into a Runtime |
| Configured from | The relevant aspect(s) of the Compiled Policy |
| Distinguished from | The two cross-cutting layers (LLM Gateway, MCP Broker) which sit between processes |
The three rings
Section titled “The three rings”| Ring | Type | Governs | Failure mode caught |
|---|---|---|---|
| Ring 1 — Harness | Semantic, cooperative | What tool calls an agent attempts | Agent "helpfully" runs rm -rf in the wrong directory; agent chains an allowed tool with a dangerous parameter |
| Ring 2 — Kernel | Compulsory, coarse | What the agent process can do (FS, network, syscalls, credentials) | Compromised agent binary; exfiltration over DNS/WebSocket; credential theft via env-var dump |
| Ring 3 — Interpreter | Narrow, hard | What code the agent writes can do (codemode) | LLM writes Python that tries to shell out; unbounded memory/CPU as DoS; reading env vars from generated code |
Why "rings" and not "layers"
Section titled “Why "rings" and not "layers"”Per ADR 0001:
- Rings sit inside the agent's process; their enforcement depends on the agent's runtime cooperating (cooperative for harness; compulsory for kernel; narrow for interpreter).
- Cross-cutting layers sit between processes and are always compulsory regardless of agent runtime.
The earlier "5 flat layers" framing hid this structural distinction. Calling them all the same thing obscured the fact that one cooperates with the agent's process while the others are structurally above it.
Ring vs. Target vs. Provider
Section titled “Ring vs. Target vs. Provider”These three are commonly confused; clarification:
- A Ring is a category of enforcement (one of three: harness, kernel, interpreter).
- A Target is a specific implementation that fills out a ring on a particular platform (e.g., within the kernel ring: nono, OpenShell, gVisor, Firecracker, sandbox-exec, K8s NetworkPolicy + Gatekeeper).
- A Provider is the per-target translator (pure function
provider(compiled_policy, capabilities) → target_config) that renders the Compiled Policy as native config for one target.
Rings are the stable taxonomy. Targets are the long tail. Providers are how each target is filled.
Compiled Policy aspects each ring consumes
Section titled “Compiled Policy aspects each ring consumes”The Compiled Policy is organized by aspect (network / filesystem / tools / interpreter / budget / compliance) per ADR 0003. Each ring's Provider consumes the aspects it can act on:
| Ring | Aspects typically consumed |
|---|---|
| Harness | tools.allow / tools.deny + compliance_tags (rendered into settings.json allow/deny lists, hooks) |
| Kernel | network.* + filesystem.* + identity (rendered into Landlock rules, L7 egress, credential hiding) |
| Interpreter | interpreter.* (host functions, memory/CPU caps) + network.allow_domains (for executor network) |
The same aspect can be enforced at multiple positions — defense in depth — without duplication in the Compiled Policy.
Update model per ring
Section titled “Update model per ring”| Ring | When the Compiled Policy changes, the Provider… |
|---|---|
| Harness | Rewrites the settings file; agent reloads on next prompt |
| Kernel | Hot-reload-network where supported (OpenShell L7 proxy <100 ms); restart for FS/exec changes |
| Interpreter | Re-imported on next interpreter boot |
The host runtime supervisor handles the per-target update semantics so the user-visible promise — "policy updates apply within seconds" — holds across all rings.
Related concepts
Section titled “Related concepts”- filled by → Provider (per target)
- composed into → Runtime (recipe with one provider per ring + cross-cutting)
- applied to → Sandbox (one running agent)
- paired with → cross-cutting layers (LLM Gateway, MCP Broker) — same enforcement plane, different position class
Authoritative docs
Section titled “Authoritative docs”| Topic | File |
|---|---|
| Strategic frame | Strategy Memo v3 §06 — Pillar 1: Enforcement Plane |
| Long-form vision | governed-agents.md §9 — bypass matrix |
| Detailed taxonomy | enforcement-layers.md — rings + cross-cutting taxonomy |
| Component cards | q09-rings-and-cross-cutting/ |
| Decision | ADR 0001 — Rings, not layers |
Common confusions
Section titled “Common confusions”- Ring ≠ Layer. Rings are in-process. The "5 layers" framing conflated them with cross-cutting layers (LLM Gateway, MCP Broker), which are between processes.
- Ring ≠ Target. A ring is a category; targets fill it. Within the kernel ring there are many targets (nono, OpenShell, gVisor, …) — they don't compete; they cover different platforms.
- Ring numbering is taxonomic, not sequential. Ring 1 (Harness) is not "applied first" — at sandbox start the kernel-ring Provider applies first (you need a sandbox before you can launch the harness inside it). Numbering reflects what each ring governs (most semantic → most compulsory → most narrow), not application order.