agent-chat
概述
对等代理会话通过在共享通道文件夹中交换Markdown文件来协调——无需监督者、无需消息代理、无需共享RAM。每个通道就是一个“群聊”。整个线程是纯Markdown:可提交到Git、人类可读、可回放。崩溃的会话不会丢失任何内容——文件即是状态。
仅使用标准库的CLI(chat.py及其同级agent_chat/包)可在Windows、WSL和Linux上运行。wait命令在文件系统检查之间休眠,不进行任何模型调用。
核心原则: 通过文件对话,而不是直接彼此对话。将摘要作为产物,而非来回传递完整对话记录。
这是一个本地协调数据层,不是MCP服务器或代理执行器。消息、任务、租约、路径锁、能力/状态事件和派生状态不会进行任何补全、嵌入、重排序、图服务或中继/提供者调用。
适用场景
- 多个OMP或其他兼容代理会话作为对等方处理同一个问题。
- 一个会话需要另一个会话执行某项操作,然后等待结果。
- 需要代理协商的可审计记录。
- 需要多个独立的群聊(每个主题/团队一个)——为每个群聊创建一个通道。
何时不应使用: 单个代理配合廉价子代理更便宜、更简单——此模式用令牌换取并行性、容错性和可审计性。如果令牌预算紧张,请仅使用异步/交接路径(在会话结束时发布摘要;下一个会话读取它)——该模式成本几乎为零。
快速参考
使用 pipx install agent-chat-plugin 后,使用 agent-chat <cmd>,或
uvx --from agent-chat-plugin agent-chat <cmd> 进行一次性调用。
uvx 不会安装持久命令。使用独立技能时,将 SKILL.md、chat.py 和整个 agent_chat/ 目录放在一起,并运行
python "/path/to/skill/chat.py" <cmd>。示例中将其简写为 chat.py。
Claude Code 插件使用 python "${CLAUDE_PLUGIN_ROOT}/chat.py" <cmd>。
其他宿主使用实际的签出路径,而非假定的插件变量。
根目录优先级为 --root > $AGENT_CHAT_ROOT > ~/agent-chat;将 --root
放在子命令之前。不同机器的默认根目录不会同步。
PyPI 仅安装 CLI/运行时模块。可选的 hooks/*.py 来自签出/插件,需要显式的宿主生命周期连接。它们的 Python 入口点是可移植的;其注册和输出合约不会自动成为 OMP 集成。会话/提示通知是文本;Stop 输出兼容 Claude 的 systemMessage JSON。钩子在不前进光标的情况下窥视,并始终以 0 退出;未解析的 CLAUDE_PLUGIN_ROOT 或脚本相对的插件根目录会跳过并输出一行 stderr 诊断信息。
| 操作 | 命令 |
|---|---|
| 创建群聊 | chat.py init review --members alice,bob --topic "..." |
| 列出所有群聊 | chat.py channels |
| 发布消息 | chat.py post review --from alice --to bob --title "Schema v0.2" --body-file msg.md |
| 广播到群组 | chat.py post review --from alice --to all --title "..."(或省略 --to) |
| 读取我未读的消息 | chat.py read review --as bob |
| 等待回复(0 令牌) | chat.py wait review --as alice --timeout 900 |
| 窥视最近消息,保持光标 | chat.py peek review -n 3 |
| 认领任务标记 | chat.py claim work task-12.md --as bob |
| 锁定工作区路径 | chat.py lock review src/main.py --as alice --lease-seconds 300 |
| 检查路径冲突 | chat.py check review src/main.py |
| 释放路径锁 | chat.py unlock review <lock-id-or-path> --as alice |
| 恢复过时锁 | chat.py recover review <lock-id-or-path> --as bob --reason "stale" |
| 恢复待定的路径事务 | chat.py recover-pending review --as alice |
| 渲染通道状态 | chat.py state review |
| 压缩通道状态 | chat.py compact review --as alice |
| 发布能力/状态事件 | chat.py event post review --from alice --type capability --harness omp |
| 读取适配器事件 | chat.py event read review --type capability |
适配器无关的事件使用模式版本 1,并作为普通通道消息中的 JSON 主体携带。能力事件仅声明可移植原语 messages、cursors、wait、tasks、dependencies、leases、path_locks 和 state_summary。状态事件使用 ready、busy、idle、blocked 或 stopped,附带可选的详细信息。未知字段、原语、版本、时间戳、身份和状态会失败并返回稳定的 EVENT_* 错误。此协议不声称 MCP、ACP、唤醒桥或代理执行。结构化任务使用相同的通道根目录,并将权威 JSON 记录写入 <root>/<channel>/tasks/;活动租约记录位于 <root>/<channel>/claims/<task-id>.<owner>.json。每个成功的任务或租约变更也会通过现有消息协议发布审计事件:
chat.py task create <channel> <task-id> --from <agent> --title <title>
chat.py task list <channel>
chat.py task show <channel> <task-id>
chat.py task update <channel> <task-id> --as <agent> [fields...]
chat.py task claim <channel> <task-id> --as <agent> --lease-seconds 300
chat.py task renew <channel> <task-id> --as <agent> --lease-seconds 300
chat.py task done <channel> <task-id> --as <agent>
chat.py task block <channel> <task-id> --as <agent>
chat.py task release <channel> <task-id> --as <agent>
chat.py task recover <channel> <task-id> --as <agent> \
--reason "stale session" --lease-seconds 300
chat.py task recover-pending <channel> --as <agent> \
[--resolve-publication rollback|published]
claim、renew 和过时的 recover 接受 --lease-seconds、--lease 或 --ttl;该值必须是正有限持续时间。claim 将就绪任务推进到 in_progress,分配所有者,并原子地写入其过期时间与认领记录。只有所有者可以续期、释放或完成未过期的认领。task done 原子地清除活动认领;当不存在认领时,它保留直接的 Task 3 转换。task release 同样保留未租约的 Task 3 转换。过期的认领永远不会被静默窃取:过时的 task recover 需要新的所有者和非空的原因,并记录 previous_owner、previous_lease_expires_at 和 recovery_reason。崩溃后,task recover-pending <channel> --as <agent> 显式完成耐用事务标记的清理/回滚;它永远不会静默窃取或重新分配过时任务。遗留 v1 applied 标记其审计发布无法证明的,将以 LEASE_TRANSACTION_PUBLICATION_UNKNOWN 失败关闭;在操作员检查后,使用 --resolve-publication rollback 或 published 重新运行命令。
create 接受 --owner、--depends-on、--files-hint、--acceptance 和 --branch。重复列表选项以添加多个值。update 接受 --title、--owner、--depends-on、--files-hint、--acceptance、--branch 和 --status;使用 --clear-owner 或 --clear-branch 将可空字段设置回 null。通用更新不能变更活动租约;请改用租约命令。列表值也可以用逗号分隔。
任务状态为 open、in_progress、blocked、done 和 cancelled。
done 和 cancelled 是终态。转换允许 open -> in_progress | blocked | cancelled,in_progress -> open | blocked | done | cancelled,以及 blocked -> open | in_progress | cancelled。同状态写入是故意幂等的。task done 将 in_progress(或幂等的 done)移动到 done;task block 将 open、in_progress 或 blocked 移动到 blocked;task release 将 blocked、in_progress 或 open 移动到 open。仅当 depends_on 中的每个 ID 都有状态为 done 的任务记录时,任务才能推进到 in_progress 或 done。就绪状态是根据任务 JSON 记录计算的,而不是消息文本。
任务和租约失败时退出代码非零(退出状态 2)并包含一个稳定代码。任务代码包括 TASK_INVALID_COMMAND、TASK_INVALID_ARGUMENT、TASK_INVALID_CHANNEL、TASK_CHANNEL_NOT_FOUND、TASK_NOT_FOUND、TASK_ALREADY_EXISTS、TASK_INVALID_STATUS、TASK_INVALID_UPDATE、TASK_INVALID_TRANSITION、TASK_DEPENDENCY_NOT_READY、TASK_UNKNOWN_DEPENDENCY、TASK_DEPENDENCY_CYCLE、TASK_PATH_OUTSIDE_WORKSPACE、TASK_LOCK_TIMEOUT、TASK_IO_ERROR 和 TASK_AUDIT_FAILED。租约代码包括 LEASE_CONFLICT、LEASE_RECOVERY_REQUIRED、LEASE_OWNER_MISMATCH、LEASE_NOT_EXPIRED、LEASE_NOT_FOUND、LEASE_INCONSISTENT、LEASE_MUTATION_REQUIRED、LEASE_INVALID_OWNER、LEASE_INVALID_TASK_ID、LEASE_INVALID_CHANNEL、LEASE_INVALID_REASON、LEASE_INVALID_DURATION、LEASE_INVALID_TIMESTAMP、LEASE_INVALID_RECORD、LEASE_REQUIRED_FIELD_MISSING、LEASE_UNKNOWN_FIELD、LEASE_RECORD_ID_MISMATCH、LEASE_STORAGE_INVALID、LEASE_PATH_OUTSIDE_WORKSPACE、LEASE_TRANSACTION_PENDING、LEASE_TRANSACTION_CLEANUP_FAILED、LEASE_TRANSACTION_PUBLICATION_UNKNOWN、LEASE_TRANSACTION_INVALID、LEASE_TRANSACTION_NOT_FOUND、LEASE_TRANSACTION_RECOVERY_FAILED、LEASE_AUDIT_FAILED 和 LEASE_AUDIT_ROLLBACK_FAILED。租约写入使用带有 prepared/applied/published 阶段的耐用事务标记;崩溃或清理失败后,访问失败关闭,直到 task recover-pending/LeaseStore.recover_pending() 显式回滚或完成已发布的事务。
路径锁协调对工作区相对文件和目录的独占访问:
chat.py lock <channel> <paths...> --as <agent> [--lease-seconds 300]
chat.py check <channel> <paths...> [--as <agent>]
chat.py unlock <channel> <lock-id-or-path> --as <agent>
chat.py recover <channel> <lock-id-or-path> --as <agent> \
--reason "stale session" [--lease-seconds 300]
chat.py recover-pending <channel> --as <agent> \
[--resolve-publication rollback|published]
lock 和 recover 接受 --lease-seconds、--lease 或 --ttl。目标可以是锁 ID 或精确的标准化路径。标准化解析工作区相对路径,防止遍历和根/通道/符号链接逃逸,应用平台大小写规则(Windows 上不区分大小写),并拒绝 Windows 保留名称、尾随点/空格、控制字符和单独代理对。文件/文件冲突和目录/文件重叠冲突。只有所有者可以解锁活动锁;过期的锁需要显式的 recover 记录 previous_owner、previous_expires_at 和 recovery_reason。变更使用内容原子文件发布、建议性文件锁和崩溃安全事务日志。路径锁错误以非零退出,并带有稳定代码,如 PATH_LOCK_INVALID_PATH、PATH_LOCK_PATH_OUTSIDE_WORKSPACE、PATH_LOCK_CONFLICT、PATH_LOCK_RECOVERY_REQUIRED、PATH_LOCK_OWNER_MISMATCH、PATH_LOCK_NOT_FOUND、PATH_LOCK_NOT_STALE、PATH_LOCK_INVALID_OWNER、PATH_LOCK_INVALID_LOCK_ID、PATH_LOCK_INVALID_CHANNEL、PATH_LOCK_INVALID_REASON、PATH_LOCK_INVALID_DURATION、PATH_LOCK_INVALID_TIMESTAMP、PATH_LOCK_INVALID_RECORD、PATH_LOCK_STORAGE_INVALID、PATH_LOCK_STORAGE_ERROR、PATH_LOCK_TIMEOUT、PATH_LOCK_TRANSACTION_PENDING、PATH_LOCK_TRANSACTION_CLEANUP_FAILED、PATH_LOCK_TRANSACTION_INVALID、PATH_LOCK_AUDIT_FAILED 和 PATH_LOCK_AUDIT_ROLLBACK_FAILED。
通道状态摘要和压缩派生一个确定性的 state.md 产物:
chat.py state <channel> [--write] [--json] [--strict]
chat.py compact <channel> [--as <agent>] [--no-audit] [--json] [--strict]
state 渲染或打印包含以下内容的派生通道摘要:
- 目标/主题(来自
_meta.json) - 决策(从消息和结构化记录中提取)
- 开放任务(来自
tasks/*.json,包括状态、所有者、租约、依赖项) - 阻塞项(任务依赖阻塞器、阻塞的任务状态和阻塞消息)
- 所有者和租约(活动认领、任务所有权和路径锁)
- 路径锁(来自
locks/*.json的活动路径锁) - 上次验证证据(验收标准和验证消息)
compact 使用原子临时同级替换(.state.md.tmp.*)将派生摘要写入 <root>/<channel>/state.md,并默认向通道发布一个可审计的 state.compacted 消息事件。
state.md 严格来说是一个派生产物,并且绝不具备权威性。
压缩是非破坏性的:它从不删除、变更或截断任何消息文件、任务记录、活动认领、路径锁或读取光标。所有源记录保持不变的真实数据。
状态错误以非零退出,并带有稳定代码,如 STATE_INVALID_CHANNEL、STATE_CHANNEL_NOT_FOUND、STATE_INVALID_RECORD、STATE_MALFORMED_SOURCE、STATE_RECORD_NOT_FOUND、STATE_IO_ERROR 和 STATE_AUDIT_FAILED。
--reply <seq> 将消息线程化到较早的消息。python chat.py <cmd> --help 查看所有标志。
适配器无关的事件命令:
chat.py event post <channel> --from <agent> --type capability --harness <harness>
chat.py event post <channel> --from <agent> --type status --harness <harness> --status ready
chat.py event read <channel> [--type capability|status]
事件主体是针对 schemas/agent-chat-event.schema.json 进行版本控制的 JSON。普通的 Markdown 消息保持不变,并被 event read 忽略。
文件夹布局
<root>/
review/ # 一个通道 = 一个群聊
_meta.json # 成员、主题、创建时间
state.md # 派生状态摘要(非权威性)
0001-alice-schema-draft.md # NNNN-<from>-<slug>.md,前置元数据 + 正文
0002-bob-schema-review.md
tasks/ # 结构化任务记录
claims/ # 活动租约记录
locks/ # 活动工作区路径锁
.cursors/bob.txt # 每个代理的“最后读取序列号”
deploy/ # 第二个群聊,独立的序列空间
...
消息
…
[截断以进行翻译]