ARF · Audit Record Foundry

Documentation &
Wild Examples

ARF is the Audit Record Foundry every example below produces a cryptographically signed, tamper-evident proof bundle. You're not just running agents; you're building a permanent record of every decision they made.

Installation

ARF requires PostgreSQL 16 with the pgvector extension for its task and provenance database. Start that first, then install the ARF binary.

# Step 1: Start the required database (Docker Compose) docker compose up -d # Starts PostgreSQL 16 + pgvector on localhost:5432 # Step 2: Install ARF from crates.io cargo install arf # Or download a pre-built binary (macOS arm64) curl -fsSL https://github.com/arf-io/arf/releases/latest/download/arf-macos-arm64 \ -o ~/.local/bin/arf && chmod +x ~/.local/bin/arf # Verify installation arf --version # arf 0.x.x (build date) # Step 3: Initialize ARF in a project arf config init # Creates .arf/config.toml in the current directory # Step 4: Apply database migrations arf migrate # Set your API keys as environment variables (or add to .arf/config.toml) export ANTHROPIC_API_KEY=sk-ant-... export OPENAI_API_KEY=sk-... # ARF injects these into outbound requests; never logged or written to disk

ARF requires: Rust 1.78+, Docker (for PostgreSQL), git 2.40+. Supports macOS 13+ and Linux (kernel 5.15+). Windows support is planned.

Your First Governance Policy

ARF generates a default config on arf config init. The main config lives at .arf/config.toml. Customize it:

# .arf/config.toml [routing] default_runner = "claude" # claude | codex | gemini | antigravity default_engine = "anthropic" # anthropic | openai | gemini | ollama [governance] require_approval_for_tools = ["Write", "Bash"] blocked_commands = ["rm -rf", "curl * | sh"] blocked_paths = ["/etc", "~/.ssh"] [governance.sandbox] default_level = "sandbox" # jailed | sandbox | workspace | full project_dir = "." [circuit_breakers] consecutive_failures = 3 error_rate_threshold = 0.15 cooldown_seconds = 60 # Validate config before starting arf config validate # ✓ .arf/config.toml: config valid

Your First Governed Session

# Start the ARF proxy (runs in the background) arf start # Proxy listening on localhost:4554 # Launch the TUI to monitor (separate command) arf tui # In another terminal -- point your CLI at ARF and go export ANTHROPIC_BASE_URL=http://localhost:4554 claude . # Check governance event log arf audit --last 10 # {"event_type":"runner_invoked","detail":{"engine":"claude","prompt_tokens":1024}} # Export the proof bundle when done arf provenance export --format json --out .arf/bundle.json # Verify bundle integrity arf provenance verify

Wild Example 1: Approve Reads, Block Network

Auto-approve all read operations. Require human sign-off on any network call. Block writes to files outside the src/ directory.

[governance] # Read operations are auto-approved; writes and shell require sign-off require_approval_for_tools = ["Write", "Bash"] # Block any command that touches external network resources blocked_commands = ["curl", "wget", "fetch", "axios"] blocked_paths = [".env", "config/production"] [governance.sandbox] default_level = "workspace" # agent confined to project dir project_dir = "."

The result: the agent can freely read and explore the codebase, but every write and shell command requires human approval, and any attempt to touch production config or .env files is blocked at the filesystem level. The approval decisions are visible in the proof chain.

Wild Example 2: 12 Agents in Parallel, Merge Only Passing Ones

Decompose a large refactor into 12 subtasks, run them in parallel using isolated git worktrees, and merge only branches that pass quality gates.

# Decompose the task and fan out to 12 parallel agents arf launch "Migrate the entire codebase from callbacks to async/await" \ --parallel 12 \ --worktree \ --profile standard # Each subtask runs in its own git worktree. # Conflict resolution: auto for clean merges, HITL for conflicts. # Watch progress in the TUI (separate terminal): arf tui # After merge, export the full multi-agent proof bundle arf provenance export --format json --out migration-proof.json

Wild Example 3: Dead Man's Switch

If no human interaction is detected for 4 hours, ARF automatically trips the circuit breakers. Useful for long-running autonomous sessions where you want a guaranteed check-in.

[circuit_breakers] # 4-hour dead man's switch idle_trip_seconds = 14400 # What counts as "human interaction": # - Any approval event in the TUI [y]/[n] # - Any manual TUI keypress # - arf governance reset stall (from any terminal) [circuit_breakers.trip_action] # When dead man's switch trips: action = "open_all" # open all breakers notify_webhook = "https://hooks.slack.com/..." seal_on_trip = false # keep session open for recovery

Wild Example 4: Fully Auditable AI-Assisted Code Review Pipeline

Run three agents in sequence: Producer writes code in an isolated worktree, Reviewer audits it, Archivist exports the proof. Every decision is in the provenance chain.

# Step 1: Producer writes the code (isolated worktree) arf launch "Implement rate limiting for the auth endpoints" \ --engine anthropic \ --worktree # Creates a git worktree, runs the agent, builds proof chain # Step 2: Reviewer audits the changes arf launch "Review the rate limiting implementation for security issues" \ --engine anthropic # Step 3: Export a full proof bundle for the review arf provenance export --format json --out code-review-proof.json # Every decision, every approval, every model response -- one bundle # Verify the bundle is intact and the chain is unbroken arf provenance verify # ✓ provenance chain valid (n entries, Ed25519 signatures intact) # Check governance grades for the session arf governance grade

Wild Example 5: Route by Task Type -- Claude for Architecture, Ollama for Boilerplate

Expensive creative work goes to Claude. Mechanical transforms -- boilerplate, format conversion, test generation from spec -- route to a local Ollama model for free.

# .arf/config.toml -- configure named engine aliases [providers.ollama] type = "chat_completions" base_url = "http://localhost:11434" models = ["qwen2.5:72b", "llama3.3:70b"] [routes.aliases] # Aliases let runners select engines by model name "claude-arch" = { backend = "anthropic", model = "claude-opus-4-7" } "local-fast" = { backend = "ollama", model = "qwen2.5:72b" } # Launch architecture work at Claude, boilerplate at Ollama arf launch "Design the new caching layer architecture" --engine claude-arch arf launch "Generate CRUD boilerplate for User, Post, Comment models" --engine local-fast # Free. Runs offline. No data leaves the machine.

Wild Example 6: Air-Gapped Session -- Zero Cloud API Calls

Run an entire agent session with no network access to cloud APIs. Everything stays local. Still fully governed, still fully audited.

# .arf/config.toml -- route everything to a local Ollama instance [providers.ollama] type = "chat_completions" base_url = "http://127.0.0.1:11434" models = ["qwen2.5:72b"] [routing] default_engine = "ollama" default_model = "qwen2.5:72b" [governance] blocked_paths = ["/etc"] # No ANTHROPIC_API_KEY or OPENAI_API_KEY required # All inference stays on 127.0.0.1 -- nothing reaches the internet

Configuration Reference

Config is discovered and merged in order: compiled defaults, then ~/.config/arf/config.toml, then .arf/config.toml in the project directory. Pass --config <path> to arf start to bypass auto-discovery and use only the specified file.

Engine vs. backend: engine is the user-facing term — it's what you pass to arf launch --engine and set in [routing] default_engine. backend is the config term used inside [routes.aliases] and [routes.default.*] to name the actual destination provider. Both refer to the same set of providers (anthropic, openai, ollama, etc.) but in different contexts.

[proxy]

[routing]

[routes.default.<facade>] and [routes.aliases]

Routes map incoming facades (the protocol a runner speaks) to a backend + model pair.

# When Claude Code connects (anthropic facade), route it to OpenAI [routes.default.anthropic] backend = "openai" model = "gpt-4.1" # Named aliases: use as model name in the runner to select a backend # e.g.: OPENAI_BASE_URL=http://localhost:4554 codex --model claude-heavy "prompt" [routes.aliases] "claude-heavy" = { backend = "anthropic", model = "claude-opus-4-7" } "local" = { backend = "ollama", model = "qwen2.5:72b" }

[providers.<name>]

Add additional backends (OAI-compatible endpoints, self-hosted, OpenRouter, etc.). The provider key becomes the backend name in routes and --engine.

[providers.ollama] type = "chat_completions" base_url = "http://localhost:11434" [providers.openrouter] type = "chat_completions" base_url = "https://openrouter.ai/api" api_key_env = "OPENROUTER_API_KEY"

[governance]

[governance.sandbox]

[circuit_breakers]

[task_db]

[[governance.rules]] — Rule Language

Custom rules live in .arf/governance/rules.toml. A rule with the same name as a built-in replaces it; new names extend the rule set.

[[governance.rules]] name = "no-prod-writes" # unique rule identifier description = "Block writes to production config" severity = "block" # block | warn | rewrite | modify trigger = "request" # request | stream_text_match match_patterns = [ "config/production/", "(?i)\\.env\\.prod", ] owasp_risks = ["1", "6"] # OWASP Top 10 risk tags (optional) # Rewrite: replace matched text in streamed output [[governance.rules]] name = "redact-tokens" severity = "rewrite" trigger = "stream_text_match" match_patterns = ["ghp_[A-Za-z0-9]{36,}"] replacement = "[REDACTED]" # Modify: clamp a model parameter to a safe value [[governance.rules]] name = "clamp-temperature" severity = "modify" trigger = "request" condition = "temperature > 1.0" modification = "clamp_temperature(1.0)" message = "Temperature clamped to 1.0"

Severity values: block — reject the request outright. warn — log and continue. rewrite — mutate streamed output (requires replacement). modify — patch request parameters (requires condition and modification).

Trigger values: request — evaluated on the inbound request body. stream_text_match — evaluated on each streamed text chunk from the model.

Run arf governance rules to list all active rules. Run arf config validate to verify your rules file before starting.

Keyboard Shortcuts Reference

See the full Terminal UI page for keyboard shortcuts. Quick reference:

Frequently Asked Questions

Yes. ARF itself requires no internet access. Configure any OAI-compatible local inference server — Ollama, DeepSeek, Qwen, llama.cpp — as your engine, set an empty network allowlist, and run entirely offline. Governance, auditing, and the TUI all function identically.
ARF reads API keys from environment variables (ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.) and injects them just-in-time into outbound requests. The keys are never written to disk in plaintext and never visible in the TUI or logs. The vault subsystem (arf vault) manages session-scoped secrets that agents can check out and return during a task -- separate from your own API keys.
With OS-level isolation enabled (Agent Relay Fence), no. The agent process is in a network namespace that routes all traffic through the ARF proxy. There's no other route to the internet. Without OS isolation, a sufficiently adversarial agent could potentially use a hard-coded IP that bypasses DNS which is why the Agent Relay Fence and network policy enforcement exist.
It depends on message sizes. A typical 4-hour session with 200 messages produces a compressed bundle of 2–8MB. The bundle contains all message content, so size scales with how much text the agents exchanged. Bundles are compressed with zstd.
ARF's architecture, threat model, and reference policies are documented at github.com/arf-io/arf and in this site's documentation. If you want to understand how a particular guarantee is enforced, the code paths and rule files are linked from the reference section above.
Yes. arf start runs headless by default -- it backgrounds the proxy without opening a TUI. In CI, set your governance policy to auto-approve the actions the agent needs, then use arf launch <PROMPT> to drive the agent. Use arf provenance export at the end of the job to capture the full proof bundle as a build artifact.