mcpField
A
agent-sync

agent-sync

github.com/sshelegAgent 工作流5259 次安装2 天前更新
代码仓库

关于 agent-sync

agent-sync 是用于协调多个 Agent 在同一仓库并行工作的 Skill。它结合 Git 持久记录与可过期的协调状态,提供租约、编辑保护和项目配置检查。

主要功能

  1. 01通过可过期租约协调 Agent
  2. 02保护共享注册表的编辑
  3. 03跟踪跨仓库依赖
  4. 04设置并验证项目配置
  5. 05协调 Git 记录与云端状态

适用场景

  1. 01避免多个 Agent 覆盖共享文件
  2. 02在 Agent 会话间领取和释放任务
  3. 03检查离开期间的依赖变更

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ssheleg/agent-sync --skill agent-sync

安装后在 Claude Code 中输入/agent-sync确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
adapter-contract.md
backend-fs.md
backend-notion.md
backend-outline.md
branching.md
earned-rules.md
fabric-coordination.md
hooks.md
lease-protocol.md
pipeline-binding.md
roadmap.md
two-sources.md
scripts/
agent_sync.py
bash_writes.py

详细介绍

agent-sync——一个项目,多个 Agent,互不冲突

两个平面,以及它们之间的一条规则:

Git 是记录平面,云端是协调平面。 必须留存的事实先写入 Git,再在云端引用。 谁此刻在做什么 这样的事实存于云端,并会过期。

云端对象绝不会是持久事实的唯一存放位置。下面的所有内容都是为了确保 多个 Agent 同时写入时仍能做到这一点。

**即使无人要求,也要在以下情况下使用:**在包含 .claude/agent-sync.json 的项目中,编辑共享注册表(决策、待解决问题、路线图、工作流、依赖项)之前;未认领的编辑会让两个 Agent 相互覆盖。也可使用 /agent-sync。

四个陷阱——先读这些

**1. 知识库永远不会决定租约。**它做不到:对同一篇 Outline 文档并发追加 12 次,返回了 12 次成功,却只留下了 3 行。互斥必须依靠真正的比较并交换机制。该平面只承载记录,不做其他事。

2. 弄清楚自己持有哪种租约,并明确说明。leaseBackend: "local" 是原子文件创建——在同一文件系统的进程之间互斥,跨机器时仅具建议性。leaseBackend: "git" 会推送一个引用,而远程端拒绝非快进更新,就是比较并交换机制——跨机器互斥。acquire 会打印所用的租约类型。假装持有租约比没有租约更糟:其他 Agent 会停止检查。

acquire 还会将认领信息写入路线图,而 release 会准确还原原状——只改一行、一个单元格;遇到歧义则拒绝操作;往返后 git diff 为空。配置 claimTags 或关闭任务前,请先阅读 references/roadmap.md;关闭任务是对工作成果的说明,应由你负责。

在分支上工作;集成分支是他人维护的稳定基线。acquire 只会在集成分支上写入认领信息——在其他任何分支上,持有者都会留在协调平面中,所有 Agent 都能通过 status 看到它。认领信息一旦提交到某个分支,在合并之前就不可见,而且会让共享路线图变成两个分支都会编辑的文件。使用 merge 落地工作:先计算冲突,不触及任何内容;将合并记录写入 docs/MERGES.md,并释放 --key 租约;merges 会说明你离开期间落地了哪些内容。合并前请先阅读 references/branching.md。

**3. 验证 Claude hook 适配器。**在强制执行未经验证时,请明确运行 guard。将 hook 证据与 gated 租约仲裁情况分别报告。某个模式的五个能力字段只在一处定义——references/adapter-contract.md → 状态能力契约,此处不再重复说明。项目未受保护时,不要声称它已受保护。

**4. 日志无法读取不等于竞争失败。**输出 -,接受 -/*/+,过滤之前统计所有格式错误的类条目行,并拒绝无法解析比例超过 2% 的情况。解析契约和观察到的故障详见 references/lease-protocol.md。

将其引入任何项目——完整流程

scaffold  → create the documentation architecture, only where it is absent
adopt     → read the repository, propose a config, write nothing
init      → write the approved config + the gitignored env file
            (operator places the token — never you)
reconcile --set-baseline    → make history a counted backlog, once
setup     → generate the snapshot that describes this project's wiring
check     → validate the whole thing; non-zero if it is not healthy

check 会拒绝缺失的规则目标、凭据或注册表基线、过期快照,以及由 Git 跟踪的环境文件。在引入后、配置变更后以及 CI 中运行它;它会逐一列出所有失败条件。

**scaffold 从不覆盖文件。**它会初始化一个决策注册表和一个指向快照的 AGENTS.md,并保留所有现有文件不变。

现有项目:从 adopt 开始

在 init 之前运行 adopt。它会读取仓库并打印发现的内容——ID 注册表、注册表文件、门控项——以及它拒绝替你做出的决定,然后提出配置建议。

python3 "$SKILL_DIR/scripts/agent_sync.py" adopt

先与操作员确认注册表和受保护文件:如果注册表指向错误的文件,之后的每次检查都会自信地给出错误结果;如果受保护文件列表漏掉了某个共享文件,唯一会发生冲突的位置就得不到保护。在子模块中,它不会声明任何注册表——决策属于父项目。然后从上面的 init 开始完整流程。

项目中的首个命令:init

切勿对未初始化的项目运行任何其他操作。 init 会一次性询问并确定存储方式,然后将其记录下来。

在聊天中向操作人员询问以下两项——不要猜测,也不要选择默认值:

  1. 协调状态应存放在哪里?

    • 知识云——outline(托管或可自托管)或 notion——供多台机器共享的记录、状态感知和看板——两者都不负责决定租约(陷阱 1);
    • 或本地文件(fs)——无需凭据,但其他机器上的 Agent 无法看到——没有共享状态感知、跨仓库信号或看板。

    租约由 leaseBackend 单独决定(陷阱 2),而且 gated 取决于该选择,绝不取决于记录层面——报告你实际拥有的保障。ID 也是如此:在 leaseBackend: "git" 下,即使使用 fs,注册项也会从 git refs 中预留。

  2. 如果选择云端:具体位置。 Outline 需要其实例 URL;Notion 需要容器所属页面的 ID。这些都属于配置,不是秘密,因此可以记录。令牌不可以——绝不在聊天中索要令牌、绝不读回令牌,也绝不替对方放置令牌。

然后使用对方提供的信息运行:

python3 "$SKILL_DIR/scripts/agent_sync.py" init --backend outline --url https://<their-instance>
python3 "$SKILL_DIR/scripts/agent_sync.py" init --backend notion
python3 "$SKILL_DIR/scripts/agent_sync.py" init --backend fs

init 会写入 .claude/agent-sync.json(结构,可提交)和 .env.agent-sync(身份,权限模式为 600),其中令牌一栏为空;它还会将这两个文件加入 gitignore,并打印唯一需要操作人员执行的步骤——创建令牌并放置令牌(notion:放入保管库)。除非使用 --force,否则绝不覆盖任一文件。原样转达最后的说明;此设计依赖令牌始终由对方掌管。

然后,在每次会话开始前

python3 "$SKILL_DIR/scripts/agent_sync.py" status

幂等:检查、修复、报告,并根据 check 的判定指出一个后续操作。

阅读两个状态感知部分:

  • 当前正在处理此项目的其他运行实例。 此刻谁持有哪些内容。不要接手这些任务,也不要“只是看一眼”它们所覆盖的文件。
  • 你上次查看后新增的内容。 你离开期间落地的跨仓库依赖变更——每个运行实例都带有水印,因此只有发生变化时才会打扰你。依赖变更可能解除你原计划的阻碍,也可能使计划失效。

status 还会作出以下判断:没有凭据 → 降级模式;缺少 task-pipeline → 打印安装命令并停止。检查会覆盖所有主机布局,或明确指定的 pipelinePath,因此不会被任何主机上的副本遮蔽或遗漏。租约核心(acquire/renew/release)需要后端和租约,不需要绑定。

npx sshlg-skills install

命令

命令作用
init**首先运行。**询问状态存放位置,写入配置和被 git 忽略的环境文件,打印操作员的步骤
status检查、修复、报告,并指出一个下一步操作
bootstrap创建云容器,并打印要粘贴到环境文件中的 ID
acquire <KEY>获取任务 ID 的租约。打印 won 或 lost <holder>
renew <KEY>显式保活。钩子使用 --active-only;无关调用不会延长认领
release <KEY>在所有路径上归还租约;released 表示远程引用已消失
release --held在一个进程中归还本次运行持有的所有租约——这是 SessionEnd 执行的操作
reserve <REG> [--key K] [--offline]在登记簿中预留下一个 ID(DEC、OQ、DEP 等);打印该 ID。--key 可确保重试幂等(一个键对应一个编号);--offline 会生成带命名空间的 REG-o-… ID,不具备全局权威性
map-offline <REG> <ID> <N>将离线 ID 绑定到正式预留的编号——只追加,绝不重新绑定
release-id <REG> <ID>归还最终未写入 git 的 ID
journal <text>在本次运行的日志中追加一行
record <text>追加记录实际构建的内容——--decision DEC-…、--files a,b
reconcile对比意图(git)与实际构建状态(云端)。每个项目运行一次 --set-baseline
signal <DEP-ID> <state>记录依赖状态,绝不发起请求。使用 Fabric 时,通过 com.submit 发起请求;DEP 会引用其看板消息
guard <path>回答本次运行是否可以写入该路径。退出码 0 = 可以,2 = 不可以
board重新生成共享看板和本仓库的页面。--mirror 还会将配置的 git 文档渲染到 plane 中
whoami打印本次运行的 ID 及其持有的租约
residue查看本次运行在两个 plane 中留下的内容:磁盘上的过期锁,以及没有有效租约对应的认领标签
reap [KEY…]仅清理本次运行能够证明归其所有且已用完的内容,然后重新读取目录以确认其已清除
reap --long-expired列出两个 plane 上过期 7 天以上的锁,并逐一给出判断。--apply 仅按过期时间清理——由操作员决定,绝非由你决定
setup写入生成的快照,说明本项目的配置方式,供 Agent 阅读
adopt检查现有项目并提出配置方案——不会写入任何内容
merge合并此分支:在触碰任何内容之前检查冲突,写入合并日志,并在推送后释放 --key 租约。支持 --summary、--dry-run、--push
merges查看你在此分支期间合并的内容。--all 会包含压缩后的历史记录
check从头到尾验证整个配置。配置不健康时返回非零值
scaffold [--full]仅创建缺失内容,绝不改动现有行。--full 还会初始化问题登记簿、索引、依赖看板、数据模型和文档门禁
finish [--gates]工作是否已完成——每个仓库都干净、已推送并已指向目标,且没有遗留的持有项。check 判断项目配置是否正确;此命令判断你是否已完成

根据当前 SKILL.md 的位置解析 $SKILL_DIR,并复用绝对路径; ${CLAUDE_PLUGIN_ROOT}/skills/agent-sync 是 Claude 的文本替换,不保证是 Bash 环境变量。

每个会话使用一个身份,以及身份的判定方式

身份优先级(references/earned-rules.md):AGENT_SYNC_RUN_ID · CLAUDE_SESSION_ID · CLAUDE_CODE_SESSION_ID(每次 Claude Code Bash 调用都会携带它)· 启动此 shell 的 会话(SessionStart 会将其写入 .agent-sync/sessions/<CLI pid>;命令会沿着 进程祖先链查找它)· 共享——共享身份会明确说明,绝不会被描述成相互独立。

认领——关键的形态

acquire → do the work → release

即使失败,也要释放;被遗弃的租约会阻塞任务,直到 TTL 到期。 对于 PR:先推送持久交接,再释放;参见 references/branching.md。 在另一个仓库中获取的租约会列在此会话下,renew 和 SessionEnd 钩子也会在该仓库中执行(AS-07)。

租约不等于认领。 租约说明当前由谁持有,并会到期;持久认领是 git 中的标签, 由 acquire 写入,并由 release 清除。一项事实,一个归处——不要另创第三处来记录所有权。

两个平面都采用同一种持有状态。 TTL 结束时租约也结束,因此,指向租约已结束的 run 的标签属于残留:status、residue 和 reconcile 会报告它,并由 release <KEY> 清除, 以说明它原本属于谁。租约仍有效的标签绝不会被另一个 run 触碰。

更改获取、到期、抢占或 ID 分配前,请阅读 references/lease-protocol.md。

受保护文件

配置列出了多个 Agent 都会写入的注册表文件。编辑其中一个之前:

python3 "$SKILL_DIR/scripts/agent_sync.py" guard docs/DECISIONS.md

退出码 2 说的是此 run:它没有持有租约——而不是说其他人持有该文件。 拒绝信息会指出另一个 run 及其 key,因为路径旁边的“r-x 持有租约” 很容易被转述成“r-x 持有此文件”。不要因此仍去编辑,也不要“只修一行”—— 被覆盖的决策看起来和原决策一模一样。

两种写入模式。 任务租约授权的是 TASK,而不是文件,因此受保护的写入还要获取 该文件的资源认领(res--<repo>--<canonical path>,SY-04)——即 短事务锁:同一个注册表串行处理,不同文件互不影响; 只有在 leaseBackend: "git" 时才支持跨机器。重度冲突:隔离的 worktree + 合并。 保护机制不能保证由单个任务所有者来执行强制管控。

随附的 PreToolUse 适配器会在所属仓库中针对 Edit/Write、git commit(包括同一命令暂存的内容) 以及由 scripts/bash_writes.py 解析的 Bash 写入运行此检查——它是解析器,不是沙箱。没有经过验证的适配器时,请自行运行。

预留 ID

读取“下一个可用 ID”这一行不等于预留它——两个 Agent 读到同一个数字,就都会使用它。

python3 "$SKILL_DIR/scripts/agent_sync.py" reserve DEC   # → DEC-0216

分配按合并后的日志进行定位——包括所有分片,绝不只看此 run 的日志——因此每个 Agent 都会计算出相同的答案。已预留但未写入 git?请执行 release-id,否则该数字会成为一个缺口,并被看板报告为泄漏。

日志中的内容永远不会被编辑或删除

日志会按顺序重放,因此编辑会悄无声息地改写其他 Agent 已据此采取行动的结论。应通过追加来更正:释放租约,为未使用的 ID 执行 release-id,并用较晚的记录取代错误的竣工记录。生成的页面是唯一例外。生命周期和生成对象约定:references/two-sources.md。

两种文档来源,以及协调它们的责任

Git 文档回答应当如何;竣工记录回答实际情况如何。 两者都不高于另一方,两者之间的差距就是发现的问题,而不是缺陷。这项责任贯穿任务的开始和结束:开始前执行 reconcile,完成后执行 record 和 reconcile——而 reconcile 是机械操作,因此把它显示为绿色视为双方一致,正是差异在任务两端都得以留存的原因。

首次执行 reconcile 前,请阅读 references/two-sources.md:其中包含完整责任说明、reconcile 不会判断的内容、生成的 setup 快照、文档应归属的位置,以及为何没有内容会被删除。

绑定到 task-pipeline

此技能提供各个阶段;阶段名称由 task-pipeline 自行定义。 11 个阶段中,有 5 个带有顺序规则:0 在 brief 提交前执行 acquire;1 在编写代码前执行 reconcile;3 在提交 git 前预留 ID;9 执行主要写入;10 对每个租约执行 merge/release。

配置 pipeline.json 时,请阅读 references/pipeline-binding.md——其中说明了各阶段的理由、skills[] 条目、需要保护的内容以及门控表达式。

配置

两个文件,它们之间的划分就是整个安全模型。

.claude/agent-sync.json — 结构,提交到仓库:使用哪个后端、TTL、保护哪些文件、 有哪些寄存器、运行哪些门禁。

.env.agent-sync — 身份信息,由 init 写入,权限模式为 600,并被 Git 忽略;可在此处、 父项目中或 AGENT_SYNC_ENV 指定的位置找到 — check 会打印具体位置。工具会自行读取它: 不要对它执行 source。notion 令牌应存放在 Observatory 保险库中(1.22.0)— init 会打印 vault.py put 命令;记录平面的命令会在 use_secret.py run --vault-only 下重新运行,而 保护钩子不会请求保险库。outline 会将令牌保留在文件中。scheduledIntervalSeconds(≥ 60): 租约持有时间超过此值时,会发出一次警告。

绝不要将主机名或令牌写入配置、测试、示例或提交;绝不要处理、回显令牌值,也不要通过 argv 传递令牌值。如果有人在聊天中提供令牌,请让对方改用该文件。

子模块的配置只声明它自己的寄存器。 跨仓库事实属于父项目;服务仓库列出父项目的决策寄存器 属于配置缺陷。

不可妥协的原则

  • 先追加、读回,然后再操作。绝不重写协作文档。
  • 没有 agent-sync:generated 标记的生成对象会被拒绝,而不是覆盖 — 说明有人接管了它。约定: references/two-sources.md。
  • 无论成功还是失败,所有路径上都要释放已获取的资源。
  • 运行报告必须说明留下了什么:过期只会结束租约,不会删除文件 — residue。
  • 凭据绝不能进入 argv、日志行或仓库。
  • 降级时要明确说明。ungated 是可接受的状态;谎称已执行强制检查则不可接受。
  • 同一检出目录中的两个 Agent 必须使用两个身份,否则租约只是装饰。
  • 子模块提交只有在父项目指向该提交后才算完成 — 运行 finish。
  • 云端持有的所有持久事实都必须是指向 Git 的链接,绝不能取代 Git 中的事实。
  • 边界:.claude/agent-sync.json。未配置,或只有一个 Agent 独自工作 — 跳过协调。操作者可豁免: “no coordination” / «без координации»。

触发条件

除描述中的内容外,还包括:“认领此任务”、“谁在处理这个任务”、“设置 Agent 协调” / «настрой координацию агентов»、“子模块已推送” / «сабмодуль запушен»、“父项目仍指向旧提交” / «родитель на старом коммите»。

参考资料

每个文件只在其对应触发条件下加载,而非默认加载。

文件阅读时机
references/adapter-contract.md添加或审查知识后端时 — 六个基本操作、能力标志、如实说明降级的路径
references/lease-protocol.md更改获取、过期、抢占或 ID 分配逻辑时
references/backend-outline.md调用 Outline API 或调试相关调用时
references/backend-notion.md调用 Notion API 或调试相关调用时
references/backend-fs.md不使用云端后端运行,或说明降级模式时
references/pipeline-binding.md配置 pipeline.json 或添加阶段钩子时
references/hooks.md安装、调试或移除 Claude Code 钩子时
references/two-sources.md首次协调前、决定文档归属时,或编写生成对象时
references/roadmap.md配置 claimTags、认领或关闭任务,或重新规划看板时
references/branching.md开始会产出提交的工作、合并分支,或询问离开期间有哪些工作已合并时
references/earned-rules.md询问身份为何如此解析,或询问为何需要 finish 时
references/fabric-coordination.mdFabric 协调约定,或使用 reap --long-expired 时

缺少 references/?请从 https://raw.githubusercontent.com/ssheleg/agent-sync/main/plugins/agent-sync/skills/agent-sync/references/<file> 获取。

评论

支持 Markdown