ECC GitHub Epic 确定性同步指南:用 /epic-sync 对齐 Issue 正文、标签与本地协调快照
【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC
/epic-sync是 ECC(The agent harness performance optimization system)中面向 GitHub Epic Issue 的确定性同步命令,它将 Issue 正文视为唯一事实来源(source of truth),一键完成「正文 → 协调块 → 标签 → 本地 SQLite 缓存」的对齐闭环。阅读本文后,你将掌握github-coordination.js同步子命令的完整用法、协调块(Coordination Block)的 JSON 结构、标签推导规则与本地快照落库原理,并能在 Claude Code / Codex 等 harness 中直接复用这套以 GitHub Issue 为中心的 Epic 治理流程。
/epic-sync 是什么:一条命令完成四步确定性同步
在 commands/epic-sync.md 中,/epic-sync被定义为「对 Epic Issue 执行一次确定性同步」(Run a deterministic sync for epic issues),其核心命令为:
node scripts/github-coordination.js sync --repo <owner/repo>命令背后实际完成的四件事(原文档定义,源码逐一对应):
- 读取 Issue 正文作为权威的 Epic 状态:以 GitHub Issue 的
body为唯一事实来源,从中提取协调块; - 将协调块与标签进行对账(reconcile):根据协调块中的
status、validation、review等字段推导出期望标签集合,与 Issue 现有标签比对后计算增删; - 为每个 Epic Issue 写出全新的本地快照:把同步后的完整状态落库到本地 state store;
- 保持 SQLite 缓存与 GitHub 对齐:快照记录以
github-<owner-repo>-epic-<number>为稳定 ID 幂等 upsert。
上述实现分别落在 actions.js 的applySync、parsing.js、state.js 与 store.js 中,下文逐一展开。
运行前提:gh CLI、--repo 与默认行为
同步依赖 GitHub 官方 CLIgh。在 gh-api.js 中,所有 GitHub 操作(issue view、issue list、issue edit、issue comment)均通过spawnSync('gh', args)执行,因此运行前必须:
- 已安装并登录
gh(环境变量GITHUB_TOKEN可用); --repo为必填参数,格式必须是owner/repo。normalizeRepo会严格校验:owner/repo之外的形式(如裸字符串justowner、多段路径)都会抛出Invalid repo format;- 不传子命令时,github-coordination.js 会默认执行
sync(if (!parsed.command) parsed.command = 'sync'); - 默认扫描上限为
--limit 100个 Issue,状态默认取all(state: options.state || 'all')。
完整命令行参考:选项与输出格式
同步子命令支持以下参数(与 github-coordination.js 的usage()完全一致):
| 参数 | 说明 |
|---|---|
--repo <owner/repo> | 目标 GitHub 仓库,必填 |
--limit <n> | sync/unblock 扫描的 Issue 数量上限,默认 100 |
--config <path> | 可选协调策略配置文件,默认读取<rootDir>/config/github-native-coordination.json |
--db <path> | SQLite state store 路径 |
--home <dir> | 覆盖 state store 使用的 home 目录(默认取$HOME) |
--dry-run | 只预览变更,不修改 GitHub 与本地状态 |
--json | 输出机器可读 JSON |
--help, -h | 显示帮助 |
输出格式由formatOutput决定:--json时输出完整 JSON;sync/unblock默认走formatCollection(Repo:、Items:与逐条- #<number> <status>: <title>);单个 Issue 的操作默认走formatSummary(Status、Owner、Branch、Validation、Review、Tasks、Dependencies等字段)。
安全预演:--dry-run
applySync中对dryRun的处理是:仍完整计算每条 Issue 的期望标签与 body 差异,但跳过editIssue与upsertCoordinationWorkItem,并把snapshot置为null,同时在结果中附带labelPlan({ addLabels, removeLabels })。因此生产环境建议先执行:
node scripts/github-coordination.js sync --repo <owner/repo> --dry-run核对标签增删计划与将要重写的正文后,再去掉--dry-run正式执行。
同步的底层实现:applySync 的调用链
applySync(actions.js)对每条 Issue 依次执行:
- 拉取:
listIssues(repo, { state: 'all', limit }),通过gh issue list --json number,title,body,url,state,labels,author,updatedAt,assignees批量获取; - 读取状态:
getCoordinationState(issue, policy)—— 从 body 中正则提取协调块 JSON 并解析,解析失败时仅输出 warning 并退回默认状态(defaultCoordinationState); - 构造下一状态:
buildIssueStateFromAction(issue, currentState, 'sync', {...})—— 保留现有status/validation/review,project.state缺省回退为backlog,并刷新lastAction: 'sync'、lastActionAt、lastSyncAt时间戳; - 推导标签:
desiredLabelsForState(nextState, policy)生成期望标签集合; - 对账标签:
syncIssueLabels(repo, issue, nextState, policy, options)计算addLabels与removeLabels(移除规则:coordination:*前缀或 epic 标签且不在期望集合中),非 dry-run 且确有差异时调用gh issue edit --add-label/--remove-label; - 重写正文:
mergeIssueBody(issue, nextState, policy)渲染新的协调块并替换旧块;normalizeBodyForComparison会先把lastSyncAt归一化后再比较,避免时间戳抖动造成无谓的editIssue调用; - 落库:
upsertCoordinationWorkItem(store, repo, trackedIssue, nextState, 'sync', ...)写入本地 SQLite。
最终返回{ repo, syncedAt, count, items },items中每条都包含summarizeStateForOutput的完整字段、labelPlan与snapshot。
协调块(Coordination Block):Issue 正文中的单一事实来源
协调块是同步机制的核心数据载体。其标记名由策略中的sectionMarker决定(默认ecc-coordination,见 policy.js),格式为 HTML 注释包裹的 JSON 代码块:
<!-- ecc-coordination:start --> ```json { ... }`renderCoordinationState`([parsing.js](https://link.gitcode.com/i/c75b92e2173a5efb4d1e1c7adb5d0618))渲染出的完整字段包括: - `schemaVersion`:默认 `ecc.github.coordination.v1`; - `kind`:固定 `epic`; - `status`:`available` / `claimed` / `ready` / `blocked` / `published` 等; - `owner`、`branch`:认领人与分支; - `validation`:`pending` / `passed` / `failed`; - `review`:`not-requested` / `requested` / `approved` / `changes-requested`; - `project`:`{ state: 'backlog' | ..., fields: {} }`; - `dependencies`:从正文 `#123` 引用中提取的依赖 Issue 号数组; - `tasks`:从 `## Tasks` / `## Task List` 标题下的 `- [ ]` / `- [x]` 清单解析出的任务数组; - `labels`:规范化后的标签列表; - `lastAction`、`lastActionAt`、`lastSyncAt`、`notes`。 `mergeIssueBody` 负责幂等合并:若正文已存在相同 marker 的块则整体替换,否则追加到正文末尾。`extractCoordinationState` 在 JSON 畸形时会抛出 `SyntaxError`(提示 `Malformed coordination JSON in body`),`getCoordinationState` 捕获后降级为默认状态并打印 warning,保证同步流程不会因单条 Issue 损坏而中断。相关解析逻辑均有对应测试用例,见 [tests/lib/github-coordination.test.js](https://link.gitcode.com/i/c1de2b0716ffd123835857780949c5f4)。 ## 标签与状态映射:coord标签的推导规则 同步不直接复制标签,而是根据协调状态「推导」期望标签。`desiredLabelsForState` 的规则(默认值定义在 `DEFAULT_LABELS`,[policy.js](https://link.gitcode.com/i/b895168714274744350ab9fdd0ea6427)): | 状态 | 追加的标签 | | --- | --- | | 任何 Epic | `epic`、`coordination:synced` | | `status: available` | `coordination:available` | | `status: claimed` | `coordination:claimed` | | `status: ready` | `coordination:ready` | | `status: blocked` | `coordination:blocked` | | `validation: passed` | `coordination:validated` | | `review: requested` | `coordination:review-requested` | | `review: approved` | `coordination:review-approved` | | `review: changes-requested` | `coordination:review-changes-requested` | | `status: published` | `coordination:published` | `syncIssueLabels` 在加标签时只关心「期望集 vs 当前集」的差集;删除时只清理 `coordination:*` 或 epic 标签,绝不触碰用户自定义的业务标签,避免同步误删。因此 `/epic-sync` 可以安全地反复运行——它是幂等的(idempotent),重复执行不会产生标签漂移或正文重复。 ## 本地快照与 SQLite 缓存 同步的最后一步是把每个 Epic 写入本地 state store([store.js](https://link.gitcode.com/i/ad6bbd680919f201a73ba2ce326a1a81)): - 快照 ID:`epicWorkItemId(repo, issueNumber)` 生成 `github-<owner-repo>-epic-<number>`,保证同一 Epic 跨多次 sync 幂等 upsert; - `source: 'github-epic'`、`sourceId` 为 Issue 号,`status` 通过 `mapStateToWorkItemStatus` 映射(如 `blocked → blocked`、`claimed/ready/validated → in-progress`、`published → done`、`available → open`); - `priority`:`blocked` 状态标记为 `high`,其余为 `normal`; - 完整协调状态、project 投影、标签与动作时间戳存入 `metadata`,`syncedBy: 'ecc-github-coordination'` 标识来源。 存储后端由 `createStateStore({ dbPath, homeDir })` 创建;传 `--db false` 可禁用本地缓存(`openStore` 直接返回 `null`,此时 `upsert` 返回 `null`,但 GitHub 侧同步照常执行)。 ## 策略配置:github-native-coordination.json 同步行为由协调策略控制,配置文件默认为 [config/github-native-coordination.json](https://link.gitcode.com/i/d83c0b2b464a01f1f24df4aa6ffdd146)。`loadPolicy` 会递归合并 `DEFAULT_POLICY` 与用户配置(各子对象按字段级浅合并),关键可配置项: - `schemaVersion`、`sectionMarker`:协调块版本与标记名; - `labels`:覆盖上述全部标签名; - `review.required`:是否强制 review 门禁(默认 `true`); - `validation.required`:是否强制校验门禁(默认 `true`); - `branchModel`:`epicOnly`(默认 `true`)、`taskBranches`(默认 `false`),即默认不创建任务分支; - `project`:GitHub Projects 投影开关(默认 `enabled: false`)与字段名映射。 可用 `--config <path>` 指向自定义策略文件;文件缺失时静默回退到 `DEFAULT_POLICY`,存在但无法解析或不是 JSON 对象时则直接抛错。 ## 兼容别名与 Epic 命令族 `/epic-sync` 提供两个兼容别名([commands/epic-sync.md](https://link.gitcode.com/i/4b06a65d5de41e53459e547c739df5ea)): - `/projects` - `/work-items sync-github` 它与同族的 Epic 治理命令形成完整生命周期闭环: - [commands/epic-claim.md](https://link.gitcode.com/i/dd12859bcd4d3fad4c0678151eb3bfb5)(`claim <issue-number>`):认领 Epic,写入 owner/branch 并追加认领审计评论; - [commands/epic-decompose.md](https://link.gitcode.com/i/95eec7965dca454db9983166cc8f8b26)(`decompose <issue-number>`):从正文任务清单与 `#依赖` 引用重建任务分解; - `validate <issue-number>`:校验依赖是否全部关闭并更新 `coordination:validated`; - `review <issue-number>`:标记 `approved/requested/changes-requested`; - `publish <issue-number>`:通过校验与 review 门禁后发布(`status: published`); - `unblock`:扫描所有 `blocked` Epic,当其依赖全部关闭时自动置为 `ready`。 其中 `publish` 会先以 dry-run 方式执行 `validate`,任一检查失败即抛错拒绝发布;若策略要求 review 且当前不是 `approved` 也会拒绝。`sync` 本身是所有状态流转的公共底座——无论之前执行过哪条命令,`/epic-sync` 都能把 GitHub 现状重新收敛为一致的协调块、标签与本地快照。 ## 安全边界与已知限制 - **写操作需谨慎**:`sync` 会批量改写 Issue 正文与标签,务必先用 `--dry-run` 与 `--limit` 小范围验证; - **gh shim 信任边界**:环境变量 `ECC_GH_SHIM` 仅用于隔离测试环境(让 `gh` 调用重定向到测试脚本),生产环境设置它等同于允许任意脚本以调用者权限执行([gh-api.js](https://link.gitcode.com/i/d20e958a4627de891c5149459e17bdc6) 有明确注释警告); - **claim 非原子性**:`applyClaim` 是「读→检查→写」序列,并发调用可能双重认领,源码注释建议通过外部串行化(如任务队列)规避——`sync` 本身不受此影响,因为它是基于当前状态的幂等收敛。 ## 小结 `/epic-sync` 用一次幂等同步把「Issue 正文 = 协调块 = 标签 = 本地快照」四层状态收敛为同一事实。对多 Agent / 多 harness 协作场景而言,它提供了可审计、可回放、可预演的 Epic 治理基线:正文中的 JSON 协调块是机器可读的单一事实来源,`coordination:*` 标签是 GitHub 原生的状态索引,SQLite 快照则是本地可离线查询的投影。配合 `claim / validate / review / publish / unblock` 命令族,即可在不引入第三方项目管理工具的前提下,用纯 GitHub 原语跑通完整的 Epic 生命周期。【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考