Architecture
System layers
Section titled “System layers”┌──────────────────────────────────────────────────────────┐│ AGENT SANDBOX (optional) ││ Linux user/network/mount/PID/UTS/IPC/cgroup namespaces ││ - Empty network stack ││ - HTTPS proxy for LLM APIs (allowed hosts only) ││ - Gate UDS for protected actions ││ - Workspace mount (single RW dir) ││ latchgate-sandbox crate · Linux ≥ 5.8 only │└────────────────────────┬─────────────────────────────────┘ │Agent Runtime / IDE / Orchestrator / MCP Host │ │ northbound call ▼┌──────────────────────────────────────────────────────────┐│ NORTHBOUND INTERFACES ││ - MCP adapter (optional) ││ - REST Action + Approval API ││ - thin SDKs / operator CLI / TUI │└─────────────────────────┬────────────────────────────────┘ │ ▼┌──────────────────────────────────────────────────────────┐│ LATCHGATE KERNEL ││ ││ Auth + Registry ││ 1. Drain guard ││ 2. Lease validation + DPoP sender binding + replay ││ 3. Registry lookup (ActionSpec by action_id) ││ 4. Trust / digest verification ││ 5. Input schema validation ││ 6. Canonicalization + request_hash (JCS RFC 8785) ││ ││ Domain + Policy + Approval ││ 7. Domain pre-check (optimization — early reject) ││ 8. Budget snapshot + OPA/Rego evaluation ││ 9. Pending approval hold (if policy requires) ││ ││ Pre-dispatch ││ 10. Atomic budget debit (Redis Lua) ││ 11. ExecutionGrant construction + Ed25519 signing ││ 12. Secret resolution + template expansion ││ ││ Shared execution tail (execute_authorized_plan) ││ 13. Grant validity + signature verification ││ 14. ExecutionIntent write (pre-dispatch evidence) ││ 15. WASM provider dispatch (fresh instance per call) ││ 16. Response schema validation ││ 17. Effect verification ││ 18. ExecutionReceipt hashing + Ed25519 signing ││ 19. Evidence finalization (receipt + audit, single txn) │└────────┬───────────────────────────────────────┬─────────┘ │ │ ▼ ▼┌─────────────────────┐ ┌──────────────────────────┐│ WASM SANDBOX │ imports │ HOST I/O LAYER ││ │────────>│ ││ Provider .wasm │ │ Sink validation ││ module executes │<────────│ Credential injection ││ in wasmtime │ returns │ SSRF protection ││ │ │ DNS pinning ││ - no filesystem │ │ Timeout enforcement ││ - no network │ │ ││ - no syscalls │ │ Clients: ││ - no secrets │ │ - HTTP (reqwest) ││ - fuel metered │ │ - SMTP (lettre) ││ - memory capped │ │ - SQL (sqlx) ││ - epoch deadline │ │ - Queue (lapin) ││ │ │ - Storage (object_store)│└─────────────────────┘ └───────────┬──────────────┘ │ ▼ External systems / side effectsThe execution tail — grant re-validation through evidence finalization — is shared: both the auto-allow path and the human-approved path converge into a single function (execute_authorized_plan). There is exactly one code path that dispatches a WASM provider. A bug that bypasses a check in one path cannot selectively affect either origin.
The agent sandbox (top of diagram) is an optional containment layer that wraps the agent process itself. When active, the agent runtime runs inside Linux namespaces with no host filesystem access, no host network, and no inherited credentials. The only paths out are the gate UDS and the HTTPS proxy. See Agent Sandbox.
Crate layout
Section titled “Crate layout”| Crate | Responsibility |
|---|---|
latchgate-core | Shared types: ActionSpec, ExecutionGrant, ExecutionReceipt, canonical hashing, signing, approval plan, filesystem path evaluation, security constants |
latchgate-crypto | Cryptographic primitives: Ed25519 signing, SHA-256, JWK thumbprints, constant-time comparison |
latchgate-config | Configuration loading, TOML parsing, env var overrides, production validation, path resolution |
latchgate-auth | Lease issuance, DPoP verification, identity providers (peercred / none), replay protection, operator auth |
latchgate-registry | Action registry, manifest loading, digest verification, schema validators |
latchgate-policy | OPA client, embedded Rego evaluator (regorus), policy input/output types |
latchgate-state | Approval stores (in-memory, Redis, SQLite), budget tracking (Redis Lua), session state |
latchgate-kernel | Execution pipeline: orchestrates all steps from request to receipt; owns execute_authorized_plan |
latchgate-providers | WASM runtime (wasmtime), host I/O layer, sink validation, SSRF protection, secrets manager |
latchgate-ledger | SQLite evidence ledger, receipt signing, integrity chain, JSONL export, intent tracking, learned domains, learned paths |
latchgate-api | HTTP server (axum), client + admin routers, health/readiness probes, rate limiting |
latchgate-webhooks | Outbound webhook notifications: HMAC signing, SSRF protection, outbox delivery with retry |
latchgate-mcp | MCP adapter binary (latchgate-mcp) for exposing actions as MCP tools to IDE agents |
latchgate-sandbox | Linux namespace sandbox: user/network/mount/PID isolation, HTTPS CONNECT proxy, workspace mounts |
latchgate-cli | Operator CLI and TUI: approvals, audit, status, revoke, config, ledger, doctor, sandbox, presets, paths, domains, completions, uninstall |
latchgate-client | Rust client library for programmatic gate access |
latchgate-embed | Compile-time embedded assets and egress sync: manifests, policies, presets, providers |
latchgate-bin | Binary entry point; dispatches to CLI commands |
Boundary rules
Section titled “Boundary rules”corehas no provider or API dependencieskerneldepends on traits, not concrete transportsprovidershost I/O never callspolicydirectlyapidoes not contain business decisions- Provider
.wasmmodules never import kernel internals — onlylatchgate:io/* - Secrets never cross the WASM boundary
- There is exactly one function that dispatches WASM providers (
execute_authorized_plan) sandboxhas no dependency on the kernel — it is a launcher, not a pipeline participantembedis a compile-time-only crate for embedded assets (manifests, policies, presets, providers)
Security invariants
Section titled “Security invariants”These define the architecture. If any invariant is violated, the system is broken.
SI-1 Complete mediation. Every protected action passes through the kernel. No protected side effect bypasses the kernel.
SI-2 Fail closed. If identity, policy, registry, secret release, provider dispatch, or verification fails, the action is denied. No silent fallback to permissive behavior. 503 responses still mean DENY.
SI-3 Sender-bound identity. A stolen token alone is not enough. Every execution path is bound to a caller-controlled key via DPoP (RFC 9449).
SI-4 Body-bound integrity. The exact request body is canonically hashed (JCS RFC 8785) and bound into the authorization path.
SI-5 Immutable approval plan. Human approval binds the exact execution plan via plan_hash and approval_hash. The approval path executes the stored plan, never re-derives from the current manifest or registry state. Approval consumption is atomic and one-shot.
SI-6 Shared execution tail. The auto-allow path and the approved path converge into a single kernel function before any side effect. They cannot diverge at dispatch, verification, or evidence.
SI-7 Provider isolation. Providers execute in WASM sandbox with linear memory isolation. Each execution creates a fresh instance. Fuel, memory, I/O budget, and wall-clock deadline are enforced per execution.
SI-8 Host-mediated I/O. Providers communicate with external systems only through host-implemented import functions. The kernel validates sinks, injects credentials, and enforces egress policy at the host layer.
SI-9 Default-deny egress. Providers have no direct network access. All I/O goes through host imports which enforce allowlists from the grant.
SI-10 Least-privilege secret release. Secrets are injected by the host I/O layer at execution time. Secrets never enter the WASM sandbox. Only secrets declared in the action manifest AND approved by the policy decision are injected.
SI-11 Capability-gated imports. Only I/O imports declared in the action manifest are linked to the WASM instance. Runtime check (check_import_allowed) is a second layer of defense beyond linker-level gating.
SI-12 Verified outcomes. For high-risk effects, success is not declared from request acceptance alone. Verification or explicit unverifiable classification is required. Verified is never attached without an actual verification step.
SI-13 Pre-dispatch evidence. Every dispatch writes an ExecutionIntent to durable storage before the WASM provider runs. If the process crashes post-dispatch, operators can detect intents without matching receipts.
SI-14 Tamper-evident evidence. Receipts and events are append-only and chained (prev_hash) for integrity. Receipt signing key rotation preserves verifiability via a historical verifying key store.
SI-15 Grant integrity. Every grant is Ed25519-signed immediately after construction and verified before dispatch. Separate signing key from receipt signing (defense-in-depth). Any field mutation between construction and dispatch is detectable.
SI-16 Production fail-fast. The gate refuses to start in non-dev mode with insecure defaults: IdentityProvider::None, allow_unmapped = true, shared operator keys, ephemeral signing keys, response_schema_enforcement = warn, or missing JWKS path.
Dependencies
Section titled “Dependencies”| Component | Purpose | Mode | Failure mode |
|---|---|---|---|
| SQLite | Evidence ledger, learned domains, learned paths | Always | Fail closed for protected actions; success gated on receipt write |
| SQLite (state) | Budgets, approvals (embedded mode) | Embedded (default) | Fail closed (deny) |
| In-memory DashMap | Replay cache (embedded mode, bounded 100k entries) | Embedded (default) | Fail closed (deny) |
| Redis | Replay cache, budget atomics, approval state, revocation epoch | --infra / custom | Fail closed (deny) |
| Embedded regorus | Rego policy evaluation (in-process) | Embedded (default) | Fail closed (deny) |
| OPA | Policy evaluation (external HTTP) | --infra / custom | Fail closed (deny, with 503 to signal transient) |
Squid (with proxy_allowlist actions) | Defense-in-depth egress proxy | Optional | Fail closed (deny) |
| SOPS binary | Secret decryption | When configured | Required when sops_secrets_file is set; absence fails doctor |
In embedded mode (the default for latchgate up), no external services are required. Redis and OPA are used when configured via --infra, --with-redis, --with-opa, or explicit TOML settings.
Redis should have persistence enabled when used in production (appendonly yes). Without it, replay cache and budget counters reset on restart — the replay window is short-lived (180s default) so this is low-risk, but budget accounting will be inaccurate.
For the full threat model and trust boundaries, see Security Model. For the execution pipeline and key artifacts, see Core Concepts.