把已批准的 OpenSpec change 跑到完成,同时让模型只做机械转发:内置本地 MCP 服务计算票据 DAG 前沿、原子认领任务、为每个 assignment 准备独立 git worktree,并返回确定的 actions。会话用 DSH subagent 派发每个 action,完成后按在干净且已前进的 HEAD 上重跑验证命令得到的哈希绑定回执来 reconcile,子代理口头说“做完了”不算成功。运行中改范围就是直接改 tasks.md。需要 PATH 上有 Python 3.10+,且目标项目使用 OpenSpec 的 git 仓库。
安装
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:Lumos-789/baton
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
OpenSpec 变更唯一的 ticket / DAG / 会话子代理控制面。 本地 MCP server 返回确定性的会话动作;主会话用 DSH
subagent工具派发每个任务包、 绑定子代理 id,并依据密封回执(sealed receipt)结算完成通知。
解决什么问题
OpenSpec 擅长规格驱动的分解(proposal -> tasks -> archive),但不负责执行。
Baton 把一个已批准的变更确定性地变成完成的工作:主会话从不自行决定 ticket 状态,
而是原样转发 Baton MCP server 返回的确定性 actions 给 DSH 子代理,再把每个完成
通知对照密封回执(任务的验证命令在隔离 worktree 中全绿)结算。子代理的自由文本
输出不被采信。
密封回执是 receipt.py 在本地产生的哈希绑定证据(任务包哈希 + 干净前进的 HEAD +
退出码为 0 的验证结果)。它是完整性证据,不是对抗恶意子代理的密码学证明。
三条接缝由确定性机制桥接:
| 接缝 | Baton 的答案 |
|---|---|
| 依赖(按 section 顺序的 DAG -> 下一步跑什么) | SessionController.actions() 每次调用重算前沿并原子认领不同任务 |
| 并发(<=5 个并行任务) | 每个任务一个隔离 git worktree;集成由仓库级锁串行化 |
| 状态(子代理结束 -> 任务完成) | 密封回执是唯一成功证据;控制器集成分支、落定尝试、回写 tasks.md 的 [x] |
Baton 是指挥。SessionController 是唯一确定性调度器;主会话是机械转发器;
OpenSpec 是计划面。
安装(DSH)
Baton 是一个 DSH bundle:一个包同时挂载 baton 技能并启动本地 MCP server。
要求 DSH 0.2.1-rc.2 或更新、提供 subagent 工具的 profile(自带的 dsh-base
即可)、PATH 上有 Python 3.10+(或用 BATON_PYTHON 指定)。
# 从 checkout 安装
dsh plugin add /path/to/baton
# 发布后
dsh plugin add dsh-openspec-baton
自检(自包含,只需 python3 + git;通过 stdio 驱动真实 MCP server,健康则退出 0):
python3 tests/mcp_smoke.py
包名用 dsh-openspec-baton 以避开无关的 dsh-baton 插件;仓库名与品牌保持
baton,MCP 命名空间保持 mcp__baton__*。
安装(ZCode,仅本地开发)
同一仓库还带有 ZCode 插件形态(.zcode-plugin/plugin.json,未发布到任何公开
marketplace):挂载同一份 skills/baton/SKILL.md,并以同样的 stdio 方式启动
python3 + mcp-servers/baton-server.py,mcp__baton__* 工具在 ZCode 会话中
行为一致。要求 python3 可达且为 Python 3.10+。
快速开始
在业务项目里按项目自身的 openspec 工作流写一个变更并获批:
openspec/changes/<change-id>/proposal.md + tasks.md (未勾选的 N.M 任务)
tasks.md 就是 ticket 源:section 是阶段,任务带 N.M 编号,一个任务被它之前
所有 section 的任务阻塞(同一 section 内并行)。最小形态:
# Tasks: add-login
## 1. 后端
- [x] 1.1 token 端点
- [ ] 1.2 会话持久化
## 2. 前端
- [ ] 2.1 登录表单
[x] = 已完成,[ ] = 就绪(没有草稿态);精确解析规则见
docs/ticket-format.md。
然后对会话说:
run baton on <project_path> <change-id>
技能会驱动 actions -> subagent -> bind_agent -> 完成通知 -> reconcile,
直到批次返回 complete。
架构
主会话(机械转发器 — 不做任何模型驱动的状态决策)
|- mcp__baton__actions(project_path, feature, session_id, capacity<=5)
| -> SessionController.actions():恢复/结算密封回执、计算前沿、原子认领、
| 准备隔离 worktree 与不可变任务包,返回
| dispatch/recover/resolve_merge/wait/blocked/complete 动作
|- subagent(dispatch.prompt, cwd=dispatch.cwd) -> 子代理 id
|- mcp__baton__bind_agent(assignment_id, claim_token, agent_id)
|- 运行时送达子代理完成通知
`- mcp__baton__reconcile(assignment_id, claim_token, agent_terminal, ...)
-> 密封回执 -> 成功并集成;否则 unknown + recover
SessionController(唯一确定性调度器)
|- 持久计划存储(.dsh/baton/queue.db):修订、尝试、租约、密封回执、完成事实
|- 隔离的任务 worktree + 共享集成 worktree
|- 串行 git 集成;合并冲突保留(从不自动放弃)
`- 按最新计划判定完成(全部必需 ticket 已验证并集成)
能力
会话子代理执行(唯一路径):
- 确定性调度 — 认领、租约、worktree、回执验证、集成、完成判定全部脚本化, 模型不决定状态。
- 隔离 worktree — 每个任务一个分支;容量 <=5 的滑动窗口;集成由仓库级锁串行。
- 密封回执 —
scripts/receipt.py的verify/seal是唯一被采信的成功 证据;没有回执的完成通知把尝试翻成unknown。
控制面:
- OpenSpec 原生的认知阶段 — “用 baton 完成 X” 指先跑项目的 OpenSpec 工作流
(对齐 -> 写变更 -> 用户批准),再驱动执行到
complete。 - 活计划 = 直接改 tasks.md — 运行中增删任务,下一次
actions()记录新计划 修订并重算前沿;在飞的任务包保持不可变。
可观测性:scripts/ticket_board.py 为项目的 OpenSpec 变更生成纯静态 HTML
看板(零进程、零端口):
python3 scripts/ticket_board.py build-all /path/to/project
# -> .dsh/baton/board-all.html (所有变更一板)
python3 scripts/ticket_board.py build /path/to/project <change-id>
# -> .dsh/baton/<change-id>/board.html
独立协同内核:scripts/queue.py 不依赖 MCP server、不依赖会话 — 把任意 shell
命令包进资源闸门、提交后台任务、冻结资源、全量审计。状态在一个 SQLite 库
(默认 ~/.baton/coordination/queue.db,--db 可覆盖)。核心是排空屏障
(drain barrier):破坏性命令(迁移、重建索引)与资源上的其他使用者不再竞速 —
新的认领排队,在飞租约跑完,屏障始终会解冻:
python3 scripts/queue.py gate --resource db:prod --reason "schema migration" \
-- ./migrate.sh
包内容
| 路径 | 用途 |
|---|---|
index.js |
挂载内置 skills/ provider 与 stdio MCP server |
cordis.patch.yml |
DSH bundle insert 行(dsh-openspec-baton) |
.zcode-plugin/plugin.json |
ZCode 插件清单(本地开发安装;同一技能 + MCP server) |
skills/baton/SKILL.md |
baton 技能(actions -> subagent -> reconcile) |
mcp-servers/baton-server.py |
本地 stdio MCP server(mcp__baton__*) |
scripts/ |
确定性控制器、计划存储、回执、队列 CLI |
回归
标准回测入口 — 完整 pytest 套件(含临时 git fixture 的 e2e)、真实 MCP stdio 冒烟、文档/文件一致性检查:
./tests/regression.sh
文档
- docs/architecture.md — 为什么确定性控制面是核心 IP
- docs/ticket-format.md — OpenSpec 变更 -> ticket 映射规格
许可
MIT
链接
同类插件
loopx-project/loopx#dsh-loopx-plugin★ 6537
LoopX——面向长周期 Agent 的提供商中立、本地优先状态内核与控制平面:在 DeepSeek Harness 执行层之上持久化 Goal、Todo、门禁、证据、配额、恢复与交接状态;插件负责引导安装 CLI 与技能、准入有界的同会话续跑,并为精确绑定的工作循环提供本地 GoalBar。
Q00/ouroboros#integrations/dsh-plugin★ 6308
通过 DSH MCP 客户端挂载 Ouroboros 的纯配置包,在 DSH 中提供 36 个涵盖需求访谈、Seed、执行、评估与演化流程的工具。
chuspeeism/dashi-taskboard#deepseek-harness★ 3434
把当前已安装并运行中的 Codex Taskboard 嵌入 DeepSeek Harness 侧边栏,并通过 Launcher 运行时描述文件连接,而不是使用固定端口。
NanmiCoder/dsh-agent-teams★ 2647
AgentTeams 多智能体团队。
EthanYoQ/AI-Novel-Writer#dsh-ai-novel-writer★ 2265
安装专用 AI 小说创作预设与工作台:提供带修订号的本地项目资产、紧凑侧边工作台,以及需要原生审批的逐文件变更。
Miaotofu01/Study-Mate★ 1307
你的AI学习搭档:定计划、讲知识、做项目,学透一门科目。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。