Vigil
Supports migrating the append-only NDJSON ledger to SQLite for concurrent ledger use.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Vigilcheck whether my agent may send this email and log the verdict"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Vigil
English / 英文版: README.en.md
AI 决策账本与熔断内核,带完整的五岔路统筹循环。 让每一个 agent 的决定都可拦截、可追溯、可校准、可签名验证,让每一次派工都走路由、质量门、止损、验收、升级。
你的 agent 会做事,但没人记得它为什么这么做、错了谁负责、下次该改哪条规则。 Vigil 就是补上这一层的那块东西。
┌─ 统筹助理 Orchestrator ──────────────────────────────────┐
│ │
│ ┌→ 止损 ──够差就停──→ STOPPED │
│ │ 路由 ──选不出人──→ 升级人工 → ESCALATED │
│ │ 干活(每一轮执行都落账) │
│ │ 质量门 ──不过──→ 带反馈回路由 │
│ └───验收(四项清单缺一不可)──通过──→ COMPLETED │
└────────────────── 每个岔路都是一次内核裁决 ───────────────┘
↓
只追加账本(哈希链 + Ed25519 签名)
↓
事后梳理 → 校准 → 按题型自动调阈值 → 预警
导出离线验证包(第三方零依赖验证)/ OTel span
agent 想动手 → ┌──────────────┐ → 放行 / 转人工 / 否决
│ Vigil │
│ 硬规则否决 │ → 写入只追加账本(哈希链)
│ 灰区概率判断 │ → 事后回填标签 → 校准阈值
└──────────────┘为什么需要它
现在这一层是断的:
你在用什么 | 它回答的问题 | 它不回答的 |
Langfuse / Phoenix / AgentOps | 发生了什么(trace、span、成本) | 这个决定当时有依据吗 |
OPA / Guardrails / 各种 firewall | 能不能做(规则、黑名单) | 做错的那些,规则该怎么改 |
LLM-as-judge | 这次输出好不好 | 它说 0.9 把握的时候,实际准不准 |
中间那块空着:决定的责任归属。Jev 这类系统一模型的流行恰好暴露了这个缺口 —— 它给了你 150 毫秒返回的概率,却没给你账本、没给你校准、没给你仲裁。概率一旦没有校准闭环,所有阈值都是拍脑袋。
Related MCP server: Dvarapala
它不是什么
不是 agent 编排框架。用 Claude Code、Grok Bot、Cursor 都行,Vigil 只在动手前插一脚。
不是模型。它调用判断模型,不训练模型。
不是日志系统。日志记录发生的事,账本记录做的决定 —— 两者字段都不一样。
0.1 版本,骨架通了,规则库还很薄。不要直接接生产支付。
核心设计
1. 决定是一等公民,不是一条日志
一条 DecisionRecord 至少包含:谁做的、依据什么证据、要求几级授权、实际持有几级、确定性命中了什么、概率判断给了多少、结论是什么、事后被证明对错。缺任何一项,事后就没法复盘。
2. 硬约束绝不用概率
这是和大多数项目最大的分歧。不要让模型去判断逻辑。
金额上限、不可逆操作、对外发送、密钥外泄、禁止目标 —— 全部走确定性规则。精确、可测、可证明,一票否决。
「这活该派给谁」「这份研究够不够」「这个承诺有没有风险」—— 才交给概率模型。
概率模型永远没有否决权,也没有放行权。它只能把一个本来会放行的动作变成"需要人看一眼"。
合起来就是:逻辑守底线,概率做灰区。
2.5 五岔路统筹循环(一比一对应 Jev 的判断点)
岔路 | 问题 | 确定性部分 | 概率部分 |
路由 | 下一个该谁干 | 选出的执行者必须在名册里,否则直接升级 | 在名册内做选择题 |
质量门 | 这份产出够不够 | 检查者结构上永远不是产出人 | 独立复核打分 |
止损 | 继续还是停 | 重试上限、连续失败次数,数数就够 | 进展评分(低于 2 停) |
验收 | 算不算完成 | 四项清单:交付物及位置、独立核验记录、遗留问题声明,缺一项模型说了也不算 | 实质满足度判断 |
升级 | 要不要人接手 | 涉及金额直接 critical | 风险分级(routine/urgent/critical) |
「监督过程」不是独立模块:循环里每个岔路、每轮执行都是一次被哈希链记录的裁决,postmortem(sessionId) 能完整回放每一步为什么这么走。
2.6 冲突仲裁:多 agent 结论相反时由谁定夺
情况 | 谁说了算 | 依据 |
立场一致 | 直接采纳 | 无争议 |
同一个 agent 的多个立场 | 取最严格的那个 | 它自己改主意不算数,取最保守的 |
动作本身触红线 | 否决 | 全票同意也不行 |
有否决立场,它有独立核验证据而对方没有 | 采信否决 | 证据优势 |
有否决立场,它授权等级严格更高 | 采信否决 | 权级 |
有否决立场,但分不出高下 | 交人工 | 证据和权级都定不了 |
只剩"可以继续"与"需要人看"打架 | 模型排序 | 唯一动用模型的地方 |
一条没被驳倒的否决立场,永远不会被自动放行。 模型没有权力把 deny 变成 allow —— 它只能帮你在"都同意放行"和"需要人看"之间排序。这是 fail-closed 在多 agent 场景的延伸。
仲裁记录和普通决策记录在账本里无法区分 —— 这正是要的:仲裁也是一次决定,同样要能被追溯和复盘。
3. 概率判断只能是选择题
Vigil 只向判断模型发送类型化问题(boolean / choice / score),永远不索取自由文本。它返回概率分布,不返回句子。这在结构上就堵死了"模型自由发挥越权"这条路。
4. fail-closed
判断服务超时、返回格式不对、返回缺字段 —— 一律判为无效并升级人工,绝不当作默认放行。failOpen 开关存在,但默认关闭。
5. 五级授权(相对原方案改了一处)
级别 | 含义 | 典型动作 |
L0 | read_only | 查询、检索 |
L1 | draft | 起草、提议 |
L2 | reversible_write | 可撤销的写入 |
L3 | external_or_irreversible | 对外发送、不可逆修改 |
L4 | money | 任何涉及钱的 |
原方案把"金钱"和"不可逆"放在同一级。我们把它们拆开了:内网删库和对外发信都收不回来,破坏半径相近,可以合并;但钱出去了没有任何技术手段能挽回,必须独占一级。
决策循环(DecisionLoop):从"会分析的聊天机器人"到"决策系统"
早期版本的本质缺陷:拉取式 CLI —— 你问一句它答一句,不主动推送、不替你执行、要花钱的动作没有确认关卡、证据没查全就敢下结论。那不是决策系统,那是"带账本的聊天机器人"。
vigil loop 把"决策"做成可运行、可追踪、可中断、可闭环的状态机,而不是一段一次性的分析文字。它直接回应三条硬需求:
实时知道 —— 循环的每一步都发射事件(目标 / 证据 / 裁决 / 闸门 / 执行),边跑边打印,并落盘成事件流,对话关了也能
vigil loop --watch <id>回看。按逻辑自动执行 + 重要节点让你确认后闭环 —— 对外且不可逆(花钱)的动作,必须经过人工确认闸门(
--resume <id> --confirm)才真正执行;可逆/非对外的动作自动放行。证据必须真实完整 —— 决策前必须把该领域要求的证据维度全跑到(权威 / 市场 / 监管 / 财务 / 风险 / 专家 / 替代 / 口碑);缺一类即禁止裁决,从根上堵住"只看线上价就误判超预算"的翻车。
四个支柱
支柱 | 实现 | 解决什么 |
实时事件 |
| 不再沉默地分析,每一步你都看得见 |
证据完整性闸门 |
| 证据不全/未核验就裁决 = 瞎决策,直接封死 |
确认闸门(HITL) |
| 花钱动作 100% 人确认才执行(对标 Operator 金融交易护栏) |
可暂停 / 可续跑 | 状态落盘 | 等确认、等降价时能挂起,不丢进度 |
推送通道(拉→推) |
| 不再只能 |
真实执行适配器 |
| 确认闸门放行后才落地,deny / 未确认绝不执行 |
证据驱动裁决(Reasoning) |
| 根治"证据只打印不进决策"——裁决真正由实时数据驱动 |
决策领域注册表(覆盖人一生,不止购物)
证据闸门之所以能通用,是因为证据维度是跨领域通用词汇,每个生活领域从中挑出"本决策必备"的子集:
维度 | 含义 |
authoritative | 官方/权威来源:政策、法规、官方定价、官方指南 |
market | 市场/商业:价格、供应、竞品、行情、比价 |
peer | 用户/社群真实经验:口碑、踩坑、长期持有反馈 |
expert | 专业人士/专家:医生、律师、行业人士、顾问 |
regulatory | 合规/政策/资质:牌照、认证、补贴、入学/入境、法律风险 |
financial | 成本/财务影响:总拥有成本、隐性费用、现金流、利率、报销 |
risk | 风险/安全:健康、安全、退出成本、爆雷、诈骗、副作用 |
alternative | 替代方案对比:更好 / 更便宜 / 更稳 / 更合规的选择 |
已注册领域(vigil domains 可查看):
领域 | key | 必备维度 | 排除 |
购物消费 | purchase | authoritative / market / regulatory / financial / alternative / peer | — |
医疗健康 | medical | authoritative / expert / regulatory / risk / financial / alternative | market(商业推销不算证据) |
教育升学 | education | authoritative / expert / regulatory / financial / alternative / risk | — |
旅行出行 | travel | authoritative / market / regulatory / risk / financial / alternative | — |
融资理财 | financing | authoritative / regulatory / financial / risk / expert / alternative | market(推销方一面之词不算证据) |
投资理财 | invest | authoritative / regulatory / financial / risk / expert / alternative | market(卖方推销 / 喊单不算证据) |
求职职业 | work | authoritative / expert / financial / risk / alternative / regulatory | — |
居住置业 | housing | authoritative / market / regulatory / financial / risk / alternative | — |
想加新领域(保险 / 婚恋 / 移民 / 养老……),往 DECISION_DOMAINS 加一项即可,证据闸门自动生效。
状态机
goal_received → plan → evidence_gathered → [evidence_complete | evidence_gap→blocked]
→ arbitrating → decision → (deny→completed)
→ (isGatedAction ? gate→awaiting_confirmation → resume→execute : execute)
→ completed实时证据采集(Evidence Provider):让证据自己跑
证据完整闸门要求"真实完整"。但证据不该永远是人手填进 goal.json —— 系统应当能自己抓取能机读的数据,抓不到的维度则诚实标记未核验、交闸门拦截,绝不编造"已核验"。
src/loop/evidenceProvider.ts 定义 EvidenceSource 接口与 gatherEvidence 编排器。同一规范维度可挂多路实时源(如 invest/financial 同时跑汇率、黄金、白银、国债、股指、加密),只要有一路成功核验,该维度即视为已覆盖。已内置的公开 API 真源(均无需 key):
源 | 维度 | 数据 | 沙箱可达 |
| financial | USD/CNY 实时汇率(ECB) | ✓ |
| financial | 现货黄金 XAU / 白银 XAG(gold-api.com) | ✓ |
| financial | 美国 10 年期国债收益率(AlphaVantage,可用 | ✓ |
| financial | BTC / ETH 行情(CoinGecko) | 公网可达,沙箱出网拦截 |
| financial | S&P 500 等股指(Stooq CSV) | 公网可达,沙箱出网拦截 |
| 非机读维度 | 可注入 | 取决于是否接后端 |
vigil evidence fetch <领域> "<问题>" [--extended]:实时采集该领域必备维度证据,输出带 source URL + 抓取时间戳的 JSON;--extended纳入加密 / 股指等公网源。vigil loop <goal.json> --gather [--extended]:证据为空或显式--gather时,先用实时源补抓(已核验的整维度沿用既有、不重复抓)再跑循环。
# 实时抓取 invest 领域证据(汇率/黄金/白银/国债 真抓,加密/股指沙箱不可达则诚实降级)
node src/cli.ts evidence fetch invest "配置20万美金全球分散" --extended
# → 已实时核验:financial(USD/CNY=6.6675 / 黄金 $4045 / 白银 $53.9 / 10Y 国债 4.99%)
# → 未核验:authoritative / regulatory / risk / expert / alternative(需人工/搜索补充)
# 用空证据骨架跑 --gather:live 抓到 financial,但其余 5 维未核验 → 闸门直接 blocked(不假决策)
node src/cli.ts loop examples/goal-invest-200k-skeleton.json --gather
# 用全维度真实核验的目标文件跑完整闭环(financial 实时抓 + 其余维度已核验)
node src/cli.ts loop examples/goal-invest-200k-demo.json --gather --extended设计底线:能机读的实时真抓、附来源与时间戳;抓不到的维度绝不假核验,由完整性闸门拦截,强制人工/搜索补充。
推送通道(Notifier):把"实时知道"从拉变推
LoopEventBus 在每次 emit(目标 / 证据 / 裁决 / 闸门 / 执行……)的同时,会把事件主动推送到你配置的通道,不再只能 vigil loop --watch 事后回看:
企业微信:
VIGIL_NOTIFY_WECOM配群机器人 webhook,把事件文本推到群里。邮件:
VIGIL_NOTIFY_EMAIL_API+VIGIL_NOTIFY_EMAIL_FROM/TO(Resend / Mailgun / SendGrid 形态)发事件邮件。通用 webhook:
VIGIL_NOTIFY_WEBHOOK把整个事件 JSON POST 出去(飞书 / Slack / Discord / Zapier / Make 等任意能收 JSON 的服务)。
未配置任何通道时,总线只落盘、不推送(不假装已通知);推送失败只记录、绝不因通道抖动卡死决策循环。
真实执行适配器(Executor):确认闸门放行后才落地
闭环的"执行"由 ActionExecutor 负责,默认是 DryRunExecutor(只打印执行清单、不发生任何真实副作用)。配置 VIGIL_EXECUTOR_WEBHOOK 后,已确认的动作会被 POST 到你自己的端点(券商 / 开户系统 / 支付 / Zapier),由该端点完成真实下单或开户 —— Vigil 只负责"确认后触发",不持有任何资金凭证。
关键护栏:执行器只在确认闸门放行之后被调用(
deny永远到不了这里,未确认也到不了)。所以"真实下单 / 开户"的安全性来自闸门,而不是执行器本身。
# 配置真实执行端点 + 推送通道后,还原真实的"确认即下单"
VIGIL_EXECUTOR_WEBHOOK=https://your-broker.example.com/vigil-execute \
VIGIL_NOTIFY_WEBHOOK=https://hooks.example.com/vigil \
node src/cli.ts loop examples/goal-invest-200k-demo.json --gather
# → 证据齐 → 仲裁 → ⏸ 确认闸门挂起(每个事件已推送到你的 webhook)
vigil loop --resume lp_xxxx --confirm
# → 确认后:解除闸门 → 触发 WebhookExecutor POST 你的端点(payload 含 decisionBrief 配置方案)→ 拿到外部订单号 → completed证据驱动裁决(Reasoning):让实时数据真的参与决策
之前的致命短板:循环把实时采集到的行情(黄金 / 国债 / FX)只打印、不进裁决,决策实际由 goal 里预写的 positions 立场决定 —— 等于没在决策。
src/loop/reasoning.ts 的 buildBrief() 在完整性闸门放行后、仲裁之前运行,把已核验的金融证据按透明规则转成一份可复核的配置方案(DecisionBrief):
invest/financing领域:实时信号 → 具体仓位(债券随 10Y 收益率在 15/25/35% 三档浮动、权益取到实时标普给 30% 否则降到 20% 转现金、黄金 15% / 白银 5% 对冲、比特币仅取到实时价才给 5% 卫星仓、现金补足到 100%),每一条都引用实时数值 + 时间戳。非金融领域(医疗 / 教育 / 工作 / 购物 / 旅行 / 购房…)也真决策:当证据按
option标签分组(≥2 个方案)时,生成多方案决策矩阵——每个方案在必备维度上的「证据完整度 × 风险红牌」排序,给出推荐方案与诚实警示。排名规则透明:score = 证据完整度(0~1) − (明确风险红牌 ? 0.4 : 0);风险维度缺失(未评估)给温和惩罚 0.15;风险证据含「风险/红牌/失败/拒/极低…」关键词才计为红牌,避免"已评估风险=有风险"的误判。单方案 / 无方案时退化为证据摘要,不编造。诚实边界:抓不到的行情,对应仓位下调 / 移除并明确警示、置信度降级(实时信号 5/6→high、3-4→medium、<3→low),绝不填数字假装算过。
DecisionBrief 随后被 emit 为 reasoning 事件(实时可见)、透传进仲裁账本(extras.decisionBrief)、写入循环状态、并在确认后随执行上下文发给券商端点(payload.decisionBrief)。
# 实跑会看到 reasoning 事件里的真实配置(数据来自上面的实时采集)
node src/cli.ts loop examples/goal-invest-200k-demo.json --gather --extended
# [reasoning] 证据驱动分析:实时信号:USD/CNY=6.67 | 美10Y=4.99%
# [reasoning] 建议配置(合计 100%):美国10年期国债 35% / 标普500指数 20% / 现货黄金 15% / 现货白银 5% / 现金(美元) 25%
# [reasoning] 置信度:low ⚠ 未取到实时标普/加密行情,仓位已下调(沙箱内部分源不可达,公网可正常抓取)统一入口 vigil ask:用一句话发起决策
不用再手搓 goal.json。一句话描述目标,系统自动识别领域 → 实时采集证据 → 证据驱动裁决 → 确认闸门 → 闭环:
# 自然语言 → 自动识别为 invest 领域 → 实时抓 FX/黄金/白银/10Y → 生成配置方案
vigil ask "帮我配置20万美金做全球分散投资,股债黄金都要" --gather --extended
# 自然语言 → 自动识别为 education 领域 → 若证据不全则诚实 blocked(见 goal-edu-daughter.json 演示完整矩阵)
# 识别不出时用 --domain 强制指定;配置 VIGIL_SEARCH_URL 后,政策/专家/风险等维度自动补抓
vigil ask "女儿专升本还是竞赛免试升本科" --domain education --gather领域识别为关键词匹配(投资/融资/医疗/教育/旅行/工作/购房/购物),命中第一个即返回;也可用 --domain <领域> 绕过。
搜索源接真后端(让"证据自己跑"覆盖政策/专家/风险)
机读维度(汇率/贵金属/国债/行情)已实时真抓;政策、专家、风险、替代等非机读维度默认无后端、canServe=false、保持未核验交由闸门拦截。配置真实搜索后端后,这些维度也能自动补抓:
# 设置一个接受 POST { query, dimension }、返回 { answer | snippet } 的搜索代理 / 向量库 / 爬虫
export VIGIL_SEARCH_URL=https://your-search.example.com/query
vigil ask "女儿专升本还是竞赛免试升本科" --gather # 政策/专家/风险维度自动补抓未配置时该系统绝不假核验——相关维度保持未核验,由完整性闸门拦截。
实跑:买 MacBook Neo(预算 4000,旧机不卖)
# 1) 起一个循环,加载全维度证据(见 examples/goal-neo-purchase.json)
node src/cli.ts loop examples/goal-neo-purchase.json
# 打印:6 个证据维度(权威/市场/监管/财务/替代/口碑,全部已核验)
# → 证据完整放行 → 裁决 require_human → ⏸ 确认闸门挂起(awaiting_confirmation)
# 2) 你看过事件流、确认无误后,放行闭环
node src/cli.ts loop --resume lp_xxxx --confirm
# 打印:解除闸门 → 闭环执行(dry-run:比对最优价、锁定≤4000渠道、生成下单清单)
# 3) 随时回看某循环的每一步
node src/cli.ts loop --watch lp_xxxx关键纠正:首轮只查线上价(5499)一度误判"超预算否决"。补全国补 15%(4599→3909)、教育 3999、学生补贴 + 线下 ~4030 之后,补贴后实付压线或低于 4000,预算约束满足 —— 这正是"证据完整"闸门存在的意义。
同一套机制已用非购买领域验证:examples/goal-medical.json(冠心病择期支架手术,6 维度全核验 → 闸门挂起 → 确认闭环)、examples/goal-financing.json(20 万经营贷,覆盖融资领域全维度且排除"推销方一面之词" → 闸门挂起 → 确认闭环)、examples/goal-invest-200k-live.json($200K 全球分散配置,6 维度真实核验:含实时抓取 USD/CNY 汇率 + 美联储利率 / 中国跨境合规 / 估值风险 / 资管建议 / 标的对比的 WebSearch 来源 → 仲裁 require_human → 确认闸门 → 闭环输出配置清单)。另有 examples/goal-invest-200k-skeleton.json 用于演示 --gather 在证据不全时诚实 blocked。决策系统不是"买电脑专用",而是覆盖衣食住行、工作、购物、旅行、融资、投资、医疗、教育的通用框架。
goal.json 形态
{
"sessionId": "buy-macbook-neo-2026-10-28",
"question": "是否购买 MacBook Neo(办公,预算 4000)",
"action": { "kind": "purchase_laptop", "target": "...", "reversible": false, "external": true, "moneyUsd": 563 },
"positions": [ /* 各立场(allow/deny/require_human)+ 证据 */ ],
"evidence": [ /* 该领域必备维度;每条含 dimension(规范维度,闸门据此判定)/channel(来源标签)/source/verified;无 dimension 时回退到 channel */ ],
"evidenceSpec": "purchase" // 领域 key:purchase / medical / education / travel / financing / invest / work / housing
}测试覆盖:npm test 已含 tests/loop.test.ts(决策循环 / 领域注册表 / 完整性 / 未核验阻塞 / 事件落盘 / 闸门挂起 / deny 不可被执行 / resume 确认·未确认 / autoConfirm / 可逆动作自动放行)、tests/evidenceProvider.test.ts(实时源与采集编排)、tests/reasoning.test.ts(证据驱动裁决:债券随 10Y 浮动、缺失行情诚实降级、置信度分级、非金融多方案决策矩阵按完整度×风险红牌排序、风险红牌关键词判定、HttpSearchSource 接后端、无后端诚实不假核验)与 tests/decisionSystem.test.ts(真实数据源多路采集、推送通道企微/邮件/webhook、执行适配器 dry-run/webhook、确认闸门放行后才触发、brief 进入循环状态并随执行 payload 传递的集成测试)。
快速开始
要求 Node ≥ 22.18(原生支持 TypeScript,无需构建)。
git clone <this-repo> && cd vigil
node examples/demo.ts # 单线场景:裁决、复盘、校准、预警
node examples/company.ts # 一家 AI 公司:统筹助理带四名工人跑三个任务,
# 覆盖退回重做、自产自验被识破、虚假完成止损
node examples/resumable.ts # 可续跑统筹循环:外部 agent 扮演工人,跨调用跑完
node examples/arbiter.ts # 冲突仲裁:四个案例走完仲裁阶梯的每一级
npm test # 129 个测试demo 会打印:每一步的裁决与理由、事后梳理、置信度校准、预警。
真实使用时给上判断模型的 key:
export TYPESAFE_API_KEY=tsf_xxx没有 key 会退回确定性的 MockJudge —— 同样的输入永远同样的结论,适合写测试和复现事故。
接入方式
先扫一遍 —— vigil scan
治理配置不该靠人肉读文档写出来。一条命令先看清"你的 agent 到底能干什么":
vigil scan # 扫当前目录
vigil scan /path/to/app # 扫别的项目
vigil scan --write # 把建议策略写进 vigil.config.json,立即生效它做三件事:
1. 盘能力。 读 .mcp.json、~/.claude.json、.cursor/mcp.json、.claude/settings.json、
package.json 的 scripts、根目录的 shell 脚本,给每一项推断授权等级:
等级 | 含义 | 例子 |
L0 | 只读 |
|
L1 | 草稿 | 生成提案、写初稿 |
L2 | 可逆写入 |
|
L3 | 对外或不可逆 |
|
L4 | 资金 |
|
名字看不出来的(internal-crm)按 L3 保守处理并标 ?,等你确认一次,不猜。
2. 报风险。 只报真正要动手的事:资金能力在工作目录里、
凭据文件(.env)和文件访问能力同时存在、某个 server 的根目录被设成了整个 ~、
钩子根本没挂、账本里有 N 条升级没人批。
3. 用历史校准。 如果账本里已有记录,它会告诉你哪类动作被否过多少次、 高危动作是不是集中在了一个 actor 身上。这些是真实的规则验证样本。
--write 生成的 vigil.config.json 会被内核在启动时读取并立即生效
(VIGIL_CONFIG 可改路径)。配置文件只能收紧内置默认策略,删掉它就回到保守默认值。
规则包 —— 事故形态可以搬运
护城河不在代码,在规则库。所以规则库必须能被抄走、被搬运、被非工程师维护。
规则包是声明式 JSON,不是代码 —— 装进流程的东西不会执行任何代码, 即使来源不可信,它最多让一条规则永远命中:
vigil rules list # 有哪些包
vigil rules show healthcare.patient-data # 看细节
vigil rules check ./my-pack.json # 校验,不安装
vigil rules install healthcare.patient-data # 安装,下次启动生效内置四个行业包:医疗患者数据、付款审批、多租户隔离、代码发布。
完整格式见 docs/rule-packs.md。
可分发,也因此可被攻击。 包一旦能从别人那儿下载进来, "别人写的东西"就能进你的决策链路。四道防线:
防线 | 做什么 |
指纹 | 索引记内容的 sha256,装之前必须对上 |
签名 | 有签名的包要验签;没签名的会明确警告"没人给它背书" |
信任锚在本地 | 索引自带的公钥不算数 —— 能改索引就能换掉公钥和签名一起伪造。公钥必须由你显式信任( |
只能收紧不能放松 | 包的策略补丁只能压低金额上限、加长禁止清单、降低授权。装一个恶意包放宽不了你的任何一项防护 |
vigil rules publish my-pack.json --sign # 登记进索引并签名
vigil rules search 医疗 # 检索
vigil rules install healthcare.patient-data # 从索引装(先过指纹与签名)
vigil trust add signer.pem 某医院 # 信任签名者的公钥特性 | 为什么这么定 |
不用正则,只用子串和 | 规则包可能来自外部,正则的 ReDoS 能卡死你的进程 |
规则的 | 复盘时要看得懂,规则过时时要知道改哪条 |
| 否决是确定的;升级要占一个人,只有需要人判断时才用 |
包的 | 授权是 |
钩子 —— 让约定变成强制(推荐)
提示词里写"发邮件前请确认",模型抽风时就失效了。所以判断点必须放在执行边界上:
Vigil 接住 6 类生命周期点,不只是动手前:
事件 | 做什么 |
| 裁决 —— 唯一能真正阻止动作的时机 |
| 记录执行结果;扫描工具输出里的凭据(凭据顺着响应流出去,只有事后看得见) |
| 失败也落账 |
| 落账,并把本次会话的监督状态注入 agent 上下文 |
| 给会话封口:累计决策数与花费 |
紧急制动 —— 一条命令,让后面所有动作立刻全部转人工,直到你手动解除:
vigil kill --reason "agent 在批量改生产配置" # 拉闸
vigil unkill # 解闸不做成"直接拒绝",是因为拒绝了连"停下来看看发生了什么"都做不到。
解除动作本身留痕(.vigil/killed.released),事后能查是谁解的。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash|Write|Edit|MultiEdit|WebFetch|mcp__.*",
"hooks": [{ "type": "command", "command": "node /绝对路径/vigil/src/cli.ts hook claude", "timeout": 10 }]
}
]
}
}放进 ~/.claude/settings.json 即生效。三种结论映射:allow → 直接执行,require_human → 弹给用户确认,deny → 硬拦。
钩子自身出故障(分类失败、超时 4 秒、载荷损坏)永远退出码 0 且不阻断 agent —— 那是我们的 bug,不该由用户承担。
上线顺序别跳:先 VIGIL_SHADOW=1 跑一周,只看账本不拦截,确认误杀率可接受再开拦截。没跑过影子模式就开拦截,第二天钩子就会被关掉。
完整说明见 docs/hooks.md,配置模板见 examples/claude-settings.json。
命令包装器 —— 任何客户端都能用
vigil run -- rm -rf build # 退出码 3,未执行
vigil run -- npm test # 退出码 0,正常执行退出码 | 含义 |
0 | 放行并执行 |
2 | 被否决 |
3 | 需人工确认,未执行 |
CLI
vigil kill [--reason "原因"] 紧急制动:此后所有动作一律转人工
vigil unkill 解除紧急制动
vigil status 当前账本与制动状态一览
vigil rules list|show|check|install|search|publish|verify 规则包:查看、校验、安装、检索、登记
vigil trust list|add|remove 信任的签名公钥(规则包验签用)
vigil ledger-migrate <源> <目标.db> 把 NDJSON 账本迁到 SQLite(并发用)
vigil scan [目录] --write # 扫描 agent 能力并生成治理配置(--write 立即生效)
vigil arbitrate <文件.json|-> 多 agent 结论冲突时定夺
vigil loop <goal.json> [--auto-confirm] [--gather] 决策循环:实时事件+证据完整性闸门+确认闸门+闭环执行(--gather 实时补抓证据)
vigil loop --resume <id> [--confirm] 从挂起恢复(确认后闭环执行)
vigil loop --watch <id> 实时回看某循环的事件流
vigil evidence fetch <领域> "<问题>" 实时采集该领域必备维度证据(附 source URL + 抓取时间戳)
vigil domains 列出所有支持的决策领域(衣食住行/工作/购物/旅行/融资/医疗/教育…)
vigil decide request.json # 或从 stdin 读:vigil decide -
vigil ledger # 列出所有决策
vigil verify # 校验哈希链 + Ed25519 签名
vigil keygen # 生成签名身份,之后的记录全部签名
vigil bundle # 导出离线验证包(第三方零依赖验证,见 verify-standalone.mjs)
vigil thresholds --write # 从你回填的标签按题型算推荐阈值,写回配置立即生效
vigil approvals # 列出待人工审批的升级项
vigil approve <id> approved "同意" --by human/boss # 审批落账,绑定记录哈希
vigil export-otel spans.jsonl # 导出 OTel GenAI span,直接喂 Langfuse/Phoenix
vigil postmortem <sessionId> # 事后梳理
vigil calibrate proceed # 置信度校准 + 阈值扫描
vigil alerts # 扫描预警
vigil label <decisionId> wrong "客户否认需求" # 回填结果判断模型三选一,按优先级:
环境变量 | 后端 | 适用 |
| 本地决策服务(strands-decider / laya,/v1/systemone 方言) | 零成本、数据不出门、可用自有数据微调 |
| TypeSafe Jev 云端 | 不想本地跑模型 |
都不设 | MockJudge(确定性) | 测试、复现事故 |
MCP(推荐)
vigil mcp给 Claude Code:
claude mcp add vigil -- node /abs/path/to/vigil/src/cli.ts mcp暴露 10 个工具。每个工具都带 annotations,含协议标准的
readOnlyHint / destructiveHint,以及我们自有的 vigilAuthority
(这个工具需要几级授权)与 vigilEffect(它会改什么)——
MCP 协议本身只有两个布尔位,表达不了五级授权。
单点决策(6 个):vigil_decide、vigil_postmortem、vigil_verify、vigil_alerts、vigil_calibrate、vigil_label。
统筹循环(3 个):vigil_task_start、vigil_task_submit、vigil_task_status。
冲突仲裁(1 个):vigil_arbitrate。
约定:agent 在动手之前必须调用 vigil_decide,拿到 allow 才执行。 这不是靠自觉,是靠 hook —— 在 PreToolUse 里拦。
统筹循环:让外部 agent 扮演工人
原本统筹循环只能在同一个进程里跑完,外部 agent 接不上 —— 它没法中途接管工人角色。 现在它是一个可跨调用续跑的状态机,干活的可以是另一个进程:
// 1. 开任务:Vigil 决定下一个该谁干
{"name": "vigil_task_start", "arguments": {
"task": "给客户 ACME 写一封报价邮件",
"roster": [{"id": "bot/writer", "role": "写手"}, {"id": "bot/checker", "role": "复核"}],
"taskId": "t1"
}}
// → {"turn": {"kind": "work", "workerId": "bot/writer", "attempt": 1,
// "instructions": "...", "requirements": [...]}}
// 2. 外部 agent 按指令干活,然后交回
{"name": "vigil_task_submit", "arguments": {
"taskId": "t1",
"summary": "写好草稿",
"claim": "报价邮件已完成",
"deliverableUri": "drafts/quote-acme.md",
"leftoverIssues": "",
"evidence": [{"id": "ev_check", "producedBy": "bot/checker", "verified": true}]
}}
// → 缺项则 {"turn": {"kind": "work", "attempt": 2, "feedback": "验收未过,缺:..."}}
// 齐全则 {"turn": {"kind": "completed"}}requirements 会把验收的四项清单直接告诉执行者,不让它猜。
feedback 会把上轮被拒的具体原因带到下一轮,不用瞎改。
一个要知道的局限:如果同一个 agent 既扮演执行者又扮演复核者, "独立核验"就退化成形式独立 —— 账本会如实记下谁产出了证据、谁声称完成, 但真正的独立性需要两个进程。这一点我们没有假装解决。
SDK
只要裁决(单点决策)
import { Kernel, Ledger, JevJudge, defaultPolicy } from 'vigil-oversight';
const kernel = new Kernel({
ledger: new Ledger('.vigil/ledger.ndjson'),
judge: new JevJudge({ apiKey: process.env.TYPESAFE_API_KEY! }),
policy: defaultPolicy({ moneyCapPerAction: 50 }),
});
const verdict = await kernel.decide({
sessionId: 'sess_1',
actor: 'bot/outbound',
intent: '把报价单发给客户',
action: { kind: 'send_email', target: 'ceo@acme.com', reversible: false, external: true },
evidence: [
{ id: 'ev_pricing', producedBy: 'bot/researcher', claim: '对方有 3 档定价', verified: true },
],
questions: [
{ name: 'proceed', type: 'boolean', instructions: '这一步是否应当继续', floor: 0.8 },
{ name: 'risk', type: 'boolean', instructions: '是否构成商业承诺风险', escalateWhenTrue: true, floor: 0.75 },
],
});
if (verdict.outcome !== 'allow') throw new Error(`被拦截:${verdict.reason}`);要完整回路(统筹助理带工人跑任务)
import { createPipelineKernel, Orchestrator, JevJudge, Ledger } from 'vigil-oversight';
const kernel = createPipelineKernel(
new Ledger('.vigil/ledger.ndjson'),
new JevJudge({ apiKey: process.env.TYPESAFE_API_KEY! }),
);
const company = new Orchestrator(kernel, { maxAttempts: 3 });
const report = await company.runTask('sess_1', 'task_1', '写一份行业调研', [
{ id: 'bot/researcher', role: '研究员', run: async (ctx) => ({ /* 产出 */ }) },
{ id: 'bot/writer', role: '写手', run: async (ctx) => ({ /* 产出 */ }) },
]);
// report.status: completed | stopped | escalated
// report.steps: 每个岔路的走向,人能直接读懂工人只管干活和交证据;路由、质量门、止损、验收、升级全部由 Orchestrator 驱动,每一步过内核、落账本。ctx.feedback 会告诉你上一轮为什么被打回。
四项指标
不看这四个数,这套系统就是在自娱自乐。
指标 | 定义 | 健康区间 |
决策可追溯率 | 被放行的动作里,能追到证据链的比例 | > 90% |
虚假完成率 | 被放行、事后被证伪的比例 | < 5% |
自主完成率 | 无需人工介入的比例 | 越低说明越保守,不是越低越好 |
单位任务成本 | 每个成功任务的累计花费 | 自己定基线,重点看突变 |
与相邻项目的关系
项目 | 定位 | 与 Vigil 的关系 |
| 12 个判断工具封装 | 可直接作为 Judge 后端 |
Langfuse / Phoenix | trace 与评估 | Vigil 记录决定,它记录过程,互补 |
OPA / Rego | 策略引擎 | 我们故意不用 Rego:0.1 阶段 YAML 化的谓词函数更快出活,等规则过百条再换 |
Guardrails AI | 输出校验 | 管的是模型输出,Vigil 管的是动作 |
存储层
两种后端,哈希链语义完全一致 —— 哈希只覆盖记录内容,与存储方式无关, 所以换后端不会让已有的验证包失效。
后端 | 什么时候用 | 特点 |
NDJSON(默认) | 单进程、个人使用 | 零依赖、人可读、可以直接 |
SQLite | 多个进程 / 多个 agent 同时写 | Node 22 内置 |
选哪个由路径决定:.db / .sqlite 结尾就用 SQLite。
export VIGIL_LEDGER=.vigil/ledger.db # 切到 SQLite
vigil ledger-migrate .vigil/ledger.ndjson .vigil/ledger.db # 迁移现有账本SQLite 后端用 WAL 模式 + BEGIN IMMEDIATE:写锁排队而不是报错,
"读上一条 → 算哈希 → 写入"是一个原子操作,所以多个进程同时写也不会算错 prevHash。
实测:三个进程各写 40 条,共 120 条,哈希链完整,序号连续。
已知局限
诚实列出来,免得你踩:
SQLite 后端还是实验特性。Node 22 的
node:sqlite尚未转正,接口可能变。 我们屏蔽了它的警告提示(VIGIL_SHOW_SQLITE_WARNING=1可以放出来),但这不改变它随时可能变的性质。NDJSON 后端不支持并发写。要用多个进程同时写,请切到 SQLite。
规则库很薄。默认规则只覆盖了最常见的事故形态。真正的护城河是规则库随事故积累变厚,不是代码。
校准需要标签。没有事后回填,
calibrate和thresholds就是个空壳。这是运营问题,不是技术问题。判定不了"意图是否真诚"。agent 说它要发邮件,实际可能干别的。Vigil 看的是动作形状,不是自述。要防这个得在工具边界强制执行,不在这一层。
阈值的"按题型建议"只覆盖放行方向。风险型问题(escalateWhenTrue)的自动标定还没做,因为放行/拦截语义相反,需要更大样本才可靠。
合规对照
采购或审计场景看 docs/compliance-mapping.md:OWASP Agentic Top 10 逐条对照(4 项完整覆盖、5 项部分覆盖),EU AI Act 相关义务映射。
路线图
决策内核(硬规则 + 概率灰区 + fail-closed)
哈希链账本与校验
事后梳理 / 校准 / 预警
MCP stdio 服务端(零依赖)
Claude Code PreToolUse 钩子 + 通用命令包装器
五岔路统筹循环(路由 / 质量门 / 止损 / 验收 / 升级)
Ed25519 账本签名 + 离线验证包(verify-standalone.mjs)
本地决策模型接入(strands-decider / laya / kev,/v1/systemone 方言)
按题型阈值自动建议与生效(校准闭环最后一公里)
审批事件绑定记录哈希 + 升级回调(人工可续命)
OTel GenAI span 导出(进 Langfuse/Phoenix 生态)
vigil scan上手工具:扫描能力清单与风险,一键生成生效的治理配置统筹循环接入 MCP(可续跑状态机,外部 agent 扮演工人)
冲突仲裁
Arbiter:证据与权级定夺,未被驳倒的否决立场绝不放行规则包(声明式 JSON,4 个内置行业包,可安装可校验)
存储层换 SQLite(node:sqlite 内置,多进程并发写,哈希链语义不变)
决策循环 DecisionLoop:实时事件总线 + 证据完整性闸门 + 确认闸门(HITL) + 可暂停续跑
决策领域注册表:衣食住行 / 工作 / 购物 / 旅行 / 融资 / 投资 / 医疗 / 教育(新增领域往
DECISION_DOMAINS加一项即生效)证据驱动裁决 Reasoning:金融实时信号 → 具体仓位;非金融证据 → 多方案决策矩阵(完整度 × 风险红牌排序)
实时证据采集层:汇率 / 黄金 / 白银 / 10Y 国债 / 加密 / 股指多源真抓(附 source+时间戳),抓不到诚实 blocked
推送通道 Notifier:企微 / 邮件 / 通用 webhook(拉→推,每次事件主动推送)
真实执行适配器 Executor:确认闸门放行后才触发(dry-run / webhook 两种),deny / 未确认绝不执行
统一入口
vigil ask:一句话自然语言 → 自动识别领域 → 实时采集 → 证据驱动裁决 → 闭环搜索源接真后端:配置
VIGIL_SEARCH_URL后政策 / 专家 / 风险等维度自动补抓(未配置诚实不假核验)GitHub 顶级 AI 项目 Top 50 调研(报告)+ MCP 协议合规与工具授权标注
竞品对标 ECC 实跑(报告):多事件钩子、输出侧凭据检测、告警级规则、紧急制动
规则包索引与分发:指纹 + 签名 + 本地信任锚 + 只能收紧不放松
vigil init一键接入 +vigil doctor体检(对标 ECC 的 doctor/repair)
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Pre-execution governance for AI agents. Deterministic PASS/FAIL/REVIEW verdicts, replayable proof.
Agent routing, safety preflight, execution receipts, best execution and verified outcomes.
Supervised API-write gateway for AI agents with policy, human approval and execution receipts.
The system of record for AI agent authority: playbooks, routed policy questions, reusable rules.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceEnables controlled AI-agent access to enterprise-shaped tools with a deny-by-default gated write path, human approval, dry-run execution, and append-only audit logging.1-
- AlicenseNot gradedqualityBmaintenanceProvides permission gates and tamper-evident audit logging for AI agent tool executions, with declarative policies, consent ladders, and hash-chained verification.MIT
- AlicenseAqualityAmaintenanceGates every AI agent tool call against your policy before it runs, then writes a hash-chained, tamper-evident record of what was decided and what happened. Anyone can verify that record offline, without your software, your systems or any key you hold.4529 PyPI15AGPL 3.0
- AlicenseNot gradedqualityBmaintenanceEnables governed tool-calling agents with policy decisions, optional human approval, hash-chained audit logging, and deterministic evaluation.MIT