Skip to content

Roadmap and status

Early, but traffic flows and TLS is intercepted. Policy evaluates the real decrypted request, not just the tunnel destination, and each request inside a connection is judged and audited separately.

MilestoneContentsState
M0Workspace, core traits, config load + validate, CIdone
M1Explicit proxy (CONNECT + SOCKS5), chain runner, denylist + allowlist, upstream guard, auditdone
M2TLS MITM, streaming (WebSocket / SSE / chunked)done
M3Secret injection, egress DLP, CEL rules layerdone
M4Identity resolution, profiles, marshal rundone
M4.5LLM judge layerdone
M5MCP tool-level policydone
M6Transparent capture and DNS resolverdone, later partially reverted¹
M7Management API, hot reload, warn mode, metricsdone²
M8OAuth2 credential acquisitiondone³
M9LLM model routing, OpenAI/Anthropic translation and native decision APIsdone

¹ Transparent (nftables REDIRECT) capture was removed after M6 — see Removed below. The DNS resolver remains; its direct HTTP/TLS ingress limitation is listed below.

² OpenTelemetry export is not implemented — see below.

³ Complete: client_credentials, refresh_token, jwt_bearer, authorization_code (with PKCE) and device_code, the last two enrolled via marshal secrets oauth login; client_secret_basic/_post, private_key_jwt and public clients; and two capture mechanisms with deliberately different threat models — capture: in_band, which owns the PKCE verifier so an untrusted agent cannot redeem its own code (ADR-0032), and oauth login --wait/--run, which learns a credential whose OAuth application marshal does not control by observing a real login (ADR-0034).

Transparent (nftables REDIRECT) capture. Shipped in M6, removed afterward: it derived the policy hostname from TLS SNI or the HTTP Host header but never verified the redirected destination actually belonged to it, and it byte-relayed the connection rather than intercepting, so rules/dlp/mcp/judge and every transform never ran on that traffic — the same gap interception being mandatory exists to close for explicit traffic. See ADR-0022.

Losing it also broke listener_port identity, which depended on transparent’s multi-listener mechanism to bind more than one port. That resolver now works again through a different, simpler path: listeners.explicit.listen accepts a list of addresses, each running the full policy pipeline (not a raw relay) — see Identity and ADR-0023.

Workloads must use the explicit proxy protocol. DNS answers do not supply a replacement HTTP/TLS ingress for clients that cannot use a proxy.

OpenTelemetry export. The audit log is already structured JSON carrying the full layer trail, identity attribution, status and timing, and /v1/metrics covers scraping. OTLP would add correlation with an agent’s own traces, which is genuinely useful — but it is a large dependency tree for something a log shipper largely covers, so it is left as a deliberate decision rather than assumed.

An interactive approval decider. The Defer verdict and the Decider trait exist and the chain resolves them; the only implementation refuses. A human-in-the-loop approval flow plugs in without touching the chain.

Rate limits and budgets. Per-identity counters exist and are exported, which is the groundwork; enforcement does not.

Response body transforms — redact, summarize, compact. Declared as config shapes since M3 (they determine whether a response can stream, which the rest of the design has to respect) but never implemented. A profile naming one fails to start rather than serving a response that was supposed to be rewritten, unrewritten. The shipped coding-agent profile declares redact and therefore remains a reference example that cannot start as written, even with its judge API credential. Use the minimal getting-started configuration for a runnable example. Log/audit credential redaction is implemented independently of response-body redaction.

Rego rules via regorus. The rules layer is CEL only. Rego is designed for as an opt-in for anyone already running OPA policy.

DLP response scanning. scan_response exists in the schema but is not wired into the runtime. Request header/query scanning and optional request-body scanning are implemented.

Direct HTTP/TLS ingress after DNS resolution. The DNS server supplies proxy addresses, static records and passthrough answers, but there is no direct origin-HTTP/TLS listener that intercepts ordinary clients sent to those addresses. DNS alone is not a complete capture path; use an explicit proxy. See Capture.

Already-enrolled authorization-code credentials are supported: the builder checks the stored grant and permits omitting authorization_endpoint and redirect_uri. Consequently that configuration’s validation depends on the machine’s credential state; keep the endpoint fields for a portable configuration, or validate bootstrap output on its enrolled host.

marshal-core holds the traits and types and depends on no other crate in the workspace; everything else builds on it. That keeps the boundaries honest and the policy chain testable without a network.

crate
marshal-coretypes and traits — verdicts, policy layers, transforms, identities. No I/O.
marshal-configlayered YAML load, the profiles//bundles//transforms/ convention, the env file, validation
marshal-tlsCA load/generate, leaf minting, cache, rustls configs
marshal-policychain runner and the denylist, allowlist, rules, dlp, mcp layers
marshal-secretsenv/file/oauth2 sources, TTL cache, token store, in-band and bootstrap capture, injection and redaction
marshal-judgethe LLM judge layer: providers, structured verdicts, cache, breaker
marshal-llmmodel-table routing, OpenAI/Anthropic JSON and SSE translation, and native System One decision routing
marshal-launchmarshal run: netns and cgroup isolation, identity registration
marshal-httpthe upstream guard, and the one-shot client for calls marshal makes as itself
marshal-proxylisteners, CONNECT, SOCKS5, MITM, streaming
marshal-dnshickory authority: resolve-to-proxy, passthrough, static records
marshal-auditJSON records, tracing layer
marshal-clithe marshal binary

Native System One decisions are supported as judge providers (system_one and decisions_api) and as agent model routes. DecisionsApi is an independent service; an official OpenAI decision adapter awaits a published contract. See Decision APIs.