IronCurtain: compiling a plain-English constitution into an enforced agent policy
A secure* runtime for autonomous AI agents. Policy from plain-English constitutions. (*https://ironcurtain.dev)
At a glance
- What is it?
- IronCurtain is a research-prototype TypeScript runtime that turns a short natural-language constitution into deterministic allow, deny and escalate rules applied to every MCP tool call. It is aimed at engineers who want agents to run autonomously without handing them the user's ambient authority.
- Who is it for?
- Adopt IronCurtain if you run MCP-capable agents against a real filesystem or git remote and want the policy to live outside the model, and if you can accept a research prototype whose APIs and configuration formats the README says may change. Do not adopt it if you need a stable interface, if your tooling is not MCP-based, or if you cannot run Docker or Apple container for the stronger Docker Agent Mode.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The ambient authority problem IronCurtain is built around
Most agent frameworks hand the model the same privileges as the person running it: the filesystem, credentials, the network. The README calls this ambient authority and treats it as the root cause. One prompt injection, or drift across a long session, is then enough for the agent to delete files, exfiltrate data or push code. The two usual answers both cost something. A narrow sandbox removes capability until the agent stops being useful. Approving every action removes autonomy. IronCurtain's claim is that the choice is false, because the boundary can be expressed as intent and enforced mechanically. The target user is an engineer running an agent that touches a repository, a shell or an API, who wants it to proceed without a human in the loop for routine work but wants a hard stop on the destructive subset. The README is explicit that this is a research prototype and that APIs, configuration formats and architecture may change, so the audience is closer to early adopters than to teams standardising a platform.
Two session modes, two trust models
The architecture offers two ways to run an agent, and they differ in who owns the agent loop. In Builtin Agent (Code Mode) IronCurtain supplies its own LLM agent, which writes TypeScript snippets that execute inside a V8 isolate. IronCurtain controls the agent, the sandbox and the policy engine together. Every tool call leaves the sandbox as a structured MCP request, hits the policy engine, and only reaches the real MCP server if the decision is allow. In Docker Agent Mode an external agent such as Claude Code or Goose runs in a container with no network access, and IronCurtain mediates the external effects instead: LLM API calls pass through a TLS-terminating MITM proxy that applies a host allowlist and swaps a fake key for the real one, MCP tool calls pass through the same policy engine, and npm or PyPI installs go through a validating registry proxy. The second mode is the more interesting design, because it does not require the agent to be written by IronCurtain at all. It assumes the agent process is hostile and constrains what that process can reach. The README states that in both modes the agent is untrusted and that security is enforced at the boundary rather than by the model following instructions.
What happens between the constitution and the tool call
The pipeline has an offline half and an online half. Offline, you write a constitution: a short document in plain English describing what the agent may and may not do. An LLM pipeline compiles that into a deterministic security policy, and the compiled rules are validated against generated test scenarios. Online, the policy engine sees each MCP tool call and returns one of three decisions: allow, deny, or escalate to the user for approval. The runtime does not consult an LLM to make that decision, which is the point of the compile step. The README summarises the intent as "English in, enforcement out", and the phrase is accurate about where the model sits: in the translation from prose to rules, not in the per-call decision. The default policy is tuned for developer work. Read-only operations are allowed; mutations such as writes, pushes and pull request creation escalate for human approval. The demo in the README shows the escalation path being short-circuited by trusted input: an agent asked to clone a repository and push changes has both git_clone and git_push escalated by the policy engine, but the auto-approver approves them because the user typed a clear instruction in command mode, so no manual /approve was needed. That distinction between an escalated action and an escalated action with trusted intent is the part of the design worth studying closely, because it is where autonomy is actually recovered.
Installing and getting to a first session
The package is published as @provos/ironcurtain under Apache-2.0. The global install is npm install -g @provos/ironcurtain. From source it is git clone, cd ironcurtain, npm install. Node is the first constraint: 22, 24 or 26 are the even-numbered lines the project tests, because isolated-vm requires it. Node 24 and 26 install prebuilt binaries; Node 22 compiles from source at install time and needs a C and C++ toolchain. Odd-numbered lines such as 23 and 25 run but are untested, and the README says ironcurtain doctor warns about them, which makes doctor the first command to run on an unfamiliar machine. Docker is not required but is strongly recommended for Docker Agent Mode. On macOS 26 or later on Apple silicon, Apple container works as an alternative backend, giving a VM per container, and the README says it is used automatically when its services are running; the setting is containerRuntime in ironcurtain config. Provider keys come from the environment, a .env file in the project root loaded through dotenv, or ~/.ironcurtain/config.json written by ironcurtain config. Environment variables take precedence. The supported names are ANTHROPIC_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY and OPENAI_API_KEY. Then ironcurtain setup runs the first-start wizard, which covers the GitHub token, the web search provider and model selection, and writes ~/.ironcurtain/config.json. The README notes the wizard also runs automatically on the first non-mux ironcurtain start, but recommends running it explicitly first. The recommended entry point afterwards is ironcurtain mux, which runs the agent's interactive TUI in a PTY inside a Docker container while every tool call is mediated.
The policy engine is only as good as the constitution and the compile step
The honest limitation is stated by the project itself: the asterisk in "secure" links to a page titled What do we mean by secure?, and the README opens with a warning that this is an early-stage research project. That framing is not modesty for its own sake. Enforcement is deterministic once rules exist, but the rules come from an LLM reading prose, and the README does not describe what happens when a constitution is ambiguous or when the generated scenarios fail to cover a rule. Nor does it describe the false-negative rate of the compile step. A constitution that is vague produces rules that are vague in the same way, and no amount of deterministic execution downstream repairs that. The escalation path has its own failure mode. The demo shows the auto-approver clearing git_push because trusted input signalled intent, which is convenient and also means the strength of the boundary depends on how intent is inferred from what the user typed. Treat the tool as the wrong choice when your actions are not expressed as MCP tool calls, because the boundary is defined at that interface. It is also the wrong choice if you need a frozen API today; the README says configuration formats and architecture may change.
How this differs from a container or a permission prompt
The obvious alternative is to run the agent in a plain container and accept whatever the container allows. That gives you a coarse boundary: the agent can do anything inside the box, and the box is sized by what the task needs. IronCurtain keeps the container in Docker Agent Mode but inserts a policy engine between the agent and its effects, so the unit of control is the individual tool call rather than the process. The other alternative is per-action user approval, which many agent CLIs already provide. That is the same decision point as IronCurtain's escalate, reached by a different route: there is no compiled policy, no constitution, and no offline validation, just a prompt every time. IronCurtain's difference is that allow and deny are decided without asking, and only the escalate set reaches a human, with trusted input able to clear that set. Whether that trade is worth it depends on whether your constitution can be written precisely enough that the compiled rules match your intent. A container alone cannot express "no destructive git operations without approval"; a prompt-every-time cannot express it without asking about everything else too.
Maintenance, releases and licence
The repository is active and not archived, with a last push in September 2026. Recent releases are v0.13.0 in July 2026, v0.12.0 in June 2026, and a separate tag for memory-mcp-server v0.2.0, which indicates the MCP server component is versioned independently of the main runtime. Pre-1.0 version numbers across both lines mean breaking changes are a realistic upgrade cost, and the README's own warning about changing configuration formats reinforces that. The Node constraint adds a second maintenance axis: upgrading Node to an odd-numbered line puts you off the tested path, and Node 22 costs a source build of isolated-vm at install. On the licence side, the project is Apache-2.0, which is permissive and includes an express grant of patent rights from contributors, but this is a description of the identifier and not legal advice. If you embed the runtime in a product, have counsel review the notice and attribution requirements, and note that the README does not discuss how a constitution or compiled policy should be handled as a distributable artefact.
Editorial conclusion
Adopt IronCurtain if you run MCP-capable agents against a real filesystem or git remote and want the policy to live outside the model, and if you can accept a research prototype whose APIs and configuration formats the README says may change. Do not adopt it if you need a stable interface, if your tooling is not MCP-based, or if you cannot run Docker or Apple container for the stronger Docker Agent Mode. Verify first that your Node line is one of 22, 24 or 26 by running ironcurtain doctor, and read SANDBOXING.md for the layer-by-layer trust analysis before you rely on the boundary.
Community notes