Sandboxed shell exec for MCP clients: run untrusted agent commands in a gVisor container.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent — or use 1-click editor setup below.
💡 Paste into ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows)
Each one runs sealed in a sandbox that provably cannot phone home, read your host, or rewrite its own rules.
IronClaw runs autonomous AI agents on infrastructure you control, reached through the chat apps
you already use. Each agent can read, write, schedule, and reply like any assistant, but it lives
inside a sealed sandbox with network=none: it reaches the model only through a host proxy, and it
cannot change its own configuration. It is for anyone who wants what agents can do without
handing an autonomous program the keys to their machine.
Now on the GitHub Marketplace. The
ironctl scancontainment grader ships as a GitHub Action: drop one line into a workflow and every pull request gets a 0 to 100 sandbox isolation scorecard as a sticky comment. Local, read-only, credential-free.Report-only by default; set
min-score: 90to gate merges. See scan in CI.
Watch it catch a real escape. A fully-jailbroken agent inside a real sandbox tries to phone home, read the host filesystem, and seize the host through the Docker socket. Each attempt is denied at the isolation boundary, then a containment summary prints. One command, zero credentials, reduced-motion friendly. examples/live-containment/run.sh
⭐ Like the idea of agents you do not have to trust? Star the repo so it is one click to follow along and easier for the next person to find. Then run the exact demo above in 30 seconds, no signup and no API key.
Make sure the Docker daemon is running (start Docker Desktop, or sudo systemctl start docker
on Linux), then paste one block:
That single command runs the whole secured path on your laptop: it starts the offline mock-agent
control-plane (no API key), engages a real per-session sandbox, lets a jailbroken agent try
to break out, and prints the containment summary you saw above. Want to chat with an agent in a
browser first? Run hello-ironclaw or the
zero-credential quickstart. Production seals each sandbox with gVisor and
network=none.
[!WARNING] Alpha software, work in progress. Please read before relying on it.
- It's an alpha. Flags, the on-disk format, and the HTTP/contract surfaces can still change without notice or a migration path. Don't point it at anything you can't afford to lose.
- Not every feature is tested end-to-end. The control-plane, gateway, and encrypted-queue core have real coverage (800+ Go tests plus a black-box parity suite); channel adapters, some tools, multi-provider routing, and a live sandbox launch are exercised more lightly. Treat anything outside the tested core as experimental.
macOS gets a weaker sandbox boundary than Linux+gVisor, and native Windows can't run the agent sandbox at all (use WSL2). See Platform support.
The security model, in one line: each sandboxed agent runs with
network=none, reaches the model only through a host proxy, and cannot change its own configuration. Every capability change is held at a gateway for a human decision. The full design is in the architecture overview and the threat model.
Zero credentials, one command. The offline mock-agent runs the full chat to per-session sandbox to reply path with no API key. Production seals each sandbox with gVisor and network=none. Quickstart
Zero-cred demo, connect a real provider, first approved task. The one credential step keeps the key host-side; every agent change is held at the gateway for a human, then written to the append-only audit log. Animation freezes on the final frame under prefers-reduced-motion. Quickstart
One command installs the two host binaries (ironctl + ironclaw-controlplane); in dev mode the
control-plane serves its API at http://127.0.0.1:8787. From a cold machine, you'll have a
capability change waiting at the security gateway in under two minutes:
On Windows, irm https://raw.githubusercontent.com/IronSecCo/ironclaw/main/scripts/install.ps1 | iex
installs the host binaries (ironclaw-controlplane.exe + ironctl.exe) and --dev runs, but the
agent sandbox needs WSL2 or Linux — see Windows via WSL2.
Version pinning, system-wide installs, and building from source are all in Installation.
Run the hardened control-plane on a PaaS in ~2 minutes with zero local tooling — the approval gateway, encrypted per-session queues, host-side credential custody, and the web console:
These PaaS paths run the control-plane only — a single container has no gVisor and no Docker socket, so agent sandboxes don't launch there (same boundary as the hardened Compose path). For full agent isolation use a gVisor host or k8s node. Details + env in the deployment guide (Path D).
This is a feature, not a missing dashboard. Every capability is a documented HTTP endpoint and an
ironctl subcommand, so IronClaw is scriptable, auditable, and CI-friendly from the first command —
with no public web surface to phish, misconfigure, or leave exposed. (There is now a private,
mesh-only web console at /ui/ — but it's additive, never the only way in, and rides the same
Tailscale-bound API, so it adds no public port.)
| Pillar | What it is | Attack surface it removes |
|---|---|---|
| Sealed runtime | The agent ships as a compiled Go binary | Agent self-modification — there's no source inside the box to rewrite |
| Approved by humans | Every change to the harness clears a deterministic gateway | Silent setting changes — nothing changes without a human seeing and approving it |
| Encrypted queues | Per-session encrypted message queues; read-only inbound | Data theft at rest, and cross-session reads |
| Sealed sandbox | gVisor container, no network, host-proxied model calls | Data exfiltration and sandbox escape |
| Private control panel | Admin access over a private mesh (Tailscale) only | Remote attacks on the controls |
The throughline: treat the agent as untrusted, and make the security boundary something you can verify — not something you take on faith.
⚖️ Weighing your options? See Why IronClaw / vs. the alternatives for an honest comparison against hosted agent platforms, raw container + LLM glue, and other self-hosted agent runtimes.
Do not take our word for any of that. ironctl scan grades the containment posture of
any running container, docker-compose service, or Kubernetes pod on a 0 to 100 scale.
It works on your own setups, not just IronClaw's, so you can measure how much isolation you
actually have before you hand a sandbox to untrusted code. It is fail-closed: any boundary
it cannot observe is scored insecure, never waved through.
It also grades a Dockerfile statically, at authoring or CI time, with no daemon and no image pull, so you catch a leaked credential, an unpinned base, or a root default in review instead of in production:
Grade Dockerfiles automatically on every commit with the
pre-commit hook, which builds ironctl from source, so
there is nothing to install first:
Walkthrough: How to scan a Dockerfile for security issues takes a deliberately bad Dockerfile from 5/100 (F) to 100/100 (A), one fix at a time.
A container started the usual way (root user, default caps, bridge network, docker.sock
mounted in) grades 23/100, F. An IronClaw ic-sbx-* session sandbox grades a clean
100/100, A:
| Target | Score | Grade | Posture |
|---|---|---|---|
Typical docker run container | 23/100 | F | runs as root, docker.sock mounted, writable rootfs, bridge egress |
| IronClaw session sandbox | 100/100 | A | non-root, all caps dropped, seccomp on, network=none, read-only rootfs, gVisor |
Every failing line names the specific hole and why it matters. Drop the grade into your own
README with ironctl scan --badge scan.svg, or gate CI with ironctl scan --min-score 90.
See the scan reference for all seven dimensions and every flag. Or browse the Container Isolation Scores directory: the default-config grade for 150+ of the most-pulled public images, so you can see how the containers you already run stack up. Rankings live on the Container Isolation Leaderboard (Hall of Fame vs worst offenders), and the interactive scores explorer lets you filter and grab a badge for your repo.
Head-to-head reads backed by the same scan data: Alpine vs Debian vs Ubuntu (does the base image change isolation?), Docker default vs hardened (the 48-point gap, flag by flag), and gVisor vs runc (when a shared host kernel is the weak link).
Per-image hardening walkthroughs, the default grade, the dimensions that fail, and the exact
ironctl scan --fix flags that close the gap. Start at the
hardening guides hub, or jump to one:
Postgres,
MySQL,
MariaDB,
MongoDB,
Cassandra,
ClickHouse,
Redis,
Memcached,
Elasticsearch,
Kafka,
RabbitMQ,
Vault,
Consul,
MinIO,
nginx,
Grafana,
Prometheus,
Traefik,
InfluxDB,
CockroachDB,
TimescaleDB,
Valkey,
HAProxy,
ZooKeeper and
untrusted Node.js.
The same grader is published on the GitHub Marketplace as IronClaw sandbox scan. One line in a workflow and every pull request gets a containment scorecard as a sticky comment that updates in place:
It runs on a stock ubuntu-latest runner with no credentials and no control-plane. mode: k8s
adds policy-check: true to fail the check on any rule --emit-policy would generate, and
upload-sarif: true sends failed dimensions to the Security tab. Full inputs and outputs:
scan in CI.
Put your containment grade in your README, the same way a coverage or build badge does. Generate a shields.io endpoint file, commit it (no server, so a badge hit never triggers a remote scan), and embed it:
The badge at the top of this README is IronClaw's own, graded 100/100 A from
.ironclaw/sandbox-posture.yml. Full walkthrough:
Add a live Sandbox Isolation Score badge to your repo.
Two compiled Go programs that never share memory and talk only through a pair of encrypted SQLite files per conversation:
internal/contract) is the only package both sides import: typed IDs,
row shapes, the embedded SQL schema, pinned cipher params, and the gateway protocol.A single message rides a clean loop; anything that would change what the agent can do takes the separate dashed path through the human-approval gateway:
For the full design, see docs/architecture.md,
docs/threat-model.md, and the plain-language tour in
docs/ironclaw-explained.md.
📚 Full documentation site: ironsecco.github.io/ironclaw — quickstart, architecture, threat model, channels, skills, the OpenAPI reference, and security, all in one navigable place (built from
docs/and published on every push tomain).🧭 New here? The hands-on tutorials take you from
git cloneto a running agent: your first sandboxed agent in 5 minutes, connecting Slack, and writing a custom channel adapter.
IronClaw's security model rests on gVisor (runsc) — a user-space kernel that intercepts the
agent's Linux syscalls and is the layer that actually enforces network=none, the seccomp
syscall allowlist, dropped Linux capabilities, and a read-only rootfs. gVisor is Linux-only, and
that one fact drives the whole platform story:
| Capability | Linux + gVisor (production target) | macOS / Windows |
|---|---|---|
Host side — control-plane, gateway, API, ironctl, web console | ✅ native | ✅ native (incl. native Windows) |
| Real agent sandbox | ✅ gVisor (runsc) | ⚠️ --runtime docker only — runc in Docker Desktop's Linux VM. macOS: Docker Desktop. Windows: WSL2 (native Windows can't reach it — see below) |
| Per-sandbox syscall interception | ✅ | ❌ not available |
| Seccomp syscall allowlist | ✅ enforced | ❌ not applied on the Docker path |
network=none | ✅ enforced by the OCI spec | ⚠️ not auto-enforced — you must point IRONCLAW_DOCKER_NETWORK at a no-egress network |
| Dropped capabilities · read-only rootfs | ✅ enforced by the runtime | ⚠️ only as strong as the Docker Desktop VM kernel |
On macOS you can build, script, demo, and develop against the entire system natively, and you
can even run agents through Docker Desktop — but understand that the sandbox boundary then comes from
runc inside the Docker Desktop Linux VM, not gVisor. There is no per-sandbox syscall
interception, the curated seccomp profile is not applied, and network=none is not enforced for you
(the Docker isolator passes whatever network you configure straight through — set
IRONCLAW_DOCKER_NETWORK to a no-egress bridge yourself). That is weaker than the posture the
threat model assumes.
The install.ps1 PowerShell installer gives you the host plane natively on Windows:
ironclaw-controlplane.exe and ironctl.exe run, the encrypted SQLCipher queue works, and --dev
mode (no real sandbox) runs end-to-end. A real agent sandbox does not run on native Windows —
gVisor (runsc) is Linux-only, and the Docker fallback talks to the Docker Engine over a Unix
socket (/var/run/docker.sock), which native Windows Docker Desktop does not expose (it serves a
Windows named pipe instead). So on native Windows you get the control plane and ironctl, but the
agent runtime has nowhere to launch.
To actually run agents on Windows, use WSL2:
Then, inside the WSL2 Ubuntu shell, install the Linux build and run it exactly as on Linux:
Inside WSL2, /var/run/docker.sock is present (Docker Desktop's WSL integration, or Docker installed
in the distro), so IRONCLAW_RUNTIME=docker launches real Linux sandbox containers. For the full
gVisor posture, install runsc inside the WSL2 distro just as you would on bare-metal Linux. Treat a
WSL2 host the same as the Linux row above.
For anything past local development, run the sandbox host on Linux with gVisor (bare-metal, a VM, or WSL2). The control plane can live wherever you like — including native Windows — but it's the agent sandbox that needs the Linux + gVisor substrate to give you the boundary IronClaw is built around.
Alpha. The architecture is settled and the full control-plane and sandbox pipelines are implemented and tested. The encrypted-queue binding is now wired:
contract.Open* open
per-session SQLCipher databases via cgo (github.com/mutecomm/go-sqlcipher/v4); a round-trip test
covers write→read, read-only-write rejection, wrong-key failure, and no-plaintext-on-disk. The
build now requires CGO_ENABLED=1 (a C toolchain). internal/host/queue uses the live binding;
in-memory backends remain for --dev and tests.isolation builds the
hardened OCI spec, provisions the bundle rootfs (with image digest/signature verification against a
trust policy), and execs runsc. A real launch still needs runsc and a provisioned/signed image
present in the environment./metrics
surface, structured logging, host respawn + sandbox provider backoff, and model-proxy rate
caps/audit/redaction have landed and are composed into cmd/controlplane. The API-server
hardening knobs (optional TLS, rate-limit, body limits, /readyz readiness gate) exist as
api.With* options but aren't attached in the entrypoint yet (see the roadmap).See the roadmap for what remains. You can build, test, and run the control-plane today;
a live sandbox launch needs runsc plus a provisioned image.
| Requirement | For | Notes |
|---|---|---|
| Go 1.23+ and a C toolchain | building everything | CGO_ENABLED=1 is required — the encrypted-SQLite binding builds via cgo |
containerd + gVisor (runsc) | production sandboxing | runtime io.containerd.runsc.v1; not needed for --dev |
| Tailscale | remote admin access | the control-plane API binds to the tailnet IP; no public port |
| SQLCipher (vendored) | encrypted queues | the SQLCipher C amalgamation is vendored by the driver; no system lib needed |
| A model credential | live model calls | an Anthropic / OpenAI / OpenRouter key, or a gateway like OneCLI — injected host-side into the model proxy, never into the sandbox (Model providers) |
The three external runtime dependencies (gVisor, Tailscale, the encrypted-SQLite binding) are
intentionally not vendored. See deploy/README.md for host setup.
This installs ironctl, ironclaw-controlplane, and ironclaw-sandbox from the release the
formula currently pins. The formula pins each archive to the SHA-256 recorded in that release's
signed SHA256SUMS, so Homebrew verifies the download before installing. Confirm it with
ironctl version.
The tap carries exactly one version at a time. An automated pull request bumps the formula after
every release, and it lands only once a required CI check has re-derived the formula from that
release's cosign-verified SHA256SUMS, so the tap can briefly trail the newest release. Run
brew update first, and see
Releases for the newest version. To
install a specific version, including one the tap has not picked up yet, use the installer
script's IRONCLAW_VERSION (below).
Use the fully-qualified name. homebrew-core ships an unrelated formula also called
ironclaw, and core wins the bare name — so installironsecco/ironclaw/ironclaw, not bareironclaw. The explicit tap URL is required too: our tap lives in this repo, not ahomebrew-ironclawrepo.
In production the control plane usually runs as the GHCR container image (see the deployment guide); the native
ironclaw-controlplanebinary is convenient for local /--devruns.
One command installs the latest release — ironctl and ironclaw-controlplane. The script
detects your OS/arch, downloads the matching archive from
GitHub Releases, and verifies its SHA-256
checksum before installing.
macOS / Linux
Windows (PowerShell)
This installs the host binaries (
ironclaw-controlplane.exe+ironctl.exe) and runs--devnatively, but it cannot run a real agent sandbox — that needs Linux. To run agents on Windows, install inside WSL2; see Windows via WSL2.
A fresh release is published on every push to main, with prebuilt archives for:
| OS | Architectures |
|---|---|
| macOS | Intel (amd64) · Apple Silicon (arm64) |
| Linux | amd64 · arm64 |
| Windows | amd64 |
The installer reads a few environment variables (pass them on the sh side of the pipe):
Then confirm what you installed:
Prefer to grab files by hand? Download the archive and SHA256SUMS for your platform from the
latest release.
Pin IronClaw per project with mise or asdf, no
account and no sudo. The quickest path uses mise's ubi backend to install the ironctl CLI
straight from the GitHub release (no plugin repo):
For both host binaries (ironctl + ironclaw-controlplane) and a pinned .tool-versions, use the
asdf-style plugin under packaging/asdf-ironclaw/. It downloads the
release tarball, verifies it against the published SHA256SUMS, and drops both binaries on the
managed PATH:
The plugin resolves as a standalone repo (asdf clones plugins by URL), so asdf plugin add ironclaw
and mise use asdf:... become available once the plugin lands in its own IronSecCo/asdf-ironclaw
repository. Until then the scripts in packaging/asdf-ironclaw/ are runnable directly (see that
directory's README.md).
Releases are signed and attested — a keyless cosign
signature over SHA256SUMS, an SBOM (SPDX + CycloneDX), and build-provenance attestations for
every archive and the container image. For how releases are cut, verified, and yanked, see the
release runbook.
Each release carries SHA256SUMS plus SHA256SUMS.sig + SHA256SUMS.pem (the cosign signature and
its certificate), *.spdx.json / *.cdx.json SBOMs, and per-archive + image attestations.
Verify the checksum signature (no key to manage — the identity is the release workflow):
Verify build provenance for an archive, an extracted binary, or the image:
The container image also carries a signed SBOM attestation (CycloneDX) you can verify and read anonymously:
Every third-party GitHub Action is pinned to a commit SHA, builds use a pinned
toolchain + -trimpath and are checked for bit-for-bit reproducibility by a
double-build CI job (ironctl and sandbox are verified byte-identical; the larger
control-plane binary is reproducible under newer Go and tracked for the pinned toolchain),
and the project's supply-chain posture is scored continuously by
OpenSSF Scorecard (see the badge above).
Requires Go 1.23+ and a C toolchain (CGO_ENABLED=1 — the encrypted-SQLite binding builds via cgo).
For a full system install — build and install the binaries, provision /etc/ironclaw
and /var/lib/ironclaw, and enable the service (systemd on Linux, launchd on macOS) —
run sudo deploy/install.sh. It needs root to write under /etc
and /var/lib. The external runtime dependencies it relies on (containerd + gVisor and
Tailscale) are set up separately — see deploy/README.md.
docker compose)Self-host the control-plane in one command. From a clone:
The admin/API token is minted on first run and printed once in the logs (there is
no recovery) unless you set IRONCLAW_API_TOKEN yourself. The admin API is published
on 127.0.0.1:8787 only — front it with Tailscale for remote access.
Prefer the published image? It is pushed to GitHub Container Registry on every release:
Set IRONCLAW_IMAGE in .env to pin that tag for docker compose. Every variable the
control-plane reads is documented in .env.example. The agent sandboxes
themselves are not compose services — the control-plane launches them as gVisor
(runsc) children with network=none; running real sandboxes needs a runsc-capable
host (see deploy/README.md).
Going to production? The deployment guide
covers the hardened, durable posture: locked-down deploy/docker-compose.prod.yml
(read-only rootfs, dropped caps, resource limits) behind a TLS reverse proxy
(deploy/Caddyfile), secrets via an env-file, encrypted-state
backup/restore, pinned-digest upgrades, and Prometheus /metrics.
A fuller local walkthrough — run the control-plane from source in dev mode (no gVisor, binds to loopback) and drive it with the admin CLI:
Every mutation — persona, enabled tools, packages, wiring, permissions, mounts — flows through this same gateway. There is no file-edit path that bypasses it.
Two of them run end to end with zero credentials — no model key, no channel tokens, just Docker. Copy one line and watch it work:
hello-ironclaw — the canonical "it works." One command sends a chat through the real secured path (engage → per-session sandbox → encrypted queue → reply) and asserts the reply returns. Zero credentials; doubles as the CI smoke test. Animation freezes on the final frame under prefers-reduced-motion.
live-containment — watch it catch a real escape. The 60-second security aha: one command engages a real sandbox, a fully-jailbroken agent tries to break out (network exfil, host-filesystem breakout, host takeover via the Docker socket), and your terminal shows each attempt denied plus a containment summary. The curated cut of red-team-escape. Zero credentials.
red-team-escape — isolation you can prove. The full six-assertion battery behind live-containment: adds sibling-breakout and cross-session key-custody probes and emits a signed, versioned containment report; runs as the CI containment gate on every push. Zero credentials.
Runnable recipes live in examples/ — each is a directory with a README.md and a setup.sh.
Three of them ship a run-mock.sh that drives the whole inbound → agent → reply pipeline on the
offline mock provider, so a fresh clone runs them with no model key and no channel tokens:
scheduled-report/ — wakes itself on a schedule (schedule_task), summarizes, posts to a channel. (credential-free demo)webhook-responder/ — routes an inbound HTTP webhook to an agent that replies. (credential-free demo)slack-triage/ — classifies/labels every incoming Slack message. (credential-free demo)personal-assistant/ — a private 1:1 assistant on Telegram, plus a walk-through of the mandatory change-approval flow.channel-triage/ — a Slack triage bot that engages only on @mention, only for known senders.multi-agent-team/ — two agents sharing one channel, separated by engage mode and priority.ironclaw-controlplane — the host daemon| Flag | Default | Purpose |
|---|---|---|
--api-addr | 127.0.0.1:8787 | control-plane API address; set to the tailnet IP in production |
--model-proxy-socket | /run/ironclaw/modelproxy.sock | unix socket bound into each sandbox for model egress |
--state-dir | OS-specific | gateway change store, audit log, keystore |
--runtime | runsc | OCI runtime for sandboxes |
--bundle-root | <state-dir>/bundles | per-session OCI bundles |
--sweep-interval | 60s | stale-sandbox / due-message sweep cadence |
--egress-socket | "" (sealed) | opt-in: host unix socket for the egress broker, bound into each sandbox so an agent can reach approved external hosts (deny-by-default, audited) |
--egress-allow | "" | comma-separated hostnames the egress broker permits (only with --egress-socket) |
--search-backend | "" (off) | give each sandbox the web_search tool: duckduckgo (keyless) or brave[:cred] (keyed via the vault). Requires --egress-socket; the backend's host is auto-added to the allowlist |
--mcp-catalog | "" (off) | opt-in: enable MCP servers — a per-session host broker, the mcp_access change kind, and the MCP console tab. The 0600 JSON catalog of configured servers |
--mcp-isolation | container | how local (stdio) MCP servers run: container (hardened, network=none — production) or none (bare host process — dev only) |
--mcp-runtime / --mcp-image | "" | OCI runtime (e.g. runsc for gVisor) and default image for isolated local MCP servers |
--dev | false | loopback bind, no gVisor — local development only; also opens a DuckDuckGo-only egress path so web_search works out of the box, and enables MCP with --mcp-isolation=none |
Extend an agent with the tools of a Model Context Protocol server — local (a stdio
subprocess) or remote (an HTTPS endpoint) — without weakening the sandbox. MCP runs
host-side only: a local server is isolated in a hardened network=none container, a
remote one is dialed over TLS, and the sandbox reaches neither directly — it talks to a
per-session broker socket where every call is checked against a per-tool,
human-approved grant and audited. This closes the "blind MCP approval" gap the
reference design had. Enable it with --mcp-catalog, add servers + grant agents on the
console's MCP tab, and try it end to end with the bundled cmd/mcp-sample server.
Full guide: docs/mcp.md.
To expose IronClaw's sandbox_exec tool to Claude Desktop, Cursor, or Windsurf
as an MCP server, see docs/mcp-server/.
Environment: ANTHROPIC_API_KEY (model proxy credential, host-only) and IRONCLAW_API_TOKEN
(bearer token required on every API call when set).
The sandbox is network=none; it can only reach hosts through the host-mediated, audited
egress broker. The web_search tool rides that broker, so it is off by default and turns
on only with both --egress-socket and --search-backend:
duckduckgo — keyless, no secret. The quickest way to a working search, but DuckDuckGo's
keyless API returns instant answers / related topics rather than a full ranked web index, so
specific lookups (e.g. a person's name) can come back thin.brave[:cred] — Brave Search reached by name through the credential vault
(vault://<cred>/…), so the API key stays host-side in the injector and never enters the
sandbox. Requires --vault-endpoint with a matching credential.--dev enables the DuckDuckGo backend automatically (placing the egress socket next to the
model-proxy socket so it rides the same sandbox mount). Under the Docker isolator, make sure the
directory holding those sockets is in IRONCLAW_DOCKER_BINDS so the sandbox can reach it.
ironctl — the admin CLIA thin client of the control-plane API. --addr defaults to http://127.0.0.1:8787; the bearer
token comes from IRONCLAW_API_TOKEN or --token.
You don't have to know tool names or hand-write JSON. Pick a starter template, tweak it, and go — in one step, from the CLI or the web console's Agents → Create builder:
Persona as separate documents. Rather than one opaque prompt, an agent's persona is split by concern — IDENTITY.md (who it is), SOUL.md (personality/voice), and AGENTS.md (how it works) — which compose into the system prompt. Set them inline, or point at a directory of those files (the builder shows the same three fields):
This defines the agent (name + persona docs + model + tools) in a single operator-direct write. Enabling a web/API tool only makes it visible to the agent — actual egress still requires an approved host through the gateway, so the network posture is unchanged.
sandbox — the in-sandbox agentLaunched by the control-plane's isolator, not by hand. It receives its session key and queue paths
and runs the reasoning loop. Key flags (cmd/sandbox): --inbound, --outbound, --key,
--workspace, --heartbeat, --model-socket, --model-host, --model.
| Method & path | Purpose |
|---|---|
GET /healthz | liveness (unauthenticated) |
POST /v1/changes | submit a ChangeRequest |
GET /v1/changes/pending | list pending changes |
GET /v1/changes/history | list all changes |
POST /v1/changes/{id}/decision | record an approve/reject decision |
GET /v1/audit | read the audit log |
By default every agent talks to Anthropic (Claude). You can point an agent at OpenAI or
OpenRouter instead, or — without IronClaw holding any model key at all — route through an
operator-run credential gateway such as OneCLI, which injects the real credential at request
time. In every case the sandbox stays network=none and credential-free: it reaches the model
only through the host model-proxy unix socket, and the host proxy authenticates the call and enforces
the egress allowlist. The backend is chosen per agent group, host-side — a sandbox can never pick
or change its own provider.
Set one or more keys host-side (daemon env, or .env for docker compose). A provider's upstream
host is allowlisted only when its key is present:
A credential gateway is a host-local HTTP CONNECT proxy that holds the real credential and injects
it per request, so neither the control-plane nor the sandbox ever sees a model key. This is how
you power an agent with a ChatGPT/Codex account via OneCLI: IronClaw's codex provider
speaks the ChatGPT Codex Responses API (chatgpt.com) and OneCLI attaches the OAuth credential.
Run OneCLI on the host (its default address is 127.0.0.1:10255), then point the model-proxy at it
and allowlist the host it serves:
When a gateway is set, don't also set a key for the host it serves — the gateway is the credential
path, and the control-plane injects nothing for the gateway's hosts. Under docker compose the
gateway must be reachable from the container, so use host.docker.internal:10255 (Docker Desktop)
or put OneCLI and the control-plane on a shared Docker network instead of 127.0.0.1.
Point IronClaw at a self-hosted OpenAI-compatible endpoint and the whole stack runs on your own
box with zero cloud credentials — nothing leaves the machine. Ollama, LM Studio, vLLM, and
llama.cpp all expose the OpenAI /v1 API (Ollama at http://localhost:11434/v1).
This allowlists the local host, forwards to it over plain HTTP (these servers serve no TLS), and
makes it the deployment-default model, so every agent group without a pinned provider runs local. No
key is required; set IRONCLAW_LOCAL_MODEL_KEY only for the rare local server (e.g. a guarded vLLM)
that requires one. Under docker compose the server must be reachable from the control-plane
container, so use http://host.docker.internal:11434/v1 (Docker Desktop) instead of localhost.
Full walkthrough: Run IronClaw with a 100% local model (Ollama).
IRONCLAW_DEV_PROVIDER / IRONCLAW_DEV_MODEL set the deployment-wide default for any agent group
that doesn't pin one (the env names keep their DEV_ prefix but apply deployment-wide). To choose
per agent instead — a gateway-approved change, like any other config:
Valid --provider values: anthropic (default), openai, openrouter, codex, gemini,
vertex, local (a self-hosted OpenAI-compatible endpoint — Ollama/LM Studio/vLLM/llama.cpp), and
mock (a deterministic, offline backend for demos and tests). Each maps to a model-proxy-allowlisted
upstream; codex targets chatgpt.com and defaults to the gpt-5.5 model, and local inherits the
loopback host from IRONCLAW_LOCAL_MODEL_URL.
--state-dir: the durable gateway change store (survives restart), the
append-only JSONL audit log, and the host keystore.modelproxy; the sandbox never sees it and has network=none. Per-session 256-bit keys are
generated and held by the host and handed to the sandbox via tmpfs at launch — never via an env
var, never baked into the image.--api-addr to the Tailscale interface and firewall the API port on every other
interface. See deploy/README.md.All tests pass on a stdlib-only tree (the encrypted-SQLite CGo path is gated). The black-box
behavioral suite lives in test/parity/ and exercises routing fan-out, engage
modes, session resolution, delivery dedup, the gateway's mandatory-approval flow, and a cross-mount
live-poll spec — over the observable surfaces (the two queues + the API) only.
The frozen contract. internal/contract/** is the single seam both sides import and is
frozen: changing it requires a dated RFC in docs/contract.md and both
CODEOWNERS' approval. Drift here surfaces at runtime as a silent decrypt or routing failure, not a
build error — which is why the freeze is strict. See CONTRIBUTING.md.
IronClaw assumes the sandboxed agent is potentially compromised and designs the boundary so it
cannot escalate. The full threat-and-mitigation table is in
docs/threat-model.md. Highlights:
script-field RCE
class is designed out).PRAGMA query_only, read-only OS bind mount).network=none sandboxes; model calls only via the host proxy with a destination allowlist.Supply chain, written up in the negative: one of our published container images carries two
green SLSA provenance statements and only one of them is true. We could not retract it, so we
documented it instead:
One of our container images carries two green provenance statements. Only one of them is true.
covers the digest, why a green gh attestation verify is necessary and not sufficient, and what
to go check on your own release pipeline.
To report a vulnerability, please open a private security advisory rather than a public issue.
The living roadmap is on the docs site: Road to 1.0 — the single source of truth. It tracks the product road to 1.0 (public launch, web UI, channels, and supply-chain trust) with a status-at-a-glance table and a comparison against the category. For the short, contributor-facing view — direction, what 1.0 means, and help-wanted themes — see
ROADMAP.md. The checklist below is the engineering build-log for the security backend (Waves 0–5) and the hardening that followed.
ironctl resource subcommandsask_user_question + task-management tools (list/cancel/pause/resume/update)Production hardening (Wave 4) — composed into the daemon:
/metrics) and structured (slog) logging — wiredcmd/controlplanedocker compose/readyz gate) in the entrypoint — the api.With* options exist but aren't wired yetrunsc launch in a provisioned, signed-image environmentBeyond the reference design — landed:
network=none (host-brokered over a unix socket); powers the web_search toolIsolator interfacecreate_agent (RFC-0004)/ui/Design-gated (built, off by default):
Questions, ideas, "is this a bug or am I holding it wrong?" — bring them to GitHub Discussions. It's the project's home for Q&A, design discussion, and show-and-tell, and it's where maintainers answer first.
SECURITY.md.good first issue + help wanted). They are small, self-contained, and mentored, and every one
carries the standard labels that contributor boards such as up-for-grabs.net
and goodfirstissue.dev index by. The friendliest starting points are the
two most self-contained subsystems — ironctl scan
(containment scoring; internal/host/scan/) and the
isolation scores dataset (examples/isolation-survey/,
a data-only change). See Contributing for the workflow.We keep the whole community on GitHub — no Discord or Matrix to sign up for. Discussions is the live channel: subscribe to a category to follow along, and watch the repo for Announcements.
See CONTRIBUTING.md for the contract-freeze rule, the code layout
(the control-plane and sandbox trees build against the frozen seam), how to report a vulnerability
(SECURITY.md), our Code of Conduct, and how to open a pull request.
New here? Pick up a good first issue
(or the help wanted subset that is ready to claim).
No account or sign-up needed beyond GitHub itself.
IronClaw is dual-licensed — see LICENSING.md:
© 2026 IronSecCo
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/ironclaw)<a href="https://allmcps.com/mcp/ironclaw"><img src="https://allmcps.com/api/badge/ironclaw?style=directory" alt="Ironclaw on AllMCPs" /></a>