关于 Yapitalism
Yapitalism 是供语音客户端操作终端编码 Agent 的本地 MCP 服务,并报告经验证的交付与任务轮次状态。回执用于区分已证实的处理和未经确认的写入。
主要功能
- 01语音客户端访问终端 Agent
- 02发送并等待 Agent 任务
- 03提供交付状态回执
- 04报告 Agent 轮次状态
- 05命名窗格并连接对等机器
适用场景
- 01离开办公桌时发送编码任务
- 02确认 Agent 是否收到请求
- 03发现需要用户输入的提示
- 04跨机器监看 Agent 会话
MCP 相关
MCP 服务提供列出、读取、发送消息、等待、命名、创建和恢复 Agent 窗格的工具。MCP 客户端在本地连接;配置的对等服务也可按机器命名空间提供窗格。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
Yapitalism
通过语音驱动终端编码 Agent,绝不让回复声称超出证据所能证明的内容。
你不在办公桌前。你开口说话;终端中的 Agent 开始工作;然后你会收到语音回复。那是你能得到的全部——你看不到屏幕。因此,最糟糕的失败不是程序崩溃,而是语音说“完成了”,你的文字却还未读地留在提示框中。
Yapitalism 是一款本地 MCP 服务,让语音客户端能够访问你的编码 Agent;它还配备了回执层,用于判定语音可以说什么。如果你在办公桌前,就看屏幕——它是为你不在时准备的。
公开预发布版。仅限本地使用。不会部署到生产环境,不支持外部消息传递,也不会自动化操作闭源客户端。
它如何协同工作
MCP client (Codex · Hermes · Claude Code · Claude Desktop · Cursor)
│ MCP over loopback — no public endpoint, no OAuth, no relay
▼
yapitalism MCP server panes_list · pane_read · pane_send
│ pane_await · pane_task
│ panes_name · panes_unname
│ panes_create · panes_resume · pane_clear
├── superset backend local host-service over tRPC (127.0.0.1:48900)
└── tmux backend capture-pane / send-keys
它支持的 Agent:codex、claude、kimi、opencode——通过实际测量识别(在 tmux 上检查进程树,在 Superset 上使用主机自身的 Agent 注册表),绝不依赖调用方的声称。若窗格运行的是其他内容,则会拒绝操作,因为向 Shell 输入内容并按下 Enter 就是在运行命令。
语音客户端不会直接访问你的机器:它会驱动本地 Agent 会话,而该会话通过 127.0.0.1 与此服务通信。没有任何内容会暴露到网络上。
关键所在:回执
pane_send 返回的是判定结果,而不是含糊其辞。
| 含义 | |
|---|---|
| GREEN | Agent 回显了一次性标记。这可以证明它收到了文本并进行了处理——但这并不代表它随后完成的工作正确;没有任何回执能保证这一点,而此回执也无意作出这种保证。 |
| YELLOW | 写入已成功;但未能证明文本已被处理。绝不要把它当成更好的结果。 |
| RED | 后端拒绝了写入。没有内容到达终端。 |
YELLOW 正是这一机制的意义所在。从外部看,留在 Agent 输入框中但尚未提交的文本,与正在进行的工作毫无区别——同样的旋转指示器、同样滚动的输出、同样的 HTTP 200。若语音把它说成“完成了”,你可能要过好几个小时才会发现问题。
以下情况明确不算接受:HTTP 2xx、PTY 写入成功返回、终端输出发生变化、修订版本前进,或提示框回显了你输入的文字。
等待不等于失败
固定期限只能报告时间已到,不能说明 Agent 的状态。一个 Agent 思考一分钟后给出正确答案,其实一直都在被验证;若把这种情况判为 YELLOW,就会让操作者学会忽视 YELLOW。因此,等待采用的是空闲超时:只要窗格发生变化,计时就会重新开始,但仍受硬性上限约束。
窗格是否变化只决定是否继续等待,绝不能作为接受的证据——接受与否仍只由金丝雀标记判定。因此,YELLOW 会说明具体是哪种情况:
canary_timeout_pane_moving— 窗格文本仍在变化。名称反映了实际测量的内容:旋转指示器、时钟、日志尾部输出,或与目标 Agent 共用窗格的另一个 Agent,都可能导致这种情况,即使目标 Agent 什么也没做。它只是提示你可以再查看一次,绝不代表 Agent 正在工作。canary_timeout_pane_still— 完全没有变化。
无法消除的限制是:如果 Agent 默默忽略了文本且没有输出任何内容,就没有任何机制能区分这种情况与 Agent 根本没有收到文本。验证需要 Agent 输出一些内容。
第二份回执:这一轮如何结束
送达只是基本要求;更昂贵的失败是:你以为 Agent 正在工作,它却对一个是非问题卡了 40 分钟。pane_await 会监视窗格,直到 Agent 的轮次结束,并说明结束方式;pane_task 则将发送和等待合并为一次调用——发出指令,离开一会儿,再回来查看以下结果之一:
| 轮次 | 含义 |
|---|---|
ended | 提示词处于空闲状态,屏幕停止变化。此轮已结束——必须同时说明“这不代表工作正确”,绝不能说成“已完成”。 |
waiting_input | 阻塞式对话框占据了屏幕(信任/登录/确认)。阻塞流程的是你,而负载中的 tail 会带上问题,方便引用。 |
agent_error | 屏幕上出现已知的失败信息——Please run /login、401、速率限制——会直接指出,不会等到超时。 |
exited | 窗格中已没有运行中的 Agent。 |
running | 超时时仍在变化。尚无定论;可选择进一步查看。 |
判定为 ended 前,会再次验证 Agent 进程仍在运行:不能把已退出窗格上冻结的提示词当作一轮已结束来庆祝。
按传输方式确定谁可以写入
Bearer 令牌回答的是谁在调用,却从未回答过调用者可以做什么。从 0.5.0 起:stdio 客户端始终可以写入——操作系统允许客户端启动进程时,就已作出信任决定。默认关闭通过 HTTP 写入,每次拒绝都会说明如何解决:在那台机器上运行一次 yapitalism authority allow-http-writes(运行 yapitalism setup 时也会询问同样的问题,并打印 HTTP 注册行)。无论使用哪种传输方式,读取、监视和 doctor 都可正常使用;yapitalism-mcp --read-only 则会在所有地方关闭写入——先安装监视器,等它值得信任后再允许写入。每个写入结果都会带上其 origin。
在 tmux 中,发送路径还会固定获准 Agent 的身份(PID + 启动时间),并在按 Enter 前重新验证。如果 Agent 在输入和提交之间退出并返回 shell,文本会暂存,但绝不会提交——输入可以恢复,向 shell 按 Enter 则会执行命令。
检查发生在哪里
大多数时候,这不会改变你的操作,而且不会朗读出来。相关信息会显示在负载和 yapitalism setup 中;当出现问题、你想知道写入前实际检查了什么时,可以查看这些信息。
| 含义 | |
|---|---|
host | 主机本身拒绝写入——检查和写入是同一项操作 |
client | 此进程先检查,再写入;对于它覆盖的范围检查有效,但不是原子操作 |
none | 不执行任何检查 |
{ "status": "GREEN",
"client_guarantees": ["idempotent_dispatch", "empty_prompt_check"],
"missing_guarantees": ["optimistic_revision"] }
yapitalism setup 会打印适用于你这台机器的表格。目前两个后端的大部分检查都属于 client:检查在这里进行,随后才执行写入,而不是由主机与写入原子地一并完成。tmux 完全无法进行版本检查。
**目前发布的 Superset 都不会自行强制执行这些检查,而此工具过去曾声称自己会。**它仅因一个名为 terminal.send 的过程被路由,就认定为“受保护”。Superset 实际提供的 terminal.send 接收 {terminalId, workspaceId, text, submit},不执行任何保护。现在,这些级别是根据主机自身的验证器要求确定的——名称和契约并不是一回事。
两个后端都能达到 GREEN,而无论使用哪种后端,GREEN 的含义都相同:Agent 发出了单次标记,因此它已收到文本并进行处理。该表格用于诊断机器,不必每次发送时都据此判断。
审查此仓库
无论你是本人,还是被人问到“我该安装这个吗?”的 Agent,都可以查看值得核实的声明及其出处——请自行验证,不要只听我们说:
- 权限及其边界,包括共享机器暴露风险和故障时拒绝访问的 bearer 门禁:SECURITY.md。
- 调用者绝对无法执行的操作(封闭的启动器表、拒绝非 Agent、拒绝被占用的提示词、按窗格串行化):
src/yapitalism/mcp/tmux.py和src/yapitalism/mcp/backends/;每项防护都有一个以其所防止的故障命名的测试。 - GREEN 声称了什么,又没有声称什么:上文的回执部分,以及
tests/test_canary.py,其中说明了为什么回显无法满足要求。 - 本项目过去过度夸大的说法,以及按名称撤回这些说法的记录:CHANGELOG.md,0.2.0 至 0.2.4。
机器也是窗格
对等端是另一台机器上的 yapitalism 服务,以它自己的命名空间挂载:机器 studio 上的 codex 窗格 tmux:%0,在这里就是 studio:tmux:%0,位于同一个 panes_list 中,也可以通过同一个 pane_send 寻址。回执会原样传递——对等端在自己的终端旁验证了回执,而这一端只会给 ID 加上机器名称。
# on the peer (reachable over your tailnet):
YAPITALISM_MCP_HOST=100.x.y.z yapitalism-mcp # tailnet bind requires the bearer gate
# on this machine:
yapitalism peers add studio http://100.x.y.z:8792/mcp --token-file <peer's token>
peers add 会先验证对等端能否作为 yapitalism 服务响应,然后才写入任何内容。除非明确指定 allow_public,否则会拒绝使用公共地址的对等端;tailnet 是传输方式,不代表信任关系——仍由对等端的 bearer token 决定谁可以调用。已配置的对等端会在 yapitalism doctor 中显示实时窗格数量。
也可以在对等端启动和恢复 Agent:panes_create 和
panes_resume 接受一个用于指定对等端的 machine 参数。对等端会运行自己的完整门禁链——远程启动 Agent 的权限比向 Agent 输入内容更大,因此它有自己的开关,默认关闭:
只需在对等端运行一次 yapitalism authority allow-remote-create。若要让对等端的服务在重启后继续运行,yapitalism service --host <its tailnet IP> 会输出已填好的 launchd plist 或 systemd unit;是否安装由你决定。
说名称,不说 ID
语音无法说出 mbp3:tmux:%2。只需将一个词绑定到窗格一次——
panes_name("billing", "tmux:%4")
——之后每个工具都可以使用 billing。绑定会记录命名时窗格运行的内容,并在每次使用时根据实时列表重新验证:tmux 会重复使用窗格 ID,因此如果窗格已消失或运行环境发生变化,名称会连同原因一起被拒绝,绝不会悄悄指向其他窗格。不进行模糊匹配——“大概是正确的 codex”不是有效目标。名称会显示在 panes_list 中对应的窗格上。
妥善使用
桥接 Agent 在有常驻指令时表现最佳——说出回执,绝不重新发送 YELLOW,并像称呼人一样给窗格命名。我们使用的准确提示词见 docs/operator-prompt.md;请将其粘贴到语音客户端的自定义指令中。
示例
六种工具可以组合成值得使用的监控器:权限监控(不会让任何事项静默地停在对话框中——它首次真正捕获到的问题,是某个 Agent 静默等待钱包交易审批)、服务提供商中断监控、每日结束摘要。可用的提示词见 docs/recipes.md。
安装
需要 Python 3.11+ 和 tmux,适用于 macOS 或 Linux —— 每次发布都会在纯净的 python:3.11-slim 容器中完整测试发送并验证的流程,而不只是默认认为它具备可移植性。所有操作都在你的机器上运行;不会向网络公开任何内容。
# 1. install
pipx install yapitalism # or: uv tool install yapitalism / pip install yapitalism
# 2. start the server (loopback only — it refuses to bind anything else)
yapitalism-mcp
# 3. point your voice client's agent at it, in another shell
codex mcp add yapitalism --url http://127.0.0.1:8792/mcp
# 4. ask the tool what your machine can actually do
yapitalism setup
setup 会检查机器,而不是只打印“安装成功”:哪些后端可用、PATH 中有哪些 Agent CLI、Superset 主机是否在线以及运行的是哪个版本,并为你填写上面的保证表。除非你同意,否则它不会写入任何内容;如果你同意,它只会写入 Superset 清单,并明确指出仍缺少什么,以及每项对应的准确命令。
然后对语音应用说:“列出我的窗格”,再说:“把这个发送到 Codex 窗格”。任何 MCP 客户端的用法都相同 —— yapitalism setup 会针对运行它的那台机器,打印 Hermes、Claude Code、Claude Desktop 和 Cursor 的注册信息。
如果 8792 端口已被占用,可用 YAPITALISM_MCP_PORT 更改端口。YAPITALISM_TMUX_SOCKET 用于指定非默认的 tmux 服务端。HTTP 传输默认需要 Bearer 令牌 —— 回环地址不能作为用户边界,因此服务端会在首次启动时生成一个令牌,而 yapitalism setup 会打印包含该令牌的注册行。YAPITALISM_MCP_TOKEN 可覆盖该令牌;设置 YAPITALISM_MCP_INSECURE=1 可选择不使用令牌。stdio 无需令牌:操作系统已经决定哪些进程可以与生成的进程通信。
由客户端自行启动服务端的客户端
Codex 使用 URL。Claude Desktop、Cursor 和大多数其他 MCP 客户端则会生成进程,并通过 stdin/stdout 通信,因此应将它们指向 --stdio,而不要单独运行服务端:
{
"mcpServers": {
"yapitalism": {
"command": "yapitalism-mcp",
"args": ["--stdio"]
}
}
}
如果客户端无法继承你的 PATH,请使用 command -v yapitalism-mcp 返回的绝对路径 —— macOS 上的 GUI 应用通常无法继承该路径。对于只允许设置环境变量的客户端,设置 YAPITALISM_MCP_TRANSPORT=stdio 与使用该标志效果相同。
在 stdio 模式下,stdout 只能输出协议内容,因此服务端会抑制自身的启动横幅。如果用 shell 脚本包装它,该脚本也必须保持静默。
保持运行
服务端停止运行时,语音路由也会失效,因此应使用 init 系统运行,而不是在终端中运行。这两种单元都会以你的用户身份运行,绝不会以 root 身份运行:服务端可以读取你能看到的所有终端。
- macOS ——
.agents/launchd/。plist 是一个模板;其 README 中有一行sed命令,用于填入实际的二进制文件路径,因为 launchd 既不会搜索PATH,也不会搜索~。 - Linux ——
.agents/systemd/,一个--user单元。systemctl --user enable --now yapitalism-mcp。
无论使用哪种方式,都要先终止任何 shell 实例,否则两个实例会争用 8792 端口,由谁胜出取决于时机。
Superset 终端(可选)
tmux 后端无需任何额外配置。Superset 需要一个权限为 0600、包含主机端点和令牌的清单 —— 你不必手动编写,因为 Superset 已经会写入所需内容:
yapitalism superset setup # shows what it found and would do
yapitalism superset setup --confirm # writes it
该命令会读取应用自身的 ~/.superset/host/<organizationId>/manifest.json,验证令牌是否可用于在线主机,选择默认终端,并写入 ~/.cache/superset-watch-voice/yapitalism-manifest.json(或 $YAPITALISM_SUPERSET_MANIFEST)。它不会自行猜测,而是会拒绝继续:源文件权限宽于 0600、清单指向已停止的进程,或有两个在线组织且无法选择时,都会导致操作停止。绝不会打印令牌。
没有清单时,panes_list 仍会返回你的 tmux 窗格,并在 errors 中报告 Superset 的情况 —— 无法访问的后端绝不会被悄悄报告为“没有终端”。
教会语音如何读出回执
.agents/skills/superset-operator/ 包含相应策略,防止模型把 YELLOW 擅自说成“已完成”,还会检查该策略与你的 Agent 实际加载的副本是否存在偏差。
收据核心,可独立运行
无需 MCP 服务也可使用五阶段模型:
capture— 捕获了意图dispatch— 向具体目标尝试写入accept— 目标通过 canary 或明确确认表明已接受work— 观察到了实质性的 Agent 进展deliver— 向用户发送了最终更新
证据带有来源信息 — api、terminal_diff、ui_observation、user_report、inferred —
且 inferred 绝不能标记某个阶段为成功。
本项目缘起的事故是:音频会话仍然保持连接,语音进度播报却停止了;两个 180 秒的监视器
都看到终端停在版本 920118,canary 始终没有到达 —
与此同时,语音仍在暗示工作正在进行。这个产品不是“修复语音客户端”,而是绝不伪造
GREEN。
CLI 提供:doctor、receipt show、ledger verify|manifest|migrate 和 superset status|send。
要确认 superset send,必须复用试运行所生成的确切 client-token,在发送前立即创建快照,
拒绝版本已变更的情况,且绝不重试结果不明的 POST。
已知限制
坦率说明这些限制,因为夸大能力的收据系统还不如没有:
- 无法检测尾部截断。 删除 ledger 的最后几行后,剩余前缀仍会通过验证。要发现这种情况,
需要在文件之外设置锚点 — 参见
docs/adr/0004。 - Ledger 为自身提供证明。 哈希验证只能证明行未被编辑或重新排序;无法证明是谁写入的, 而完全伪造的 ledger 也能通过验证。
- 没有任何后端能为 tmux 提供乐观版本保护。 这需要调用方提供预期值 —“仅当窗格仍与我读取
时一样时才写入” — 而
pane_send不接受预期版本。先读取两次窗格、并在内容变化时拒绝写入, 属于名不副实的另一种保证,因此系统报告为none,而非提供近似保证。 - 在没有受保护主机的情况下,空提示词检查只是启发式判断。 它读取渲染后的屏幕,因此误判为
“空”就会把内容追加到某人的半成品文本后并提交合并。因此,除非能确信内容为空,否则一律拒绝,
包括无法读取的屏幕;此时可通过
pane_clear继续操作。已在真实窗格上验证,但样本量不大。 - 用于衡量的 Superset 是已发布的原版构建 — 其
terminal.send不提供任何保护。自 0.2.4 起, 已多次在该运行中的主机上完成有证据的发送(观察到 canary,状态为 GREEN),既通过直接调用, 也通过完整 MCP 接口完成。受保护主机分支只针对记录下来的形态进行测试,因为没有已发布的构建 带有这些保护措施可供测试。 - 受保护的 Superset 主机会对 Codex 占位文本过度拒绝,将 Agent 自己的建议行也计为已暂存输入, 因此会拒绝向这类窗格发送内容,清空也无济于事。收据会如实说明这一点,而不是建议清空。此问题 应由主机修复。
- tmux 窗格的运行时信息可能会在检查与写入之间变得过时。 Superset 的运行时信息来自主机自身的 注册表,因此它的检查关卡可以在写入前运行,而非写入后。
- canary 证明的内容远不及“已成功”。 它只能证明文本已到达某处,且该处随后回显了一次性标记 — 即已送达并得到确认。它无法证明 Agent 完成了工作、只做了该工作,或窗格就是你想要的那个。 GREEN 是送达收据,不是工作收据。
- 发往同一窗格的并发发送会串行处理,而非排队。 第二次发送会等待第一次完成;不会被暂存、排序 或重试。如果语音客户端的发送速度超过终端的接收速度,它会阻塞自己的当前轮次,而不会交错发送。
- 闭源客户端中的连接器语音行为没有文档记录,且可能在不另行通知的情况下发生变化。
仓库结构
src/yapitalism/mcp/ MCP server, backend registry, receipts, tmux driver
src/yapitalism/adapters/ Superset host-service client
src/yapitalism/ receipt core: model, canary, claims, ledger, CLI
tests/ deterministic unit, replay, and real-tmux tests
fixtures/ scrubbed incident replays
.agents/skills/ voice policy + drift check
.agents/launchd/ run the server as a login agent
docs/adr/ load-bearing decisions
docs/architecture.md component boundaries and evidence model
明确不涉及的目标
- 对闭源语音客户端内部实现进行逆向工程或打补丁;
- 虚构并不存在的后台轮次或推送 API;
- 多租户 SaaS;
- 自动发送电子邮件、私信或消息;
- 将终端修订版本的变动视为命令已接受。
致谢
收据完整性核心由 @liri-ha 编写,其提交未经改写,直接保留于此。请参阅 CONTRIBUTORS.md。
安全
原始转录、终端文本和凭据不应存放在此代码库中。台账仅存储有界元数据、哈希和分类信息。包含持有者令牌的清单存放在代码库之外,文件权限为 0600,且只有在显式传入其路径时才会读取;绝不会打印该令牌。请参阅 SECURITY.md。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。