code-coordinator 0.5.46__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. code_coordinator-0.5.46.dist-info/METADATA +625 -0
  2. code_coordinator-0.5.46.dist-info/RECORD +295 -0
  3. code_coordinator-0.5.46.dist-info/WHEEL +5 -0
  4. code_coordinator-0.5.46.dist-info/entry_points.txt +2 -0
  5. code_coordinator-0.5.46.dist-info/licenses/LICENSE +110 -0
  6. code_coordinator-0.5.46.dist-info/top_level.txt +1 -0
  7. coord/__init__.py +176 -0
  8. coord/_board_mapping.py +229 -0
  9. coord/acceptance.py +468 -0
  10. coord/acceptance_drivers.py +632 -0
  11. coord/agent.py +7517 -0
  12. coord/agent_app.py +1555 -0
  13. coord/agent_update.py +417 -0
  14. coord/agents/opencode/.gitignore +13 -0
  15. coord/agents/opencode/agents/work.md +129 -0
  16. coord/agents/opencode/routing.jsonc +49 -0
  17. coord/audit.py +301 -0
  18. coord/auto_loop.py +1440 -0
  19. coord/board_bool_guard.py +72 -0
  20. coord/board_service.py +141 -0
  21. coord/board_wire.py +309 -0
  22. coord/brain.py +581 -0
  23. coord/branch_model.py +214 -0
  24. coord/cargo_cache.py +258 -0
  25. coord/ci_github.py +386 -0
  26. coord/ci_store.py +560 -0
  27. coord/claim.py +353 -0
  28. coord/cli.py +454 -0
  29. coord/client.py +610 -0
  30. coord/commands/__init__.py +1 -0
  31. coord/commands/_common.py +329 -0
  32. coord/commands/acceptance.py +916 -0
  33. coord/commands/agent_ops.py +1339 -0
  34. coord/commands/audit.py +131 -0
  35. coord/commands/chat.py +320 -0
  36. coord/commands/dispatch.py +1780 -0
  37. coord/commands/dispatch_workers.py +4894 -0
  38. coord/commands/drive.py +616 -0
  39. coord/commands/drive_queue.py +1203 -0
  40. coord/commands/gate_a.py +217 -0
  41. coord/commands/gates.py +89 -0
  42. coord/commands/issues.py +681 -0
  43. coord/commands/lifecycle.py +513 -0
  44. coord/commands/merge.py +1900 -0
  45. coord/commands/milestone.py +2081 -0
  46. coord/commands/plan_followup.py +1243 -0
  47. coord/commands/plans.py +156 -0
  48. coord/commands/release.py +2232 -0
  49. coord/commands/report.py +341 -0
  50. coord/commands/review.py +1523 -0
  51. coord/commands/scorecard.py +252 -0
  52. coord/commands/sessions.py +1930 -0
  53. coord/commands/setup.py +576 -0
  54. coord/commands/status.py +2089 -0
  55. coord/commands/terminal.py +385 -0
  56. coord/commands/test_gate.py +775 -0
  57. coord/commands/tui.py +288 -0
  58. coord/comments.py +718 -0
  59. coord/config.py +3032 -0
  60. coord/conflict_fix.py +633 -0
  61. coord/dao.py +483 -0
  62. coord/dashboard/__init__.py +0 -0
  63. coord/dashboard/fixture.py +376 -0
  64. coord/dashboard/index.html +658 -0
  65. coord/dashboard/server.py +1894 -0
  66. coord/dashboard/terminal.py +382 -0
  67. coord/dashboard/webapp/.gitignore +9 -0
  68. coord/dashboard/webapp/components.json +17 -0
  69. coord/dashboard/webapp/dist/assets/Gallery-da3qNiIw.js +71 -0
  70. coord/dashboard/webapp/dist/assets/Terminal-9CEnUXvW.css +32 -0
  71. coord/dashboard/webapp/dist/assets/Terminal-skVFCxPU.js +63 -0
  72. coord/dashboard/webapp/dist/assets/index-DltfZR5f.js +184 -0
  73. coord/dashboard/webapp/dist/assets/index-Dq4kwTdw.css +1 -0
  74. coord/dashboard/webapp/dist/assets/workbox-window.prod.es5-BqEJf4Xk.js +2 -0
  75. coord/dashboard/webapp/dist/icons/icon-192.png +0 -0
  76. coord/dashboard/webapp/dist/icons/icon-512.png +0 -0
  77. coord/dashboard/webapp/dist/icons/icon.svg +5 -0
  78. coord/dashboard/webapp/dist/index.html +38 -0
  79. coord/dashboard/webapp/dist/manifest.webmanifest +1 -0
  80. coord/dashboard/webapp/dist/sw.js +1 -0
  81. coord/dashboard/webapp/dist/workbox-e4022e15.js +1 -0
  82. coord/dashboard/webapp/e2e/available-gates-terminal.spec.ts +75 -0
  83. coord/dashboard/webapp/e2e/deep-link.spec.ts +172 -0
  84. coord/dashboard/webapp/e2e/fixtureServer.ts +155 -0
  85. coord/dashboard/webapp/e2e/live-update-fixture.spec.ts +113 -0
  86. coord/dashboard/webapp/e2e/realtime.spec.ts +238 -0
  87. coord/dashboard/webapp/e2e/shell.spec.ts +309 -0
  88. coord/dashboard/webapp/e2e/smoke.spec.ts +191 -0
  89. coord/dashboard/webapp/e2e/terminal.spec.ts +420 -0
  90. coord/dashboard/webapp/e2e/theme.spec.ts +138 -0
  91. coord/dashboard/webapp/eslint.config.js +20 -0
  92. coord/dashboard/webapp/index.html +37 -0
  93. coord/dashboard/webapp/node_modules/flatted/python/flatted.py +144 -0
  94. coord/dashboard/webapp/package-lock.json +10584 -0
  95. coord/dashboard/webapp/package.json +63 -0
  96. coord/dashboard/webapp/playwright.acceptance.config.ts +166 -0
  97. coord/dashboard/webapp/playwright.config.ts +93 -0
  98. coord/dashboard/webapp/postcss.config.js +6 -0
  99. coord/dashboard/webapp/public/icons/icon-192.png +0 -0
  100. coord/dashboard/webapp/public/icons/icon-512.png +0 -0
  101. coord/dashboard/webapp/public/icons/icon.svg +5 -0
  102. coord/dashboard/webapp/src/App.tsx +140 -0
  103. coord/dashboard/webapp/src/api/client.ts +199 -0
  104. coord/dashboard/webapp/src/api/generated.ts +176 -0
  105. coord/dashboard/webapp/src/components/ConnectionBadge.tsx +52 -0
  106. coord/dashboard/webapp/src/components/Detail.tsx +800 -0
  107. coord/dashboard/webapp/src/components/Gallery.tsx +341 -0
  108. coord/dashboard/webapp/src/components/Home.tsx +435 -0
  109. coord/dashboard/webapp/src/components/MobileKeyBar.tsx +280 -0
  110. coord/dashboard/webapp/src/components/PanelHeader.tsx +59 -0
  111. coord/dashboard/webapp/src/components/PipelineCard.tsx +168 -0
  112. coord/dashboard/webapp/src/components/SessionCard.tsx +99 -0
  113. coord/dashboard/webapp/src/components/SessionDetail.tsx +140 -0
  114. coord/dashboard/webapp/src/components/SessionsList.tsx +81 -0
  115. coord/dashboard/webapp/src/components/Terminal.tsx +376 -0
  116. coord/dashboard/webapp/src/components/__tests__/ConnectionBadge.test.tsx +81 -0
  117. coord/dashboard/webapp/src/components/__tests__/Detail.test.tsx +680 -0
  118. coord/dashboard/webapp/src/components/__tests__/Gallery.test.tsx +83 -0
  119. coord/dashboard/webapp/src/components/__tests__/Home.test.tsx +271 -0
  120. coord/dashboard/webapp/src/components/__tests__/MobileKeyBar.test.tsx +197 -0
  121. coord/dashboard/webapp/src/components/__tests__/PipelineCard.test.tsx +143 -0
  122. coord/dashboard/webapp/src/components/__tests__/SessionCard.test.tsx +106 -0
  123. coord/dashboard/webapp/src/components/__tests__/Terminal.test.tsx +504 -0
  124. coord/dashboard/webapp/src/components/ui/badge.tsx +41 -0
  125. coord/dashboard/webapp/src/components/ui/button.tsx +54 -0
  126. coord/dashboard/webapp/src/components/ui/card.tsx +55 -0
  127. coord/dashboard/webapp/src/components/ui/dialog.tsx +99 -0
  128. coord/dashboard/webapp/src/components/ui/dropdown-menu.tsx +189 -0
  129. coord/dashboard/webapp/src/components/ui/empty-state.tsx +35 -0
  130. coord/dashboard/webapp/src/components/ui/sheet.tsx +123 -0
  131. coord/dashboard/webapp/src/components/ui/skeleton.tsx +9 -0
  132. coord/dashboard/webapp/src/components/ui/tabs.tsx +55 -0
  133. coord/dashboard/webapp/src/components/ui/theme-provider.tsx +78 -0
  134. coord/dashboard/webapp/src/components/ui/theme-toggle.tsx +20 -0
  135. coord/dashboard/webapp/src/components/ui/toast.tsx +123 -0
  136. coord/dashboard/webapp/src/components/ui/toaster.tsx +30 -0
  137. coord/dashboard/webapp/src/components/ui/tooltip.tsx +26 -0
  138. coord/dashboard/webapp/src/components/ui/use-toast.ts +134 -0
  139. coord/dashboard/webapp/src/index.css +210 -0
  140. coord/dashboard/webapp/src/lib/pipeline.ts +29 -0
  141. coord/dashboard/webapp/src/lib/utils.ts +6 -0
  142. coord/dashboard/webapp/src/main.tsx +46 -0
  143. coord/dashboard/webapp/src/realtime/RealtimeProvider.tsx +112 -0
  144. coord/dashboard/webapp/src/realtime/__tests__/RealtimeProvider.test.tsx +189 -0
  145. coord/dashboard/webapp/src/realtime/__tests__/connection.test.ts +255 -0
  146. coord/dashboard/webapp/src/realtime/connection.ts +227 -0
  147. coord/dashboard/webapp/src/realtime/events.ts +100 -0
  148. coord/dashboard/webapp/src/routes/__tests__/paths.test.ts +92 -0
  149. coord/dashboard/webapp/src/routes/paths.ts +92 -0
  150. coord/dashboard/webapp/src/shell/ActivityRail.tsx +335 -0
  151. coord/dashboard/webapp/src/shell/AppShell.tsx +276 -0
  152. coord/dashboard/webapp/src/shell/ComingSoon.tsx +33 -0
  153. coord/dashboard/webapp/src/shell/EmptyDetail.tsx +26 -0
  154. coord/dashboard/webapp/src/shell/RouteNotFound.tsx +33 -0
  155. coord/dashboard/webapp/src/shell/ShellLayout.tsx +147 -0
  156. coord/dashboard/webapp/src/shell/StatusBar.tsx +46 -0
  157. coord/dashboard/webapp/src/shell/__tests__/ShellLayout.test.tsx +520 -0
  158. coord/dashboard/webapp/src/shell/__tests__/shellState.test.ts +95 -0
  159. coord/dashboard/webapp/src/shell/__tests__/stubViewport.ts +40 -0
  160. coord/dashboard/webapp/src/shell/breakpoints.ts +87 -0
  161. coord/dashboard/webapp/src/shell/railItems.ts +105 -0
  162. coord/dashboard/webapp/src/shell/shellState.ts +174 -0
  163. coord/dashboard/webapp/src/shell/useRegionFocus.ts +95 -0
  164. coord/dashboard/webapp/src/test-setup.ts +41 -0
  165. coord/dashboard/webapp/src/vite-env.d.ts +2 -0
  166. coord/dashboard/webapp/tailwind.config.js +140 -0
  167. coord/dashboard/webapp/tsconfig.json +25 -0
  168. coord/dashboard/webapp/tsconfig.node.json +11 -0
  169. coord/dashboard/webapp/vite.config.ts +71 -0
  170. coord/db.py +1076 -0
  171. coord/dead_end.py +332 -0
  172. coord/deploy/README.md +33 -0
  173. coord/deploy/coord-agent.service +89 -0
  174. coord/deploy/coord-db-backup.service +60 -0
  175. coord/deploy/coord-db-backup.sh +74 -0
  176. coord/deploy/coord-db-backup.timer +18 -0
  177. coord/deploy/coord-drive-queue.service +117 -0
  178. coord/deploy/coord-drive-queue.timer +39 -0
  179. coord/deploy/coord-notify.service +48 -0
  180. coord/deploy/coord-notify.timer +24 -0
  181. coord/deploy/coord-release-propagate.service +83 -0
  182. coord/deploy/coord-release-propagate.timer +38 -0
  183. coord/deploy/coord-release-window.service +119 -0
  184. coord/deploy/coord-release-window.timer +36 -0
  185. coord/deploy/coord-serve.service +82 -0
  186. coord/deploy/coord-web-dist-build.service +43 -0
  187. coord/deploy/coord-web-dist-build.timer +36 -0
  188. coord/deploy/coord-web.service +125 -0
  189. coord/deploy_manifest.py +80 -0
  190. coord/deploy_units.py +384 -0
  191. coord/deps.py +115 -0
  192. coord/diagnose.py +1623 -0
  193. coord/dispatch.py +1009 -0
  194. coord/dist_name.py +123 -0
  195. coord/drive.py +3101 -0
  196. coord/drive_queue.py +2298 -0
  197. coord/drive_state.py +870 -0
  198. coord/events.py +381 -0
  199. coord/failure_class.py +914 -0
  200. coord/filelock.py +168 -0
  201. coord/fleet_config_health.py +300 -0
  202. coord/freshness.py +206 -0
  203. coord/gate_a.py +469 -0
  204. coord/gate_b.py +411 -0
  205. coord/gate_snapshot.py +385 -0
  206. coord/gates.py +582 -0
  207. coord/github_ops.py +1954 -0
  208. coord/goal.py +125 -0
  209. coord/graph_health.py +348 -0
  210. coord/health/__init__.py +69 -0
  211. coord/health/aggregate.py +129 -0
  212. coord/health/checks/__init__.py +13 -0
  213. coord/health/checks/agent_install.py +280 -0
  214. coord/health/checks/cargo_targets.py +171 -0
  215. coord/health/checks/claude_binary.py +65 -0
  216. coord/health/checks/deploy_lane_facts.py +458 -0
  217. coord/health/checks/disk.py +99 -0
  218. coord/health/checks/fleet_board.py +89 -0
  219. coord/health/checks/fleet_deploy_lanes.py +469 -0
  220. coord/health/checks/fleet_phantom.py +69 -0
  221. coord/health/checks/fleet_unit_drift.py +151 -0
  222. coord/health/checks/graph.py +192 -0
  223. coord/health/checks/plan_usage.py +88 -0
  224. coord/health/checks/repo_state.py +161 -0
  225. coord/health/checks/spawned_coord.py +465 -0
  226. coord/health/checks/timer_active.py +254 -0
  227. coord/health/checks/toolchain.py +547 -0
  228. coord/health/checks/unit_drift.py +648 -0
  229. coord/health/checks/unit_enablement.py +171 -0
  230. coord/health/checks/worktrees.py +96 -0
  231. coord/health/cli.py +121 -0
  232. coord/health/context.py +106 -0
  233. coord/health/fleet_snapshot.py +477 -0
  234. coord/health/models.py +250 -0
  235. coord/health/pypi.py +231 -0
  236. coord/health/registry.py +240 -0
  237. coord/health/render.py +82 -0
  238. coord/health/units.py +60 -0
  239. coord/hooks.py +106 -0
  240. coord/housekeeping.py +204 -0
  241. coord/interactive.py +4286 -0
  242. coord/issue_store.py +1496 -0
  243. coord/liveness_auditor.py +293 -0
  244. coord/machine_pause.py +755 -0
  245. coord/merge_queue.py +4681 -0
  246. coord/milestone_chat.py +600 -0
  247. coord/milestone_dispatch.py +943 -0
  248. coord/milestone_gate.py +709 -0
  249. coord/milestone_order.py +840 -0
  250. coord/mock_author.py +334 -0
  251. coord/models.py +891 -0
  252. coord/network.py +269 -0
  253. coord/new_issue_chat.py +229 -0
  254. coord/notify.py +3226 -0
  255. coord/openapi.py +404 -0
  256. coord/overlap_fence.py +133 -0
  257. coord/parentage.py +200 -0
  258. coord/parentage_github.py +58 -0
  259. coord/pipeline.py +481 -0
  260. coord/plan_parser.py +266 -0
  261. coord/plans.py +543 -0
  262. coord/platform_paths.py +43 -0
  263. coord/pr_body_lint.py +67 -0
  264. coord/prereqs.py +533 -0
  265. coord/progress.py +425 -0
  266. coord/providers/__init__.py +683 -0
  267. coord/providers/base.py +218 -0
  268. coord/providers/claude.py +284 -0
  269. coord/providers/claude_pty.py +610 -0
  270. coord/providers/opencode.py +896 -0
  271. coord/reconcile.py +2233 -0
  272. coord/refine_chat.py +485 -0
  273. coord/release_cordon.py +525 -0
  274. coord/release_propagate.py +1176 -0
  275. coord/release_verify.py +777 -0
  276. coord/release_window.py +322 -0
  277. coord/reports.py +1643 -0
  278. coord/revalidate.py +1101 -0
  279. coord/review.py +3317 -0
  280. coord/scorecard.py +484 -0
  281. coord/serve_app.py +7192 -0
  282. coord/skills/update-issue/SKILL.md +93 -0
  283. coord/smoke.py +1030 -0
  284. coord/split_work.py +210 -0
  285. coord/stage_projection.py +650 -0
  286. coord/state.py +5720 -0
  287. coord/test_author.py +1064 -0
  288. coord/test_chat.py +352 -0
  289. coord/test_orchestrator.py +494 -0
  290. coord/test_report.py +178 -0
  291. coord/tui_release.py +271 -0
  292. coord/usage.py +753 -0
  293. coord/usage_limits.py +358 -0
  294. coord/usage_rollup.py +709 -0
  295. coord/worker_events.py +954 -0
@@ -0,0 +1,625 @@
1
+ Metadata-Version: 2.4
2
+ Name: code-coordinator
3
+ Version: 0.5.46
4
+ Summary: Coordinate Claude Code workers across multiple machines and repos.
5
+ Author-email: John Donaghy <johnfdonaghy@gmail.com>
6
+ License-Expression: LicenseRef-FSL-1.1-MIT
7
+ Project-URL: Homepage, https://github.com/JDonaghy/claude-coordinator
8
+ Project-URL: Repository, https://github.com/JDonaghy/claude-coordinator
9
+ Project-URL: Issues, https://github.com/JDonaghy/claude-coordinator/issues
10
+ Keywords: claude,claude-code,multi-agent,coordinator,automation
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: Software Development :: Build Tools
16
+ Requires-Python: >=3.12
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: click>=8.1
20
+ Requires-Dist: pyyaml>=6.0
21
+ Requires-Dist: httpx>=0.27
22
+ Requires-Dist: platformdirs>=4.0
23
+ Requires-Dist: tzdata; sys_platform == "win32"
24
+ Provides-Extra: server
25
+ Requires-Dist: starlette>=0.37; extra == "server"
26
+ Requires-Dist: uvicorn>=0.30; extra == "server"
27
+ Requires-Dist: websockets>=12.0; extra == "server"
28
+ Requires-Dist: psutil>=5.9; extra == "server"
29
+ Provides-Extra: all
30
+ Requires-Dist: code-coordinator[server]; extra == "all"
31
+ Provides-Extra: dev
32
+ Requires-Dist: code-coordinator[server]; extra == "dev"
33
+ Requires-Dist: pytest>=8.0; extra == "dev"
34
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
35
+ Requires-Dist: pytest-xdist>=3.5; extra == "dev"
36
+ Requires-Dist: setuptools>=68; extra == "dev"
37
+ Requires-Dist: setuptools-scm>=8; extra == "dev"
38
+ Requires-Dist: wheel; extra == "dev"
39
+ Dynamic: license-file
40
+
41
+ # claude-coordinator
42
+
43
+ Coordinate a fleet of Claude Code workers — and human-attended interactive `claude` sessions — from a single board.
44
+
45
+ Claude Code is great at one task at a time. Real projects have dozens of issues, spread across repos, that each want their own session, their own scoping, and their own review. `claude-coordinator` runs many workers in parallel — on one machine or across several over Tailscale — behind a coordinator that picks the model, avoids file conflicts, routes by capability, and drives the full **Work → Test → Review → Merge** pipeline. Each stage can run as a cheap `claude -p` worker *or* as a human-attended interactive session you launch and steer from the board.
46
+
47
+ ## The problem
48
+
49
+ Running one Claude Code session at a time is a bottleneck. You context-switch between issues, lose session state, and can't parallelize. A complex issue gets one shot; if the session dies mid-flight, you start over. There's no audit trail, no conflict detection, and no way to see what happened last Thursday.
50
+
51
+ ## The solution
52
+
53
+ One config file describes your repos and machines. Workers run in isolated git worktrees so they never step on each other. The coordinator tracks what's in flight, prevents conflicts, sequences PRs, and moves each issue through a gated pipeline. You approve the decisions; the workers do the work.
54
+
55
+ Works on **one machine** with multiple worktrees. Add more machines over Tailscale when you want true parallelism, capability routing (a GTK box, a browser box), or a remote review.
56
+
57
+ ## How it works
58
+
59
+ ```
60
+ ~/.coord/coord.db (SQLite) · coordinator.yml · GitHub (issues / PRs / comments)
61
+
62
+ ┌─────────────────────────┼─────────────────────────┐
63
+ │ │ │
64
+ coord CLI coord-tui coord web
65
+ (Python) (Rust board) (phone PWA + REST)
66
+ │ │ │
67
+ └──────────── coord serve ─┴─ (optional daemon, port 7435) ──┘
68
+ │ canonical board for thin clients
69
+
70
+ │ HTTP (port 7433)
71
+
72
+ ┌────────────────┐
73
+ │ coord agent │ one per machine
74
+ │ (HTTP server) │
75
+ └───────┬────────┘
76
+ │ spawns
77
+ ┌───────────────┴───────────────┐
78
+ ▼ ▼
79
+ claude -p worker interactive claude session
80
+ (headless, isolated worktree) (human-attended, tmux, #437)
81
+ ```
82
+
83
+ Three kinds of process:
84
+
85
+ 1. **Coordinator clients** — the CLI (`coord`), the terminal board (`coord-tui`), and the web dashboard / phone PWA (`coord web`). They read shared state and dispatch work. All three are **peers** of the same state, not layers — use whichever fits the task.
86
+ 2. **Agent servers** — one `coord agent` per worker machine (port 7433). A dumb dispatcher: it spawns and tracks worker processes and owns the worktrees and logs. All the intelligence lives in the coordinator.
87
+ 3. **Workers** — either a headless `claude -p` subprocess in an isolated worktree, or a human-attended interactive `claude` session in a named tmux session that you drive from the board. Both report their result through the same board seam.
88
+
89
+ State lives in SQLite (`~/.coord/`) plus GitHub issue comments (the durable message bus — every briefing, completion, failure, and review verdict is a comment carrying a `<!-- coord:event=... -->` marker). Either can reconstruct the other. An optional **control-center daemon** (`coord serve`) fronts one canonical DB so every client on your tailnet renders and drives the same board.
90
+
91
+ ## The pipeline: Work → Test → Review → Merge
92
+
93
+ Every issue moves through four gated stages:
94
+
95
+ | Stage | What happens | Automated path | Interactive path |
96
+ |-------|--------------|----------------|------------------|
97
+ | **Work** | Read the issue, write code, push a branch | `claude -p` worker | `coord assign --interactive` |
98
+ | **Test** | Build + run tests on capability-matched hardware; record a verdict | headless smoke assignment | `--smoke-of` testing agent |
99
+ | **Review** | A fresh, zero-context session reviews the diff against the repo's rules | `type="review"` worker on a *different* machine | `--review-of` reviewer |
100
+ | **Merge** | Rebase onto the base branch, resolve conflicts, run tests, merge | merge queue + auto-rebase | `--merge-of` merge agent |
101
+
102
+ Two rules shape the flow:
103
+
104
+ - **Test precedes Review.** The smoke test runs *before* the PR/review — the natural order. Review auto-dispatch is **held** until the work has a `passed`/`skipped` Test verdict. A work item left at *Pending Test* gets no review, so it never merges — this is the single most common reason a story silently stalls. Record the verdict with `coord test <id> --passed|--skipped|--fail`, or the **P / S / F** keys on the Test stage in the TUI. The displayed stage order and this gate both come from `pipeline.default_gates` in `coordinator.yml` (default `[test, review, merge]`).
105
+ - **A failed test routes exactly like a request-changes review.** Both drop the issue back to a fix on the *same* branch (`coord fix`, or the interactive `--fix-of`), never an orphan.
106
+
107
+ `coord notify` drives the automated legs — review-on-completion, fix-on-request-changes, re-review-on-fix. Run it periodically (cron, a TUI timer, or by hand); nothing advances on its own.
108
+
109
+ ## Quick demo
110
+
111
+ ```bash
112
+ pip install claude-coordinator # from PyPI
113
+ coord init # interactive setup: detects repos, writes coordinator.yml
114
+ coord agent & # start the agent server (port 7433) — see Quick Start for the systemd setup
115
+
116
+ coord assign laptop myrepo 42 --model sonnet --briefing "Fix the auth middleware timeout"
117
+ # → laptop → myrepo #42: Fix the auth middleware timeout
118
+ # → model: sonnet
119
+ # → dispatched (assignment a1b2c3)
120
+
121
+ coord watch a1b2c3 # filtered live output (stream-json events)
122
+ # → [init] session a1b2 · model sonnet
123
+ # → [tool] Read auth/middleware.py
124
+ # → [tool] Edit auth/middleware.py
125
+ # → [result] completed in 3m · 6 turns · $0.45
126
+
127
+ coord test a1b2c3 --passed # record the Test-gate verdict (or run the build+tests locally first)
128
+ coord pr a1b2c3 # open the PR + auto-dispatch an adversarial review
129
+ # → PR worker dispatched (assignment d4e5f6) · branch issue-42-fix-auth-middleware → main
130
+ # → Review dispatched (assignment g7h8i9) · reviewer: server
131
+ coord merge # once the review approves + CI is green
132
+ ```
133
+
134
+ Prefer to drive it by hand? Launch any stage as an interactive session from `coord-tui` (or with `coord assign --interactive --smoke-of / --review-of / --merge-of`) and steer it yourself — see [Driving from coord-tui](#driving-from-coord-tui).
135
+
136
+ ## Quick start
137
+
138
+ ### 1. Install
139
+
140
+ ```bash
141
+ pip install claude-coordinator
142
+ ```
143
+
144
+ The `coord` CLI is now on your PATH. The same package provides the agent server (`coord agent`), so the coordinator side and the worker side share one install.
145
+
146
+ > **Developing the coordinator itself?** Clone the repo and `pip install -e .`. Reserve editable installs for development machines — agent machines must always be PyPI installs (see [`docs/AGENT_OPERATIONS.md`](docs/AGENT_OPERATIONS.md)).
147
+
148
+ The Rust terminal board, `coord-tui`, ships separately as a locally-built binary — see [Driving from coord-tui](#driving-from-coord-tui).
149
+
150
+ ### 2. Configure
151
+
152
+ ```bash
153
+ coord init # interactive wizard: detects repos in cwd and ~/src/, writes coordinator.yml
154
+ coord config # verify it parsed cleanly (prints the resolved config path)
155
+ ```
156
+
157
+ Or copy `coordinator.example.yml` and edit by hand. `coordinator.yml` is gitignored — keep secrets out of version control. Its canonical home is `~/.coord/coordinator.yml` so the tool runs on a machine with no repo checkout.
158
+
159
+ ### 3. Start the agent server
160
+
161
+ For a quick local trial:
162
+
163
+ ```bash
164
+ coord agent & # port 7433; auto-detects the machine from hostname
165
+ ```
166
+
167
+ For anything beyond a trial, use the installer (systemd user service, auto-restart, survives reboots, separate worker logs):
168
+
169
+ ```bash
170
+ curl -sSL https://raw.githubusercontent.com/JDonaghy/claude-coordinator/main/install-agent.sh | bash
171
+ ```
172
+
173
+ The same script sets up remote worker machines — see [Worker node setup](#worker-node-setup).
174
+
175
+ ### 4. Coordinate
176
+
177
+ Three peer clients drive the same board — pick per task, they don't conflict:
178
+
179
+ **`coord-tui` (recommended for interactive use)** — a terminal board with a live pipeline, right-click actions, and the one-key stage-to-stage handoffs. See [Driving from coord-tui](#driving-from-coord-tui).
180
+
181
+ **The `coord` CLI directly:**
182
+
183
+ ```bash
184
+ coord status # machines, assignments, connectivity
185
+ coord assign laptop myrepo 42 --model sonnet --briefing "Fix the auth bug"
186
+ coord watch <id> # live filtered output
187
+ coord test <id> --passed # record the Test-gate verdict
188
+ coord pr <id> # open the PR + adversarial review
189
+ coord notify # drive the auto-loop (run periodically)
190
+ coord merge # open + merge PRs in sequence
191
+ ```
192
+
193
+ **The `/coordinator` slash command in Claude Code** — open Claude Code in the repo and type `/coordinator` for guided setup, triage, dispatch, monitoring, and PR creation (`.claude/commands/coordinator.md`).
194
+
195
+ To share one board across every Tailscale host, run the control-center daemon (`coord serve`, port 7435) on an always-on machine; the CLI and TUI then read from it as thin clients. See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).
196
+
197
+ ## Driving from coord-tui
198
+
199
+ `coord-tui` is the rich terminal board: a live pipeline view, a machines panel, an embedded terminal for interactive sessions, SSE log tailing, and a per-issue usage view. Interaction is **right-click-first** — right-click a pipeline row for its context menu; `?` opens a help overlay and command palette. It's distributed as a locally-built Rust binary (it links `quadraui` by path), so after a `tui/` change:
200
+
201
+ ```bash
202
+ cd tui && cargo build && cp target/debug/coord-tui ~/.local/bin/coord-tui
203
+ ```
204
+
205
+ ### Board-driven stage handoffs
206
+
207
+ The whole lifecycle can be driven as **human-attended interactive sessions** launched from a pipeline row's right-click menu. Verdicts are always recorded through the board (`coord report-result` / `coord test`), never scraped from the session's terminal:
208
+
209
+ - **Start testing** → launches an interactive testing agent (`--smoke-of`) read-only in the live checkout; it lists the smoke plan, offers `coord pull-artifact`, and records `coord test --passed|--fail`.
210
+ - A `passed`/`skipped` test arms **pass → review**, which launches the interactive reviewer (`--review-of`).
211
+ - An approved review arms **Start merge** (`--merge-of`): a merge agent worktrees the branch, proactively rebases onto the base branch, resolves mechanical conflicts (escalating semantic ones to you), runs tests, `git push --force-with-lease`, then `coord verify-merge` and `coord merge`.
212
+ - A failed test **or** a request-changes review offers one-key **Fix** (`--fix-of`) on the same branch.
213
+
214
+ Each stage also has a `claude -p` automation peer in the **Start (automated)** submenu, so you can mix attended and headless per stage. Review and Fix can run on a **remote** machine over ssh+tmux (pick the machine from the card) — useful for reviewer independence or capability routing.
215
+
216
+ ### Keyboard shortcuts
217
+
218
+ Right-click is the primary surface; these keys are the fast paths. Press `?` for the full, always-current list.
219
+
220
+ | Key | Where | Action |
221
+ |-----|-------|--------|
222
+ | `j` / `k` | Pipeline | Navigate issues |
223
+ | `Enter` | Pipeline | Fire the active pipeline action (`[Go]` / `[Retry]`) |
224
+ | `m` / `M` | Pipeline | Merge the selected issue's PR (surfaces blocked-on-review / blocked-on-CI as toasts) |
225
+ | `P` / `S` / `F` | Test stage | Record Test verdict: pass / skip / fail |
226
+ | `f` | Pipeline | Bounce after a request-changes review (re-runs the fix against cached findings) |
227
+ | `B` | Pipeline | Pull the branch + run build & tests locally |
228
+ | `W` | Pipeline | Watch overlay (SSE log tail of the active worker) |
229
+ | `L` | All | Sessions panel (running interactive sessions: attach / kill / reap) |
230
+ | `R` | All | Immediate refresh from GitHub (the background poll runs every 60s) |
231
+ | `u` / `r` / `c` | Machines | Update / restart the agent · clean stale worktrees |
232
+
233
+ ## Milestones & epics (Pipeline v2)
234
+
235
+ For work bigger than one issue, group issues under an **epic** and drive the whole thing as one unit. An epic is a GitHub tracking issue (carrying the `epic` label) whose body holds a `## Work order` block — a DAG of child issues written as `- #762 {group: A, after: #761}`, where `group` is a parallel cohort and `after` is a hard dependency. Membership is backed by GitHub's native sub-issues API. The issue pipeline (above) nests inside a **milestone pipeline** so expensive gates are paid once per milestone, not once per issue:
236
+
237
+ | Gate | Command | What it checks |
238
+ |------|---------|----------------|
239
+ | **A — contract** | `coord acceptance mock` | A mock-first, black-box acceptance contract exists before any issue dispatches (repos with an `acceptance.drivers` entry). |
240
+ | **B — architecture** | `coord milestone gate-b` | An independent review confirms the *assembled* milestone was built to the Gate-A contract. |
241
+ | **C — acceptance** | `coord milestone gate-c` | The full accumulated acceptance suite is green (catches integration gaps between issues). |
242
+ | **D — ship** | `coord milestone ship` | Merges the milestone's `feature/ms-NN` branch to `develop`, gated on Gate B (approved) + Gate C (re-run live), then closes the tracking issue — the signal `coord milestone drive`'s Gate D watches for. |
243
+
244
+ `coord milestone drive` (below) walks a milestone through all four as a single durable state machine instead of four manual steps.
245
+
246
+ Drive a milestone with the `coord milestone` group:
247
+
248
+ ```bash
249
+ coord milestone chat myrepo --new # steward session: draft the milestone + Work order DAG
250
+ coord milestone write-order myrepo <epic> # validate + write the ## Work order block
251
+ coord milestone dispatch myrepo <epic> # dispatch the ready frontier; drain as `after` deps clear
252
+ coord milestone gate-b myrepo <epic> # architecture review of the assembled result
253
+ coord milestone gate-c myrepo <epic> # full acceptance suite
254
+ coord milestone ship myrepo <epic> # Gate D → merge feature/ms-NN into develop
255
+ ```
256
+
257
+ **Driving the whole walk (`coord milestone drive`, #1929).** The commands above are each a manual step. `coord milestone drive myrepo <epic>` instead puts the milestone under **gate control**: a durable, board-backed gate record (`coord/milestone_gate.py`) records which gate it is in, when it entered, and what it is waiting on, and the daemon advances it one step per tick through **A → work → B → C → D → done**. Because the record lives on the board, a daemon restarted mid-milestone resumes at the gate it was in and never re-runs a gate it already cleared. `coord milestone drive myrepo <epic> --dry-run` prints the full planned sequence — every gate, the work order's ready frontier, what would dispatch — and dispatches nothing.
258
+
259
+ Today every gate edge past `work` is an explicit, **logged hold**: the machine reports *why* it cannot advance and stays put (the individual edge behaviours — Gate-A pause, contract amendment, red acceptance, Gate-B request-changes, Gate-C red — are separate work). Nothing ever falls through silently. Gate D is the one exception that already resolves on its own: a successful `coord milestone ship` closes the tracking issue as its last step, and that closure — not the `ship` invocation itself — is what Gate D observes to advance to `done` and deregister.
260
+
261
+ > **`drive` vs. `milestone.auto_dispatch`.** They are mutually exclusive per milestone, and gate driving wins. `milestone.auto_dispatch` enables the *legacy standalone drain* — the daemon re-dispatching a milestone's ready frontier with no gate walk around it. A gate-driven milestone is drained by the gate tick as its `work` state instead, so the drain tick skips it. Otherwise a milestone parked at Gate A could still have work dispatched behind the gate walk's back. `drive` is therefore its own per-milestone opt-in and is not behind the global flag.
262
+ >
263
+ > **Exactly one overseer, structurally (#1930).** The daemon's gate tick is the sole owner of a gate-controlled milestone's drain. `coord milestone drive` only registers/re-registers the walk — it never dispatches, so running it twice never races. `coord milestone dispatch`, the manual command, now **refuses** outright against a milestone under gate control instead of racing the tick's own drain.
264
+
265
+ **Branch model (opt-in).** Set `develop_branch:` on a repo to enable the develop + feature-branch flow: issues in a milestone branch off `feature/ms-NN`, merge back into it, and reach `develop` only via `coord milestone ship`. Repos that don't set `develop_branch` keep the default single-branch (`default_branch`) flow unchanged. `develop → main` is a separate release cut, not automated by `ship`.
266
+
267
+ See [`docs/PIPELINE_V2.md`](docs/PIPELINE_V2.md) and [`docs/ORACLE_LOOP.md`](docs/ORACLE_LOOP.md) for the full model.
268
+
269
+ ## Command reference
270
+
271
+ `coord <cmd> --help` documents every command and flag. This is the curated set; the CLI has more (`coord --help`).
272
+
273
+ ### Core workflow
274
+
275
+ | Command | Description |
276
+ |---------|-------------|
277
+ | `coord plan [--dry-run]` | Brain proposes assignments for idle machines |
278
+ | `coord approve <IDs> [--dry-run] [--auto-pull] [--skip-freshness]` | Dispatch approved proposals (comma-separated) |
279
+ | `coord assign <machine> <repo> <issue> [--model haiku\|sonnet\|opus] [--briefing TEXT\|--briefing-file F] [--dry-run]` | Direct dispatch, bypasses the brain |
280
+ | `coord status [--machine NAME] [--freshness] [--no-reconcile]` | Machines, assignments, connectivity |
281
+ | `coord watch <id> [--all]` | Filtered live log (stream-json events) |
282
+ | `coord wait <id>` | Block until an assignment completes |
283
+ | `coord log <id> [-f] [--machine NAME] [--local]` | Raw `claude -p` output |
284
+
285
+ ### Post-completion & merge
286
+
287
+ | Command | Description |
288
+ |---------|-------------|
289
+ | `coord test <id>` | Pull the worker's branch locally, run build + tests |
290
+ | `coord test <id> --passed \| --skipped \| --fail --reason "..."` | Record the Test-gate verdict |
291
+ | `coord pr <id> [--no-review]` | Open a PR (auto-dispatches an adversarial review unless `--no-review`) |
292
+ | `coord fix <id> [--guidance "..."]` | Dispatch a fix-up worker for a failed test (auto-escalates model) |
293
+ | `coord bounce <review-id>` | Bounce back to Work after a request-changes review (uses cached findings) |
294
+ | `coord notify` | Poll agents, post GitHub comments, drive the auto-loop |
295
+ | `coord merge [--dry-run] [--plan] [--repo N] [--method rebase\|squash\|merge] [--order IDs \| --only ID]` | Process the merge queue |
296
+ | `coord merge --force-merge \| --skip-review \| --skip-smoke` | Override the CI / review / smoke gate for a merge (`--skip-review` is local-only — a daemon-routed run rejects it outright rather than honouring or silently dropping it, #821/#1489) |
297
+ | `coord merge --only <id> --override-human-required "<reason>"` | Audited override of a HUMAN_REQUIRED entry |
298
+ | `coord verify-merge <work-id>` | Self-check a `--merge-of` rebase before reporting done |
299
+ | `coord reconcile-merges [--repo N] [--dry-run]` | Backfill branches + record out-of-band merges |
300
+
301
+ ### Interactive session driving
302
+
303
+ All of these take `coord assign --interactive` and record their verdict through the board (`coord report-result` / `coord test`). Read-only flavours run in the live checkout with no worktree; writing flavours use an isolated worktree and push back.
304
+
305
+ | Flag on `coord assign --interactive` | What it launches |
306
+ |---|---|
307
+ | *(none)* | A human-attended Work session with the briefing pre-filled |
308
+ | `--plan-only` | A read-only planning session (structured plan, no branch) |
309
+ | `--smoke-of <work-id>` | A testing agent (records `coord test`) |
310
+ | `--review-of <work-id>` | A reviewer (records `coord report-result --verdict`) |
311
+ | `--merge-of <work-id>` | A merge agent (worktree, proactive rebase, `verify-merge`, `coord merge`) |
312
+ | `--fix-of <id>` | A fix on the existing branch — takes a request-changes review id **or** a test-failed work id |
313
+ | `--rework-of <id\|branch>` | Continue an existing branch with a fresh `--briefing` |
314
+ | `--troubleshoot` / `--chat` | Read-only diagnostic / issue-chat session |
315
+ | `--audit-of <epic>` / `--milestone-chat-of <epic>` | Milestone outcome audit / milestone-steward chat |
316
+
317
+ Verdict-relay helpers: `coord report-result`, `coord set-review-findings`, `coord fix-briefing`, `coord reattach <id>`, `coord inject <id> <text>`.
318
+
319
+ ### Milestones & epics
320
+
321
+ | Command | Description |
322
+ |---------|-------------|
323
+ | `coord milestone create\|edit\|assign\|remove` | Manage the native GitHub milestone + issue membership |
324
+ | `coord milestone add-child\|sync` | Manage epic sub-issue membership (checklist → live sub-issues API) |
325
+ | `coord milestone chat [--new]` | Steward session to draft the milestone + `## Work order` |
326
+ | `coord milestone order\|write-order` | Read / validate + write the `## Work order` DAG |
327
+ | `coord milestone dispatch [--dry-run\|--next\|--pick N]` | Dispatch the ready frontier into the pipeline |
328
+ | `coord milestone gate-b\|gate-c\|ship` | Architecture review · acceptance suite · Gate-D ship to `develop` |
329
+ | `coord plans [--repo N] [--json]` | Cross-repo milestone roster |
330
+ | `coord acceptance mock\|author\|run\|record` | Gate-A contract, sealed-suite authoring + runs (oracle loop) |
331
+
332
+ ### Observability
333
+
334
+ | Command | Description |
335
+ |---------|-------------|
336
+ | `coord usage [--today\|--week\|--month\|--since S] [--by-issue\|--issue N\|--by repo\|week\|month\|issue] [--by-time]` | Per-issue/repo/window cost, tokens, and time-spent |
337
+ | `coord gates <repo> <issue> [--json]` | A work row's gate columns (`test_state`, `smoke_test`, `review_verdict`, ...) plus the live review/test/merge decision — including whether a verdict is #1479-stale and the SHAs compared. Read-only |
338
+ | `coord audit [--category C] [--repo N] [--issue N] [--since T] [--json]` | Query the durable, ordered event log |
339
+ | `coord report list` / `coord report run <id> [--param k=v ...] [--format table\|json\|csv]` | Named reports folded out of the audit trail. One today: `issue-activity` — one row per issue that moved in a window (start, machines, fix iterations, Test/Review verdicts, merge, driver exit, outcome) plus derived anomaly notes. `--format csv` (#1765) emits the machine-readable form on stdout — raw values (an epoch stays an epoch), notes as leading `#` lines — identical to the daemon's `GET /report/{id}?format=csv` |
340
+ | `coord sessions [--remote] [--prune] [--reap-merged]` | List interactive tmux sessions; reap dead/merged ones |
341
+ | `coord terminal new\|list\|kill\|attach` | Persistent fleet-wide shell sessions |
342
+
343
+ ### Recovery & lifecycle
344
+
345
+ | Command | Description |
346
+ |---------|-------------|
347
+ | `coord retry <id>` | Re-dispatch a failed assignment to a different machine |
348
+ | `coord stop <id> [--rescue]` | Cancel a running assignment. Uncommitted work is committed locally only (remote branch untouched); `--rescue` publishes it to a disposable `rescue/<id>` ref instead — the worker's own branch is never pushed to (#1567) |
349
+ | `coord resume-stuck <id> --guidance "..."` | Cancel a stuck worker, dispatch a continuation |
350
+ | `coord resume` | Reconcile board state after a crash |
351
+ | `coord diagnose [repo issue] [--stage S] [--reset] [--orphan-worktrees]` | Diagnose / recover a stuck pipeline stage or sweep orphaned worktrees |
352
+ | `coord done` | End the session, run housekeeping hooks, show a summary |
353
+
354
+ ### Setup & diagnostics
355
+
356
+ | Command | Description |
357
+ |---------|-------------|
358
+ | `coord init` / `coord config` | Interactive setup / pretty-print the parsed config |
359
+ | `coord agent [--machine N] [--host H] [--port P]` | Start the agent server (default 7433) |
360
+ | `coord agent update\|restart\|clean-worktrees [--machine N \| --all]` | Manage remote agents |
361
+ | `coord web [--host H] [--port P]` | Web dashboard + phone PWA (default 7434) |
362
+ | `coord serve [--host H] [--port P]` | Control-center board daemon (default 7435) |
363
+ | `coord sync [--quiet]` | Sync open issues from GitHub into the local cache |
364
+ | `coord pause <machine>` / `coord unpause <machine>` | Stop / resume routing to a machine (a machine can also declare a recurring `quiet_hours:` window in `coordinator.yml` — see below; `coord unpause` during that window grants a one-window override) |
365
+ | `coord track\|untrack\|backlog <repo> <issue>` | Move an issue into / out of the Pipeline |
366
+ | `coord version` | Print the version |
367
+
368
+ ### Model tiers
369
+
370
+ | Flag | Use for |
371
+ |------|---------|
372
+ | `--model haiku` | Docs, config, trivial single-file changes |
373
+ | `--model sonnet` | Standard features, bug fixes (default) |
374
+ | `--model opus` | Complex multi-file or architectural work |
375
+
376
+ `coord fix` escalates to the next tier on failure. Configure the ladder in `models.escalation` and pin exact model ids per alias with `models.versions`.
377
+
378
+ ### Ports
379
+
380
+ | Port | Service |
381
+ |------|---------|
382
+ | 7433 | `coord agent` — per-machine worker dispatcher |
383
+ | 7434 | `coord web` — web dashboard + phone PWA |
384
+ | 7435 | `coord serve` — control-center board daemon |
385
+
386
+ ## Configuration
387
+
388
+ ### Minimal single-machine config
389
+
390
+ ```yaml
391
+ # coordinator.yml
392
+ repos:
393
+ - name: my-project
394
+ github: owner/my-project
395
+ default_branch: main
396
+ build_command: "pytest"
397
+ test_command: "pytest"
398
+
399
+ machines:
400
+ - name: laptop
401
+ host: localhost # single machine: localhost works fine
402
+ capabilities: [python]
403
+ repos: [my-project]
404
+ repo_paths:
405
+ my-project: ~/src/my-project
406
+
407
+ concurrency:
408
+ max_workers: 3 # how many worker sessions run at once
409
+ stagger_seconds: 30 # delay between dispatches (avoids rate limits)
410
+
411
+ models:
412
+ default: sonnet
413
+ escalation: [haiku, sonnet, opus]
414
+ labels: # assign model by GitHub issue label
415
+ documentation: haiku
416
+ architecture: opus
417
+ ```
418
+
419
+ ### Full reference
420
+
421
+ ```yaml
422
+ repos:
423
+ - name: api-gateway
424
+ github: acme/api-gateway
425
+ depends_on: [] # blocks dispatch if listed repos have active work
426
+ default_branch: main
427
+ develop_branch: develop # opt in to the milestone feature-branch model (see Milestones)
428
+ build_command: "npm run build"
429
+ test_command: "npm test"
430
+ artifact_paths: # stash built binaries so `coord pull-artifact` can rsync them
431
+ - dist/
432
+
433
+ - name: shared-lib
434
+ github: acme/shared-lib
435
+
436
+ machines:
437
+ - name: laptop
438
+ host: localhost
439
+ capabilities: [python, node]
440
+ repos: [api-gateway, shared-lib]
441
+ repo_paths:
442
+ api-gateway: ~/src/api-gateway
443
+ shared-lib: ~/src/shared-lib
444
+
445
+ - name: server # second machine (Tailscale hostname)
446
+ host: server.tailnet
447
+ capabilities: [docker, python, browser]
448
+ repos: [shared-lib]
449
+ repo_paths:
450
+ shared-lib: ~/src/shared-lib
451
+ quiet_hours: # recurring daily no-new-dispatch window (#1862)
452
+ start: "23:00" # 24h "HH:MM", in `tz` below
453
+ end: "08:00" # (start > end wraps midnight)
454
+ tz: America/Chicago # REQUIRED — never defaults to the daemon's UTC clock
455
+
456
+ concurrency:
457
+ max_workers: 2
458
+ stagger_seconds: 30
459
+ backoff_base: 60
460
+ max_retries: 3
461
+ auto_reassign: false # auto-retry failed assignments on a different machine
462
+ # interactive_session_timeout_hours: 12 # SSH-probe idle remote interactive sessions (#588)
463
+
464
+ pipeline:
465
+ default_gates: [test, review, merge] # displayed stage order + the test-before-review gate
466
+
467
+ models:
468
+ default: sonnet
469
+ escalation: [haiku, sonnet, opus]
470
+ labels:
471
+ documentation: haiku
472
+ architecture: opus
473
+ # versions: # pin an alias to an exact model id passed to `claude -p --model`
474
+ # sonnet: claude-sonnet-5
475
+
476
+ reviews:
477
+ enabled: true # adversarial review on completion (set false to opt out)
478
+ auto_dispatch: true
479
+ checklist:
480
+ - "Did the worker add tests?"
481
+ - "Did the worker stay within file scope?"
482
+ repo_overrides:
483
+ api-gateway:
484
+ - "Check rate limiting on new endpoints"
485
+
486
+ smoke_tests:
487
+ auto_queue: true # auto-dispatch a headless Test when Work completes
488
+ capability_rules:
489
+ - files: [src/gtk/]
490
+ requires: [gtk] # route GTK changes to a machine with the gtk capability
491
+
492
+ ci_store:
493
+ type: github # gate merges on `gh pr checks`; `type: none` disables the gate
494
+
495
+ # acceptance: # per-repo sealed-oracle drivers for the milestone acceptance gates
496
+ # drivers:
497
+ # api-gateway: { type: web-playwright }
498
+
499
+ hooks:
500
+ on_round_complete: [summary_report]
501
+ on_session_end: [summary_report]
502
+ ```
503
+
504
+ `coordinator.yml` is gitignored; `coordinator.example.yml` is the checked-in reference. Config resolves in order: `$COORD_CONFIG` → `~/.coord/coordinator.yml` (the canonical home, so a machine needs no repo checkout) → `./coordinator.yml` (a development fallback). `coord config` and `coord serve` print the resolved path so it's never ambiguous which file loaded.
505
+
506
+ ## Pipeline lifecycle (`status:*` labels)
507
+
508
+ The Pipeline organizes GitHub issues into lifecycle sections from their labels and assignment state. Membership is **label-driven** — an open issue with a `status:ready` label shows as a Pipeline card even with zero assignments (only issues carrying the `coord` label appear at all).
509
+
510
+ | Section | Condition |
511
+ |---|---|
512
+ | **New** | Open issue, no `status:*` label |
513
+ | **Refining** | Label `status:refining` |
514
+ | **Pending** | Label `status:ready`, no assignment yet |
515
+ | **In-progress** | At least one assignment row (any status) |
516
+ | **Done** | Issue is closed on GitHub |
517
+
518
+ Transitions: `coord refine` → `coord ready` marks an issue New → Refining → Pending; `[Go]` (or `coord assign`) starts it; merging a PR with `Closes #N` closes the issue. To drop a card back to the Board, `coord backlog <repo> <issue>` (strips `status:*`). Epics add a milestone tier on top of these sections — see [Milestones & epics](#milestones--epics-pipeline-v2).
519
+
520
+ ## Features
521
+
522
+ - **No API key** — uses `claude -p` on your Max/Pro subscription; billing stays per-seat.
523
+ - **Two ways to run every stage** — cheap headless `claude -p` workers *or* human-attended interactive sessions you launch and steer from the board. `claude -p` is a first-class automation path, not a deprecated one.
524
+ - **Single-machine first** — one agent server, many workers in isolated git worktrees; no Tailscale needed. Add machines for parallelism, capability routing, or remote review.
525
+ - **Gated pipeline** — Work → Test → Review → Merge, with Test gating Review and CI/review/smoke gating Merge.
526
+ - **Model tiering** — haiku for docs, sonnet for standard work, opus for architecture; `coord fix` auto-escalates on failure.
527
+ - **Adversarial review + auto-loop** — a fresh, zero-context session reviews the diff against the repo's rules; request-changes dispatches a fix pinned to the same branch, then re-reviews. Up to 3 iterations before asking for human judgment. Independence comes from a fresh session, not separate hardware.
528
+ - **Milestones & epics** — group issues under an epic with a `## Work order` DAG; amortize architecture and acceptance gates across the milestone; ship as one unit (`coord milestone ship`).
529
+ - **Merge queue** — dependency-aware sequencing, CI gating (`gh pr checks`), auto-rebase of mechanical conflicts, and escalation of semantic ones.
530
+ - **Capability-aware testing** — `smoke_tests.capability_rules` route platform-specific suites to capable hardware (a GTK box, a browser box).
531
+ - **Observability** — `coord usage` (per-issue/repo/window cost, tokens, time), `coord audit` (durable event log), `coord report` (the event log folded into per-issue outcomes), stream-json `coord watch`, and `STATUS:`/`STUCK:` progress lines.
532
+ - **Crash recovery** — `coord resume` / `coord diagnose` reconcile the board with live agent and git state; interactive tmux sessions survive a TUI crash and are reattachable.
533
+ - **Web dashboard + phone PWA** — a board view and a React/Vite phone control-center at port 7434, served over Tailscale.
534
+
535
+ ## Why this works (even with one machine)
536
+
537
+ The tool encodes a pattern from real multi-agent sessions: **separate the tech lead from the IC.** The coordinator thinks about *what to do next* — priority, dependencies, conflicts, which machine is idle. Workers think about *how to do this one thing*. Neither is distracted by the other's concern.
538
+
539
+ - **Forced scoping.** One issue per worker session. No "while I'm here, let me also refactor this."
540
+ - **Structured handoffs.** Every assignment is a briefing posted as a GitHub comment. If a session dies, a new one resumes from the comment — zero context loss.
541
+ - **Persistent record.** Every decision, briefing, verdict, and result lives on GitHub. Review what happened a week later; terminal scrollback is gone when the window closes.
542
+ - **Fresh eyes.** Each worker starts with no prior context. Adversarial review takes it further: a separate session reviews with zero shared context — even on the same machine.
543
+ - **Human stays strategic.** You approve assignments and make judgment calls; you don't ferry messages between terminals or track who's touching which file.
544
+ - **Cost discipline.** Model tiering means no opus prices for a docs fix; auto-escalation starts cheap and pays more only when needed.
545
+
546
+ ## Scaling up
547
+
548
+ 1. On the new machine, run the installer (venv + systemd service in one shot):
549
+ ```bash
550
+ curl -sSL https://raw.githubusercontent.com/JDonaghy/claude-coordinator/main/install-agent.sh | bash -s -- --machine <name>
551
+ ```
552
+ No git clone needed — `install-agent.sh` pulls from PyPI.
553
+ 2. Add the machine to `coordinator.yml` under `machines:` with its Tailscale hostname and capabilities.
554
+ 3. `coord status` from the coordinator machine shows all machines and their connectivity.
555
+
556
+ For Tailscale setup, see [tailscale.com/kb](https://tailscale.com/kb/). The agent server only needs port 7433 reachable on the tailnet.
557
+
558
+ ## Worker node setup
559
+
560
+ To add a worker machine (no repo checkout needed):
561
+
562
+ ```bash
563
+ curl -sSL https://raw.githubusercontent.com/JDonaghy/claude-coordinator/main/install-agent.sh | bash
564
+ # or with options:
565
+ curl -sSL https://raw.githubusercontent.com/JDonaghy/claude-coordinator/main/install-agent.sh | bash -s -- --machine myserver --port 7433
566
+ ```
567
+
568
+ This installs coord, sets up a systemd service with auto-restart, and starts the agent. Then add the machine to `coordinator.yml` and run `coord status` to verify connectivity.
569
+
570
+ ## Upgrading agents
571
+
572
+ Check a running agent's version:
573
+
574
+ ```bash
575
+ curl -s http://<host>:7433/health | python3 -c "import sys,json; print(json.load(sys.stdin).get('version'))"
576
+ ```
577
+
578
+ Trigger a remote self-update (installs the latest PyPI version and restarts):
579
+
580
+ ```bash
581
+ coord agent update --machine <name> # or --all
582
+ ```
583
+
584
+ If `/update` fails or the version doesn't advance, the most common cause is an old editable (`pip install -e .`) install on the agent machine — convert it to a PyPI install with the recipe in [`docs/AGENT_OPERATIONS.md`](docs/AGENT_OPERATIONS.md). Read that doc end-to-end before touching any agent install.
585
+
586
+ ## Troubleshooting
587
+
588
+ **Agent won't start** — port in use (`lsof -i :7433`, or `--port`), or a hostname mismatch (`socket.gethostname()` vs `coordinator.yml`; pass `--machine NAME`).
589
+
590
+ **"connection refused" in `coord status`** — agent not running, Tailscale down (`tailscale status`), or a firewall rule.
591
+
592
+ **Worker fails immediately** — wrong `repo_paths` (check `coord config`), `gh` not authenticated (the *coordinator* uses `gh`; workers do not — `gh auth status`), or the `claude` CLI not on PATH on the agent machine.
593
+
594
+ **A story won't merge / "Go does nothing"** — almost always the **Test gate**: no review is dispatched until the work has a `passed`/`skipped` verdict. Record it (`coord test <id> --passed`, or **P/S** in the TUI). Other gates: review not approved, CI red (`--force-merge` overrides), a PR conflict (a conflict-fix worker runs invisibly), or a queue clog. Full gate-by-gate checklist: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md#when-a-merge-isnt-happening).
595
+
596
+ **An issue you never dispatched is in the Pipeline** — it carries a `status:ready` label. Drop it back with `coord backlog <repo> <issue>`. See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md#when-an-issue-is-sitting-in-the-pipeline-you-never-dispatched).
597
+
598
+ **Board state issues** — `coord resume` reconciles the board with live agent state and garbage-collects stale entries.
599
+
600
+ ## Requirements
601
+
602
+ - Python 3.12+
603
+ - Claude Code CLI with a Max or Pro subscription
604
+ - `gh` CLI (authenticated, for coordinator-side GitHub operations)
605
+ - Rust toolchain — only to build `coord-tui`
606
+ - Tailscale — optional, only for multi-machine setups
607
+
608
+ ## Documentation
609
+
610
+ - [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — how the clients, agents, daemon, and workers fit together; the agent HTTP API; the auto-loop end to end; the merge-gate checklist.
611
+ - [`docs/PIPELINE_V2.md`](docs/PIPELINE_V2.md) / [`docs/ORACLE_LOOP.md`](docs/ORACLE_LOOP.md) — the two-tier milestone pipeline and the sealed-acceptance oracle loop.
612
+ - [`docs/PHONE_WEBAPP.md`](docs/PHONE_WEBAPP.md) — build + serve the phone control-center PWA over Tailscale.
613
+ - [`docs/AGENT_OPERATIONS.md`](docs/AGENT_OPERATIONS.md) — agent install, upgrade, editable-drift recovery, and releasing to PyPI.
614
+
615
+ ## Releasing a new version
616
+
617
+ 1. Bump the version in `coord/__init__.py` and `pyproject.toml` (both must match).
618
+ 2. Commit, then tag and push:
619
+ ```bash
620
+ git tag vX.Y.Z && git push origin main vX.Y.Z
621
+ ```
622
+ 3. GitHub Actions (`publish.yml`) builds and publishes to PyPI using the `PYPI_API_TOKEN` secret.
623
+ 4. After the publish completes, upgrade remote agents — `coord agent update --all`.
624
+
625
+ `coord-tui` ships as a locally-built binary, not via PyPI — rebuild and reinstall it after a `tui/` change (see [Driving from coord-tui](#driving-from-coord-tui)).