一个用于自主AI代理的安全*运行时,其安全策略源自人类可读的章程。
*当有人写"安全"时,你应该立即持怀疑态度。我们所说的安全是什么意思?
[!WARNING] 研究原型。 IronCurtain 是一个早期研究项目,探索如何使AI代理足够安全以真正有用。API、配置格式和架构可能会发生变化。欢迎贡献和反馈。
代理被要求克隆一个仓库并推送更改。git_clone 和 git_push 都被策略引擎升级,但自动审批器自动批准了它们——用户来自命令模式的可信输入(Ctrl-A)提供了明确的意图,因此无需手动 /approve。
自主AI代理可以代表你管理文件、运行git命令、发送消息以及与API交互。但当今的代理框架赋予代理与用户相同的权限,例如对文件系统、凭据和网络的完全访问权限。安全研究人员将此称为环境权限(ambient authority),这意味着一次提示注入或多轮漂移就能导致代理删除文件、泄露数据或推送恶意代码。
常见的应对措施要么是将代理限制在狭窄的沙箱中(限制其有用性),要么是要求用户批准每个操作(限制其自主性)。两者都不令人满意。
IronCurtain 采取了一条不同的路径:用简单的英语表达你的安全意图,然后让系统自行确定执行方式。
你编写一份章程(constitution),这是一份简短的文档,描述你的代理被允许和不允许做什么。IronCurtain 使用LLM流水线将其编译成确定性的安全策略,对生成的测试场景验证编译后的规则,然后在运行时对每个工具调用强制执行该策略。结果是一个可以在你用自然语言定义的边界内自主工作的代理。
关键思想:
IronCurtain 支持两种具有不同信任模型的会话模式:
内置代理(代码模式) — IronCurtain 自己的LLM代理编写 TypeScript 代码片段,在 V8 沙箱中执行。IronCurtain 控制代理、沙箱和策略引擎。每个工具调用以结构化 MCP 请求的形式退出沙箱,经过策略引擎(允许/拒绝/升级),然后才到达真正的 MCP 服务器。
Docker 代理模式 — 外部代理(Claude Code、Goose 等)在 Docker 容器内运行,无网络访问权限。IronCurtain 中介外部效果:LLM API 调用通过 TLS 终止的 MITM 代理(主机白名单、假密钥到真密钥交换),MCP 工具调用通过相同的策略引擎,包安装(npm/PyPI)通过验证注册表代理。
在两种模式下,代理都是不可信的。安全性不依赖于模型遵循指令——而是在边界强制执行。
参见 SANDBOXING.md 了解带有图表的完整架构、逐层信任分析和 macOS 平台说明。
isolated-vm 所需;24 和 26 安装预构建二进制文件,Node 22 在安装时从源代码编译并需要 C/C++ 工具链)。奇数版本(23、25)可运行但未经测试——ironcurtain doctor 会发出警告。container 可作为替代后端(每个容器一个虚拟机;当其服务运行时自动使用——参见 ironcurtain config 中的 containerRuntime)作为全局 CLI 工具(最终用户):```bash npm install -g @provos/ironcurtain
**从源代码(开发版本):**```bash
git clone https://github.com/provos/ironcurtain.git
cd ironcurtain
npm install
1. 设置你的 API 密钥:```bash export ANTHROPIC_API_KEY=sk-ant-...
你还可以将密钥放置在项目根目录的 `.env` 文件中(通过 `dotenv` 自动加载),或者通过 `ironcurtain config` 将其添加到 `~/.ironcurtain/config.json`。环境变量优先级高于配置文件值。支持:`ANTHROPIC_API_KEY`、`GOOGLE_GENERATIVE_AI_API_KEY`、`OPENAI_API_KEY`。
**2. 运行首次启动向导**(在使用推荐的 mux 路径之前显式运行此命令;它也会在首次非 mux 的 `ironcurtain start` 时自动运行):```bash
ironcurtain setup
引导您完成 GitHub 令牌设置、网络搜索提供商、模型选择及其他配置。根据您的选择创建 ~/.ironcurtain/config.json。
IronCurtain 自带一个默认策略,专为开发者体验而设计——允许只读操作,而更改操作(写入、推送、创建 PR)需要人工批准才能执行。设置完成后即可立即使用。
这是使用 IronCurtain 的推荐方式。它让您可以充分发挥代理交互式 TUI(Claude Code 或 Goose)的全部功能,同时 IronCurtain 通过其策略引擎对每次工具调用进行调解——全部都在一个终端内完成。```bash ironcurtain mux
**关键能力:**
- **完整代理 TUI** — 代理在无网络访问的 Docker 容器内的 PTY 中运行。你与它的交互方式与本地运行完全相同。
- **内联升级处理** — 当工具调用需要批准时,升级选择器会在视口上覆盖单键操作(a/d/w 分别对应批准/拒绝/白名单)。使用 `/approve+ N` 为会话剩余部分将域名或路径加入白名单。
- **受信任的用户输入** — 在命令模式(Ctrl-A)下输入的文本会在进入容器之前在主机侧捕获。这会创建一个经过验证的意图信号,自动批准器可以使用该信号——例如,输入“push my changes to origin”将自动批准后续的 `git_push` 升级。
- **标签页管理** — 生成多个并发会话(`/new`),在它们之间切换(`/tab N`,Alt-1..9),关闭它们(`/close`)。多个 mux 实例可以并行运行。
请参阅 [DEVELOPER_GUIDE.md](https://github.com/provos/ironcurtain/blob/master/DEVELOPER_GUIDE.md) 获取完整指南:输入模式、受信任输入安全模型、升级工作流以及键盘参考。
### 非 mux 会话
使用 `ironcurtain start` 执行快速的一次性任务、脚本,或者当你明确想要本地内置代理时。对于正常的交互式 Docker 代理工作,请使用 `ironcurtain mux`。```bash
ironcurtain start "Summarize the files in ./src" # Single-shot mode
ironcurtain start -w ./my-project "Fix the tests" # Single-shot workspace mode
ironcurtain start --agent builtin # Local builtin REPL, no Docker
ironcurtain start --persona my-assistant "Check my email" # Use a persona
IronCurtain 还支持会话恢复(--resume <session-id>)、传统的原始 PTY/调试模式、用于移动审批的 Signal 消息传输,以及用于计划 cron 作业的守护进程模式。守护进程可选配 Web UI(--web-ui),用于基于浏览器的监控和升级处理。详见 RUNNING_MODES.md。
IronCurtain 通过结构化工作流协调多个 AI 代理。内置的 漏洞发现 工作流通过分层 harness 流水线(第1层独立函数 → 第2层多组件 → 第3层完整构建),结合 libFuzzer/AFL++ 覆盖率门控、假设驱动的 discover/triage 状态以及最终的人工报告审查关卡,来搜寻原生代码中的内存安全与逻辑漏洞。设计与编码 工作流则执行计划/设计/实现/审查循环,同样包含人工关卡。每个代理在自己的 Docker 容器中运行,并配有角色特定的策略边界;引擎自动管理状态转换、工件传递和崩溃恢复检查点。该项目开源,完全在本地运行,通过基于宪法的策略引擎强制每个代理的安全策略,并与任何 Docker 容器化的代理兼容——在编码任务方面与 Amazon Kiro 和 Google Jules 相当,但具有一流的安全性以及可扩展的工作流定义格式。

Web UI 是运行工作流的预期接口。 启动守护进程,打开打印的 URL,然后从工作流页面驱动运行——上述状态机图是实时的,代理消息时间线以 Markdown 渲染方式流式呈现,关卡审查包含工作区 + 工件浏览器,历史运行也会保留在列表中。```bash ironcurtain daemon --web-ui
CLI访问可用于脚本编写、自动化和调试:```bash
ironcurtain workflow start vuln-discovery \
"Find memory-safety bugs in libical" --workspace ~/src/libical
ironcurtain workflow start design-and-code \
"Build a REST API with authentication"
请参阅 WORKFLOWS.md 获取完整文档。
默认策略对一般开发工作效果良好,但您可以针对自己的工作流程进行定制:
1. 自定义您的准则(可选但推荐):```bash ironcurtain customize-policy
一个由LLM辅助的对话,生成适合您工作流程的宪章,保存到 `~/.ironcurtain/constitution-user.md`。您也可以直接编辑此文件。
**2. 编译策略:**```bash
ironcurtain compile-policy
将你的规程转换为确定性规则,生成测试场景并进行验证。编译后的产物会输出到 ~/.ironcurtain/generated/。
角色是命名的策略配置文件 — 每个角色都绑定了一份规程、编译后的策略、持久化工作区和语义记忆。使用它们来运行不同角色或访问权限的代理。```bash ironcurtain persona create my-assistant # Create a persona ironcurtain persona compile my-assistant # Compile its policy ironcurtain start --persona my-assistant "Check my calendar"
在复用(mux)模式下,`/new my-assistant` 会使用该角色启动一个标签页。角色也可以分配给 cron 作业。有关定时作业配置,请参阅 [DAEMON.md](https://github.com/provos/ironcurtain/blob/master/DAEMON.md)。
角色也可以通过 [web UI](https://github.com/provos/ironcurtain/blob/master/DAEMON.md#persona-policy-management) 进行管理——浏览、创建、编辑章程,并实时编译策略。由于策略是安全边界,除非守护进程以 `--allow-policy-mutation` 参数启动(默认关闭),否则 web UI 的更改控制为只读。
### 技能
将 `SKILL.md` 包放入 `~/.ironcurtain/skills/<name>/` 下,使特定目的的指导(辅助脚本、确定性检查、领域知识)可供每个 Docker 代理会话使用。合并后的集合被暂存到一个按包划分的主机目录中,并以**只读**方式绑定挂载到容器中,路径为活动代理的原生发现遍历路径——Claude Code 通过 `--add-dir` 指向暂存目录,Goose 扫描 `~/.config/goose/skills/<name>/SKILL.md`。代理自动发现它们,并根据每个技能的前言描述决定何时读取。SKILL.md _格式_是 Claude Code、Goose 和 Codex 采用的开放标准;只有 _发现路径_ 因代理而异。工作流可以在工作流包内提供按状态的技能——请参阅 [WORKFLOWS.md](https://github.com/provos/ironcurtain/blob/master/WORKFLOWS.md#skills)。
## 策略:章程 → 执行
你用纯英语编写意图;IronCurtain 将其编译为确定性规则:```
constitution.md → [Annotate] → [Compile] → [Resolve Lists] → [Generate Scenarios] → [Verify & Repair]
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
tool-annotations compiled-policy dynamic-lists test-scenarios verified policy
.json .json .json .json (or build failure)
@list-name 符号引用发出。dynamic-lists.json,用户可编辑。当没有列表时跳过。所有工件按内容哈希缓存——只有更改的输入才会触发重新编译。
类似于这样的章程条款:```markdown
编译为:```json
[
{ "tool": "git_status", "decision": "allow", "condition": { "directory": { "within": "$SANDBOX" } } },
{ "tool": "git_diff", "decision": "allow", "condition": { "directory": { "within": "$SANDBOX" } } },
{ "tool": "git_push", "decision": "escalate", "reason": "Remote-contacting git operations require human approval" }
]
任何不匹配明确的 allow 或 escalate 规则的调用都默认被 拒绝。```bash
ironcurtain annotate-tools --server filesystem # Annotate one server (merge with existing)
ironcurtain annotate-tools --all # Re-annotate all servers
ironcurtain compile-policy # Compile constitution into rules and verify
ironcurtain refresh-lists # Re-resolve dynamic lists without full recompilation
ironcurtain refresh-lists --list major-news # Refresh a single list
查看生成的 `~/.ironcurtain/generated/compiled-policy.json` — 这些是运行时强制执行的确切规则。
## 配置
IronCurtain 将配置和会话数据存储在 `~/.ironcurtain/` 中:```
~/.ironcurtain/
├── config.json # User configuration
├── constitution.md # User-local base constitution (overrides package default)
├── constitution-user.md # Your policy customizations (generated by customize-policy)
├── generated/ # User-compiled policy artifacts (overrides package defaults)
├── personas/ # Persona directories (constitution, policy, workspace, memory)
├── skills/ # User-global SKILL.md packages, mounted into every Docker session
├── jobs/ # Cron job definitions, workspaces, and run records
├── sessions/
│ └── {sessionId}/
│ ├── sandbox/ # Per-session filesystem sandbox
│ ├── escalations/ # File-based IPC for human approval
│ ├── audit.jsonl # Per-session audit log
│ └── session.log # Diagnostics
└── workflow-runs/ # Shared-container workflow runs (see below)
单会话运行(ironcurtain start、mux 标签页、cron 作业)写入到 sessions/ 下。共享容器工作流运行则写入到 workflow-runs/ 下——参见下一节。
工作流定义可以通过在 YAML 中设置 settings.sharedContainer: true 来选择加入共享 Docker 容器。在该模式下,每个代理状态都在同一个长期存在的容器内运行,并共享一个策略引擎实例;状态之间,编排器会热切换活动策略,使得每个角色都能看到自己的规则。运行的所有产物都存放在单一目录树中:```
~/.ironcurtain/workflow-runs//
├── audit.jsonl # Persona-tagged append-only audit
├── messages.jsonl # Orchestrator message log
├── workspace/ # Agent workspace (filesystem MCP root)
├── bundle/ # Shared container support (claude-state, orientation, sockets, escalations, system-prompt.txt)
├── states/
│ └── ./ # session.log + session-metadata.json per invocation
└── proxy-control.sock # Coordinator UDS for policy hot-swap
对于共享容器工作流运行,不会在 `~/.ironcurtain/sessions/` 下创建每个会话的条目。用户可见的命令(`ironcurtain workflow start|resume|inspect|list`)保持不变。请参阅 [WORKFLOWS.md](https://github.com/provos/ironcurtain/blob/master/WORKFLOWS.md) 了解工作流定义的编写和完整生命周期。
交互式编辑配置:```bash
ironcurtain config
关键配置区域:模型和 API 密钥、资源预算(token/步骤/时间/成本限制)、自动批准升级、网络搜索提供商、审计编辑和记忆服务器 LLM 设置。请参阅 CONFIG.md 获取完整参考。
要通过 LiteLLM 或 OpenRouter 之类的网关路由 LLM 流量(在代码模式和 Docker 代理模式下均适用),请参阅 MODEL_ROUTING.md。
通过 ironcurtain config → Model Providers 使用模型提供商配置文件(例如通过 OpenRouter 的 GLM-5.2,无 sidecar)路由 Docker 代理,然后在 /new 或使用 --provider-profile 选择配置文件——请参阅 MODEL_ROUTING.md。
IronCurtain 提供了六个预配置的 MCP 服务器。所有工具调用(除记忆外)均受编译策略控制。
默认策略允许只读操作;变更(写入、推送、创建 PR)需升级到人工审批。工具使用 server.tool 命名(例如 filesystem.read_file、memory.recall)。请参阅 ADDING_MCP_SERVERS.md 添加你自己的服务器。
在 Docker 代理模式下,容器没有网络访问权限——所有流量都经过 IronCurtain 的 MITM 代理。默认情况下,只有 LLM 提供商域名可达。代理可以通过 proxy 虚拟 MCP 服务器(add_proxy_domain)在运行时请求访问其他域名。每个请求都需要通过升级流程进行人工审批。
批准的域名获得原始穿透隧道——HTTP、HTTPS 和 WebSocket 连接被转发,不进行内容检查或凭据注入。这为代理提供了更大的实用性(调用第三方 API、从外部服务流式传输数据),但意味着到这些域名的流量是未调解的。请参阅 SECURITY_CONCERNS.md 第 2b-i 节了解威胁模型,以及 DEVELOPER_GUIDE.md 了解使用详情。
IronCurtain 围绕一个特定的威胁模型设计:LLM 出现异常。 这可能通过提示注入(恶意电子邮件或网页劫持代理)或多轮漂移(代理在长时间会话中逐渐偏离用户意图)发生。
这是一个研究原型。已知的不足包括:
compiled-policy.json。请参阅 docs/SECURITY_CONCERNS.md 了解详细的威胁分析。
npm test # Run all tests npm test -- test/policy-engine.test.ts # Run a single test file npm test -- -t "denies delete_file" # Run a single test by name npm run lint # Lint npm run build # TypeScript compilation + asset copy
请参阅 [TESTING.md](https://github.com/provos/ironcurtain/blob/master/TESTING.md) 了解完整的测试指南,包括集成测试标志和约定。
### 项目结构```
src/
├── index.ts # Entry point
├── cli.ts # CLI command dispatcher
├── config/ # Configuration loading, constitution, MCP server definitions
├── session/ # Multi-turn session management, budgets, loop detection
├── sandbox/ # V8 isolated execution environment
├── trusted-process/ # Policy engine, MCP proxy, audit log, escalation handler
├── pipeline/ # Constitution → policy compilation pipeline
├── escalation/ # Escalation listener: session registry, TUI dashboard, state
├── mux/ # Terminal multiplexer: PTY bridge, renderer, trusted input
├── persona/ # Persona management (create, compile, resolve)
├── memory/ # Memory server integration (config, annotations, path resolution)
├── signal/ # Signal messaging transport (bot daemon, setup, formatting)
├── daemon/ # Unified daemon (Signal + cron scheduler, control socket)
├── cron/ # Cron job management (scheduler, job store, git sync, policy)
├── docker/ # Docker agent mode, PTY session, MITM proxy, registry proxy
├── workflow/ # Multi-agent workflow engine (orchestrator, state machine, gates)
├── web-ui/ # Web UI backend (JSON-RPC dispatch, event bus, workflow manager)
├── servers/ # Built-in MCP servers (fetch, web search providers)
└── types/ # Shared type definitions
packages/
└── memory-mcp-server/ # Standalone memory MCP server (publishable npm package)
| 服务器 | 工具 | 关键功能 |
|---|
| 文件系统 | 14 | 读取、写入、编辑、搜索文件;目录树;移动;差异计算 |
| Git | 28 | 完整的 git 工作流:状态、diff、log、commit、branch、push/pull/fetch、clone、stash、blame |
| 获取 | 2 | HTTP GET 并转换为 HTML 到 Markdown;网络搜索(Brave、Tavily、SerpAPI) |
| GitHub | 41 | Issues、PRs、代码搜索、通过 ghcr.io/github/github-mcp-server 进行审查;需要 GitHub 个人访问令牌 |
| Google Workspace | 128 | Gmail、日历、云端硬盘、文档、表格——需要通过 ironcurtain auth 设置 OAuth |
| 记忆 | 5 | 持久化语义记忆,集成向量+关键词混合搜索、LLM 摘要和自动压缩。对角色和定时任务会话启用。 |
| 问题 | 指导 |
|---|
| 缺少 API 密钥 | 设置环境变量(ANTHROPIC_API_KEY、GOOGLE_GENERATIVE_AI_API_KEY 或 OPENAI_API_KEY)或在 ~/.ironcurtain/config.json 中添加相应的密钥。 |
| 沙箱不可用 | 操作系统级沙箱需要 bubblewrap 和 socat。安装两者,或在 MCP 服务器配置中设置 "sandboxPolicy": "warn" 以用于开发。 |
| 预算耗尽 | 在 ~/.ironcurtain/config.json 中的 resourceBudget 下调整限制。将任何单个限制设置为 null 以禁用它。 |
| Node 版本错误 | 支持的 Node.js 主线是 22、24 和 26——IronCurtain 测试的偶数大版本(isolated-vm)。24 和 26 安装预构建的二进制文件;Node 22 从源代码编译 isolated-vm,需要 C/C++ 工具链。奇数版本(23、25)未经测试——ironcurtain doctor 会标记它们为警告而非硬性失败。 |
| 策略与意图不匹配 | 查看 compiled-policy.json 以查看生成的规则。运行 ironcurtain customize-policy 来完善你的宪法,然后运行 ironcurtain compile-policy 来重新编译。具体的措辞会产生更好的规则——含糊的措辞导致模糊的策略。 |
| 自动批准未触发 | 自动审批者仅在用户消息明确授权操作时才批准(例如,对于 git_push 使用“push to origin”)。含糊的消息总是升级到人工审查。确认 config.json 中 autoApprove.enabled 为 true。 |
| PTY/mux 终端退出后乱码 | 在该终端中运行 reset 以恢复正常模式。当进程被非正常终止且原始模式未恢复时需要这样做。 |
| Mux/listener:'already running' | 一次只能运行一个 mux 或升级监听器。如果之前的进程已死,~/.ironcurtain/escalation-listener.lock 处的锁会自动清除。如果它仍然存在,检查锁文件中的 PID。 |
| Signal 机器人无响应 | 确认 signal-cli 容器正在运行(`docker ps |