Skip to content

ADR 0003 — Manifest organized by aspect, not by ring

ADR 0003 — Manifest organized by aspect, not by ring

Section titled “ADR 0003 — Manifest organized by aspect, not by ring”

Date: 2026-05-07 Status: Accepted Strategic frame: TapPass Strategy Memo v3 §07 (Pillar 2: Control Plane — Compiled Policy example)


Earlier drafts described the canonical IR (then called the Keyring) as "5-layer" — one slice per enforcement position (gateway / mcp / codemode / harness / kernel), each with its own config block.

The strategy memo's example Manifest is organized by aspect (network / filesystem / tools / interpreter / budget / compliance), not by ring.

The two organizations are subtly different but the consequences are large. Specifically:

  • The same content (e.g. tools.deny: ["Bash(curl:*)"]) gets enforced at multiple positions depending on which providers are selected.
    • Harness provider (Claude Code) honors it via settings.json allow/deny.
    • MCP broker honors it per-call.
    • Kernel provider can backstop it via egress allowlist (curl HTTPS would fail anyway).
  • A "per-ring slice" structure forced operators to think "which ring should this rule sit in?" — an artificial choice. The real answer is "the rule applies wherever a provider can enforce it."

The canonical Manifest carries content by aspect:

AspectExample fields
identitysandbox_id, runtime_id, policy_version, signing metadata
networkallow_domains, deny_categories
filesystemworkspace, read_only, deny_paths
toolsallow, deny
interpreterhost_functions, memory_mb, cpu_time_ms
budgettokens_per_day, dollars_per_month, tool_calls_per_minute
compliance_tagsSOC2, ISO42001, EU AI Act, …

Providers per target select which aspects they consume and how to render them. Same aspect → multiple rings (defense in depth).


  • Manifest is shorter and more uniform than a per-ring slice structure.
  • Cleaner separation between what to enforce (compiled-policy) and where to enforce (provider selection).
  • Coverage is computed by intersecting Manifest aspects × runtime providers. This is what produces the Compatibility Matrix.
  • Defense in depth becomes structural. The same tools.deny aspect lands at harness ring (cooperative) AND MCP broker (compulsory) — not because we bolted on duplication, but because two providers chose to consume it.
  • "Keyring" becomes operational alias. The formal name is Manifest (Terraform-aligned). "Keyring" persists in: file path on disk (keyring.json), SDK class name (Keyring), historical conversations.

Per-ring slices (the rejected previous framing)

Section titled “Per-ring slices (the rejected previous framing)”

Rejected because:

  • The same content is enforced at multiple rings (e.g. tools at harness + MCP broker), forcing duplication in the manifest.
  • Operator authoring becomes weird: "which ring should this rule live in?" — there's often no single right answer.
  • Coverage analysis is harder when the IR is split into ring-shaped buckets.

Rejected as adding cognitive overhead without solving the duplication problem. Pure "by aspect" is cleaner.

"Plain key-value manifest" (no nesting at all)

Section titled “"Plain key-value manifest" (no nesting at all)”

Rejected as too unstructured. The aspect grouping is meaningful (every authoring/UI surface naturally groups around it).


FileActionStatus
concept-cards/keyring.mdReframe as Manifest with content by aspect✅ done 2026-05-07
components/q09-rings-and-cross-cutting/Pointer cards re-framed: Compiled Policy aspects → per-position rendering. Full per-target provider component split is post-MCS.✅ done 2026-05-08
architecture/strategic/governed-agents.md §10Reframe Keyring section to use aspect-organized Compiled Policy example✅ done 2026-05-08