FrankClaw
#FrankClaw
A security-hardened personal AI assistant gateway written in Rust. Connects messaging channels to AI model providers through a local WebSocket control plane.
FrankClaw is a ground-up Rust rewrite of OpenClaw, achieving functional parity with the core feature set while providing stronger security guarantees through Rust's memory safety, encryption at rest, stricter input validation, and defense-in-depth hardening at every layer.
What's at parity:
- 7 messaging channels: Web, Telegram, Discord, Slack, Signal, WhatsApp, Email (IMAP/SMTP)
- Multi-provider AI with model-aware failover routing, circuit breaker, retry with exponential backoff
- Full agent runtime: context compaction, subagent orchestration, command system, skills, hooks
- Smart model routing: 13-dimension complexity scorer routes simple queries to cheaper models
- MCP (Model Context Protocol) client: stdio and HTTP transports for tool ecosystem integration
- Response caching: SHA-256 keyed LRU cache with TTL
- Cost tracking with daily budget guards
- Credential leak detection (12 patterns scanned in all LLM/tool output)
- Extended thinking support for Claude 3.7+ and o1-style models
- Multi-provider media understanding: OpenAI, Anthropic, Ollama vision + Whisper transcription with fallback chain
- Memory/RAG: SQLite FTS5 + vector search with embedding providers, file sync
- Rich 8-tab web console: dark mode, tool approval UI, usage analytics, agent management, cron jobs, logs viewer, focus mode
- Webhook transforms: JSON path extraction, templates, per-mapping rate limiting and concurrency control
- Canvas host with revision conflict detection, SVG/HTML/Markdown rendering in web console
- OpenAI-compatible API (
/v1/chat/completions,/v1/models) for drop-in client support - Browser automation (CDP-based, 11 tools including screenshot and ARIA snapshot)
- Bash tool with allowlist + sandbox (ai-jail)
- 3-tier tool risk levels (ReadOnly → Mutating → Destructive) with per-tool approval overrides and inline approval UI
- Tunnel support: Cloudflare Tunnel, ngrok, and custom commands for webhook exposure
- Job state machine with self-repair for background tasks
- Event-driven routine triggers (cron, message pattern, system events, manual)
- Interactive REPL (
frankclaw chat) with streaming, slash commands, and tab completion - Full-screen TUI (
frankclaw chat --tui) with ratatui: streaming chat log, slash commands, model/session status - ACP (Agent Client Protocol): JSON-RPC 2.0 over NDJSON for agent interop (
frankclaw acp) - Plugin management: manifest-based discovery, enable/disable lifecycle (
frankclaw plugin) - Browser profiles: named CDP configurations with port allocation (18800-18899)
- Batch embedding providers: Gemini (768D) and Voyage AI (1024D) with 100-text batching
- Rich markdown rendering: CommonMark → IR → ANSI terminal output
- Operator experience: setup wizard, doctor diagnostics, security audit, daemon management
What's intentionally skipped (low value or over-engineered):
- TTS, polls, WhatsApp Web (Baileys), Gmail Pub/Sub, auto-update
- 17 long-tail channels (Google Chat, iMessage, IRC, Teams, Matrix, etc.) — can be added via the plugin trait
For full details, see PARITY_TODO.md and FEATURE_PLANS.md.
For channel setup, see CHANNEL_SETUP.md, examples/channels/, or frankclaw config-example --channel <name>.
#Features
- Multi-channel messaging — Web, Telegram, Discord, Slack, Signal, WhatsApp, Email (IMAP/SMTP)
- Multi-provider AI — OpenAI, Anthropic, Ollama, GitHub Copilot, Google Gemini, OpenRouter, Groq, Together, DeepSeek with model-aware failover routing, circuit breaker, and retry with exponential backoff + jitter
- Smart model routing — 13-dimension complexity scorer routes simple queries to cheaper/faster models, saving cost without sacrificing quality
- MCP integration — Model Context Protocol client (stdio + HTTP transports) connects any MCP server as a tool source
- Response caching — SHA-256 keyed LRU cache with configurable TTL avoids redundant API calls
- Cost tracking — Per-model token cost tables with configurable daily budget guards (warn at 80%, block at 100%)
- Credential leak detection — 12 regex patterns scan all LLM and tool output for accidentally exposed API keys, tokens, and secrets
- Extended thinking — Supports Claude 3.7+ and o1-style extended reasoning with configurable thinking budget
- Encrypted sessions — SQLite-backed with ChaCha20-Poly1305 encryption at rest
- Scheduled jobs — Cron, event triggers (message pattern, system events), manual invocation with guardrails (cooldown, max concurrent, dedup)
- Job state machine — Full lifecycle tracking (Pending→InProgress→Completed→Accepted) with stuck detection and self-repair
- Interactive REPL —
frankclaw chatwith streaming responses, slash commands, tab completion, and history persistence - Canvas host — local authenticated visual workspace surface
- Bounded tools — session inspection plus Chromium-backed
browser_open,browser_extract,browser_snapshot,browser_click,browser_type,browser_wait,browser_press,browser_sessions, andbrowser_close - 3-tier tool risk levels — Tools are classified as ReadOnly, Mutating, or Destructive. Approval gates are controlled via
FRANKCLAW_TOOL_APPROVALwith per-tool overrides. - Bash tool — Shell command execution with timeout, output truncation, and configurable security policy (deny-all, allowlist, or allow-all)
- Optional sandbox — ai-jail integration (bubblewrap + landlock) for OS-level command isolation, complementary to the bash allowlist
- Operator support — interactive setup wizard, doctor diagnostics, security audit with severity ratings, process management (start/stop daemon), status, remote exposure checks, onboarding, and systemd unit generation
- Docker runtime —
docker compose up -dstarts the gateway, headless Chromium, and Cloudflare tunnel in one command - Prompt templates — All LLM-facing text lives in editable markdown files, embedded at compile time
- Media understanding — Multi-provider vision (OpenAI, Anthropic, Ollama) and audio transcription (Whisper) with ordered fallback chain, configurable via
understandingconfig section - Memory/RAG — SQLite FTS5 full-text search + cosine vector similarity with hybrid scoring, embedding providers (OpenAI, Ollama, Gemini, Voyage AI) with SHA-256 caching, paragraph-based chunking, automatic file sync
- Rich web console — 8-tab interface (Connect, Chat, Canvas, System, Usage, Agents, Cron, Logs) with dark/light mode, tool approval cards, image paste, usage analytics with CSV export, focus mode, resizable markdown sidebar, WebSocket auto-reconnect with keepalive
- Webhook transforms — JSON path extraction from nested payloads, message templates, per-mapping concurrency limits and fixed-window rate limiting
- Media pipeline — File handling with SSRF protection, filename sanitization, and optional VirusTotal malware scanning
- Internationalized CLI — 9 locales (en, pt-BR, pt-PT, es, fr, de, it, ja, ko) via
FRANKCLAW_LANG - Plugin system — Manifest-based plugin discovery, enable/disable lifecycle, CLI management (
frankclaw plugin) - Zero unsafe code —
#![forbid(unsafe_code)]on every crate
#Architecture
┌─────────────────────────────────────────────┐ │ CLI / Control UI / Apps │ ├─────────────────────────────────────────────┤ │ Gateway (WebSocket + HTTP) │ │ ┌──────┬───────┬──────┬──────┬─────────┐ │ │ │ Auth │ Proto │ Cron │Hooks │ Sessions│ │ │ └──────┴───────┴──────┴──────┴─────────┘ │ ├─────────────────────────────────────────────┤ │ Model Providers │ │ ┌────────┬───────────┬────────┐ │ │ │ OpenAI │ Anthropic │ Ollama │ │ │ └────────┴───────────┴────────┘ │ ├─────────────────────────────────────────────┤ │ Channel Adapters │ │ ┌──────────┬─────┬─────────┬───────────┐ │ │ │ Telegram │ Web │ Discord │ Slack ... │ │ │ └──────────┴─────┴─────────┴───────────┘ │ ├─────────────────────────────────────────────┤ │ Storage │ │ ┌──────────┬───────┬────────┐ │ │ │ Sessions │ Media │ Memory │ │ │ │ (SQLite) │(Files)│(Vector)│ │ │ └──────────┴───────┴────────┘ │ └─────────────────────────────────────────────┘
#Crate Map
| Crate | Description |
|---|---|
frankclaw-core |
Shared types, traits, error hierarchy, SSRF IP blocklist |
frankclaw-crypto |
ChaCha20-Poly1305 encryption, Argon2id hashing, HMAC-SHA256 key derivation |
frankclaw-gateway |
Axum WebSocket + HTTP server, auth, rate limiting, config hot-reload, tunnel support, 8-tab web console, webhook limiter |
frankclaw-sessions |
SQLite session store with optional encrypted transcripts |
frankclaw-models |
AI provider adapters (OpenAI, Anthropic, Ollama, Copilot, Gemini, OpenRouter, Groq, Together, DeepSeek) with model-aware failover, circuit breaker, caching, cost tracking, smart routing |
frankclaw-channels |
Messaging channel adapters (Web, Telegram, Discord, Slack, Signal, WhatsApp, Email) |
frankclaw-runtime |
Agent runtime, prompt templates, subagent orchestration, context compaction, hooks wiring |
frankclaw-tools |
Tool registry, bash execution (with optional ai-jail sandbox), browser tools, MCP client, audio transcription |
frankclaw-memory |
SQLite FTS5 + vector memory store with embedding providers (OpenAI, Ollama, Gemini, Voyage AI), caching, file sync |
frankclaw-cron |
Scheduled jobs with event triggers, job state machine, and self-repair |
frankclaw-media |
File storage with SSRF-safe HTTP fetcher, optional VirusTotal malware scanning, multi-provider media understanding (vision + transcription) |
frankclaw-plugin-sdk |
Plugin registry with manifest parsing, filesystem discovery, enable/disable lifecycle |
frankclaw-cli |
CLI binary with all subcommands |
#Requirements
- Rust 1.93+ (edition 2024)
- SQLite (bundled via
rusqlite, no system install needed) - Optional: Ollama for local model inference
#Quick Start
#1. Build
git clone https://github.com/akitaonrails/FrankClaw.git cd FrankClaw cargo build --release
The binary is at target/release/frankclaw.
#2. Initialize Configuration
./target/release/frankclaw onboard --channel web
This creates ~/.local/share/frankclaw/frankclaw.toml with secure defaults and 0600 file permissions.
Use --channel telegram, --channel whatsapp, --channel slack, --channel discord, --channel signal, or --channel email to start from a channel-specific profile.
#3. Generate an Auth Token
./target/release/frankclaw gen-token
Copy the output token (256-bit, base64url-encoded) and add it to your config:
[gateway.auth] mode = "token" token = "YOUR_TOKEN_HERE"
#4. Configure a Model Provider
Add at least one AI provider to your config. For local-only setup with Ollama:
[models] default_model = "llama3" [[models.providers]] id = "ollama" api = "ollama" base_url = "http://127.0.0.1:11434"
For OpenAI or Anthropic, set the API key via environment variable:
export OPENAI_API_KEY="sk-..." # or export ANTHROPIC_API_KEY="sk-ant-..."
And add the provider to config:
[[models.providers]] id = "openai" api = "openai" base_url = "https://api.openai.com/v1" api_key_ref = "OPENAI_API_KEY" models = ["gpt-4o", "gpt-4o-mini"]
#5. Start the Gateway
./target/release/frankclaw gateway
The gateway starts on 127.0.0.1:18789 by default. Connect via WebSocket for the control protocol.
#6. Validate Configuration
./target/release/frankclaw check ./target/release/frankclaw doctor ./target/release/frankclaw status
#7. Run Tests
cargo test
#Browser Tools
FrankClaw can now drive a real Chromium instance over the DevTools protocol for safe browser-backed page sessions.
#Local Dev Mode
You can run Chromium directly on the host:
chromium \ --headless=new \ --disable-gpu \ --no-sandbox \ --remote-debugging-address=127.0.0.1 \ --remote-debugging-port=9222 \ --user-data-dir=/tmp/frankclaw-chromium \ about:blank
#Docker Compose Mode
docker compose up -d starts three services: the FrankClaw gateway, headless Chromium (for browser tools), and a Cloudflare tunnel (for webhook exposure). All services communicate over an internal Docker network.
# 1. Create your config from the example cp frankclaw.toml.example frankclaw.toml # Edit frankclaw.toml — enable channels, set auth token, add tools # 2. Set up secrets cp .env.docker.example .env.docker # Edit .env.docker — add API keys, channel tokens # 3. If you use GitHub Copilot, authenticate inside the Docker state volume docker compose run --rm gateway login copilot # Then add a Copilot provider to frankclaw.toml: # [models] # default_model = "gpt-4o" # # [[models.providers]] # id = "copilot" # api = "github-copilot" # models = ["gpt-4o"] # 4. If agents need a workspace, mount it in docker-compose.yml and use # the same container path in frankclaw.toml: # [agents.agents.default] # workspace = "/workspace" # 5. Set up Cloudflare tunnel (for public webhook access) cp docker/cloudflared/config.yml.example docker/cloudflared/config.yml # Edit config.yml — set your hostname cp ~/.cloudflared/<tunnel-id>.json docker/cloudflared/credentials.json cp ~/.cloudflared/cert.pem docker/cloudflared/cert.pem chmod 644 docker/cloudflared/credentials.json docker/cloudflared/cert.pem # 6. Start everything docker compose up -d
The gateway binds to 0.0.0.0 inside the container (LAN mode) so cloudflared can reach it. Auth is required — set a token in frankclaw.toml. To access the gateway directly from the host (for debugging), uncomment the ports section in docker-compose.yml. Copilot credentials, sessions, media, and logs are kept in the frankclaw-state volume mounted at /var/lib/frankclaw.
Then allow browser tools on an agent:
[agents]
default_agent = "default"
[agents.agents.default]
tools = [
"session_inspect",
"browser_open",
"browser_extract",
"browser_snapshot",
"browser_click",
"browser_type",
"browser_wait",
"browser_press",
"browser_sessions",
"browser_close",
]
Example use:
frankclaw tools invoke --tool browser_open --session default:web:control --args '{"url":"https://example.com"}' frankclaw tools invoke --tool browser_extract --session default:web:control frankclaw tools invoke --tool browser_snapshot --session default:web:control FRANKCLAW_TOOL_APPROVAL=mutating \ frankclaw tools invoke --tool browser_type --session default:web:control --args '{"selector":"input[name=q]","text":"frankclaw"}' FRANKCLAW_TOOL_APPROVAL=mutating \ frankclaw tools invoke --tool browser_click --session default:web:control --args '{"selector":"button[type=submit]"}' frankclaw tools invoke --tool browser_wait --session default:web:control --args '{"selector":"#results","timeout_ms":2000}' FRANKCLAW_TOOL_APPROVAL=mutating \ frankclaw tools invoke --tool browser_press --session default:web:control --args '{"selector":"input[name=q]","key":"Enter"}' frankclaw tools invoke --tool browser_sessions --session default:web:control frankclaw tools invoke --tool browser_close --session default:web:control
browser_click, browser_type, browser_press, and browser_select_option are classified as Mutating tools and require FRANKCLAW_TOOL_APPROVAL=mutating (or the legacy FRANKCLAW_ALLOW_BROWSER_MUTATIONS=1).
Live regression check against a real local Chromium instance:
FRANKCLAW_BROWSER_DEVTOOLS_URL=http://127.0.0.1:9223/ \ cargo test -p frankclaw-tools browser_tools_drive_real_chromium -- --ignored
#CLI Reference
frankclaw chat Interactive REPL chat (streaming, slash commands, tab completion) frankclaw chat --tui Full-screen TUI mode (ratatui) frankclaw acp Start ACP server (JSON-RPC 2.0 over NDJSON stdin/stdout) frankclaw plugin list List discovered plugins frankclaw plugin enable Enable a plugin by ID frankclaw plugin disable Disable a plugin by ID frankclaw plugin info Show plugin details frankclaw gateway Start the gateway server frankclaw gen-token Generate a 256-bit auth token frankclaw hash-password Hash a password with Argon2id for config frankclaw setup Interactive setup wizard (provider, channel, auth) frankclaw onboard Create a starter config for a supported channel profile frankclaw init Create a blank config with secure defaults frankclaw check Validate config file frankclaw doctor Run high-signal validation and readiness checks frankclaw audit Security audit with severity-rated findings frankclaw start Start the gateway as a background daemon frankclaw stop Stop the running daemon frankclaw config-example Print a supported channel config snippet frankclaw status Show runtime and exposure status frankclaw remote-status Show remote exposure posture frankclaw install-systemd Print a systemd unit for the current install frankclaw config Show resolved configuration (secrets redacted) frankclaw tools list Show tools allowed for an agent frankclaw tools invoke Invoke a configured tool locally frankclaw tools activity Show recent tool activity for a session frankclaw message-delete-last Delete the last tracked reply for a session
#Global Options
-c, --config <PATH> Config file path (env: FRANKCLAW_CONFIG)
--state-dir <PATH> State directory (env: FRANKCLAW_STATE_DIR)
--log-level <LEVEL> Log level: trace|debug|info|warn|error (env: FRANKCLAW_LOG)
#Gateway Options
frankclaw gateway -p 9000 Override listen port
#Security
FrankClaw is designed with defense-in-depth. Every layer enforces its own security boundaries. A comprehensive audit of both FrankClaw and OpenClaw (see OPENCLAW_SECURITY_AUDIT.md) confirms that FrankClaw resolves every critical and high-severity vulnerability found in the reference implementation.
#Why FrankClaw is More Secure Than OpenClaw
| Area | OpenClaw | FrankClaw |
|---|---|---|
| Memory safety | JavaScript (GC, no buffer overflows) | Rust with #![forbid(unsafe_code)] — no unsafe blocks anywhere |
| Encryption at rest | Plaintext transcripts and config on disk | ChaCha20-Poly1305 encryption with master key |
| Password hashing | No password auth mode found | Argon2id (t=3, m=64MB, p=4) |
| Token comparison | SHA-256 + timingSafeEqual, but type-check short-circuit leaks timing | Constant-time byte comparison, no early returns |
| Shell execution | No mandatory command allowlist; eval() in browser tool |
Deny-all default + binary allowlist + metacharacter rejection + optional ai-jail sandbox |
| Webhook auth | Discord: hardcoded placeholder key; Slack: zero signature verification | Application-layer signature validation on all channels |
| File permissions | 0o644 (world-readable) for media files |
0o600 (owner-only) for everything |
| Session encryption | None — all conversation history readable on disk | ChaCha20-Poly1305 when master key is set |
| Prompt injection | sanitizeForPromptLiteral() + <untrusted-text> wrapping |
Unicode Cc/Cf stripping on all inputs + tool outputs, external content tags, 2 MB prompt size limit, no user data in system prompts |
| Input validation | No identifier length limits, no WebSocket frame size enforcement | 255-byte ID limits, 800-byte session key limits, configurable WS frame size |
| Malware scanning | None | Optional VirusTotal integration on all file uploads |
| Sandbox | Docker with gaps (no --cap-drop=ALL, eval() in browser, symlink bypass) |
ai-jail (bubblewrap + landlock), read-only lockdown mode available |
| Security audit CLI | secrets/audit.ts (detects plaintext secrets only) |
frankclaw audit with 7 categories, severity ratings, CI exit codes |
| Prototype pollution | Explicitly guarded in config merge | N/A — Rust has no prototype chain |
| OAuth/credential storage | Plaintext files in ~/.openclaw/credentials/ |
Encrypted via master key |
| Session fixation | User-controlled session key header with no validation | Session keys validated against agent ownership |
OpenClaw's audit found 7 CRITICAL and 9 HIGH severity issues. FrankClaw addresses all of them by design or explicit mitigation.
#What's Hardened
| Area | Implementation |
|---|---|
| Memory safety | #![forbid(unsafe_code)] on all crates. Rust ownership prevents buffer overflows, use-after-free, and data races. |
| Session storage | SQLite with WAL mode and PRAGMA secure_delete = ON. Transcript content encrypted with ChaCha20-Poly1305 when a master key is provided. |
| Password hashing | Argon2id with OWASP-recommended parameters (t=3, m=64MB, p=4). |
| Token comparison | Constant-time byte comparison prevents timing side-channels. |
| Secret handling | All secrets wrapped in SecretString (zeroed from memory on drop, prints [REDACTED] in Debug/logs). |
| File permissions | All sensitive files created with 0600 (owner-only). Directories 0700. |
| Network binding | Gateway refuses to start if bound to a non-loopback address without authentication configured. This is a hard error, not a warning. |
| SSRF protection | All outbound HTTP requests resolve DNS first and block connections to private IPs (RFC 1918), loopback, link-local, CGNAT (100.64.0.0/10), documentation ranges, benchmarking ranges, and IPv4-mapped IPv6 private addresses. |
| Prompt injection | Unicode control/format chars (Cc, Cf) stripped from all user input and tool output before LLM ingestion. External content wrapped in boundary tags. Total prompt hard-capped at 2 MB. |
| Media files | Filenames sanitized (path traversal stripped, leading dots removed). MIME types mapped to safe extensions only (never .exe, .sh, .bat). Optional VirusTotal malware scanning before storage. |
| Config hot-reload | File watcher plus lock-free ArcSwap swap for the reloadable gateway subset. Restart-sensitive config changes are detected and flagged instead of being silently applied. |
| Rate limiting | Per-IP auth failure tracking with sliding window and lockout. Cleared on successful auth. |
| Dependencies | No OpenSSL (uses rustls only). Release builds use LTO, stripped symbols, and panic = abort. |
#Intentionally Open Surfaces
These components must remain open for the system to function. Understand the trade-offs:
#1. Channel Bot Tokens
Bot tokens for Telegram, Discord, Slack, etc. are sent to those platforms over HTTPS. If a token leaks, an attacker can impersonate your bot. Mitigation: store tokens encrypted, rotate regularly, use IP allowlists where the platform supports them.
#2. Gateway WebSocket Port
The gateway must accept TCP connections to function. Mitigation: binds to 127.0.0.1 by default. Use Tailscale or a VPN for remote access. Auth is required for any non-loopback bind.
#3. Model Provider API Keys
API keys are sent to OpenAI/Anthropic/Google in HTTP headers. Mitigation: keys are never logged (redaction layer), encrypted at rest, and you should set spending limits at the provider's dashboard.
#4. Webhook Endpoints
Some channels require public webhook URLs. Mitigation: always configure webhook signature verification. FrankClaw validates per-platform signatures (Telegram secret token, Slack signing secret, Discord Ed25519) where available.
#5. Media Files in Sandbox Mode
Files shared into sandboxed environments (ai-jail, Docker) are accessible to agent code. Mitigation: use a dedicated ephemeral media directory, read-only bind mounts where possible, and automatic cleanup after sandbox exits. With ai-jail --lockdown, the filesystem is read-only by default.
#6. Memory Vector Embeddings
Vector embeddings cannot be encrypted if you want semantic search to work. They partially encode the original text content. Mitigation: use local embedding models (Ollama) to avoid sending content to external APIs. Text content is encrypted at rest; only vectors remain searchable.
#7. Config and Environment Variables
The config file and .env may contain API keys and tokens. Mitigation: 0600 file permissions, encrypted config mode (master passphrase), and never commit these files to version control.
#Security Recommendations
- Always use auth — Run
frankclaw gen-tokenand configure token auth before exposing the gateway to any network. - Use local models for privacy — Ollama keeps all inference on-device. No data leaves your machine.
- Set provider spending limits — Configure hard spending caps in your OpenAI/Anthropic dashboard.
- Rotate tokens regularly — Bot tokens and API keys should be rotated on a schedule.
- Monitor logs — Run with
--log-level infominimum. Auth failures and SSRF blocks are logged. - Keep Rust updated — Run
rustup updateto get security fixes in the compiler and standard library. - Audit dependencies — Run
cargo auditbefore deploying. Addcargo-denyto CI.
#FrankClaw vs IronClaw
IronClaw (NEAR AI) is another Rust rewrite of OpenClaw. The two projects share the same ancestor but make fundamentally different design choices. They are complementary, not competing.
| Dimension | IronClaw | FrankClaw |
|---|---|---|
| Deployment | Requires PostgreSQL 15+ with pgvector | Single binary, embedded SQLite — zero external dependencies |
| Sandbox model | WASM (wasmtime) — tools run inside a WebAssembly VM | OS-level (bubblewrap + landlock via ai-jail) — processes run in a Linux namespace jail |
| Channel adapters | WASM-based plugin channels | 7 native compiled-in adapters (Web, Telegram, Discord, Slack, Signal, WhatsApp, Email) |
| Tool approval | Capability-based permissions per workspace | 3-tier risk levels (ReadOnly/Mutating/Destructive) with per-tool overrides |
| Encryption at rest | AES-256-GCM credential vault | ChaCha20-Poly1305 for sessions, config, and credentials |
| Memory / search | PostgreSQL pgvector + FTS with reciprocal rank fusion | SQLite FTS5 + cosine vector search with hybrid scoring, embedding providers (OpenAI, Ollama), file sync |
| LLM resilience | Circuit breaker + retry + smart routing | Circuit breaker + retry with exponential backoff + jitter, smart routing (13-dimension complexity scorer), response caching, cost tracking with budget guards |
| MCP integration | JSON-RPC client (stdio, HTTP, Unix socket) | JSON-RPC 2.0 client (stdio, HTTP) with tool wrapping and risk level mapping |
| Default AI provider | NEAR AI (with OpenRouter, Together, Fireworks, Ollama) | Any OpenAI-compatible API, Anthropic, Ollama |
| Streaming | SSE + WebSocket web gateway | WebSocket control protocol |
| Routines | Built-in cron + event-driven + webhook routines engine | Cron + event triggers (message pattern, system events) + manual, with guardrails and job state machine |
| Operator CLI | Basic CLI | Full CLI: setup wizard, doctor, audit (severity-rated), daemon, systemd, onboarding, interactive REPL |
| Tunnel support | Cloudflare Tunnel, ngrok, Tailscale funnel, custom | Cloudflare Tunnel, ngrok, custom commands with URL extraction |
| Prompt injection defense | Not documented | Unicode Cc/Cf stripping, external content boundary tags, 2 MB prompt limit |
| Credential leak detection | Scans outputs for API keys | 12 regex patterns scan all LLM and tool output |
| Malware scanning | Not documented | Optional VirusTotal integration on file uploads |
#When to choose which
Choose IronClaw if you want WASM-based tool sandboxing, need PostgreSQL-backed vector search today, or are building on the NEAR AI ecosystem.
Choose FrankClaw if you want a single-binary deployment with no database server, need native channel adapters that work out of the box, want OS-level sandboxing via bubblewrap/landlock, or need defense-in-depth security hardening (encryption at rest, prompt injection defense, audit CLI, malware scanning).
#Configuration Reference
FrankClaw uses a single TOML config file. All fields have secure defaults.
# Gateway server settings [gateway] port = 18789 # TCP port bind = "loopback" # "loopback", "lan", or a specific IP max_ws_message_bytes = 4194304 # 4 MB max_connections = 64 [gateway.auth] mode = "token" # "none", "token", "password", "trusted_proxy", "tailscale" token = "..." # 256-bit base64url token (from gen-token) [gateway.rate_limit] max_attempts = 5 # Failed auths before lockout window_secs = 60 # Sliding window lockout_secs = 300 # Lockout duration # Agent definitions [agents] default_agent = "default" [agents.agents.default] name = "Default Agent" model = "gpt-4o" system_prompt = "You are a helpful assistant." [agents.agents.default.sandbox] mode = "none" # Model providers (tried in order for failover) [models] default_model = "gpt-4o" [[models.providers]] id = "openai" api = "openai" base_url = "https://api.openai.com/v1" api_key_ref = "OPENAI_API_KEY" models = ["gpt-4o", "gpt-4o-mini"] cooldown_secs = 60 # Session management [session] scoping = "main" # "main", "per_peer", "per_channel_peer", "global" [session.reset] # daily_at_hour = 0 # UTC hour (0-23), omit to disable # idle_timeout_secs = 3600 # omit to disable max_entries = 500 [session.pruning] max_age_days = 30 max_sessions_per_agent = 500 disk_budget_bytes = 10485760 # 10 MB # Security settings [security] encrypt_sessions = true # ChaCha20-Poly1305 encryption at rest encrypt_media = false # Optional media encryption (performance trade-off) ssrf_protection = true # Block fetches to private IP ranges max_webhook_body_bytes = 1048576 # 1 MB # Media pipeline [media] max_file_size_bytes = 5242880 # 5 MB ttl_hours = 2 # Media understanding (vision + transcription) [understanding] enabled = false vision_provider = "openai" # "openai", "anthropic", "ollama", or "none" vision_model = "gpt-4o" vision_api_key_ref = "OPENAI_API_KEY" transcription_provider = "openai" # "openai" or "none" transcription_model = "whisper-1" transcription_api_key_ref = "OPENAI_API_KEY" auto_transcribe_voice = false # Logging [logging] level = "info" # trace, debug, info, warn, error format = "pretty" # "pretty", "json", "compact" redact_secrets = true # Replace secrets with [REDACTED] in logs
#Environment Variables
| Variable | Description |
|---|---|
FRANKCLAW_CONFIG |
Path to config file |
FRANKCLAW_STATE_DIR |
State directory (sessions, media, logs) |
FRANKCLAW_LOG |
Log level override |
OPENAI_API_KEY |
OpenAI API key |
ANTHROPIC_API_KEY |
Anthropic API key |
TELEGRAM_BOT_TOKEN |
Telegram bot token |
FRANKCLAW_BASH_POLICY |
Bash tool policy: deny-all (default), allow-all, or comma-separated binary allowlist |
FRANKCLAW_SANDBOX |
Optional sandbox: ai-jail or ai-jail-lockdown (requires ai-jail) |
FRANKCLAW_TOOL_APPROVAL |
Tool approval level: readonly (default), mutating, or destructive |
FRANKCLAW_ALLOW_BROWSER_MUTATIONS |
Legacy — set to 1 to enable mutating tools (use FRANKCLAW_TOOL_APPROVAL instead) |
FRANKCLAW_BROWSER_DEVTOOLS_URL |
Chromium DevTools endpoint (default: http://127.0.0.1:9222/) |
FRANKCLAW_LANG |
UI language: en, pt-BR, pt-PT, es, fr, de, it, ja, ko |
VIRUSTOTAL_API_KEY |
Optional VirusTotal API key — enables malware scanning on all file uploads |
FRANKCLAW_DAILY_BUDGET |
Optional daily spend limit (e.g. 5.00 for $5/day) |
FRANKCLAW_TUNNEL |
Tunnel provider: cloudflare, ngrok, or custom |
FRANKCLAW_TUNNEL_CF_TOKEN |
Cloudflare Tunnel token (when FRANKCLAW_TUNNEL=cloudflare) |
FRANKCLAW_TUNNEL_NGROK_TOKEN |
ngrok auth token (when FRANKCLAW_TUNNEL=ngrok) |
FRANKCLAW_TUNNEL_NGROK_DOMAIN |
Optional ngrok custom domain |
FRANKCLAW_TUNNEL_COMMAND |
Custom tunnel command with {host} and {port} placeholders |
FRANKCLAW_TUNNEL_URL_PATTERN |
URL pattern to extract from custom tunnel output |
#Development
#Running in Dev Mode
# Watch for changes and rebuild cargo watch -x 'run -- gateway' # Run with debug logging FRANKCLAW_LOG=debug cargo run -- gateway # Run specific tests cargo test -p frankclaw-crypto cargo test -p frankclaw-sessions cargo test -p frankclaw-media
#Project Structure
frankclaw/ ├── Cargo.toml # Workspace root ├── CLAUDE.md # AI assistant development guide ├── docs/ # Project documentation │ ├── AUDIT_PLAN.md │ ├── CHANNEL_SETUP.md │ ├── FEATURE_PLANS.md │ ├── OPENCLAW_ANALYSIS.md │ ├── OPENCLAW_SECURITY_AUDIT.md │ ├── PARITY_TODO.md │ └── ROADMAP.md ├── crates/ │ ├── frankclaw-core/ # Shared types and traits │ ├── frankclaw-crypto/ # Cryptographic primitives │ ├── frankclaw-gateway/ # WebSocket + HTTP server │ ├── frankclaw-sessions/ # SQLite session store │ ├── frankclaw-models/ # AI model providers │ ├── frankclaw-channels/ # Messaging channel adapters │ ├── frankclaw-memory/ # SQLite FTS5 + vector memory store │ ├── frankclaw-cron/ # Scheduled jobs │ ├── frankclaw-runtime/ # Agent runtime & prompt templates │ ├── frankclaw-tools/ # Tool registry, bash & browser tools │ ├── frankclaw-media/ # Media file handling │ ├── frankclaw-plugin-sdk/ # Plugin system │ └── frankclaw-cli/ # CLI binary └── target/ # Build artifacts (gitignored)
#Adding New Functionality
New channel adapter:
- Create
crates/frankclaw-channels/src/<name>.rs - Implement
ChannelPlugintrait fromfrankclaw-core - Export from
crates/frankclaw-channels/src/lib.rs
New model provider:
- Create
crates/frankclaw-models/src/<name>.rs - Implement
ModelProvidertrait fromfrankclaw-core - Export from
crates/frankclaw-models/src/lib.rs
#Roadmap
See PARITY_TODO.md for the current parity tracker.
- Streaming SSE response handling for OpenAI/Anthropic model providers
- Agent runtime with optional ai-jail sandbox (bubblewrap + landlock)
- Circuit breaker + retry with exponential backoff for LLM providers
- Smart model routing (13-dimension complexity scorer)
- MCP client integration (stdio + HTTP transports)
- Response caching and cost tracking with budget guards
- Credential leak detection in tool/LLM output
- Extended thinking support for reasoning models
- Interactive REPL (
frankclaw chat) - Tunnel support (Cloudflare, ngrok, custom)
- Job state machine with self-repair
- Event-driven routine triggers
- Memory/RAG with SQLite FTS5 + vector search
- Multi-provider media understanding (vision + transcription)
- Rich web console (8 tabs, dark mode, tool approval, analytics)
- Webhook transforms (JSON path, templates, rate limiting)
- Hook lifecycle wiring (message + tool events)
- Full-screen TUI with ratatui (
frankclaw chat --tui) - ACP protocol (JSON-RPC 2.0 over NDJSON)
- Plugin management with manifest discovery and lifecycle
- Browser profiles with CDP port allocation
- Batch embedding providers (Gemini, Voyage AI)
- Rich markdown rendering (CommonMark → IR → ANSI)
- Long-tail attachment/media edge cases on supported channels
- Companion nodes and apps
- Voice
#License
AGPL-3.0-or-later. See LICENSE.
Some components are derived from IronClaw (MIT OR Apache-2.0). See THIRD_PARTY_LICENSES for details.