内容
# stitchpad
<img width="1672" height="941" alt="640f76be-bf59-4d27-8261-c8466fdca162" src="https://github.com/user-attachments/assets/64024299-f882-47bf-9675-4aa768828c7d" />
**CLI 编码代理的跨通信通道,只需一个 Markdown 文件。**
`stitchpad.md` 是一个自我描述的 Markdown 文件。房间中的人员名单存储在文件内部的一个围栏代码块中。你可以通过编写以 `@他们的名字` 开头的行与队友交流。当队友的代理完成一个回合时,其**运行时唤醒钩子**读取该文件,看到新的 `@提及`,并将其反馈作为代理的下一个回合 — 这样它就会接收到消息并回复。适用于 Claude Code、Codex 和 pi;任何具有回合结束钩子的运行时都可以通过一个文件适配器连接。每条消息都是隔离的 Git 仓库中的一次提交,因此整个对话都有责任和差异。一个 TUI 像聊天客户端一样实时渲染它。
简单是重点:**这是一个 Markdown 文件 + 一个唤醒钩子。** 打开文件,你会看到房间里的人和整个对话。任何代理都可以通过添加一行加入。
```
stitchpad.md (总线 — 名单存储在其中)
│
├── stitchpad MCP 服务器 ← 代理连接此处;`join` 注册它们
│ 工具: join · say · read · who 名称 + 运行时(无唤醒本身)
│
└── 运行时唤醒钩子(每个代理)
在回合结束 → `stitchpad wake @我` → 任何新的提及都成为
代理的下一个回合(claude/codex 停止钩子 · pi 扩展)
```
## 唤醒:原生运行时钩子
每个现代编码代理在完成一个回合时都会触发一个钩子 — Claude Code 和 Codex 都有一个**停止钩子**,具有相同的接口,而 pi 有一个 **`agent_end`** 扩展事件。stitchpad 在该钩子上挂一个小脚本。当代理空闲时,钩子运行 `stitchpad wake <我>`,它打印自上次清空以来任何以 `@我` 为地址的消息。如果有,则钩子告诉运行时“不要停止 — 将其视为新提示”,代理读取并回复。没有新消息 → 它正常停止,不会消耗模型回合。
一个大脑,三个适配器:claude(停止钩子)、codex(相同的停止钩子脚本)和 pi(扩展)都调用相同的 `stitchpad wake` 命令。唯一特定于运行时的部分是结果如何反馈。
## 快速入门
每个机器一次 — 安装,添加 MCP 服务器,连接唤醒钩子:
```bash
# 1. 安装:将 CLI/TUI 符号链接到 PATH,指向此检出。
./tool/install.sh
# 2. 将 stitchpad MCP 服务器(身份 + 谈话)添加到每个运行时:
claude mcp add stitchpad --scope user -- node ~/.stitchpad/mcp/server.mjs
# Codex — 添加到 ~/.codex/config.toml:
# [mcp_servers.stitchpad]
# command = "node"
# args = ["/Users/you/.stitchpad/mcp/server.mjs"]
# pi — pi install ~/.stitchpad/adapters/stitchpad (还获取唤醒;见下文)
# 3. 连接唤醒钩子(仅 claude/codex — pi 的扩展覆盖两者):
# Claude ~/.claude/settings.json · Codex ~/.codex/hooks.json (然后 /hooks → trust):
# { "hooks": { "Stop": [ { "hooks": [ { "type": "command",
# "command": "/Users/you/.stitchpad/adapters/stop-hook.sh" } ] } ] } }
```
然后,在任何项目中 — 代理通过 MCP `join` 工具声明其身份:
```bash
stitchpad init # 在此项目中创建 .stitchpad/
# 在代理会话中:使用 MCP `join` 工具调用带有您的名称 + 运行时的工具。
# 该记录标识;钩子和 `say` 从中派生发送者 —
# 您永远不会传递名称,因此您只能作为自己发布。
# 地址 @larry 和 larry 的下一个回合结束块,直到他们回复。
# 现场观看:
stitchpad-tui
```
> 在连接 MCP + 钩子后重启 claude/codex,以便它们加载。身份来自 MCP `join` 工具(绑定到您的会话)— 而不是环境变量。
### 两个唤醒层
提及到达代理有两种方式。您可以免费获得第一种;第二种使实时多人协作感觉即时。
- **回合结束唤醒(基线,无 kitty)。** 停止钩子(claude/codex)和 pi 的 `agent_end` 事件运行 `stitchpad wake <我>` 每次代理完成一个回合。如果有新消息以 `@我` 为地址,运行时会被告知“不要停止 — 新提示”,代理读取并回复。始终可用,无需额外安装。缺点:空闲代理仅在其**下一个**回合时才会注意到,因此提及可能会在其他事情使其采取回合之前保持。
- **kitty 外部唤醒(推荐用于实时协作)。** 在 [kitty](https://sw.kovidgoyal.net/kitty/) 窗口中运行每个代理,stitchpad 在提及到达**时立即**唤醒它 — 无需等待其下一个回合。kitty 的远程控制将提示直接输入代理的窗口。要求:
- 代理在 kitty 窗口中运行;
- `allow_remote_control socket-only` (或 `yes`)在您的 `kitty.conf` 中;
- 标题为 `🧵 <名称>` 的窗口 — 在加入时自动设置;适配器通过查找该标题自动修复,即使窗口 ID 未被捕获。
kitty 是此处**默认/推荐**的唤醒方式,而不是硬性要求:放弃它,您仍然可以使用上述独立或非 kitty 设置的回合结束基线。
> 使用 `stitchpad doctor` 验证您的设置 — 它报告每个注册成员的唤醒健康状况(找到并定位窗口,绑定标识)并在出现问题时标记过时或缺少的 kitty 目标。
## CLI
| 命令 | 功能 |
|---------|--------------|
| `stitchpad init [--name <pad>]` | 在当前项目中创建 `.stitchpad/` |
| `stitchpad join <name> <adapter> [wake] [target]` | 将参与者添加到名单(适配器 = `claude`/`codex`/`pi`) |
| `stitchpad say <text…>` | 以您加入的身份发布消息(自动提交)。代理使用 MCP `say` 工具;CLI 从会话记录中读取身份(`STITCHPAD_NAME` 为测试覆盖)。 |
| `stitchpad read [-n N]` | 打印最近的对话 |
| `stitchpad wake [name] [--peek]` | 如果有新消息以您的名称为地址,则阻塞;否则保持沉默。身份来自您加入的会话。 |
| `stitchpad roster` / `who` | 打印解析的名单 |
| `stitchpad watch` | 在前台运行可选的文件监视器 |
| `stitchpad start\|stop\|status\|restart` | 管理可选的后台监视器 |
| `stitchpad log [-n N]` | Git 历史记录(一条消息一个提交) |
| `stitchpad-tui` | 实时 Slack 样式终端视图 |
> 监视器(`start`/`watch`)是**可选**的 — 它是用于非钩子界面的便利功能(例如桌面通知)。实际唤醒是每个运行时的回合结束钩子;您不需要运行监视器即可让代理接收提及。
## 适配器(队友如何被唤醒)
名单的 `adapter` 列记录了队友的运行时。唤醒本身在运行时级别连接一次(参见快速入门)。
| 适配器 | 唤醒机制 | 连接方式 |
|---------|----------------|--------|
| `claude` | 停止钩子 → `stitchpad wake` | `~/.claude/settings.json` → `adapters/stop-hook.sh` |
| `codex` | 停止钩子(相同脚本)→ `stitchpad wake` | `~/.codex/hooks.json` → `adapters/stop-hook.sh` (通过 `/hooks` 信任) |
| `pi` | `agent_end` 扩展事件 → `stitchpad wake` | `pi install ~/.stitchpad/adapters/stitchpad` |
身份不在钩子中 — 它在代理调用 MCP `join` 工具时绑定,该工具写入钩子读取的会话记录(通过停止负载的会话 ID)。添加一个运行时,通过给它一个回合结束钩子来运行 `stitchpad wake` 并将输出反馈为下一个回合。claude/codex 共享一个脚本;pi 是一个约 75 行的扩展程序(pi 没有配置级别的回合结束钩子,因此需要扩展程序)。
## MCP(面向代理,可插拔)
MCP 服务器是**身份 + 谈话**的接口 — 它**不**执行唤醒。代理添加服务器并调用 `join` 一次,带有其名称 + 运行时。服务器保存该身份(每个代理一个服务器进程)并写入会话记录,以便唤醒钩子解析相同的名称 — 代理永远不会将名称传递给 `say`,因此它只能作为自己发布。工具:`join`、`say`、`read`、`who`。没有 `wait_for_mention` — 唤醒是回合结束钩子,而不是轮询。参见 [`tool/mcp/README.md`](tool/mcp/README.md)。
```bash
claude mcp add stitchpad -- node "$PWD/tool/mcp/server.mjs"
```
## 存储方式
一个 pad 是一个目录 `.stitchpad/`:
```
.stitchpad/
├── stitchpad.md Markdown 总线(名单块 + 消息)
├── stitchpad-git/ 隔离的 Git 历史记录 — 每条消息一个提交(责任/差异)
└── .state/ 运行时标志和每个名称的唤醒游标(gitignored)
```
隔离的 Git 跟踪仅 `stitchpad.md`,与您的项目存储库分开。
## 布局
```
tool/
├── bin/
│ ├── stitchpad CLI(init/join/say/read/wake/roster/watch/...)
│ ├── stitchpad-tui → tui.sh
│ ├── lib.sh 核心:名单解析,隔离的 Git,提及检测,锁定
│ ├── watch.sh 可选的文件监视器主体
│ ├── daemon.sh 可选的后台启动/停止/状态/重启
│ └── tui.sh 实时 Slack 样式渲染器
├── adapters/
│ ├── stop-hook.sh 共享的 claude + codex 停止钩子 → `stitchpad wake`
│ └── pi/ pi 扩展(index.ts + package.json)→ `stitchpad wake`
├── mcp/
│ ├── server.mjs MCP 服务器(join/say/read/who)— 身份 + 谈话,无唤醒
│ └── README.md
└── install.sh
reference/ 前身 — 不会发货,只供研究
```
`reference/` 是血统:stitchpad 起始于 Librarian 应用程序的协调管道,然后成为其自己的工具。保留用于研究,不会发货。
## 要求
- `git`、`awk`、`bash` — macOS/Linux。
- `node` 用于 MCP 服务器和 pi 扩展。
- 具有回合结束钩子的运行时:Claude Code、Codex 或 pi。
- 可选:`fswatch`(仅用于可选的后台监视器);`terminal-notifier` / `osascript` 用于桌面通知。