@detergent-software/conductor 1.4.0-dev.8 → 1.4.0

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 (56) hide show
  1. package/CHANGELOG.md +114 -0
  2. package/README.md +26 -8
  3. package/build/broker.js +39 -13
  4. package/build/broker.js.map +1 -1
  5. package/build/cli.js +36 -10
  6. package/build/cli.js.map +1 -1
  7. package/build/client.js +35 -14
  8. package/build/client.js.map +1 -1
  9. package/build/code-host.js +2 -0
  10. package/build/code-host.js.map +1 -1
  11. package/build/config.js +7 -1
  12. package/build/config.js.map +1 -1
  13. package/build/daemon.js +36 -18
  14. package/build/daemon.js.map +1 -1
  15. package/build/help.js +27 -6
  16. package/build/help.js.map +1 -1
  17. package/build/inbox.js +24 -0
  18. package/build/inbox.js.map +1 -1
  19. package/build/lib/providers/ado/code-host.js +1 -0
  20. package/build/lib/providers/ado/code-host.js.map +1 -1
  21. package/build/lib/providers/ado/pipelines.js +16 -10
  22. package/build/lib/providers/ado/pipelines.js.map +1 -1
  23. package/build/lib/providers/github/actions.js +11 -0
  24. package/build/lib/providers/github/actions.js.map +1 -1
  25. package/build/lib/providers/github/code-host.js +17 -0
  26. package/build/lib/providers/github/code-host.js.map +1 -1
  27. package/build/manager.js +124 -10
  28. package/build/manager.js.map +1 -1
  29. package/build/paths.js +9 -1
  30. package/build/paths.js.map +1 -1
  31. package/build/project-check-cli.js +85 -0
  32. package/build/project-check-cli.js.map +1 -0
  33. package/build/project-check.js +362 -0
  34. package/build/project-check.js.map +1 -0
  35. package/build/pushover.js +11 -0
  36. package/build/pushover.js.map +1 -1
  37. package/build/rule-actions.js +17 -6
  38. package/build/rule-actions.js.map +1 -1
  39. package/build/rules-service.js +7 -2
  40. package/build/rules-service.js.map +1 -1
  41. package/build/rules.js +31 -14
  42. package/build/rules.js.map +1 -1
  43. package/build/runs.js.map +1 -1
  44. package/build/scheduler.js +46 -1
  45. package/build/scheduler.js.map +1 -1
  46. package/build/server.js +81 -0
  47. package/build/server.js.map +1 -1
  48. package/build/spend.js +37 -4
  49. package/build/spend.js.map +1 -1
  50. package/build/store.js +64 -12
  51. package/build/store.js.map +1 -1
  52. package/build/worktrees.js +1 -0
  53. package/build/worktrees.js.map +1 -1
  54. package/mod/hooks/model.ts +29 -1
  55. package/mod/hooks/register.tsx +51 -2
  56. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,120 @@
2
2
 
3
3
  Releases are tagged `conductor-v<version>` and staged on npm by `atk-conductor-release` (`pipelines/release-conductor.yml`), which writes each section below. `scripts/check-changelog.mjs` fails when a tag has no section here.
4
4
 
5
+ ## [1.4.0](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/branchCompare?baseVersion=GTconductor-v1.3.0&targetVersion=GTconductor-v1.4.0) (2026-10-15)
6
+
7
+ ### Features
8
+
9
+ * **conductor:** `conduct project check <name>` (ATK-490) ([393868c](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/393868c9d346f661c1fddb55788551cf98d66faf))
10
+ * **conductor:** a brief with the phase, the PR and the comments (ATK-456) ([cfd0f11](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/cfd0f11e8881f43eb0d4d4d4f93800738f81d57f))
11
+ * **conductor:** a GitHub Issues tracker kind (ATK-458) ([6028a13](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/6028a136cc39e1ed51072571629e68dead466d35))
12
+ * **conductor:** compact a parked worker whose context grew too big ([4259ec2](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/4259ec2d570e4dcc13760a8941a219cb60968302))
13
+ * **conductor:** conduct file, in-process notes and the PR reference (ATK-456) ([0b3311b](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/0b3311b7ec877cc7846d1c5607c35c653c43b58d))
14
+ * **conductor:** conduct project remove <name> (ATK-499) ([8ec1fda](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/8ec1fda3ee10a613840d2e96dc847fbbd416fd6a))
15
+ * **conductor:** conduct runs and conduct wait merge (ATK-455) ([e46a331](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/e46a331491ec40d01da860306f910e62b59bdf67))
16
+ * **conductor:** easier-to-scan conduct help (ATK-478) ([8c34660](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/8c34660ba7ecbac439312e317eb359767efedb21))
17
+ * **conductor:** phase notes move the tracker state (ATK-456) ([6c93b91](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/6c93b91fc7f0487c41ddfe357248a3bfdc97a463))
18
+ * **conductor:** read a branch's tip and a repo's pipelines (ATK-490) ([40af3c1](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/40af3c1362b16b07ea3c135a69880adcbdb36626))
19
+ * **conductor:** take the whole profile from disk, not only its rules ([b22705a](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/b22705ad2adb2bb6e886e5f99e011ccc0767b5c0))
20
+ * **conductor:** tracker writes for Linear and ADO Boards (ATK-456) ([b86911e](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/b86911ea478c8c4da90b6b5f8cf8586094b1fc4a))
21
+
22
+ ### Bug Fixes
23
+
24
+ * **conductor:** address review of the context compaction ([51ebe19](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/51ebe1937f83e6cd448b028afac52b6ecb585eef))
25
+ * **conductor:** approve and revise from the console through conduct (ATK-508) ([f3f1785](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/f3f1785136e152ade05cad8cab8e938c5eefef08))
26
+ * **conductor:** attach from the console by worker id (ATK-507) ([873dc09](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/873dc09e1aeab9b2006aa7fb157fd1be1f17c20b))
27
+ * **conductor:** attach from the console through conduct attach (ATK-507) ([f51bb7c](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/f51bb7cb5bc15a5b6a712d8f13d4438b4acb72cb))
28
+ * **conductor:** back off a partial retire and raise it once (ATK-496) ([7fe082a](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/7fe082a0b211b95eddc5e7fd93ced4bd3ff0a925))
29
+ * **conductor:** guard the brief found in review (ATK-456) ([5d7debe](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/5d7debe7cd670bc20798f7d55438bfc24d1095be))
30
+ * **conductor:** guard the note and follow-up paths found in review (ATK-456) ([6d881da](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/6d881daca5d5c5103943fba6a1560f7ae4db36de)), closes [AB#12](https://emergentcode.visualstudio.com/Emergent%20Software/_workitems/edit/12)
31
+ * **conductor:** guard the red-checks inbox paths found in review (ATK-468) ([c567a4d](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/c567a4d63192c1e7b6c630e4292846b4a78166e8))
32
+ * **conductor:** guard the tracker writes found in review (ATK-456) ([50c9987](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/50c998778997f5eb2b914339ed3c58f726fde83c))
33
+ * **conductor:** hold merges on red checks by item, not by worker (ATK-468) ([78c16ea](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/78c16ea33c78e6b8dd1d94b5b2f5d58a3c950b5a))
34
+ * **conductor:** keep a failed atk audit on one check line (ATK-490) ([ae78d30](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/ae78d3012bb68d178f85772f6303f5c1b97d4e32))
35
+ * **conductor:** keep a project's name, and say only what is in force ([51efeb0](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/51efeb0977e005d0daa84c67f6590c7817339b87))
36
+ * **conductor:** keep the client's timeout detail and content-length ([b7e6943](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/b7e69438cf8c04f5589883e68359db5f2d5868da))
37
+ * **conductor:** leave a worker's context unknown after a compaction ([e6c79d3](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/e6c79d3b48677620403bd9cc32bc1a9599d90b19))
38
+ * **conductor:** only ~/.conductor falls back to the Pushover credential (ATK-506) ([a87117b](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/a87117b476b78588f83f5215633422c823f37085))
39
+ * **conductor:** open an inbox link once from the terminal pane (ATK-494) ([1634517](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/16345173815330b2cea5361e964ebdf4f2921c15))
40
+ * **conductor:** open only web links, on Windows only (ATK-494) ([8d2f608](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/8d2f6084cc99900b2c012cddbb5e287b488f1213))
41
+ * **conductor:** open Windows Terminal tabs unhidden (ATK-469) ([6f3a69a](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/6f3a69aec82331727367075fe5b622a5f7c57f12))
42
+ * **conductor:** project check review fixes (ATK-490) ([7518d91](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/7518d9155066c4e7f7b301b4bee703b3d3a4a0e8))
43
+ * **conductor:** raise red PR checks as a failure and hold the merge (ATK-468) ([5897adb](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/5897adb9033b89d575fcd26f391c012637dd602b))
44
+ * **conductor:** read the default home per call, and pin env keys (ATK-506) ([e83019e](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/e83019e81875e4783d7c9b5a3ad82e55e754a658))
45
+ * **conductor:** refuse an unreadable stored profile's bad file once ([4e100f1](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/4e100f14fb2a9ed36b701cdb8f2a36d91bacacb7))
46
+ * **conductor:** rename by remove-then-add, and guard removal races (ATK-499) ([9ad7289](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/9ad72894e5ac58d0bc5de307fd36892909c59d7c))
47
+ * **conductor:** review fixes for conduct runs and merge waits (ATK-455) ([b1ff160](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/b1ff1602962f3bc902f33af57a23b06df081c5df))
48
+ * **conductor:** review fixes for the github-issues tracker (ATK-458) ([79abe60](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/79abe602f80138714098a61821d16dfc015787c0))
49
+ * **conductor:** say when an approve may have posted, on every path (ATK-508) ([8278f23](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/8278f23a6adfe6a73904674802c6026a54bba983))
50
+ * **conductor:** send API calls without undici's 300 s timeouts ([61db3e4](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/61db3e4418b6f7525105197e9503223bf7a83719))
51
+
52
+ ### Refactoring
53
+
54
+ * **conductor:** help examples a shell can run, review fixes (ATK-478) ([f1be136](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/f1be1361a1874a26a91dcfafd42626e25c307943)), closes [#12](https://emergentcode.visualstudio.com/Emergent%20Software/_workitems/edit/12) [#-word](https://emergentcode.visualstudio.com/Emergent%20Software/_workitems/edit/-word)
55
+ * **conductor:** the brief names its PR with the notes' helper (ATK-456) ([7b3f009](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/7b3f009715cce46a4ac02697bdca3680ab9f78f5))
56
+
57
+ ## [1.4.0-dev.15](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/branchCompare?baseVersion=GTconductor-v1.4.0-dev.14&targetVersion=GTconductor-v1.4.0-dev.15) (2026-10-15)
58
+
59
+ ### Bug Fixes
60
+
61
+ * **conductor:** approve and revise from the console through conduct (ATK-508) ([f3f1785](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/f3f1785136e152ade05cad8cab8e938c5eefef08))
62
+ * **conductor:** say when an approve may have posted, on every path (ATK-508) ([8278f23](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/8278f23a6adfe6a73904674802c6026a54bba983))
63
+
64
+ ## [1.4.0-dev.14](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/branchCompare?baseVersion=GTconductor-v1.4.0-dev.13&targetVersion=GTconductor-v1.4.0-dev.14) (2026-10-15)
65
+
66
+ ### Bug Fixes
67
+
68
+ * **conductor:** attach from the console by worker id (ATK-507) ([873dc09](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/873dc09e1aeab9b2006aa7fb157fd1be1f17c20b))
69
+ * **conductor:** attach from the console through conduct attach (ATK-507) ([f51bb7c](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/f51bb7cb5bc15a5b6a712d8f13d4438b4acb72cb))
70
+
71
+ ## [1.4.0-dev.13](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/branchCompare?baseVersion=GTconductor-v1.4.0-dev.12&targetVersion=GTconductor-v1.4.0-dev.13) (2026-10-15)
72
+
73
+ ### Bug Fixes
74
+
75
+ * **conductor:** keep the client's timeout detail and content-length ([b7e6943](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/b7e69438cf8c04f5589883e68359db5f2d5868da))
76
+ * **conductor:** only ~/.conductor falls back to the Pushover credential (ATK-506) ([a87117b](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/a87117b476b78588f83f5215633422c823f37085))
77
+ * **conductor:** read the default home per call, and pin env keys (ATK-506) ([e83019e](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/e83019e81875e4783d7c9b5a3ad82e55e754a658))
78
+ * **conductor:** send API calls without undici's 300 s timeouts ([61db3e4](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/61db3e4418b6f7525105197e9503223bf7a83719))
79
+
80
+ ## [1.4.0-dev.12](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/branchCompare?baseVersion=GTconductor-v1.4.0-dev.11&targetVersion=GTconductor-v1.4.0-dev.12) (2026-10-15)
81
+
82
+ ### Features
83
+
84
+ * **conductor:** conduct project remove <name> (ATK-499) ([8ec1fda](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/8ec1fda3ee10a613840d2e96dc847fbbd416fd6a))
85
+
86
+ ### Bug Fixes
87
+
88
+ * **conductor:** rename by remove-then-add, and guard removal races (ATK-499) ([9ad7289](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/9ad72894e5ac58d0bc5de307fd36892909c59d7c))
89
+
90
+ ## [1.4.0-dev.11](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/branchCompare?baseVersion=GTconductor-v1.4.0-dev.10&targetVersion=GTconductor-v1.4.0-dev.11) (2026-10-15)
91
+
92
+ ### Features
93
+
94
+ * **conductor:** compact a parked worker whose context grew too big ([4259ec2](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/4259ec2d570e4dcc13760a8941a219cb60968302))
95
+
96
+ ### Bug Fixes
97
+
98
+ * **conductor:** address review of the context compaction ([51ebe19](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/51ebe1937f83e6cd448b028afac52b6ecb585eef))
99
+ * **conductor:** leave a worker's context unknown after a compaction ([e6c79d3](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/e6c79d3b48677620403bd9cc32bc1a9599d90b19))
100
+
101
+ ## [1.4.0-dev.10](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/branchCompare?baseVersion=GTconductor-v1.4.0-dev.9&targetVersion=GTconductor-v1.4.0-dev.10) (2026-10-15)
102
+
103
+ ### Bug Fixes
104
+
105
+ * **conductor:** back off a partial retire and raise it once (ATK-496) ([7fe082a](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/7fe082a0b211b95eddc5e7fd93ced4bd3ff0a925))
106
+
107
+ ## [1.4.0-dev.9](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/branchCompare?baseVersion=GTconductor-v1.4.0-dev.8&targetVersion=GTconductor-v1.4.0-dev.9) (2026-10-15)
108
+
109
+ ### Features
110
+
111
+ * **conductor:** `conduct project check <name>` (ATK-490) ([393868c](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/393868c9d346f661c1fddb55788551cf98d66faf))
112
+ * **conductor:** read a branch's tip and a repo's pipelines (ATK-490) ([40af3c1](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/40af3c1362b16b07ea3c135a69880adcbdb36626))
113
+
114
+ ### Bug Fixes
115
+
116
+ * **conductor:** keep a failed atk audit on one check line (ATK-490) ([ae78d30](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/ae78d3012bb68d178f85772f6303f5c1b97d4e32))
117
+ * **conductor:** project check review fixes (ATK-490) ([7518d91](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/7518d9155066c4e7f7b301b4bee703b3d3a4a0e8))
118
+
5
119
  ## [1.4.0-dev.8](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/branchCompare?baseVersion=GTconductor-v1.4.0-dev.7&targetVersion=GTconductor-v1.4.0-dev.8) (2026-10-15)
6
120
 
7
121
  ### Bug Fixes
package/README.md CHANGED
@@ -12,6 +12,9 @@ conduct supervise [--fail-fast] run the daemon and restart it when it dies (se
12
12
  conduct status [--json] the daemon's pid, port, projects, workers and held locks
13
13
  conduct project add <path> register the project whose checkout holds .claude/conductor.json
14
14
  conduct project list [--json] the registered projects
15
+ conduct project remove <name> drop a registration (a renamed project's old name), resolving its inbox items
16
+ conduct project check <name> [--no-worktree] [--json]
17
+ whether the project can be conducted, before a launch finds out
15
18
  conduct launch <item> start a worker: worktree, background session, tab
16
19
  [--project <name>] [--probe] [--prompt <text>] [--conductor <name>]
17
20
  conduct retire <worker> [--force] stop a worker, remove its worktree and session
@@ -92,12 +95,14 @@ The session manager owns the `claude --bg` sessions it launches, and only those:
92
95
  - **launch:** the worktree comes first, through the project's `.claude/hooks/worktree-hooks.mjs`. In a repo with `.atk-lock.json`, the profile's work and verify skills must match the lockfile (`atk install` fixes them when it can). Then `claude --bg --worktree <name> -n <name> --disallowedTools EnterPlanMode ExitPlanMode --permission-mode auto -- <prompt>` runs from the main checkout. A profile with `"workers": { "tab": true }` also gets a Windows Terminal tab attached to the session.
93
96
  - **park:** a worker with a wait (`POST /waits`) is stopped once `claude agents` shows its turn has ended. Its status becomes `parked`, and its tab closes.
94
97
  - **resume:** when a wait resolves, the daemon lets the stop settle (`sessions.settleSeconds`). It checks the process has exited, then runs `claude --bg --resume <session> -- "[conductor] event: …"`. The session keeps its name, model, permission mode and disallowed tools. A resume of a session that still runs starts a copy; the daemon stops and removes the copy, then tries again.
98
+ - **compact:** a parked worker with no resolved wait, whose context the rules find too big (the default `compact-on-park`: past `sessions.compactTokens`, 300k), is resumed with `/compact <what to keep>` once its stop has settled (`worker.compacting`). It runs until its transcript shows the compaction's boundary (`worker.compacted`, with the context before it and the conversation it kept), then parks again on its waits, which resume it as usual. Each turn of a session re-reads its whole context from cache, so a worker left to grow pays for it every turn (ATK-454 reached 883k). A resume that starts a copy is tried again on a later sweep (`worker.compact-deferred`), as a resume is. A compaction whose resume fails, or whose turn ends with no boundary 10 minutes on, logs `worker.compact-failed`, which raises a `context` item in the inbox. The worker still parks, and the daemon doesn't try it again until it restarts or the session compacts some other way: any boundary in its transcript, Claude Code's own included, logs `worker.compacted` and resolves that item. A worker whose context is unknown is never compacted, so even a rule with no threshold can't compact it on every park.
95
99
  - **retire:** refuses uncommitted or unpushed work, and a worker whose turn still runs, unless `--force`. It never retires a session that is still starting. Then it stops the session, removes the worktree and runs `claude rm`. If the stop fails, nothing is removed.
96
100
  - **restarts:** a launch the daemon was stopped in adopts its session if one was started, and otherwise fails and removes its clean worktree.
97
101
  - **attach:** a parked worker is resumed with no event text, so it wakes idle and keeps running when its tab closes. An attached worker isn't parked until it registers a new wait, or until its turn has been over `sessions.idleMinutes` (`worker.detached`). The daemon can't see the tab, so this also delivers a wait that resolved while it was attached.
98
102
  - **park failures:** a session whose process outlives `claude stop` by 30 s logs one `worker.park-failed` per spell, which raises a `stall` in the inbox (see Inbox), and the park is tried again every 5 minutes.
99
103
  - **stalls:** a permission prompt open `sessions.permissionMinutes` (5), or idle `sessions.idleMinutes` (20) with no wait, logs one `worker.stalled` event per spell, and `worker.stall-cleared` when that spell ends. `claude agents` names no command, so a permission stall reads the session's transcripts (its own and its subagents') for the call still open: its tool, the command or path, the subagent that made it, and the auto-mode classifier denials just before it. The inbox item and its push say them, for example "ATK-297 has waited 5 min on a permission prompt: Bash `git -C … diff …` in subagent general-purpose (Review ATK-297 diff vs plan), after 2 auto-mode denials". Auto mode asks a person after 3 classifier denials in a row (20 in a session), even in a background subagent, so that count is usually why the prompt came. An open item of a Handoff kind with nothing to watch (`abandoned`, `blocked`, `failed`, `human`, `jason`, `scope`) on the worker, or on its item with no worker, counts as a wait: its idle clock starts once that item resolves. A `merge`, `npm-otp` or `plan` item doesn't: those come with a wait, so a worker idle with only the item still stalls.
100
104
  - **spend:** tokens from the session's transcript and its subagents' (`~/.claude/projects/*/<session>.jsonl`), each message counted once, go into `spend` per worker and local day. It keeps input, output, cache read and cache write; `tokens` is their sum. A worker whose tokens in all, not counting cache reads, pass `inbox.runawayTokens` logs `worker.runaway` once per daemon run. Cache reads are left out because they are nearly all of a session's tokens (97% on ATK-312) at a tenth of the price. The spend `conduct status`, `GET /fleet` and the console's fleet pane show (`spend.today`, `spend.total`) and the `spend.*` rule fields count the same tokens: input, output and cache writes. Status shows the worker's cache reads beside them, labelled (`spend 417k today, 1.0M total, 25M cache reads`; `spend.cacheRead` in `GET /fleet`).
105
+ - **context:** the session's context is its main transcript's newest model call: input, cache read, cache write and output. Subagents have contexts of their own, so theirs don't count. After a compaction it is unknown until the next call: the boundary counts only the conversation it kept, and the call adds the system prompt and tools back (a probe that kept 2.8k next read 68k). Status shows it as `context 312k` (`context` in `GET /fleet`), and the rules read it as `worker.context`.
101
106
  - **probes:** `--probe` names the worktree and session `probe-<item>` and gives it a prompt that works no issue, so tests stay out of the live fleet.
102
107
 
103
108
  Worker statuses: `launching`, `running`, `parked`, `stopped-unexpectedly`, `failed`, `exited`. Every step is an event (`worker.launched`, `worker.parked`, `worker.resumed`, …) on `GET /events`.
@@ -216,6 +221,7 @@ An item resolves itself when its condition is seen, and records what resolved it
216
221
  | `conflict` | `pr.conflict-stuck`: a watched PR has conflicted with its base for `watchers.conflictMinutes` (30) since its worker was woken for it, and the wake never reached the worker or a pass still sees the conflict; with `conduct attach` and the PR link | the PR merging cleanly again, merged or abandoned (`pr.conflict-cleared`), its retirement, or a daemon restart (the spell starts over) |
217
222
  | `login` | `provider.login-failed`: a project's provider login stopped working (see Accounts), once per provider and account however many projects and calls find it, with the command that signs in again | the login working again, found by the daemon's re-probe, any call, or a `login` wait (`provider.login-restored`), `conduct done`, or a daemon restart (the spell starts over) |
218
223
  | `runaway` | a worker passing `inbox.runawayTokens` (1.5M) input, output and cache-write tokens in all, once per worker | `conduct done`, or its retirement |
224
+ | `context` | `worker.compact-failed`: the daemon couldn't compact a worker whose context passed the `compact-on-park` rule (see Workers), while one is open, with `conduct attach` (run `/compact` in it) and `conduct retire` | the session compacting (`worker.compacted`), `conduct done`, or its retirement |
219
225
  | `ready-to-release`, `queue-drained` | the scheduler's default rules (see Scheduler) | `conduct done` |
220
226
  | `triage` | the scheduler's default rule `triage`: an item with the profile's triage label, once per item (see Scheduler) | a read of its project that no longer shows the label on the item (removed, or the item closed or left the queue), in `scheduler.mode` `on`; or `conduct done`, after which it is raised again the next day while the label stays. Once resolved, a label put back raises it again at once |
221
227
  | `console` | the console's finding on an escalation, with `conduct escalations done <id> --ask` (see Console) | `conduct done` |
@@ -240,7 +246,7 @@ If the tracker refuses the comment, nothing is resolved. Only a plan takes appro
240
246
  The notifier routes each new inbox item to the phone, on two channels:
241
247
 
242
248
  - **Remote Control:** the daemon appends `notify.requested` (`channel: "remote-control"`), and the conductor mod in the console pushes it with PushNotification. It reaches the phone only while the console is connected to Remote Control (see Mod). On Claude Code 2.1.296 these pushes are reported sent but never reach the phone (ATK-359), so the built-in `default` and `focus` also send to Pushover until a Claude Code release fixes it.
243
- - **Pushover:** sent from the daemon. The keys are `PUSHOVER_TOKEN` and `PUSHOVER_USER`, or else the Windows generic credential `atk-conductor-pushover` (`notify.pushover.credential`): its **user name is your Pushover user key** and its **password is the application's API token**. Save it with `cmdkey /generic:atk-conductor-pushover /user:<user key> /pass:<app token>` or in Credential Manager. A credential saved while the daemon runs is read on the next push. The keys are never logged or stored.
249
+ - **Pushover:** sent from the daemon. The keys are `PUSHOVER_TOKEN` and `PUSHOVER_USER`, or else the Windows generic credential `atk-conductor-pushover` (`notify.pushover.credential`): its **user name is your Pushover user key** and its **password is the application's API token**. Save it with `cmdkey /generic:atk-conductor-pushover /user:<user key> /pass:<app token>` or in Credential Manager. A credential saved while the daemon runs is read on the next push. The keys are never logged or stored. Only `~/.conductor` falls back to `atk-conductor-pushover`: a daemon on another `CONDUCTOR_HOME` (a scratch home for a test) reads a credential only when its `config.json` names `notify.pushover.credential`, so it pushes to your phone only with that or with `PUSHOVER_TOKEN` and `PUSHOVER_USER` in its environment (ATK-506).
244
250
 
245
251
  **Profiles** pick the channels. A profile is a list of rules, and the first rule that matches an item says where it goes; when none matches, the item stays in the inbox, unpushed. Three are built in, and `notify.profiles` in `config.json` replaces one by name or adds more:
246
252
 
@@ -287,11 +293,11 @@ Rules say what the conductor does when something happens (design note, section 9
287
293
  ]
288
294
  ```
289
295
 
290
- - **Sources, in order:** the item's project's `rules` (in its `.claude/conductor.json`, changed by PR), then `~/.conductor/rules.json`, then the built-in defaults: conduct-atk's behavior written as rules (`launch`, `retire-closed`, `park-on-wait`, `resume-on-wait`, `runaway`, `daily-cap`, `ready-to-release`, `queue-drained`, `triage`, which raises a new item that waits on the profile's triage label in the inbox, `conductor-handoff`, which escalates a worker's `Handoff · conductor` note to the console, and `hold-pre-start-handoff`, which adds the human label when a worker hands off as `human`, `jason`, `blocked` or `scope` before its `Started` note, so the scheduler never launches work no worker can do again; remove the label if the item should be picked later). A rule with an `id` replaces the rule with the same id further down, so a file holds only the differences.
291
- - **when:** `and`, `or`, `not` and parentheses over comparisons (`==`, `!=`, `<`, `<=`, `>`, `>=`, `in [a, b]`, `<label> in item.labels`, `Started in item.phases`) and events. An event rule fires when one of its events happens: `note`, `plan`, `wait.resolved`, `run.failed` (a failed launch, a session that stopped unexpectedly, or a PR's red checks: `pr.checks-failed`), `worker.idle`, `worker.exited`, `worker.permission`, `worker.waiting`, `inbox.raised`, `pr.comment`, `item.unblocked`, `item.closed`, `provider.login-failed` (a project's login lost, once per spell; see Accounts), `queue.pick`, `queue.drained`, `queue.ready-to-release`, `queue.triage`. A rule without one is a state rule, checked on each scheduler tick against each wait, inbox item, worker or project, or once for the machine, by the fields it reads. Fields: `project`, `item.id/area/labels/tier/priority`, `item.phases` (the phases of every note the item has had, the one being posted too), `plan.tier/landing`, `note.phase/kind`, `wait.kind/age`, `inbox.kind/age`, `worker.retries/phase`, `spend.worker/item/project/today` (input, output and cache-write tokens, without cache reads: the worker's and the item's in all, the project's and the machine's today), `time`, `day`, `notify.profile`. Values carry units: `15m`, `2h`, `500k`, `2M`, `22:00`, `saturday`.
296
+ - **Sources, in order:** the item's project's `rules` (in its `.claude/conductor.json`, changed by PR), then `~/.conductor/rules.json`, then the built-in defaults: conduct-atk's behavior written as rules (`launch`, `retire-closed`, `park-on-wait`, `resume-on-wait`, `compact-on-park`, `runaway`, `daily-cap`, `ready-to-release`, `queue-drained`, `triage`, which raises a new item that waits on the profile's triage label in the inbox, `conductor-handoff`, which escalates a worker's `Handoff · conductor` note to the console, and `hold-pre-start-handoff`, which adds the human label when a worker hands off as `human`, `jason`, `blocked` or `scope` before its `Started` note, so the scheduler never launches work no worker can do again; remove the label if the item should be picked later). A rule with an `id` replaces the rule with the same id further down, so a file holds only the differences.
297
+ - **when:** `and`, `or`, `not` and parentheses over comparisons (`==`, `!=`, `<`, `<=`, `>`, `>=`, `in [a, b]`, `<label> in item.labels`, `Started in item.phases`) and events. An event rule fires when one of its events happens: `note`, `plan`, `wait.resolved`, `run.failed` (a failed launch, a session that stopped unexpectedly, or a PR's red checks: `pr.checks-failed`), `worker.idle`, `worker.exited`, `worker.permission`, `worker.waiting`, `worker.parked` (a park; the session manager also asks it of each parked worker on a sweep, for `compact`), `inbox.raised`, `pr.comment`, `item.unblocked`, `item.closed`, `provider.login-failed` (a project's login lost, once per spell; see Accounts), `queue.pick`, `queue.drained`, `queue.ready-to-release`, `queue.triage`. A rule without one is a state rule, checked on each scheduler tick against each wait, inbox item, worker or project, or once for the machine, by the fields it reads. Fields: `project`, `item.id/area/labels/tier/priority`, `item.phases` (the phases of every note the item has had, the one being posted too), `plan.tier/landing`, `note.phase/kind`, `wait.kind/age`, `inbox.kind/age`, `worker.retries/phase`, `worker.context` (the session's context in tokens, see Workers), `spend.worker/item/project/today` (input, output and cache-write tokens, without cache reads: the worker's and the item's in all, the project's and the machine's today), `time`, `day`, `notify.profile`. Values carry units: `15m`, `2h`, `500k`, `2M`, `22:00`, `saturday`.
292
298
  - **do:** `launch`, `retire`, `park`, `resume worker`, `retry`, `pause launches [in <project>] [until <when> | for <duration>]`, `pause all launches …`, `unpause launches`, `focus [<project>] weight|slots <n> until <when>`, `auto-approve now`, `auto-approve after <duration>`, `inbox <kind> ["<text>"]`, `remind jason`, `notify <channel> ["<text>"]`, `notify profile <name> [until <when>]`, `label add|remove human|triage|shipped-open`, `flag shipped-open`, `escalate console "<ask>"`, `none`. One string, or a list.
293
- - **Guardrails:** rules act inside Area locks, slots, quiet hours and config.json's limits. A rule that would go past one is refused when it loads: `focus … slots` over `scheduler.slots`, an override with no end or one over 14 days, `retire` on anything but `item.closed`, `launch` outside `queue.pick` / `item.unblocked`, `park` outside `worker.waiting`, `resume` outside `wait.resolved` / `pr.comment`, `retry` outside `run.failed`. `merge`, `push`, `publish`, `approve`, `delete` and `run` aren't in the vocabulary: rules never merge, push, publish, approve prod, delete or run commands, and the daemon writes to a code host only when the owning worker asks (see Writes).
294
- - **Reload:** saving `rules.json` or a project's profile reloads its rules. A profile save, or a profile changed while the daemon was down, is taken whole: the daemon stores it and logs `project.updated` with the fields that `changed`, and the scheduler, watchers and the rest use it from then on. A profile that renames the project is refused: a project keeps the name it was registered under. A file the conductor refuses leaves its last good rules (for a profile, the whole last good profile) in force, logs `rules.rejected` and raises a `failed` inbox item until it loads again (`rules.loaded`), including after a restart. `conduct project add` refuses a profile whose rules don't load, with or without the daemon.
299
+ - **Guardrails:** rules act inside Area locks, slots, quiet hours and config.json's limits. A rule that would go past one is refused when it loads: `focus … slots` over `scheduler.slots`, an override with no end or one over 14 days, `retire` on anything but `item.closed`, `launch` outside `queue.pick` / `item.unblocked`, `park` outside `worker.waiting`, `resume` outside `wait.resolved` / `pr.comment`, `compact` outside `worker.parked`, `retry` outside `run.failed`. `merge`, `push`, `publish`, `approve`, `delete` and `run` aren't in the vocabulary: rules never merge, push, publish, approve prod, delete or run commands, and the daemon writes to a code host only when the owning worker asks (see Writes).
300
+ - **Reload:** saving `rules.json` or a project's profile reloads its rules. A profile save, or a profile changed while the daemon was down, is taken whole: the daemon stores it and logs `project.updated` with the fields that `changed`, and the scheduler, watchers and the rest use it from then on. A profile that renames the project is refused: a project keeps the name it was registered under. To rename one, `conduct project remove <old name>`, then `conduct project add` it under the new name (in that order: with both registered, both would read the same queue and could launch the same item). The remove drops the old registration and its queue read, resolves its open inbox items (the refusal's among them) and logs `project.removed`, on which the daemon drops its rules and its watch of the file. It is refused while the project has workers in flight, and works without the daemon. A file the conductor refuses leaves its last good rules (for a profile, the whole last good profile) in force, logs `rules.rejected` and raises a `failed` inbox item until it loads again (`rules.loaded`), including after a restart. `conduct project add` refuses a profile whose rules don't load, with or without the daemon.
295
301
  - **Checking:** `conduct rules` lists the rules in force (`project.atk:#2`, `machine:runaway`, `default:launch`) and what replaces what. `conduct rules test <file>` dry-runs a sample, such as `{ "event": "pr.comment", "project": "atk", "fields": { "wait.kind": "merge", "wait.age": "3h" } }` (leave out `event` for a state rule), and shows what fires, each action's guardrail, and why every other rule of the trigger didn't. Both read the files directly when the daemon isn't running.
296
302
 
297
303
  - **Why:** every action the conductor takes is an event that names its rule, directly (`rule`) or through the event that caused it (`data.cause`). `conduct why <event id>` follows that chain back and shows the rule as it fired; `conduct why ATK-315` does it for the item's newest actions.
@@ -332,7 +338,7 @@ The scheduler moves conduct-atk's tick into the daemon (design note, section 8).
332
338
  - **Release waits:** a Linear profile's `tracker.releaseWait: { "label": "waits-release", "shipped": "release-atk · Shipped" }` marks work that needs a dependency released, not only merged (a CLI change on npm `latest`, a prod deploy). An item with that label waits, once its open blockers have closed, until every Done blocker has a comment whose first line starts with the `shipped` text, under any heading or bold (`waits for ATK-391 to ship`), and starts on the first tick after. A comment that only quotes the text doesn't count. A blocker still open in another team waits the same way; a canceled one holds nothing. A blocker that shipped before release-atk wrote its notes (2026-10-06) holds until you add the note or remove the label. With the label and no blocker at all it waits until you act (`labelled waits-release with no blocker to wait on`), for something outside the tracker such as a Claude Code release. Such an item doesn't keep its tracker project from `queue.ready-to-release`, since the release is what it waits for. The read asks about the Done blockers in one more request, only when a labelled item has one. Without the setting, a Done blocker never holds anything.
333
339
  - **Slots:** `scheduler.slots` (4) across projects and the profile's `slots` per project (ATK's is 4), or `conduct focus --slots`, never more than the global ones. Slots count running workers only: a parked worker keeps its Area and frees its slot.
334
340
  - **Holds:** quiet hours and `conduct pause` turn picks into waits that say why.
335
- 3. **Act.** It runs the rules on what it found: `queue.pick` → `launch` (default `launch`), `item.closed` → `retire` (default `retire-closed`; a refused retire raises an inbox item once, except one refused while the worker's turn runs or its session starts, which is tried again each tick and raised only after 15 minutes), `queue.drained` and `queue.ready-to-release` → an inbox item once a day, `queue.triage` → a `triage` inbox item per item (default `triage`), resolved once the label goes. Each action is a `rule.fired` event, then `rule.done` or `rule.failed`. A launch that failed isn't tried again while its inbox item is open.
341
+ 3. **Act.** It runs the rules on what it found: `queue.pick` → `launch` (default `launch`), `item.closed` → `retire` (default `retire-closed`; a refused retire raises an inbox item once, except one refused while the worker's turn runs or its session starts, which is tried again each tick and raised only after 15 minutes; a partial retire is tried again after 15 minutes, and after 3 in a row it raises one inbox item that names the failed steps and any worktree left on disk, which the conductor never deletes, and is tried once a day), `queue.drained` and `queue.ready-to-release` → an inbox item once a day, `queue.triage` → a `triage` inbox item per item (default `triage`), resolved once the label goes. Each action is a `rule.fired` event, then `rule.done` or `rule.failed`. A launch that failed isn't tried again while its inbox item is open.
336
342
 
337
343
  `scheduler.mode` decides how far it goes:
338
344
  - **`on`** (the default): it acts.
@@ -541,7 +547,7 @@ Everything lives in `~/.conductor` (`CONDUCTOR_HOME` overrides it):
541
547
 
542
548
  | File | Holds |
543
549
  |---|---|
544
- | `config.json` | machine settings, JSONC (comments allowed), validated at startup; `inbox.runawayTokens` (1500000, the `runaway` rule's number); `notify` and `quietHours` (see Notifications); `scheduler` holds `mode` (`on`, `observe` or `off`), `slots` (4, across projects, and the most any rule can give one project), `dailyTokens` (20000000, the `daily-cap` rule's number) and `tickSeconds` (120); `sessions` holds `pollSeconds` (10), `settleSeconds` (5), `permissionMinutes` (5), `idleMinutes` (20); `watchers` holds `ado`, `github`, `health`, `linear` and `npm`, each `{ intervalSeconds, perMinute }` (30/60, 30/30, 30/30, 30/10, 20/30), `statsMinutes` (10) and `conflictMinutes` (30) |
550
+ | `config.json` | machine settings, JSONC (comments allowed), validated at startup; `inbox.runawayTokens` (1500000, the `runaway` rule's number); `notify` and `quietHours` (see Notifications); `scheduler` holds `mode` (`on`, `observe` or `off`), `slots` (4, across projects, and the most any rule can give one project), `dailyTokens` (20000000, the `daily-cap` rule's number) and `tickSeconds` (120); `sessions` holds `pollSeconds` (10), `settleSeconds` (5), `permissionMinutes` (5), `idleMinutes` (20), `compactTokens` (300000, the `compact-on-park` rule's number); `watchers` holds `ado`, `github`, `health`, `linear` and `npm`, each `{ intervalSeconds, perMinute }` (30/60, 30/30, 30/30, 30/10, 20/30), `statsMinutes` (10) and `conflictMinutes` (30) |
545
551
  | `rules.json` | machine rules, JSONC, reloaded on save (see Rules) |
546
552
  | `token` | the API token, readable by this user only; every request sends `Authorization: Bearer <token>` |
547
553
  | `conductor.pid`, `port` | the single-instance lock and where the API listens (`127.0.0.1`) |
@@ -550,7 +556,7 @@ Everything lives in `~/.conductor` (`CONDUCTOR_HOME` overrides it):
550
556
 
551
557
  ## API
552
558
 
553
- - `GET /projects`: the registered projects. `POST /projects` with `{ "path": "<absolute path>" }` registers one.
559
+ - `GET /projects`: the registered projects. `POST /projects` with `{ "path": "<absolute path>" }` registers one. `DELETE /projects/<name>` removes one: `{ project, resolved }` (the inbox items it resolved), 404 for a name no project is registered under, or 409 naming its workers in flight. `POST /projects/<name>/check` with `{ "worktree": false }` or `{}` runs `conduct project check` as the daemon's accounts: `{ project, results: [{ check, status, summary, details, fix }] }`, or 404 for a name no project is registered under.
554
560
  - `GET /events`: the event log as server-sent events. Add `?since=<id>` (or send `Last-Event-ID`) to replay from an id. Without either, the stream starts at the live end. `conduct events` prints it one JSON event per line: the events after `--since` (all of them without it), or with `--follow` everything from there on (live without `--since`). `--follow` reconnects with `Last-Event-ID` when the daemon goes away, so a restart loses nothing, and prints the stream's state as lines without an id: `{"kind":"conduct.connected"}` and, once per outage, `{"kind":"conduct.disconnected","error":…}`. `?console=1` (`conduct events --follow --console`, which the conductor mod runs, or `conduct events --follow` with `CONDUCTOR_CONSOLE=1`, as a mod from before `--console` runs it until `/reload-plugins`) marks the console's stream: while one is open, escalations have a console to wake (see Console).
555
561
  - `POST /shutdown`: a clean stop (`conduct stop`).
556
562
  - `GET /console/escalations`: the open escalations, oldest first (see Console).
@@ -607,6 +613,18 @@ conduct project add <path to the project's main checkout>
607
613
 
608
614
  `conduct project add` walks up from the path it is given to the directory that holds `.claude/conductor.json`, and maps a worktree to its main checkout. After that the daemon takes the whole profile from disk when it starts and each time the file is saved, so a `git pull` that changes `slots` or `skills.work` needs no `conduct project add`. An older daemon refuses a profile with fields it doesn't know, so upgrade the daemon before a profile that uses new ones lands. After an `--allow-downgrade` to a version without those fields, the stored copy no longer validates either: the project shows `the stored profile no longer validates` and isn't conducted until its file, saved without them, is read again.
609
615
 
616
+ Then `conduct project check <name>` says whether the project can be conducted, before its first launch finds out. Each check prints one line, `ok`, `warn`, `fail` or `skip`, with a fix under a warn or a fail, and the command exits 1 when any check fails (`--json` prints the same as data):
617
+
618
+ - **profile:** the file reads with this build's schema and keeps the registered name; a `warn` lists the fields that differ from the daemon's stored copy, which it takes on the next save or start. The later checks use the file when it reads, else the stored copy; with neither they are `skip`.
619
+ - **tracker:** the tracker's login answers, and the queue reads (Linear: the team, and whether any of its projects has a priority; Boards: the saved query; GitHub Issues: the labelled issues).
620
+ - **code-host** and **ci:** the code host's login answers and the base branch exists; each release's `pipeline` names exactly one of the repo's pipelines.
621
+ - **worktree:** the launch's first steps on a throwaway `conduct-check-<time>`: the worktree hooks create it, its skills match `.atk-lock.json`, and it is removed, whatever happened. The one check that writes; `--no-worktree` skips it, since the create hook runs `pnpm install`.
622
+ - **skills:** in the main checkout, `skills.work` is installed and declares `worker protocol v1`, `skills.verify` is installed, and `atk audit` finds both unchanged; a missing alias is a `warn`.
623
+ - **ports:** the broker has a free slot for a new worktree, up to `ports.maxSlot`, saving nothing.
624
+ - **health:** each `health` URL answers; a `warn` at most, since an environment can be down.
625
+
626
+ With the daemon running it checks through the API, as the daemon's own accounts; without it, here, as the machine's.
627
+
610
628
  The profile's optional `work` section is for the project's work skill; the daemon only checks it:
611
629
 
612
630
  ```jsonc
package/build/broker.js CHANGED
@@ -31,28 +31,36 @@ export function broker({ exists = existsSync, listening = portListening, now = (
31
31
  '`conduct project add <path>` registers one',
32
32
  ]);
33
33
  const profile = profileOf(project);
34
- const base = basePorts(profile);
35
34
  if (samePath(checkout, root))
36
- return { assignedAt: null, ports: base, project: project.name, slot: 0, worktree: checkout };
37
- const portsOf = (slot) => Object.fromEntries(Object.entries(base).map(([name, port]) => [name, port + slot]));
35
+ return { assignedAt: null, ports: basePorts(profile), project: project.name, slot: 0, worktree: checkout };
38
36
  let prefer = wanted;
39
37
  const held = sweep().find((a) => samePath(a.worktree, checkout));
40
38
  if (held) {
41
39
  // Kept while the profile still gives its slot those ports; otherwise it moves, its old slot first.
42
- if (held.slot <= profile.ports.maxSlot && samePorts(held.ports, portsOf(held.slot)))
40
+ if (held.slot <= profile.ports.maxSlot && samePorts(held.ports, slotPorts(profile, held.slot)))
43
41
  return held;
44
42
  freePorts(store, held.worktree, 'profile changed');
45
43
  prefer ??= held.slot;
46
44
  }
45
+ const free = await freeSlot(profile, prefer, store.portAssignments());
46
+ if (free === null)
47
+ throw noSlot(profile, checkout);
48
+ const assignment = store.savePorts({ ...free, project: project.name, worktree: checkout });
49
+ store.appendEvent({ data: { ...free, worktree: checkout }, kind: 'ports.assigned', project: project.name });
50
+ return assignment;
51
+ };
52
+ // The first slot of 1..maxSlot whose ports nobody has and nothing listens on, `prefer` first.
53
+ // `held`: the worktrees' assignments.
54
+ const freeSlot = async (profile, prefer, held) => {
47
55
  // Every main checkout's ports, and every worktree's.
48
56
  const taken = new Set([
49
- ...projects.flatMap((p) => (p.profile ? Object.values(basePorts(p.profile)) : [])),
50
- ...store.portAssignments().flatMap((a) => Object.values(a.ports)),
57
+ ...store.listProjects().flatMap((p) => (p.profile ? Object.values(basePorts(p.profile)) : [])),
58
+ ...held.flatMap((a) => Object.values(a.ports)),
51
59
  ]);
52
60
  const slots = Array.from({ length: profile.ports.maxSlot }, (_, i) => i + 1);
53
61
  const order = prefer !== undefined && slots.includes(prefer) ? [prefer, ...slots.filter((s) => s !== prefer)] : slots;
54
62
  for (const slot of order) {
55
- const ports = portsOf(slot);
63
+ const ports = slotPorts(profile, slot);
56
64
  const values = Object.values(ports);
57
65
  if (values.some((port) => port > MAX_PORT || taken.has(port)))
58
66
  continue;
@@ -60,13 +68,9 @@ export function broker({ exists = existsSync, listening = portListening, now = (
60
68
  // its own dev servers may be what listens there.
61
69
  if (slot !== prefer && (await Promise.all(values.map(listening))).some(Boolean))
62
70
  continue;
63
- const assignment = store.savePorts({ ports, project: project.name, slot, worktree: checkout });
64
- store.appendEvent({ data: { ports, slot, worktree: checkout }, kind: 'ports.assigned', project: project.name });
65
- return assignment;
71
+ return { ports, slot };
66
72
  }
67
- throw new ConductorError(`no free slot between 1 and ${profile.ports.maxSlot} for ${checkout}`, [
68
- '`conduct ports` lists the assignments; a removed worktree frees its slot',
69
- ]);
73
+ return null;
70
74
  };
71
75
  return {
72
76
  assignPorts: (path, prefer) => {
@@ -109,6 +113,19 @@ export function broker({ exists = existsSync, listening = portListening, now = (
109
113
  },
110
114
  locks: () => store.listLocks(),
111
115
  portAssignments: sweep,
116
+ // After the assignments in flight, so it sees the slots they took. It writes nothing: a gone
117
+ // worktree's ports count as free, as the next sweep makes them.
118
+ previewPorts: (profile) => {
119
+ const next = assigning.then(async () => {
120
+ const held = store.portAssignments().filter((a) => exists(a.worktree));
121
+ const free = await freeSlot(profile, undefined, held);
122
+ if (free === null)
123
+ throw noSlot(profile, `a new ${profile.name} worktree`);
124
+ return free;
125
+ });
126
+ assigning = next.catch(() => { });
127
+ return next;
128
+ },
112
129
  };
113
130
  }
114
131
  // Frees the ports of a worktree (a retired worker's, or one whose directory is gone).
@@ -155,6 +172,11 @@ export function releaseLocks(store, holder, reason) {
155
172
  store.appendEvent({ data: { holder, reason }, kind: 'lock.released', subject: lock.name });
156
173
  }
157
174
  }
175
+ function noSlot(profile, what) {
176
+ return new ConductorError(`no free slot between 1 and ${profile.ports.maxSlot} for ${what}`, [
177
+ '`conduct ports` lists the assignments; a removed worktree frees its slot',
178
+ ]);
179
+ }
158
180
  function profileOf(project) {
159
181
  if (project.profile)
160
182
  return project.profile;
@@ -165,4 +187,8 @@ function profileOf(project) {
165
187
  function samePorts(a, b) {
166
188
  return Object.keys(a).length === Object.keys(b).length && Object.entries(b).every(([name, port]) => a[name] === port);
167
189
  }
190
+ // A worktree's ports at slot N: each of the profile's base ports + N.
191
+ function slotPorts(profile, slot) {
192
+ return Object.fromEntries(Object.entries(basePorts(profile)).map(([name, port]) => [name, port + slot]));
193
+ }
168
194
  //# sourceMappingURL=broker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"broker.js","sourceRoot":"","sources":["../src/broker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"broker.js","sourceRoot":"","sources":["../src/broker.ts"],"names":[],"mappings":"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"}
package/build/cli.js CHANGED
@@ -20,14 +20,16 @@ import { inboxLines } from "./inbox.js";
20
20
  import { parseJsonc } from "./jsonc.js";
21
21
  import { processAlive, readPid } from "./lock.js";
22
22
  import { rotatingLog } from "./log.js";
23
- import { fleetWorkerSchema, storedFleet, workerLine } from "./manager.js";
23
+ import { fleetWorkerSchema, storedFleet, workerByRef, workerLine } from "./manager.js";
24
24
  import { installMod, removeMod } from "./mod.js";
25
25
  import { noteCommand } from "./note.js";
26
26
  import { isQuiet, notifyLines, notifyStatusSchema, parseUntil, testResultSchema } from "./notify.js";
27
27
  import { overrideViewSchema, PAUSE } from "./overrides.js";
28
28
  import { packageInfo } from "./package-info.js";
29
29
  import { conductorPaths } from "./paths.js";
30
- import { pushoverSender } from "./pushover.js";
30
+ import { projectCheckCommand } from "./project-check-cli.js";
31
+ import { noProject } from "./project-check.js";
32
+ import { pushoverCredential, pushoverSender } from "./pushover.js";
31
33
  import { registerProject } from "./registry.js";
32
34
  import { rulesLines, rulesService, rulesTestResultSchema, rulesViewSchema, testLines, } from "./rules-service.js";
33
35
  import { resolveUntil } from "./rules.js";
@@ -59,6 +61,7 @@ const ATTACH_TIMEOUT_MS = 9 * 60_000;
59
61
  const ANSWER_TIMEOUT_MS = 60_000;
60
62
  const projectsBody = z.object({ projects: z.array(projectSchema) });
61
63
  const addBody = z.object({ created: z.boolean(), project: projectSchema });
64
+ const removeBody = z.object({ project: projectSchema, resolved: z.array(inboxItemSchema) });
62
65
  const errorBody = z.object({ details: z.array(z.string()).optional(), error: z.string() });
63
66
  const fleetBody = z.object({ workers: z.array(fleetWorkerSchema) });
64
67
  const workerBody = z.object({ worker: workerSchema });
@@ -267,13 +270,7 @@ async function expectOk(call) {
267
270
  // A worker in flight by item or name. A probe and a live worker can share an item, so a name match wins.
268
271
  async function findWorker(paths, ref) {
269
272
  const { workers } = fleetBody.parse(await expectOk(callApi(paths, { method: 'GET', path: '/fleet' })));
270
- const byName = workers.filter((w) => w.name === ref);
271
- const matches = byName.length > 0 ? byName : workers.filter((w) => w.item === ref);
272
- if (matches.length === 1 && matches[0])
273
- return matches[0];
274
- if (matches.length === 0)
275
- throw new ConductorError(`no worker "${ref}" in flight`, ['`conduct status` lists them']);
276
- throw new ConductorError(`"${ref}" names several workers`, matches.map((w) => `${w.name} in ${w.project}`));
273
+ return workerByRef(workers, ref);
277
274
  }
278
275
  // `conduct help [<name>]` and `conduct <name> --help`: the listing (also `conduct help help`) or one
279
276
  // command's help, with a blank line either side, styled when stdout takes color.
@@ -450,6 +447,7 @@ async function main(argv) {
450
447
  json: { type: 'boolean' },
451
448
  kind: { type: 'string' },
452
449
  mode: { type: 'string' },
450
+ 'no-worktree': { type: 'boolean' },
453
451
  owner: { type: 'string' },
454
452
  prefer: { type: 'string' },
455
453
  probe: { type: 'boolean' },
@@ -650,8 +648,14 @@ async function main(argv) {
650
648
  case 'project':
651
649
  if (sub === 'add' && arg !== undefined)
652
650
  return addProject(paths, arg);
651
+ if (sub === 'remove' && arg !== undefined)
652
+ return removeProject(paths, arg);
653
653
  if (sub === 'list')
654
654
  return listProjects(paths, values.json === true);
655
+ if (sub === 'check' && arg !== undefined) {
656
+ process.exitCode = await projectCheckCommand(paths, arg, { json: values.json === true, worktree: values['no-worktree'] !== true }, { err: (line) => process.stderr.write(`${line}\n`), out });
657
+ return;
658
+ }
655
659
  throw usageError('project');
656
660
  case 'queue':
657
661
  return queue(paths, values.json === true, values.fresh === true);
@@ -887,6 +891,28 @@ async function queue(paths, json, fresh) {
887
891
  return out(JSON.stringify(view, null, 2));
888
892
  queueLines(view).forEach((line) => out(line));
889
893
  }
894
+ // `conduct project remove <name>`: a renamed project's old registration, or one no longer conducted.
895
+ async function removeProject(paths, name) {
896
+ let result;
897
+ try {
898
+ result = removeBody.parse(await expectOk(callApi(paths, { method: 'DELETE', path: `/projects/${encodeURIComponent(name)}` })));
899
+ }
900
+ catch (error) {
901
+ if (!(error instanceof NotRunningError))
902
+ throw error;
903
+ // No daemon: write the store directly. It doesn't load the project when it starts.
904
+ result = withStore(paths, (store) => {
905
+ const removed = store.removeProject(name);
906
+ if (removed)
907
+ return removed;
908
+ throw noProject(name, store.listProjects().map((p) => p.name));
909
+ });
910
+ }
911
+ const { project, resolved } = result;
912
+ out(`removed ${project.name} (${project.root})`);
913
+ for (const item of resolved)
914
+ out(` resolved #${item.id} (${item.kind}${item.item ? ` ${item.item}` : ''})`);
915
+ }
890
916
  // What a supervisor said about the serve it restarted (supervise.ts). One it can't read is left out:
891
917
  // the restart goes on without its event. Read once and removed, so the sessions and processes the
892
918
  // daemon starts don't inherit it.
@@ -1200,7 +1226,7 @@ async function superviseCommand(paths, failFast) {
1200
1226
  now: () => Date.now(),
1201
1227
  push: (message) => {
1202
1228
  const { notify } = config();
1203
- return pushoverSender({ credential: notify.pushover.credential })({
1229
+ return pushoverSender({ credential: pushoverCredential(notify.pushover.credential, paths.home) })({
1204
1230
  ...message,
1205
1231
  priority: notify.pushover.priority,
1206
1232
  });