mcpField
E
Estigia

Estigia

本地服务
github.com/asanabrial版本控制1今天更新

关于 Estigia

Estigia 在现有 AI 编码 Agent 下方执行工作流检查。它记录问题认领、核对后续写入,并将评审结论绑定到确切提交,在不可逆的 Git 操作前重新验证。

主要功能

  1. 01记录问题认领
  2. 02按认领核对写入
  3. 03评审绑定到确切字节
  4. 04推送与合并门禁
  5. 05Agent 配置与状态工具

适用场景

  1. 01防止处理问题时修改无关文件
  2. 02提交变化后使评审结论失效
  3. 03推送前检查问题跟踪器状态
  4. 04为编码 Agent 安装生命周期门禁

MCP 相关

Estigia 包含 MCP 服务,可通过 `npx -y @asanabrial/estigia mcp` 启动。其容器镜像通过 stdio 运行该服务,但不含 `git` 或 `gh`。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

暂未收录安装方式

我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。

代码仓库
安装包
npm@asanabrial/estigia0.1.1
cargoestigia0.1.1

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

estigIA — AI harness. 轻量。本地。Agentic。像素风夜间书桌:一只猫坐在控制台前,屏幕显示 HARNESS CONTROL,状态为 running,流程稳定,Agent 在线;旁边是一串亮起的卡片——输入、路由器、工具、记忆、输出——由一道发光的数据流连接

安装 • 工作原理 • 工具 • 配置 • 它不衡量什么

CI 许可证:MIT Rust 1.97+ MCP:36 个工具 Linux、macOS、Windows Glama MCP 服务


estigIA — AI 编码 Agent 的工作流权威

你的 Agent 说它已经认领了问题。它说评审已通过。它说分支是最新的。 Estigia 会把这些从你信以为真的话,变成经过核验的事实:认领记录在本地工作流存储中(~/.estigia/state.db),此后 Agent 所做的每次写入都会根据这条记录进行衡量,而评审结论则绑定到精确的字节——因此,之后的推送会使其失效,也不需要任何人记得去留意。

一个二进制文件。它运行在你已有的任意 Agent 之下,不会运行你的模型。唯一例外是评审:launch_review_input 会针对某个审查视角启动评审 CLI,充当反驳者或验证者:它会使用在 PATH 中找到的第一个 claude 或 codex,且没有设置项可供选择。手动调用 record_lens_report、record_refutation 和 record_validator_result 会被拒绝,并返回 recorded-by-capture-only;只有捕获流程可以写入这些记录。

誓言之河。Agent 作出的承诺,会绑定到精确的字节。

Leteo 是遗忘之河。Estigia 是誓言之河——众神以河水起誓,违背誓言便要在奥林匹斯山外受罚九年。同一个冥界中的两条河,职责恰好相反:一条让你遗忘,另一条让你信守承诺。

使用感受

大多数时候,什么也不会发生。你不会调用 Estigia,你的 Agent 也不会,除了认领它即将处理的问题之外。之后它就一直在后台运行,只有在它说“不”时,你才会注意到它。

未认领任何问题的运行完全不受它管辖,行为与以前完全相同——每个会话都设门禁,那是锁,不是工作流。Agent 认领问题 12 的那一刻,它写入的每个文件都会根据这条认领进行衡量;每个无法撤销的步骤——推送、合并、打标签、发布——都会在执行前重新核验存储中的认领记录。

当它拒绝操作时,会说明读取了什么,以及该怎么处理:

$ git push origin HEAD
estigia: git push: gh issue view failed (1): none of the git remotes ... (read-failed)
  [world-action] the tracker could not be read; write nothing and retry the read
error: failed to push some refs

无法读取跟踪器和你不得推送是不同的答复。Estigia 不会把前者变成后者。这种区分正是大部分设计的核心。

它不是什么

它不是记忆(Leteo 负责这个),也不是规划。 它不会运行你的工作模型(它启动的唯一进程是审查器),不会定义你的工具,也不会管理你的上下文——它位于你现有 Agent 的下层,只负责一件事:工作流权限。任何不符合这句话的功能都不会加入。

安装

# Linux and macOS
curl -fsSL https://raw.githubusercontent.com/asanabrial/estigia/main/scripts/install.sh | sh
# Windows
irm https://raw.githubusercontent.com/asanabrial/estigia/main/scripts/install.ps1 | iex

就是这些。无需预先安装任何东西——无论是 Rust、Python,还是运行时。压缩包是 预构建二进制文件,每个脚本都会将下载内容与旁边发布的校验和进行核对,并拒绝安装任何校验不符的文件。二进制文件会放在 ~/.local/bin,或在 Windows 上放到 PATH 中;ESTIGIA_INSTALL_DIR 可更改安装位置,ESTIGIA_VERSION 可指定非最新版本的标签。

如果机器上已经有 Node,npm 也能使用同一安装程序:

npx -y @asanabrial/estigia setup --all

该软件包不包含二进制文件。它会获取同一个压缩包,核对同一个 .sha256,以相同方式记录候选版本,将其放入同一目录并运行;关于它为何不会从 npm 缓存运行 Estigia,请参阅 docs/lifecycle.md。MCP 注册表中的条目启动的也是同一个软件包,命令为 npx -y @asanabrial/estigia mcp。其中的软件包名称是 mcp-name: io.github.asanabrial/estigia。这里将其直接写出而非放在注释中,是因为注册表会读取 crate 的 README 中这一行来接受 cargo 软件包,而 crates.io 会删除 HTML 注释。

如果要自行构建(这是唯一需要 Rust 的方式):

cargo install estigia                                     # the published crate
cargo install --git https://github.com/asanabrial/estigia  # main as it stands

之后,源码构建会一直被视为源码构建:它没有安装程序记录,因此,在向你的 Agent 写入内容的命令执行前,必须先指定 --allow-source-build。这是有意为之——请参阅 docs/lifecycle.md,了解该记录能证明什么,以及其证明范围为何比听起来更窄。

如果你正在开发 Estigia 本身,scripts/build-install.sh(macOS 和 Linux)或 scripts/build-install.ps1(Windows)可以在代码检出目录中完成整个流程:要求 rustup 和 cargo 已在 PATH 中;如有需要,通过现有的 rustup 安装固定版本的工具链;编译锁定的发布版本;通过 Cargo 重新安装;为每个 Agent 运行 setup;最后运行 status 和 doctor。请先关闭正在使用 Estigia 的 Agent——Windows 无法替换正在运行的二进制文件,任何平台也都可能拒绝替换被 Agent 锁定的文件。

目前没有发布容器镜像。根目录中的 Dockerfile 使用固定版本的工具链构建镜像,其中只包含服务:通过 stdio 运行 estigia mcp,不包含 git 和 gh,因此,在容器中,任何访问跟踪器的工具都会拒绝执行。该镜像供需要通过运行容器来检查服务的目录使用。

在你的 Agent 中完成设置

安装二进制文件本身不会带来任何变化。这一步会让 Estigia 介入 Agent 的工作流程:

estigia tui                    # the setup screen: a list of agents, each opening onto its own settings; `s` shows what it will write; `u` uninstalls an installed agent, or the push guard from the menu, after listing what would go
estigia setup claude-code      # or just one, without the screen
estigia setup --all            # or all of them

无论何时,都可以先检查再行动:

estigia setup claude-code --dry-run   # exactly what would change, writes nothing
estigia status                        # what is installed, where, and what runs still hold
estigia sessions                      # the sessions seen on this machine, the issue each holds, and which went silent
estigia sessions send <run-id> "..."   # leave a message in another session's mailbox; its next hook point delivers it
estigia doctor                        # skill, skill-assets, gh, remote, guard, prune, pi-subagents, lockfiles, permission — read-only
estigia prune                         # branches and checkouts no delivery owns; --confirm removes
estigia changes                       # uncommitted work in every checkout, held or orphan — read-only
estigia flush --status               # the GitHub writes a closed git operation window queued; plain `flush` sends them

宿主的自动权限模式会批准宿主自身的提示,但不会批准 Estigia 的决定:无论 Claude Code 使用 bypassPermissions 和 auto,OpenCode 使用 --auto,还是 Codex 使用 never 审批策略,拒绝仍然是拒绝,问题仍然是问题,因为门控会在询问宿主权限层之前作出判断,而且门控中的任何内容都不会读取该模式。测试会验证启用或未启用该模式时,钩子和插件的回答保持一致;estigia doctor 会显示 Claude Code、Codex、OpenCode 和 Pi 各自配置的模式。哪些内容经过实际运行测试,哪些没有,请参阅 docs/honesty.md。 setup 会安装三项核心内容:Agent 读取的技能、写入该 Agent 始终加载的指令文件中的简短指令,以及让权限成为硬性机制而非建议的生命周期钩子。--skill-only 会在指令之前停止。Estigia 支持八种 Agent;钩子会安装到所有具有可拒绝事件的 Agent 中——共五种,钩子门禁可读取五种方言;另有三种仅用于已退役的宿主。每次 Claude Code 设置还会安装两个稳定且不活动的审阅者定义:review-blind 和 review-blind-sealed。它们由同一个模板渲染两次,是 Judgment Day 的两位裁判,仅此而已。两份裁判定义都带有 model: inherit,并附有一段要求判决说明依据的文字。Evidence standard 决定未封存的授权——reading 下为只读,measuring 下则额外仅授予 shell;封存授权固定不变,只包含一个工具,即网页搜索,不允许读取仓库。除非启动时指定不可变目标——一个提交、差异或提交范围——以及评判标准,否则两者都不会生效。每次启动 Judgment Day 时,编排器都会传入实际生效的 judge 模型。普通审阅在任何级别都不会授权裁判;Judgment Day 是 gentle-ai v4 的可选功能,也是裁判唯一存在的场景——参见 judgment day。设置过程绝不会创建带编号的裁判文件。

普通审阅的审阅者不会被安装。review_tier 授权的封存审阅视角——review-lens、review-risk、review-readability、review-reliability 和 review-readback——以及反驳者 review-refuter 和验证器 review-validator,都由 launch_review_input 从嵌入二进制文件的模板启动,不带任何工具,也绝不会读取 ~/.claude/agents。设置过程会撤销早期版本在这七个名称之一之下安装的副本:由 Estigia 所有且未被编辑的副本会被删除;已编辑的副本会保留,并解除对其路径的所有权;Estigia 从未记录过的副本则保持原样。这些名称仍为保留名称,因此项目定义不能取而代之;手动 Task 启动其中任何一个都会被拒绝,并返回 reviewer-launched-by-the-binary——不存在手动启动途径。另外两份定义 developer.md 和 analyst.md,仅会在 Model routing 指定其角色时安装;当对应条目被移除时也会撤销,因为带有工具授权的定义就是权限,而升级不能授予任何人未曾要求的权限。它们会安装到 Claude Code 和 OpenCode 中,并分别采用各自宿主的方言:Claude Code 使用逗号分隔的 tools: 行和 effort:;OpenCode 使用 permission: 映射和文件名,不包含 effort: 字段。默认情况下路由为空;指定角色便会安装对应定义,而其旁边的模型字段只表示该定义使用的模型。该行的第三个值 by task 不指定任何角色,也不会安装任何内容:工作的性质决定模型和投入程度,启动 Agent 会记录自己的选择——正如 docs/honesty.md 所述,这是声明而非检查。在这些路径下,若定义并非由 Estigia 编写,就会被拒绝而非替换:首先在预检阶段、任何内容写入之前拒绝;然后在实际写入前再次检查,以拦截其间新出现的定义——此时技能和指令已经写入其后。直接通过 config set 和 config edit 写入不会修改外部定义。 每个保留角色都由操作者掌控。在 Claude Code 当前的 Agent 或旧版 Task 启动任何保留角色之前,Estigia 会从启动工作目录一路检查到第一个 .git 仓库根目录,并递归拒绝任何项目 .claude/agents 定义中使用了相同文件名或在有效 YAML 中声明了相同名称的情况。对于 judge,随后会证明规范的用户级定义是唯一具有该身份的用户级定义,并且与 Estigia 能生成的某种渲染结果相符——而不是嵌入的字节本身,因为嵌入内容会是未经渲染的模板;对于七个通过二进制文件启动的名称,项目目录检查就是全部验证,随后无论用户目录中有什么都会拒绝启动。安装前会对两个 judge 执行相同的递归用户目录唯一性预检,在 reviewer 边界处重新验证,并在不替换另一参与方抢先创建的路径的前提下创建新的 reviewer。证据缺失、不可读、已更改、重复或含糊不清时都会拒绝。普通 Agent 仍按项目优先的规则解析。被拒绝或无法验证的 reviewer 不计入评审;回退方案只能是单独的会话或持久化评审交接,绝不能缩减评审规模或将评审串行化。

这里唯一需要有人参与的流程是安装界面,它最后会打印出无需人工参与即可复现相同结果的命令:

the same result without the questions:
  estigia setup claude-code
  estigia config set "Model routing" "developer=inherit" --agent claude-code

普通评审会按层级,为同一不可变目标和标准分配视角:low 为零个,medium 为一个,high 为四个。每个视角的严重问题都由所有层级通用的台账裁定——没有拨盘、没有多数决,也没有一致性策略——完整说明见 skill/policies/blind-judges.md。传输层会记录一个计算得出的精确收据判定;它不能证明这些视角确实运行过。Judgment Day 仅在明确请求时运行,会取代该目标的视角评审,且不会签发收据。

已停用的 judge 小组耗费了多少成本,相关历史数据见 docs/review-cost.md;各层级视角评审的成本目前还没有测量。

无论是谁再次执行此流程——在另一台机器上、通过脚本,或在容器镜像中——都需要一种无需提问的明确写法,而刚刚成功运行的流程是了解这种写法的唯一可靠来源。这些命令会生成与通过提问得到的结果逐字节相同的结果,并且有测试会同时运行这两种方式进行验证。

status 会分别报告两件事,因为Agent 是否被告知 Estigia 的存在与Estigia 是否能够阻止它是两个不同的问题;当有人查看一次写入操作却没有声明的运行记录时,需要知道的是后者。工具部分可能永久不可用:无法确定服务器注册位置的适配器会打印 tools off 及原因;仅仅尚未注册的适配器则会打印修复命令:

claude-code    configured
               harness: gate on, tools on
codex          configured
               harness: gate off, tools on

卸载

estigia uninstall --all --dry-run   # what would go, changes nothing
estigia uninstall --all             # carry it out

第一条命令会告诉你第二条命令将执行什么操作。若要退出一个 Agent,同时保留其他 Agent:

estigia uninstall claude-code

还有推送防护,它位于仓库中,而不是某个 Agent 中:

estigia guard --uninstall

卸载只会移除 Estigia 创建的内容,不会移除其他内容。 不会移除其他工具的区块、你自己的备注、Estigia 覆写之前就已存在的文件,也不会移除后来被你编辑过的 Estigia 自有文件;这类文件会被保留,并单独列出,而不会悄悄删除。之所以能分辨这些内容,是因为安装时会记录创建了哪些文件,以及写入内容的摘要;之后,磁盘上的内容本身已无法区分它们。

有两项内容会特意保留。~/.estigia/ 属于你,而不属于任何 Agent——其中包含界面语言和你的检出列表;移除一个 Agent 时,不应连它也一起移除。检出目录在 .git/estigia/ 中的自有条目也会保留:卸载命令针对的是 Agent,而不是仓库;擅自访问你当前所在的检出目录,正是这种设计要避免的问题。只有 estigia config forget 会移除这些条目,并会说明移除了哪个文件。

关于全部内容,包括 REPLACE 和 OVERWRITE 的含义,以及为何使用这两个词,请参阅 docs/what-it-writes.md。

为问题立誓

estigia claim 12 --run-id claude-0198fe1c --horizon 2026-08-01T18:00Z
estigia gate Edit --run-id claude-0198fe1c --input '{"file_path":"src/x.rs"}'
estigia release --run-id claude-0198fe1c

Agent 会改用 MCP 工具执行此操作——你很少需要亲自输入这些命令。运行 ID 根据 Agent 的会话生成,并由 SessionStart 报告,因此 Agent 已经知道该 ID。系统会要求提供该 ID,而不是猜测,因为在错误的运行 ID 下记录的声明永远无法与门禁匹配;主动询问总比悄无声息地出错好。release 还会移除本次运行创建的隔离检出目录及其中检出的本地分支,前提是跟踪器已确认交付完成,且没有未发布的内容;它会在回复中说明保留了什么及其原因。它也会删除本次运行记录的所有远程分支头,因为 start_branch 关联的分支不一定就是已发布的分支,而 GitHub 的自动删除功能只会删除后者。estigia prune 会清理没有交付成果归属的内容:它会列出已合并或已关闭的分支和检出目录,保留任何由有效声明持有或包含远程没有的提交的内容,并且只有在指定 --confirm 时才会移除其余内容。它还会查找干净的孤立检出目录:其远程分支已不存在,但其中的提交仍存在于另一个远程引用中;修剪规则介绍了这条额外的清理路径及其保守的归属检查。

是 harness,而非文档

Estigia 是一个 harness:它不会要求 Agent 遵循工作流,而是提供工具。

skill/ 下的约定是 Agent 可以阅读、也可以忽略的文本——这意味着“机械检测伪证”只是一个美好愿望。没有任何东西能阻止一次运行在没有声明的情况下写入内容,或根据一个已不存在的 SHA 所绑定的裁决交付结果。harness 解决了第一个问题,并在交付时绑定第二个问题,但不会在交付那一刻重新检查——具体界限见 docs/honesty.md:

agent (Claude Code)
  │
  ├─ tool: Edit / Write / Bash
  │    └─ PreToolUse → estigia hook pre-tool-use
  │         └─ verify_claim against the tracker → deny
  │
  ├─ turn about to end
  │    └─ Stop → estigia hook stop
  │         └─ while the run still holds its issue → block, so the turn continues
  │
  └─ tool: mcp__estigia__claim / verify_claim / transition / …
       └─ estigia mcp → answered in this process, against `gh`

git
  └─ pre-push → estigia hook pre-push
       └─ refuses a push no live claim authorises, whoever typed it

两部分缺一不可。工具让 Agent 能够真正执行工作流——提供三十六项带有模式定义的操作,而不是手动拼接 gh 命令并听天由命。若约定要求某个名称,但没有工具执行它,就会说明未提供该名称的原因,而不是将其列出;这样,工具表面就不会提供无人响应的调用。交付路径所需的唯一一次强制推送也包含在其中,因此它会像其他写入一样经过裁定,而不是在 shell 中直接输入。门控则负责处理 Agent 试图绕过这些工具时的情况。

Estigia 不会运行你的工作模型——它只会通过 launch_review_input 启动审查者——而且它本身不持有任何权限。本地工作流存储 ~/.estigia/state.db 才是权威来源:声明、状态、回执、发现、裁决、支出、任务和 blocked-until 条款都以行的形式存储其中;同一台机器上的两次运行会在同一事务中相互裁定。跟踪系统保存问题及其文本、拉取请求、分支、标签,以及本地提交后写入的受派人信息,但这些都只是投影,永远不参与裁决——代价是该存储只是在一台机器上的一份副本,正如 docs/honesty.md 所述。运行中断后,不会留下任何权威来源:存储中关于某个检出所受约束的记录,就是支配它的全部内容,无论写入该记录的运行是否仍在,能否被询问。会话结束后留下的本地运行指针则是另一回事——它是一条机器可读的记录,绝非权威来源;estigia doctor 的 stale-run-pointer 行以及预推送钩子 estigia guard 安装的、与存储记录进行核对的机制都会运行,estigia gate 也会触及同一机制,正是为了处理已中断运行留下的虚假指针。estigia doctor 的 prune 行及其对应的 estigia prune 命令,则用于处理运行中断后留下的另一部分:没有任何存活声明拥有的分支和检出;它们只会在有人确认后才会列出并移除。

没有 Agent 能绕过的关卡

Agent 钩子只会为安装它的 Agent 触发。pre-push 钩子位于 git 之下:

estigia guard              # into this repository
estigia guard --uninstall  # removes only a hook Estigia wrote
$ git push origin HEAD
estigia: git push: gh issue view failed (1): none of the git remotes ... (read-failed)
  [world-action] the tracker could not be read; write nothing and retry the read
error: failed to push some refs

它会在最后一刻而非最初时刻拦截操作,而且对每个 Agent 和每个人都有效。PreToolUse 关卡仍然最重要——它会在推送前数小时拦截认领竞争失败的情况——但只有一个 Agent 配备了它。Claude Code 还会注册一个 Stop 钩子:只要运行仍持有其 issue,这一轮就会继续,而不会结束。成功读取后,该钩子在每个续期窗口内最多读取一次认领状态(读取失败或状态未知时会再次读取),因此,连续运行的多个短轮次不会耗尽 GitHub API 配额。OpenCode 也能做到这一点,具体取决于 TUI 编辑的 Loop plugin 设置:启用后,estigia setup opencode 会写入一个可选插件;只要 Estigia 表示运行仍在进行、还有其他 issue 可认领,或 blocked 项记录的退出条件已满足,插件就会继续会话——并保留目标及停止原因,让已停止的循环一目了然,且 /flow-status 会报告其状态;Agent 可以通过 estigia goal stop-after 要求它在当前任务结束后停止,此设置会被仍有效的认领忽略,而认领释放后则会生效。如果某一轮结束时运行仍持有认领,就会继续执行,并用一句话说明 issue 和运行,而不会再次重复整个目标。如果某个会话结束这一轮只是为了等待正在运行的子会话,就会等待而非重新提示,并在子会话结束时继续(详情)。它的命令是 /flow-loop 和 /flow-status,这些名称不会与通用的 /goal 和 /loop 冲突。Pi 将它作为自有扩展 estigia-loop.ts 接入;当 Pi 报告会话已结束时,它会继续会话并注册相同的两个命令;其目标保存在内存中,因此重启 Pi 后会丢失。Codex 通过同一行下的 Stop 和 SessionStart 钩子条目获得相同的循环,每个条目都需要在 config.toml 中设为可信,且不提供 --wait、--max 或 /flow-status。Claude Code 也能使用它:在其 commands/ 目录下放置两个斜杠命令,并添加一个 Stop 条目,同时提供上限设置和 /flow-status。默认的 off 不会写入任何内容。另有一个独立的 Goal loop plugin 行,默认也为 off;它会为 OpenCode 写入通用的 goal-loop.js,或为 Pi 写入 estigia-goal-loop.ts,提供 /goal <condition> 和 /loop [interval] <prompt>,但不关联任何 Estigia 命令:模型会在每第三轮和达到上限的那一轮评估对话记录,而 docs/honesty.md 说明了为什么这绝不能作为证据。estigia status 会在每个 Agent 的运行环境行旁报告其续行词。

誓言一经立下,便不可撤回

尚未认领任何事项的运行不受 Estigia 管辖,但下文的仓库 Unclaimed write policy 另有规定时除外:默认情况下,对于此类运行发起且门禁能够限制在检出目录内的仓库写入,会先交由用户处理;无法限制在检出目录内的写入则会被允许,并在下次会话开始时报告检出目录已被修改;若该设置为 off,则此类运行进行的所有写入都会不受干预地通过。每个会话都设置门禁,那是锁,不是工作流权限。

唯一的例外,由操作员主动启用。 在安装了 estigia guard 的 pre-push hook 的检出目录中,不持有认领事项的运行会在所有分支上被拒绝执行任何提交(git commit、cherry-pick、revert、merge、rebase、am)以及任何 git push,并返回拒绝原因 unclaimed-commit;git 运行该 hook 时,pre-push hook 也会拒绝同一推送。解决方法是认领一个 issue,然后通过 start_branch 开始工作;认领事项会覆盖其隔离检出目录。读取不受门禁限制,编辑和测试仅受下文的 Unclaimed write policy 限制;未安装 guard 的检出目录不会拒绝提交,没有跟踪器传输或未安装契约的检出目录也是如此。

另一个例外由仓库设置决定,并且默认启用。 Unclaimed write policy(ask、off 或 required,仅通过 <repo>/.git/estigia/estigia.local.md 设置)管辖在配置了跟踪器的检出目录中、不持有认领事项的运行。required 会拒绝所有无法放在检出目录外的仓库写入,并返回 issue-required;默认值 ask 会在 Claude Code 上对能够限制在检出目录内的写入询问用户,在无法询问的主机上拒绝该写入;无法限制在检出目录内的写入则会被允许,并在下次会话开始时列出检出目录中已修改的路径;off 则采用上文所述的行为。关于其适用范围,请参阅 docs/configuration.md;关于其不适用的范围,请参阅 docs/honesty.md。

运行一旦立下誓言——estigia claim 12——它进行的每次仓库写入都会根据该认领事项进行检查,而每个不可逆边界都会重新向存储验证该认领事项。价值就在这里。技能自身账本中的事件 I07,并非“Agent 未认领就进行了写入”;而是一次运行在认领竞争中落后了五秒,33 秒后才收到通知,随后又继续工作了 48 分钟,因为它的循环中没有任何步骤再次读取认领状态。那次运行已经立下誓言。门禁会阻止这种情况。

$ estigia gate Edit --run-id claude-0198fe1c --input '{"file_path":"src/x.rs"}'
estigia: src/x.rs: gh issue view failed (1): no git remotes found (read-failed)
  [world-action] the tracker could not be read; write nothing and retry the read

常规写入以及 Claude Code 的 Stop hook,可以使用两分钟续期窗口内的应答——这正是 SKILL.md 已经要求的检查频率。不可逆边界则绝不例外:git push、git merge、git pull、创建或删除标签时的 git tag(列出标签属于读取)、gh pr merge、 gh pr create、gh release create 和 gh release edit 都会始终重新验证。

门禁只会读取认领状态,因此才能置于每次编辑的关键路径上:出错的代价只会是拒绝写入,绝不会损害 issue。测试会在结构层面对此进行强制验证。

工具

共三十六项操作,由表驱动。其中三十四项各自映射到契约要求绑定必须提供的一项操作; send_message 和 list_sessions 从本地存储返回结果,并非绑定操作。tools/list 包含架构和 readOnlyHint,因此 Agent 无需阅读本文档,就能判断某项操作是读取还是写入。十项交付工具(claim、start_branch、publish_review、 launch_review_input、collect_review_input、record_computed_verdict、release_ci、release、 transition、review_status)带有 _meta["anthropic/alwaysLoad"],因此会延迟加载 MCP 工具的宿主会在启动时加载它们;每项工具都接受 compact,启用后会从回答中省略 build(docs/review-cost.md):

read   verify_claim     (issue, run_id, expect_state)
read   list_state       (state, run_id, identities)
read   check_closing_keywords (issue)
read   review_status    (issue)   # carries `lane` and `corrections`
read   review_read      (issue, view, epoch, id, with_text, candidate, request, path, side, pr, head, base, digest, phase, worktree)
read   review_tier      (base, head, parent_head, clearing_finding)
read   target           (base, recorded_base, worktree, native_start, manifest)
read   tasks            (issue)   # the task checklist, from the local store
read   list_sessions    ([status, runtime, run, session_id, repo_dir, limit, cursor])   # bounded page; no options answers the entries `estigia sessions --json` prints
WRITE  claim            (issue, run_id, horizon[, takeover, target_operation, force, reason_file])
WRITE  handoff          (issue, run_id, to)   # records it locally; projects `dev:<to>` with read-back
WRITE  heartbeat        (issue, run_id, expect_state, body_file)
WRITE  transition       (issue, to, run_id)
WRITE  comment          (issue, body_file)
WRITE  blocked_until    (issue, run_id, until_issue, until_state)   # local store only: no tracker write
WRITE  task             (issue, run_id, id, text, route)   # local store only: no tracker write
WRITE  send_message     (run_id, to, repo_dir, text)   # local store only; the person is asked first, over MCP elicitation
WRITE  release          (issue, run_id)
WRITE  ensure_states    ()
WRITE  flush            ([read_only])   # sends what a closed git operation window queued, oldest first; refuses while it is closed
WRITE  start_branch     (issue, run_id, branch, base)
WRITE  judge_workspaces (issue, run_id, epoch, pr, head, base, digest, count)   # bare per-judge directories, Judgment Day's
WRITE  assist           (issue, run_id, branch, base)         # assisted repositories only
WRITE  draft_pr         (run_id, title, body_file)            # assisted repositories only
WRITE  create           (identity, title, body_file, priority, domain, runtime, run_id)   # identity and clauses go to the local store, not the body; optional `repo` (owner/name) files in another repository, unclaimed
WRITE  publish_review   (issue, run_id, branch, base, pr_title, pr_body_file)
WRITE  republish_review (issue, run_id, branch, base, pr_title, pr_body_file)   # leased force-push
WRITE  handoff_review   (issue, run_id, target_operation, epoch, pr, head, base, digest, blocker, discharger)
WRITE  record_review_finding (issue, run_id, reviewer, epoch, pr, head, base, digest, id, class, evidence, impact)
WRITE  record_disposition (issue, run_id, epoch, pr, head, base, digest, dispositions)
WRITE  launch_review_input (issue, run_id, name)   # starts the lens, refuter or validator a review_status collect offers, detached
WRITE  collect_review_input (issue, run_id, name[, wait_seconds])   # records what the launched reviewer answered
WRITE  record_computed_verdict (issue, run_id, epoch, pr, head, base, digest)
WRITE  escalate_review  (issue, run_id, epoch, pr, head, base, digest, escalated_to, reason)
WRITE  record_spend     (issue, run_id, phase, epoch, pr, head, base, digest, conditions, input, tokens, seconds, contexts)
WRITE  release_ci       (issue, run_id, epoch, pr, head, base, digest)

三十六项工具。契约列出每个绑定都必须映射的十七项操作。工具整合的操作仍由保留下来的名称提供其能力:claim 通过 takeover 执行 reclaim,list_state 通过 identities 返回身份信息,review_status 包含发布通道和修正次数,review_read 读取过去由六项工具读取的内容,review_tier 限定修复范围,target 则对基准变动进行分类。契约要求但没有任何工具执行的名称,会在 NOT_EXPOSED 中注明,并附上原因以及 bindings/ 中负责该操作的章节;这些名称不会对外公布,因此接口不会提供无人响应的调用。接缝测试会确保两份列表保持一致:既未公开也未声明的操作会导致构建失败。

MCP 服务是手写的,而非基于 rmcp 构建。同一个二进制文件还会响应每次编辑的 PreToolUse 钩子,因此,每个进程都启动一次 tokio 运行时,只为通过管道传输几行 JSON,却要付出数千次的开销。保持 crate 同步执行,才能让这个门禁足够轻量。代价列在 UNIMPLEMENTED 中:没有资源、没有提示词、没有采样,除 send_message 的一个问题外没有引导;除 initialized 外没有通知,并且一次只处理一个请求。

配置

二十九项类型化设置详见 docs/configuration.md,按主题分组——权限、仓库与跟踪器、交付、门禁限制、审查与变更、Agent 运行时、本机——且 estigia config list、设置界面和参考文档都按同一顺序展示。每一行都注明其作用范围:设置值由谁决定,是此 Agent、此仓库、每个工作区检出,还是此机器。读取该表即可生成有效配置;如果无法生成,则会明确指出可以写入什么内容作为替代。

棘轮机制

只有运行某条命令能够解除阻断时,消息才可以提及该命令。 指出死路不如什么都不说。

每项拒绝都会给出类型化代码、世界状态发生了什么变化、能否安全重放,以及解决方案。解决方案要么是可运行的调用——由 every_command_a_rejection_names_parses 使用真实解析器进行校验;要么是封闭词汇表中的原因,用来说明为何无法诚实地提供命令:operator-knowledge、world-action、human-authority。

$ estigia setup
estigia: setup needs to know which agent to configure (agent-not-named)
  run: estigia setup --all   # or one of: agents, claude-code, codex, opencode, pi, cursor, zcode, deepseek-harness

以 2026-07-31 的 issue-flow 为基准:87 处拒绝,没有一处指向可执行的后续操作。棘轮机制只有从零开始才能启动。

本工具不衡量的内容

详见专门的文档:docs/honesty.md。文档中的每一项都说明了此 crate 不检查什么,并注明发现该问题的度量方式。本仓库其他位置新增的任何声明都要先对照该文件进行评估,而 docs/README.md 则列出了该文档所属集合的目录。

布局

src/harness/   the gate, the run pointer, the transport, the lifecycle protocol, doctor
src/harness/mcp/  the workflow tools and the stdio JSON-RPC they arrive on
src/setup/plugin.rs  the OpenCode gate, the Pi gate extension, the two review relays and the optional loop plugin and Pi loop extension, because those hosts read a module rather than a settings line
src/setup/pi_prompts/  the two Pi prompt templates, `claim.md` and `review-status.md`, embedded and written unchanged
src/setup/pi_look.js  the Pi look extension, embedded and written unchanged
src/setup/pi_theme.json  the Pi theme `estigia`, embedded and written unchanged
src/setup/goal_loop.js  the generic `/goal` and `/loop` plugin, embedded and written unchanged
build.rs       derives the transport's refusal vocabulary from the transport itself, and embeds the build's commit and dirtiness
src/fence.rs   a marked block in somebody else's file — invariant three, written once
src/config/    typed model, the settings table as data, which markers the table lives in
src/setup/     agent adapters, companions, dry-run, exact inverse
src/skill.rs   the embedded markdown and its install/status/uninstall
src/outcome.rs the failure taxonomy: what landed, what may be replayed, what to run
src/cli/       dispatch, and the only place a refusal becomes an exit code
skill/         SKILL.md, bindings/, policies/, protocols/, references/, assets/, agents/ — not compiled
docs/          the reference the sections above point at, one question each, review cost included — map: docs/README.md
scripts/       the two installers a release is fetched with, and the Windows source reinstall
assets/        branding, referenced from this file

有一份文档放在代码旁边,而不在代码里面,它回答的问题与本文不同。AGENTS.md——CLAUDE.md 链接到的文件——说明了 Agent 在这里如何工作,以及它对文档负有什么责任。这个仓库的规划材料放在议题中,而这个工作区里没有任何规划材料。

src/transport/ 是传输层,也是唯一的传输层。它最初是 skill/scripts/github.py,并随负载一同发布,因为 bindings/github.md 将每项可逆操作都路由到它——没有它的负载,其绑定的第一条命令就不存在。现在,绑定列出了 Estigia 自己的工具,操作由当前进程处理,脚本也已删除:代码树中没有 .py 文件,没有任何路径需要 Python,CI 中也没有安装 Python 的步骤。如今,与它交锋所体现的价值,已在上文独立一节的诚实性约定中说明。

完全不需要任何解释器曾是本句的说法;当一个测试开始执行这个 crate 生成的 OpenCode 插件,而不再只是读取它的源码时,这句话就不再成立了。该插件是 JavaScript;用第二种语言编写却从不运行的门禁,只不过是没有任何交锋检验的一条规则副本。因此,node 已列入 AGENTS.md 的验证清单,两个工作流也都会安装它,而不再相信运行器镜像中自带了它;docs/honesty.md 则记录了这些测试衡量的内容。此后,原来的测试又增加了两个同伴,因此现在共有三个测试需要该运行时:原测试会通过两代宿主驱动 shell 命令的运行位置;the_plugin_hands_the_gate_the_directory_every_write_lands_in 会驱动每个受门禁控制的写入工具在 OpenCode 1 的 file_path 和 OpenCode 2 的 path 上的写入位置;the_loop_plugin_continues_while_estigia_says_there_is_work 会驱动可选循环插件的退出行为。

一个 crate。首日就拆成五个,会在任何边界值得拆分之前先把边界拆开;只有当一个边界值得拥有自己的位置时,才会将它拆分出来。

退出码

四个,而且没有一个表示“出了问题”:

代码含义
0命令完成了它所述的操作
1命令拒绝执行;拒绝信息会说明是否已经写入任何内容
2世界可能已经发生变化,但此进程无法判断
3无法读取调用内容:没有尝试执行任何操作,也没有做出任何决定

第四种退出码独立于 1,因为两者的区别正是钩子要读取状态的全部原因。拒绝是一项决定——世界说了不——而这个 crate 编写的每个脚本都会传递该状态,这正是阻止推送的机制。用法错误不是决定,传递它只会让输入命令的人无法采取行动,却仍阻止推送。这一点经过了实际验证:一个构建遗留的 pre-push 钩子,其 hook 命令多接受一个标志时,会以 1 退出,而 git push 返回 error: unexpected argument --from-a-newer-build,并拒绝推送。

只要第四种退出码存在,本节就一直写着三种;这正是 CLAUDE.md 第一条规则禁止的偏差——而它所描述的读者是脚本。every_exit_code_the_readme_lists_is_one_this_binary_has 现在会将表格与枚举逐项核对。

测试框架会把传输层自身的五种代码映射到这一分类,而不是将它们合并。1 表示控制面已被读取并答复停止——不要重放。2 表示操作员的配置有误——其中包含一条可以修复问题的命令。3 表示控制面没有给出任何答复——重试读取,绝不可将其视为停手指令或放行许可。4 和 5 表示写入可能已完成,但没有人观察到——去查明情况。

这些区别体现在拒绝信息中,便于查阅。issue-flow 的 5 同时表示“没有写入任何内容”和“写入了某些内容,但我不知道是什么”;自信地报告最接近的已命名状态,就是在撒谎。

许可证

MIT。源自其他 MIT 许可项目的文件,其声明见 THIRD_PARTY_NOTICES.md。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。