System overview
Design decisions
Fail-open by default
If Rampart crashes or is unreachable, tool calls pass through. This is deliberate — fail-closed locks you out of your own machine. See the threat model for trade-offs and mitigations.Custom YAML over OPA/Rego
The domain is narrow — “should this tool call run?” — and doesn’t need a general-purpose policy language. Three lines of YAML beats fifteen lines of Rego. The custom engine also evaluates in less than 10μs vs OPA’s 0.1-1ms.Local-first
No data leaves the machine. No cloud dependency. No telemetry. You’re adding a security layer, not another SaaS.Deny-wins evaluation
If any policy says deny, the call is denied. No ambiguity, no override. Within a priority level, first match wins.Components
Policy engine
Location:internal/engine/
Loads YAML policies, evaluates tool calls. The hot path.
Evaluation order:
- Collect all policies whose
matchclause fits the tool call - Within each policy, rules evaluate top-to-bottom (first match wins)
- Across policies: any
deny→ denied. No deny + anylog→ logged. Onlyallow→ allowed - Nothing matches → configurable default action
Policies hot-reload via fsnotify. Edit the YAML, Rampart picks it up.
Interceptors
Location:internal/intercept/
Per-tool-type logic that normalizes parameters before they hit the engine:
- exec — command pattern matching, binary extraction
- read/write — path normalization, glob matching
- fetch — URL parsing, domain extraction
Audit sink
Location:internal/audit/
Append-only JSONL with hash chaining. Each event includes SHA-256 of the previous event’s hash — tamper with any record and the chain breaks.
- ULID event IDs (time-ordered, sortable)
- External anchor every 100 events (prevents full-chain recomputation)
- fsync on every write
- Log rotation with chain continuity across files
Proxy server
Location:internal/proxy/
HTTP server that accepts tool calls, evaluates them, and returns decisions. Bearer token auth, localhost-only by default.
| Endpoint | Purpose |
|---|---|
POST /v1/tool/{name} | Evaluate and execute |
POST /v1/preflight/{name} | Dry-run check |
GET /v1/approvals | Pending approvals |
POST /v1/approvals/{id}/resolve | Approve/deny |
GET /healthz | Health check |
Approval store
Location:internal/approval/
Thread-safe store for require_approval decisions. ULID-keyed, configurable timeouts. The proxy blocks the request until a human resolves it or it times out.
Wrap command
Location:cmd/rampart/cli/wrap.go
rampart wrap -- <command> starts an embedded proxy, generates a shell shim, sets $SHELL to the shim, and execs the child process. Every shell command the child spawns goes through the shim, which checks the preflight API before executing. The agent doesn’t need modification.
Daemon
Location:internal/daemon/
WebSocket client that connects to an OpenClaw gateway. Receives exec.approval.requested events, evaluates them against policies, and sends allow-once or deny resolutions. Useful when OpenClaw’s approval system is the enforcement point.
Integration patterns
rampart wrap
Wrap any process. No code changes, no config beyond a policy file. The shell shim intercepts commands transparently.Best for: Claude Code, Codex, standalone scripts
HTTP proxy
Point your agent’s tool calls atlocalhost:9090. Framework-agnostic.
Best for: custom agents, Python scripts, anything that makes HTTP calls
OpenClaw daemon
Connects via WebSocket, auto-resolves exec approvals.Best for: OpenClaw deployments where the approval system is already in use
SDK
Location:pkg/sdk/
Embed the engine directly in Go code. Zero network overhead, nanosecond evaluation.
Best for: Go agents, performance-critical paths
Policy profiles
Built-in profiles (standard, paranoid, yolo) provide ready-to-use policy sets for common use cases. Profiles include platform-specific policies where relevant — in v0.4.4, 17 macOS hardening policies were added covering Keychain access, Gatekeeper bypass, persistence mechanisms, user management, and osascript (AppleScript shell execution).
Project layout
Known limitations
Pattern matching has gaps
Common evasion techniques (shell wrappers likebash -c, quoted binaries, escaped characters) are handled via normalization and command_contains substring matching. However, novel obfuscation (find / -delete, variable expansion, encoded payloads) can bypass static patterns.
Combine with semantic verification for intent-based classification.
Proxy mode is voluntary
A compromised agent could bypasslocalhost:9090 by making direct calls. rampart wrap is harder to bypass (it controls $SHELL), but not impossible.