Policy provider
Policy provider
Section titled “Policy provider”A Policy provider is a translator.
It takes the Compiled Policy (same JSON for every agent in your org) and writes the config that one specific runtime target actually understands.
Without Policy providers, the Compiled Policy is just a file. With them, it becomes actual enforcement on a real target.
Note on naming. The earlier card simply called this "Provider", which conflated the translator concept with the LLM API client concept (
gateway/anthropic.py,gateway/openai.py, …). The two are now split:
- Policy provider (this card) — translates Compiled Policy → target-specific runtime config. Pure function.
- LLM provider — HTTP client integration to one LLM API. Executes calls.
The Compiled Policy taxonomy below is unchanged — only the name is qualified.
At a glance
Section titled “At a glance”| Takes | a Compiled Policy |
| Outputs | target-specific config (Claude Code's settings.json, OpenShell's YAML, Monty's host-function spec, …) |
| Invoked by | the host runtime (tappass-host) at Sandbox start + on every Compiled Policy update |
| Contract | provider(manifest, target_capabilities) → target_config — pure function, deterministic |
What each Policy provider knows
Section titled “What each Policy provider knows”Every Policy provider speaks one tool's local language:
| Provider | Knows how to… |
|---|---|
claude-code | Write ~/.claude/settings.json with the right permissions.allow / permissions.deny / hooks from the Compiled Policy's tools and compliance_tags |
cursor | Write Cursor's config + set its OpenAI-compat base URL |
openshell | Write an OpenShell YAML profile with the network egress allowlist (from network.allow_domains), the Landlock rules (from filesystem.deny_paths), and credential hiding |
nono | Invoke nono with the right --allow / --deny flags derived from the Compiled Policy |
gvisor | Write a runsc policy + K8s pod-spec annotations |
monty | Write a Monty host-function manifest from interpreter.host_functions, with the memory and CPU caps |
anthropic-gateway (cross-cutting) | Set ANTHROPIC_BASE_URL; configure per-call budget from budget.tokens_per_day |
mcp-broker (cross-cutting) | Configure per-tool ACLs and per-server allowlists |
Each Policy provider is one well-scoped translator — typically a 2-week project.
Why this matters
Section titled “Why this matters”Customers don't all use the same tools. A fintech CISO governs Macs running Claude Code, Linux servers running CI agents, and EKS pods running production agents — all from the same Policy. The substrate stays generic; Policy providers handle the local idioms.
Adding a new ecosystem (say, n8n) ≈ adding one Policy provider. The Runtime concept, the control plane, and the Compiled Policy itself are unchanged.
The Terraform analogy: Policy providers are to TapPass what
aws/gcp/azureplug-ins are to Terraform's HCL. Pure functions. Composable. Same source-of-truth, many targets.
The contract: provider(manifest, target_capabilities) → target_config. Pure function. Deterministic. No side effects in compilation; only on apply.
The Policy-provider taxonomy is the unit of TapPass's expanding surface coverage.
The Policy-provider taxonomy (one per target across the three rings)
Section titled “The Policy-provider taxonomy (one per target across the three rings)”Harness-ring providers (semantic, cooperative)
Section titled “Harness-ring providers (semantic, cooperative)”| Provider id | Target | Native artifact |
|---|---|---|
claude-code | Claude Code IDE | managed settings.json |
codex | Codex CLI | ~/.codex/config.toml |
cursor | Cursor IDE | per-vendor config |
cline | Cline | per-vendor config |
windsurf | Windsurf | per-vendor config |
aider | Aider OSS coding agent | .aider.conf.yml |
langgraph, crewai, autogen | Framework agents | tool catalogue API |
librechat | LibreChat self-hosted | TapPass plugin |
element-bot, slack-bot, discord-bot, teams-bot | Bot frameworks | bot-SDK wrapper |
sdk-direct | Custom code via TapPass SDK | native; the canonical fallback |
Kernel-ring providers (compulsory, coarse)
Section titled “Kernel-ring providers (compulsory, coarse)”| Provider id | Target | Best for | Update model |
|---|---|---|---|
openshell | OpenShell + L7 proxy | servers, CI, K8s | hot-reload network; restart for FS/exec |
nono | nono capability sandbox (Landlock / sandbox-exec) | dev laptops | restart-only |
gvisor | gVisor user-space kernel | Cloud Run, GKE | per-pod restart |
firecracker | Firecracker microVM | AWS, Fly.io, multi-tenant edge | VM restart |
bubblewrap | Linux namespaces | Linux dev / CI | restart-only |
macos-sandbox-exec | macOS native sandbox | macOS-specific | restart-only |
windows-appcontainer | Windows AppContainer | Windows | restart-only |
k8s-netpol-gatekeeper | K8s NetworkPolicy + OPA Gatekeeper | cluster-level | live admission + runtime |
Interpreter-ring providers (narrow, hard)
Section titled “Interpreter-ring providers (narrow, hard)”| Provider id | Target | Language |
|---|---|---|
monty | Monty (Rust-based, capability-only) | Python subset |
pyodide | Pyodide (WASM) | Python full |
v8-isolates | V8 isolates (Cloudflare Workers pattern) | JavaScript / TypeScript |
wasmtime | Wasmtime + WASI | polyglot via WASM |
restricted-duckdb | DuckDB with restricted views | SQL |
Cross-cutting providers (gateway + MCP broker)
Section titled “Cross-cutting providers (gateway + MCP broker)”These are not ring providers — they sit between processes rather than inside one. Treated as separate "providers" in code organization, but architecturally cross-cutting layers, not rings.
| Provider id | Target | What it does |
|---|---|---|
llm-gateway-anthropic | Anthropic Messages API | env-var redirect; pipeline; budget |
llm-gateway-openai | OpenAI-compat (chat completions) | same |
llm-gateway-vertex | Google Vertex AI / Gemini | same (planned) |
llm-gateway-litellm | LiteLLM 100+ providers | already shipped |
mcp-broker | MCP proxy + registry | broker for every MCP connection |
The cross-cutting gateway providers translate policy into gateway behavior (budget caps, base-URL redirection, redaction rules). They are distinct from the underlying LLM provider HTTP clients that actually execute the calls.
What the Policy provider does
Section titled “What the Policy provider does”provider(manifest, target_capabilities) → target_config
A Policy provider:
- Consumes the canonical Compiled Policy (signed, versioned, JSON).
- Selects which Compiled Policy subsections apply to this target. (A harness-ring provider reads
tools+compliance_tags; a kernel-ring provider readsnetwork+filesystem+ identity scoping.) - Renders target-native config (a managed-settings.json for
claude-code; a YAML profile foropenshell; a CLI invocation fornono; a JSON manifest formonty). - Reports what it cannot enforce (the target's surface doesn't support it) so the audit row records partial coverage with rationale.
The Policy provider is a pure function: deterministic, idempotent, side-effect-free. The control plane handles distribution; the host runtime supervisor handles application.
Lifecycle
Section titled “Lifecycle”[design] Provider author maps the target's config surface to Compiled Policy fields → declares supported_layers + capabilities ↓[publish] Provider shipped as a versioned package (PyPI / built into tappass-host) ↓[register] Operator picks providers when authoring a Runtime ↓[compile] On manifest change: provider(compiled-policy) → target_config (in-process or on host) ↓[apply] Host runtime supervisor calls provider's apply path with appropriate update model (hot-reload / restart / file rewrite) ↓[evolve] Target updates → provider version bump; operators pinEngines that operate on Policy providers
Section titled “Engines that operate on Policy providers”| Engine | What it does | Status |
|---|---|---|
| Provider registry | Per-org list of installed providers + versions | concept |
| Compiler | Routes Compiled Policy through selected providers per Runtime | concept (extends policy compiler) |
| Provider SDK | Standard interface for new providers; published spec | concept (v2 priority) |
| Provider marketplace | Third-party / community providers | future (v2+) |
Surfaces
Section titled “Surfaces”| Persona | Surface | What you do |
|---|---|---|
| Operator | tappass provider list / show <id> | inspect installed providers + versions |
| Operator | tappass runtime create --providers harness=claude-code,kernel=openshell,interpreter=monty | author a Runtime by selecting providers per ring |
| Provider author | Provider SDK + spec doc | write a new Policy provider |
| Buyer / partner | Provider availability matrix | answer "can you cover my stack?" |
Related concepts
Section titled “Related concepts”- input ← Compiled Policy — the canonical IR
- composes into ↑ Runtime — recipes combining providers per ring
- enforces at → Ring — harness / kernel / interpreter (rings) + cross-cutting LLM Gateway / MCP Broker
- distinct from ↔ LLM provider — HTTP client to an LLM API
Common confusions
Section titled “Common confusions”- Policy provider ≠ LLM provider. Policy provider = translator (Compiled Policy → target config). LLM provider = HTTP client (Anthropic / OpenAI / Bedrock API). The cross-cutting gateway Policy providers configure the LLM gateway behavior, but the LLM gateway uses LLM providers underneath to execute calls.
- Policy provider ≠ Adapter. "Adapter per ecosystem" was an earlier, conflated framing. Policy providers are per target; Runtimes are per recipe. Same target reused across many runtimes.
- Policy provider ≠ MCP server. An MCP server is a tool source (something the agent calls); a Policy provider is a runtime translator (how the target is configured).
- Policy provider ≠ Ring. A ring is what kind of enforcement (harness, kernel, interpreter). A Policy provider is one implementation that fills that ring on one target.
- Policy provider is a pure function. No side effects in compilation; side effects only on
apply. This is what makes Policy providers composable, testable, and parallel-shippable.
Why this concept matters strategically
Section titled “Why this concept matters strategically”The Policy-provider taxonomy is the unit of TapPass's expanding surface coverage. Adding a new ecosystem ≈ adding a small number of Policy providers (mostly one harness provider, sometimes also a kernel provider). Each is a 2-week project; the runtime / control plane / manifest are unchanged.
This is the substrate property that makes TapPass Terraform for agent runtimes: targets multiply, the substrate stays stable.