@detergent-software/conductor 3.0.0-dev.9 → 3.1.0-dev.1

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 (212) hide show
  1. package/CHANGELOG.md +486 -0
  2. package/README.md +272 -126
  3. package/build/brief-cli.js +5 -12
  4. package/build/brief-cli.js.map +1 -1
  5. package/build/brief.js +4 -3
  6. package/build/brief.js.map +1 -1
  7. package/build/broker-cli.js +41 -14
  8. package/build/broker-cli.js.map +1 -1
  9. package/build/broker.js +1 -1
  10. package/build/broker.js.map +1 -1
  11. package/build/cli.js +226 -64
  12. package/build/cli.js.map +1 -1
  13. package/build/clones.js +92 -0
  14. package/build/clones.js.map +1 -0
  15. package/build/code-host-cli.js +172 -40
  16. package/build/code-host-cli.js.map +1 -1
  17. package/build/code-host-service.js +35 -2
  18. package/build/code-host-service.js.map +1 -1
  19. package/build/code-host.js +138 -16
  20. package/build/code-host.js.map +1 -1
  21. package/build/conditions.js +33 -16
  22. package/build/conditions.js.map +1 -1
  23. package/build/config.js +58 -28
  24. package/build/config.js.map +1 -1
  25. package/build/console.js +17 -27
  26. package/build/console.js.map +1 -1
  27. package/build/credentials.js +86 -54
  28. package/build/credentials.js.map +1 -1
  29. package/build/daemon.js +54 -65
  30. package/build/daemon.js.map +1 -1
  31. package/build/file-lock.js +155 -40
  32. package/build/file-lock.js.map +1 -1
  33. package/build/follow-ups.js +2 -2
  34. package/build/follow-ups.js.map +1 -1
  35. package/build/help.js +242 -83
  36. package/build/help.js.map +1 -1
  37. package/build/history.js +10 -4
  38. package/build/history.js.map +1 -1
  39. package/build/host/attach-clients.js +56 -0
  40. package/build/host/attach-clients.js.map +1 -0
  41. package/build/host/credential-manager.js +109 -0
  42. package/build/host/credential-manager.js.map +1 -0
  43. package/build/host/keychain.js +44 -0
  44. package/build/host/keychain.js.map +1 -0
  45. package/build/host/launchd.js +118 -0
  46. package/build/host/launchd.js.map +1 -0
  47. package/build/host/libsecret.js +40 -0
  48. package/build/host/libsecret.js.map +1 -0
  49. package/build/host/macos-terminal.js +63 -0
  50. package/build/host/macos-terminal.js.map +1 -0
  51. package/build/host/platform.js +4 -0
  52. package/build/host/platform.js.map +1 -0
  53. package/build/host/secrets.js +46 -0
  54. package/build/host/secrets.js.map +1 -0
  55. package/build/host/shell.js +26 -0
  56. package/build/host/shell.js.map +1 -0
  57. package/build/host/startup.js +26 -0
  58. package/build/host/startup.js.map +1 -0
  59. package/build/host/systemd.js +91 -0
  60. package/build/host/systemd.js.map +1 -0
  61. package/build/host/task-scheduler.js +78 -0
  62. package/build/host/task-scheduler.js.map +1 -0
  63. package/build/host/terminal.js +47 -0
  64. package/build/host/terminal.js.map +1 -0
  65. package/build/host/tmux.js +39 -0
  66. package/build/host/tmux.js.map +1 -0
  67. package/build/host/windows-terminal.js +46 -0
  68. package/build/host/windows-terminal.js.map +1 -0
  69. package/build/in-process.js +5 -4
  70. package/build/in-process.js.map +1 -1
  71. package/build/inbox.js +47 -35
  72. package/build/inbox.js.map +1 -1
  73. package/build/init.js +509 -0
  74. package/build/init.js.map +1 -0
  75. package/build/landing.js +107 -10
  76. package/build/landing.js.map +1 -1
  77. package/build/lib/providers/ado/code-host.js +5 -1
  78. package/build/lib/providers/ado/code-host.js.map +1 -1
  79. package/build/lib/providers/ado/pipelines.js +138 -26
  80. package/build/lib/providers/ado/pipelines.js.map +1 -1
  81. package/build/lib/providers/ado/trigger.js +5 -0
  82. package/build/lib/providers/ado/trigger.js.map +1 -1
  83. package/build/lib/providers/ado/writes.js +17 -2
  84. package/build/lib/providers/ado/writes.js.map +1 -1
  85. package/build/lib/providers/github/actions.js +90 -3
  86. package/build/lib/providers/github/actions.js.map +1 -1
  87. package/build/lib/providers/github/code-host.js +2 -0
  88. package/build/lib/providers/github/code-host.js.map +1 -1
  89. package/build/lib/providers/github/writes.js +25 -2
  90. package/build/lib/providers/github/writes.js.map +1 -1
  91. package/build/lib/providers/index.js +3 -2
  92. package/build/lib/providers/index.js.map +1 -1
  93. package/build/lib/providers/npm/stage.js +14 -1
  94. package/build/lib/providers/npm/stage.js.map +1 -1
  95. package/build/lib/providers/timing.js +10 -0
  96. package/build/lib/providers/timing.js.map +1 -0
  97. package/build/lib/providers/verdicts/pr.js +47 -6
  98. package/build/lib/providers/verdicts/pr.js.map +1 -1
  99. package/build/lib/providers/verdicts/runs.js +12 -2
  100. package/build/lib/providers/verdicts/runs.js.map +1 -1
  101. package/build/logins.js +13 -6
  102. package/build/logins.js.map +1 -1
  103. package/build/manager.js +200 -55
  104. package/build/manager.js.map +1 -1
  105. package/build/note.js +5 -15
  106. package/build/note.js.map +1 -1
  107. package/build/notes.js +130 -23
  108. package/build/notes.js.map +1 -1
  109. package/build/notify.js +104 -42
  110. package/build/notify.js.map +1 -1
  111. package/build/npm-reads.js +151 -22
  112. package/build/npm-reads.js.map +1 -1
  113. package/build/ownership.js +2 -2
  114. package/build/paths.js +44 -1
  115. package/build/paths.js.map +1 -1
  116. package/build/plugin.js +4 -2
  117. package/build/plugin.js.map +1 -1
  118. package/build/profile-fields.js +153 -0
  119. package/build/profile-fields.js.map +1 -0
  120. package/build/profile-layers.js +264 -0
  121. package/build/profile-layers.js.map +1 -0
  122. package/build/profile.js +69 -49
  123. package/build/profile.js.map +1 -1
  124. package/build/project-check-cli.js +17 -19
  125. package/build/project-check-cli.js.map +1 -1
  126. package/build/project-check.js +166 -104
  127. package/build/project-check.js.map +1 -1
  128. package/build/protocol.js +5 -21
  129. package/build/protocol.js.map +1 -1
  130. package/build/pushover.js +5 -5
  131. package/build/pushover.js.map +1 -1
  132. package/build/queue.js +4 -4
  133. package/build/queue.js.map +1 -1
  134. package/build/registry.js +195 -36
  135. package/build/registry.js.map +1 -1
  136. package/build/release-kinds.js +34 -0
  137. package/build/release-kinds.js.map +1 -0
  138. package/build/rule-actions.js +8 -6
  139. package/build/rule-actions.js.map +1 -1
  140. package/build/rules-service.js +83 -44
  141. package/build/rules-service.js.map +1 -1
  142. package/build/rules.js +23 -23
  143. package/build/rules.js.map +1 -1
  144. package/build/run.js +20 -7
  145. package/build/run.js.map +1 -1
  146. package/build/runs.js +218 -68
  147. package/build/runs.js.map +1 -1
  148. package/build/scheduler.js +78 -12
  149. package/build/scheduler.js.map +1 -1
  150. package/build/search.js +2 -1
  151. package/build/search.js.map +1 -1
  152. package/build/server.js +51 -14
  153. package/build/server.js.map +1 -1
  154. package/build/spend.js +1 -1
  155. package/build/spend.js.map +1 -1
  156. package/build/store.js +79 -20
  157. package/build/store.js.map +1 -1
  158. package/build/supervise.js +1 -1
  159. package/build/supervise.js.map +1 -1
  160. package/build/timeline.js +104 -0
  161. package/build/timeline.js.map +1 -0
  162. package/build/tracker-reads-cli.js +4 -3
  163. package/build/tracker-reads-cli.js.map +1 -1
  164. package/build/trackers.js +56 -10
  165. package/build/trackers.js.map +1 -1
  166. package/build/train-cli.js +6 -5
  167. package/build/train-cli.js.map +1 -1
  168. package/build/train.js +2 -2
  169. package/build/train.js.map +1 -1
  170. package/build/upgrade.js +8 -9
  171. package/build/upgrade.js.map +1 -1
  172. package/build/wait.js +10 -10
  173. package/build/wait.js.map +1 -1
  174. package/build/watchers/ado.js +42 -19
  175. package/build/watchers/ado.js.map +1 -1
  176. package/build/watchers/github.js +18 -4
  177. package/build/watchers/github.js.map +1 -1
  178. package/build/watchers/index.js +2 -2
  179. package/build/watchers/index.js.map +1 -1
  180. package/build/watchers/linear-queue.js +47 -14
  181. package/build/watchers/linear-queue.js.map +1 -1
  182. package/build/watchers/linear-writes.js +26 -12
  183. package/build/watchers/linear-writes.js.map +1 -1
  184. package/build/watchers/linear.js +2 -2
  185. package/build/watchers/linear.js.map +1 -1
  186. package/build/watchers/source.js +5 -1
  187. package/build/watchers/source.js.map +1 -1
  188. package/build/webhook.js +80 -0
  189. package/build/webhook.js.map +1 -0
  190. package/build/why.js +1 -1
  191. package/build/why.js.map +1 -1
  192. package/build/worktrees.js +56 -93
  193. package/build/worktrees.js.map +1 -1
  194. package/package.json +61 -61
  195. package/plugin/.claude-plugin/plugin.json +1 -1
  196. package/plugin/hooks/model.ts +55 -6
  197. package/plugin/hooks/register.tsx +43 -4
  198. package/plugin/skills/conductor-console/SKILL.md +26 -27
  199. package/plugin/skills/work-item/SKILL.md +58 -54
  200. package/plugin/skills/work-item/trackers/ado-boards.md +2 -2
  201. package/plugin/skills/work-item/trackers/github-issues.md +1 -1
  202. package/plugin/skills/work-item/trackers/linear.md +2 -2
  203. package/plugin/types/index.d.ts +1 -1
  204. package/protocol/PROTOCOL.md +3 -9
  205. package/build/checkout-sync.js +0 -249
  206. package/build/checkout-sync.js.map +0 -1
  207. package/build/credential.js +0 -66
  208. package/build/credential.js.map +0 -1
  209. package/build/startup.js +0 -92
  210. package/build/startup.js.map +0 -1
  211. package/build/tab.js +0 -32
  212. package/build/tab.js.map +0 -1
package/build/help.js CHANGED
@@ -41,7 +41,7 @@ const WINDOW = [
41
41
  '<when>',
42
42
  'for --since or --until: now, today, yesterday, a span ago (30m, 24h, 7d), a date, or a date and time',
43
43
  ];
44
- const WORKER = ['<worker>', 'its item (ATK-309), its name (probe-ATK-309) or #<id>'];
44
+ const WORKER = ['<worker>', 'its item (ENG-309), its name (probe-ENG-309) or #<id>'];
45
45
  const REPORT_OPTIONS = [
46
46
  ['--json', 'print the report as JSON'],
47
47
  ['--project <name>', 'one project only'],
@@ -51,12 +51,12 @@ const REPORT_OPTIONS = [
51
51
  export const COMMANDS = [
52
52
  {
53
53
  arguments: [
54
- ['<item>', "the item (ATK-312), or the inbox item's id as '#12' (quoted: a shell reads #12 as a comment)"],
54
+ ['<item>', "the item (ENG-312), or the inbox item's id as '#12' (quoted: a shell reads #12 as a comment)"],
55
55
  ],
56
56
  description: ['Posts "approve" on the item as you and wakes its worker.'],
57
57
  examples: [
58
- ["approve ATK-312's plan", 'approve ATK-312'],
59
- ['the same, with a word for the worker', 'approve ATK-312 --text "skip the docs"'],
58
+ ["approve ENG-312's plan", 'approve ENG-312'],
59
+ ['the same, with a word for the worker', 'approve ENG-312 --text "skip the docs"'],
60
60
  ],
61
61
  group: 'Inbox and approvals',
62
62
  name: 'approve',
@@ -67,8 +67,12 @@ export const COMMANDS = [
67
67
  },
68
68
  {
69
69
  arguments: [WORKER],
70
- description: ['Wakes a parked worker (with no event text) and opens its session in a tab.'],
71
- examples: [["open ATK-309's worker in a tab", 'attach ATK-309']],
70
+ description: [
71
+ "Wakes a parked worker (with no event text) and opens its session in a tab, whatever config.json's workers.tab says: in the terminal workers.terminal names (Windows Terminal, iTerm or Terminal on macOS, tmux elsewhere).",
72
+ 'A tmux tab is in a detached session, and the command prints how to attach to it. With no terminal to open, it prints the claude attach to run yourself.',
73
+ 'A worker whose session has a claude attach running already (its tab is open) gets no second tab: the command says so. Once its tab closes, the daemon hands the worker back within about a minute.',
74
+ ],
75
+ examples: [["open ENG-309's worker in a tab", 'attach ENG-309']],
72
76
  group: 'Projects and workers',
73
77
  name: 'attach',
74
78
  seeAlso: ['launch', 'retire', 'status'],
@@ -81,10 +85,10 @@ export const COMMANDS = [
81
85
  ['<slug>', 'a few words for the branch, joined by dashes'],
82
86
  ],
83
87
  description: [
84
- "Renames the worktree's branch (worktree-ATK-454) to <type>/<key>-<slug>, such as feat/atk-454-code-host-writes, with the item from the worktree's name (or --item).",
88
+ "Renames the worktree's branch (worktree-ENG-454) to <type>/<key>-<slug>, such as feat/eng-454-code-host-writes, with the item from the worktree's name (or --item).",
85
89
  'Prints JSON. Runs here, with or without a conductor.',
86
90
  ],
87
- examples: [['in the ATK-454 worktree: feat/atk-454-code-host-writes', 'branch feat code-host-writes']],
91
+ examples: [['in the ENG-454 worktree: feat/eng-454-code-host-writes', 'branch feat code-host-writes']],
88
92
  group: 'Used by work skills',
89
93
  name: 'branch',
90
94
  options: [ITEM],
@@ -93,7 +97,7 @@ export const COMMANDS = [
93
97
  usage: ['branch <type> <slug> [--item <item>]'],
94
98
  },
95
99
  {
96
- arguments: [['<item>', 'the item (ATK-312)']],
100
+ arguments: [['<item>', 'the item (ENG-312)']],
97
101
  description: [
98
102
  "The item's context for a worker's orient step, read by the conductor from the tracker (no MCP): title, status, project, Area and labels, blockers, the items it blocks and related items, its phase notes, the approve or revise: after the newest Plan, and the description.",
99
103
  "Also the work skill's phase (orient, plan, awaiting-approval, implement, wait, land, done, abandoned, canceled), from the status, the notes and the PR; and the PR (its worker's, else the newest PR opened note's) as its code host has it, with its verdict.",
@@ -101,8 +105,8 @@ export const COMMANDS = [
101
105
  "With no conductor, it is read here from this checkout's project, as its account.",
102
106
  ],
103
107
  examples: [
104
- ['orient on ATK-312', 'brief ATK-312'],
105
- ['check for an approval after a wake', 'brief ATK-312 --fresh'],
108
+ ['orient on ENG-312', 'brief ENG-312'],
109
+ ['check for an approval after a wake', 'brief ENG-312 --fresh'],
106
110
  ],
107
111
  exitCodes: [
108
112
  [
@@ -132,9 +136,7 @@ export const COMMANDS = [
132
136
  "The clone stays out of the worktree's git status, and conduct retire checks it for unpushed work.",
133
137
  'Prints JSON. Runs here.',
134
138
  ],
135
- examples: [
136
- ['clone the registry for a skill fix', 'checkout EmergentSoftware/agentic-toolkit-registry fix lock-path'],
137
- ],
139
+ examples: [['clone the registry for a skill fix', 'checkout contoso/skills-registry fix lock-path']],
138
140
  group: 'Used by work skills',
139
141
  name: 'checkout',
140
142
  options: [ITEM],
@@ -143,13 +145,13 @@ export const COMMANDS = [
143
145
  usage: ['checkout <owner>/<repo> <type> <slug> [--item <item>]'],
144
146
  },
145
147
  {
146
- arguments: [['<item>', 'the item (ATK-312)']],
148
+ arguments: [['<item>', 'the item (ENG-312)']],
147
149
  description: [
148
150
  "Every comment on the item, oldest first, with its whole text: when, who, and whether an approver wrote it. Read as conduct brief reads the item: by the conductor (no MCP), else here from this checkout's project, as its account.",
149
151
  ],
150
152
  examples: [
151
- ['read ATK-312 whole', 'comments ATK-312'],
152
- ['what was said since the plan', 'comments ATK-312 --since 2026-10-15T09:00Z'],
153
+ ['read ENG-312 whole', 'comments ENG-312'],
154
+ ['what was said since the plan', 'comments ENG-312 --since 2026-10-15T09:00Z'],
153
155
  ],
154
156
  exitCodes: [[1, 'refused, or nothing was read, as for conduct brief: the message says why']],
155
157
  group: 'Used by work skills',
@@ -165,9 +167,9 @@ export const COMMANDS = [
165
167
  },
166
168
  {
167
169
  description: [
168
- "Opens the console, the Claude session the conductor mod serves, in a Windows Terminal tab in the conductor's own folder (~/.conductor/console): it belongs to no project, so it opens with none registered.",
170
+ "Opens the console, the Claude session the conductor mod serves, in a tab in the conductor's own folder (~/.conductor/console): it belongs to no project, so it opens with none registered.",
169
171
  'It starts with the conductor plugin (--plugin-dir ~/.conductor/plugin), which brings the mod and /conductor:conductor-console.',
170
- "The tab needs Windows Terminal (elsewhere, use --here), and starts with this terminal's environment, CONDUCTOR_HOME included.",
172
+ 'The tab opens in the terminal config.json\'s workers.terminal names: Windows Terminal (window "conductor"), iTerm or Terminal on macOS, or tmux elsewhere (session conductor: the command prints its tmux attach). It starts with this terminal\'s CONDUCTOR_HOME. With no terminal to open (no tmux), it refuses: the start is claimed by then, so run `conduct console --here --force`.',
171
173
  'Also how to get it back after it closed: it keeps no state of its own.',
172
174
  'One at a time: it refuses while a console is open, or started in the last minute and not yet following the events.',
173
175
  ],
@@ -249,8 +251,8 @@ export const COMMANDS = [
249
251
  ],
250
252
  examples: [
251
253
  [
252
- 'a follow-up in apps/conductor that waits on ATK-480',
253
- 'file --title "conductor: color the status" --body-file follow-up.md --area apps/conductor --blocked-by ATK-480',
254
+ 'a follow-up in apps/web that waits on ENG-480',
255
+ 'file --title "web: color the status" --body-file follow-up.md --area apps/web --blocked-by ENG-480',
254
256
  ],
255
257
  ],
256
258
  exitCodes: [[1, 'refused or failed'], LOST_LOGIN],
@@ -259,7 +261,7 @@ export const COMMANDS = [
259
261
  options: [
260
262
  [
261
263
  '--area <area>',
262
- "one of the tracker's Areas: a label of the Area group, a path below a board's root, or the name after a GitHub Issues area prefix",
264
+ "one of the tracker's Areas: a label of the Area group, a path below a board's root, or the name after a GitHub Issues area prefix; left out for a Linear team with no Area group (tracker.areaLabelGroup null)",
263
265
  ],
264
266
  ['--blocked-by <item>…', 'the items it waits on; repeated or comma-separated'],
265
267
  ['--body-file <file>', 'its description'],
@@ -275,7 +277,7 @@ export const COMMANDS = [
275
277
  seeAlso: ['brief', 'note'],
276
278
  summary: 'file a follow-up of the item, in Backlog with its Area',
277
279
  usage: [
278
- 'file --title <title> --body-file <file> --area <area> [--related <item>…] [--blocked-by <item>…] [--human] [--waits-release] [--item <item>]',
280
+ 'file --title <title> --body-file <file> [--area <area>] [--related <item>…] [--blocked-by <item>…] [--human] [--waits-release] [--item <item>]',
279
281
  ],
280
282
  },
281
283
  {
@@ -284,8 +286,8 @@ export const COMMANDS = [
284
286
  "Sets the project's slots or ordering weight until <when>; with neither, its items go first (weight 100).",
285
287
  ],
286
288
  examples: [
287
- ['work atk first until 17:00', 'focus atk --until 17:00'],
288
- ['six slots for atk until tomorrow', 'focus atk --slots 6 --until tomorrow'],
289
+ ['work web first until 17:00', 'focus web --until 17:00'],
290
+ ['six slots for web until tomorrow', 'focus web --slots 6 --until tomorrow'],
289
291
  ],
290
292
  group: 'Scheduling',
291
293
  name: 'focus',
@@ -306,7 +308,7 @@ export const COMMANDS = [
306
308
  ],
307
309
  examples: [
308
310
  ['the last 24 hours', 'history'],
309
- ['a week of atk', 'history 7d --project atk'],
311
+ ['a week of web', 'history 7d --project web'],
310
312
  ['the last 30 minutes', 'history --since 30m'],
311
313
  ],
312
314
  group: 'Logs and reports',
@@ -327,28 +329,70 @@ export const COMMANDS = [
327
329
  usage: ['inbox [--json]'],
328
330
  },
329
331
  {
332
+ arguments: [['<path>', 'a checkout of the repo; by default the one you are in']],
330
333
  description: [
331
- "Registers a Windows Task Scheduler task that runs conduct supervise at logon, which restarts the daemon if it dies. Run it from the main checkout: a worktree's build goes away.",
334
+ "Onboards the repo of a checkout. It detects what it can: the code host from origin (GitHub or Azure DevOps), CI as the code host's own, the base branch from origin/HEAD, setup from the lockfiles at the root, a verify-* skill in .claude/skills, and the item key the commits carry. It asks for the rest, each detected value the default.",
335
+ "It writes a starter profile to ~/.conductor/projects/<name>.json, or with --shared to the checkout's .claude/conductor.json, which counts once it is pushed. A profile file that is there is never overwritten, and a repo profile on origin/<base> that names the project means nothing is written. Then it runs project add and project check.",
336
+ "Run it again after each step it prints: trust the new clone with `claude` once, and with no verify skill, the conductor plugin's /conductor:create-verification-skill in the checkout (in `claude --plugin-dir <the plugin>`), committed and pushed. Each run goes on from what is done, so a run on a project that is set up only fetches and checks it.",
337
+ 'Without --yes it asks in the terminal, and refuses with no terminal (Git Bash under mintty is none to node).',
338
+ ],
339
+ examples: [
340
+ ['onboard the repo of the checkout you are in, answering its questions', 'init'],
341
+ ['the same with no questions, for a GitHub repo with GitHub Issues', 'init --yes --key PAR'],
342
+ ['with a Linear team as the tracker', 'init --tracker linear --team ENG'],
343
+ ['a profile the team shares, committed to the repo', 'init --shared'],
344
+ ],
345
+ group: 'Projects and workers',
346
+ name: 'init',
347
+ options: [
348
+ ['--name <name>', "the project's name; by default the repo's, or the one it was added under"],
349
+ ['--base <branch>', 'the base branch; by default origin/HEAD'],
350
+ ['--tracker <kind>', "github-issues, ado-boards or linear; by default the code host's own"],
351
+ ['--key <KEY>', 'the item key on GitHub Issues or ADO Boards (PAR-12 is issue #12)'],
352
+ ['--team <key>', 'the Linear team key, with --tracker linear'],
353
+ ['--query <query>', 'the saved Boards query that is the queue, with ADO Boards'],
354
+ ['--shared', "write the repo's .claude/conductor.json instead of the machine profile"],
355
+ ['--yes', 'ask nothing: take what was detected, and refuse what is missing with its flag'],
356
+ ],
357
+ seeAlso: ['project', 'profile', 'launch'],
358
+ summary: 'onboard a repo: a starter profile, then add and check it',
359
+ usage: [
360
+ 'init [<path>] [--name <name>] [--base <branch>] [--tracker <kind>] [--key <KEY>] [--team <key>] [--query <query>] [--shared] [--yes]',
361
+ ],
362
+ },
363
+ {
364
+ description: [
365
+ "Registers what runs conduct supervise at logon, which restarts the daemon if it dies, with this build. Run it from the main checkout: a worktree's build goes away.",
366
+ 'Windows: a Task Scheduler task, "Conductor", which it registers without starting.',
367
+ 'macOS: a launchd agent, ~/Library/LaunchAgents/software.detergent.conductor.plist, which it loads into your login session, and that starts it. Its output goes to ~/.conductor/logs/startup.log. Run it in a terminal on the Mac, not over ssh alone.',
368
+ 'Linux: a systemd user unit, ~/.config/systemd/user/conductor.service, which it enables and starts. Its output goes to the journal (journalctl --user -u conductor). It starts at your login; on a machine nobody logs in to, loginctl enable-linger starts it at boot, and the command says so.',
369
+ "The agent and the unit keep this terminal's PATH, since a login gives them a short one with no claude or git: run it again after that changes.",
370
+ 'On macOS and Linux, running it again restarts a daemon the agent or unit started, so the new one counts. A daemon started another way keeps running, and the one the startup starts beside it ends on its lock. --remove leaves a running daemon alone.',
332
371
  ],
333
372
  examples: [['start the daemon at every logon', 'install-startup']],
334
373
  group: 'Setup',
335
374
  name: 'install-startup',
336
- options: [['--remove', 'remove that logon task']],
375
+ options: [['--remove', 'remove that task, agent or unit']],
337
376
  seeAlso: ['supervise', 'start'],
338
- summary: 'start the daemon at logon (Windows Task Scheduler)',
377
+ summary: 'start the daemon at every logon',
339
378
  usage: ['install-startup', 'install-startup --remove'],
340
379
  },
341
380
  {
342
381
  arguments: [['<pr>', 'the PR number']],
343
382
  description: [
344
- "Sets the worker's PR up to land, then gives its first verdict. Safe to repeat. A brake already on the PR (a comment, a failed build, conflicts) is reported and nothing is armed. Otherwise it arms the host's own landing: on Azure DevOps a +10 vote (auto mode) and auto-complete with noFastForward; on GitHub, auto-merge with a merge commit (auto mode, where the repo allows it, refused with the reason where it doesn't). Then it posts the Landing note.",
383
+ "Sets the worker's PR up to land, then gives its first verdict. Safe to repeat, except with --requeue. A brake already on the PR (a comment, a failed build, conflicts) is reported and nothing is armed. Otherwise it arms the host's own landing: on Azure DevOps a +10 vote (auto mode) and auto-complete with noFastForward; on GitHub, auto-merge with a merge commit (auto mode, where the repo allows it, refused with the reason where it doesn't). Then it posts the Landing note.",
345
384
  'A Landing note with auto-complete or auto-merge gone means someone cancelled it: auto-merge-cancelled, until --rearm. A PR ADO started completing in the last few minutes, which clears auto-complete, is waiting instead.',
346
385
  'With a conductor, the daemon records the landing and keeps it armed while the worker waits (conduct wait pr <pr>): it queues an expired build again and restores a cleared vote.',
386
+ "--requeue <run> queues one of a build-failed PR's failed builds again, for a flake no change caused, then arms as above: on Azure Repos through its policy evaluation, on GitHub by re-running the failed jobs of the check's Actions run (a PR the item opened from a checkout; one a hook's publish opened has none, so land refuses it). It posts a closed Requeue note with the run, the build and the PR's head commit first, and refuses a second requeue of that build on that head, even for the new run: a second failure is fixed and pushed. Each build that failed on the head can be queued again once. It refuses while a comment waits for an answer, and a GitHub run with a job still running. Until the PR shows the new run, the verdict waits on the build instead of reporting the old failure, for 15 minutes at most. A GitHub re-run keeps the run's id, so a failed check of it that finished after the note is the new attempt's failure, reported at once.",
347
387
  'Prints JSON with the verdict and "via".',
348
388
  ],
349
389
  examples: [
350
390
  ['land PR 1850 by itself', 'land 1850 --mode auto --reason "S fix, no review paths"'],
351
391
  ['arm it again after a cancel', 'land 1850 --rearm --reason "the operator said go on"'],
392
+ [
393
+ 'queue a flaky build again, once',
394
+ 'land 1850 --requeue 8040 --reason "ENG-637: the known flake, no change caused it"',
395
+ ],
352
396
  ],
353
397
  exitCodes: [[1, 'refused'], LOST_LOGIN],
354
398
  group: 'Used by work skills',
@@ -359,23 +403,30 @@ export const COMMANDS = [
359
403
  '--mode auto|review',
360
404
  "held to the profile's landing rules for the PR's files and the plan's tier: auto where they allow it, else refused; without it the rules pick",
361
405
  ],
362
- ['--reason <why>', 'why this mode, for the Landing note (required)'],
406
+ [
407
+ '--reason <why>',
408
+ 'why this mode, for the Landing note (required); with --requeue, why the build is queued again, for the Requeue note',
409
+ ],
363
410
  ['--rearm', 'arm it again after someone cancelled it'],
364
411
  PR_REPO,
412
+ ['--requeue <run>', 'queue that failed build again first, once per build and head commit'],
365
413
  ['--tier S|M|L', "the plan's tier without a conductor; the daemon takes it from the item's Plan note"],
366
414
  ],
367
415
  seeAlso: ['wait', 'pr', 'runs'],
368
416
  summary: "arm the worker's PR to land, and its first verdict",
369
- usage: ['land <pr> --reason <why> [--mode auto|review] [--rearm] [--tier S|M|L] [--repo <repo>] [--item <item>]'],
417
+ usage: [
418
+ 'land <pr> --reason <why> [--mode auto|review] [--rearm] [--requeue <run>] [--tier S|M|L] [--repo <repo>] [--item <item>]',
419
+ ],
370
420
  },
371
421
  {
372
- arguments: [['<item>', 'the item to work (ATK-312)']],
422
+ arguments: [['<item>', 'the item to work (ENG-312)']],
373
423
  description: [
374
- "Starts a worker on the item: its worktree, a background session running the project's work skill, and a tab.",
424
+ "Starts a worker on the item: its worktree, and a background session running the project's work skill.",
425
+ "Workers run headless. With config.json's workers.tab, each launch also opens a tab attached to the session (as conduct attach does); a tab that fails to open never fails the launch.",
375
426
  ],
376
427
  examples: [
377
- ['start a worker on ATK-312', 'launch ATK-312'],
378
- ['a probe with its own prompt', 'launch ATK-312 --probe --prompt "time the test suite"'],
428
+ ['start a worker on ENG-312', 'launch ENG-312'],
429
+ ['a probe with its own prompt', 'launch ENG-312 --probe --prompt "time the test suite"'],
379
430
  ],
380
431
  group: 'Projects and workers',
381
432
  name: 'launch',
@@ -386,7 +437,7 @@ export const COMMANDS = [
386
437
  ['--prompt <text>', "the session's first prompt instead of the work skill (or the probe prompt)"],
387
438
  ],
388
439
  seeAlso: ['attach', 'retire', 'status'],
389
- summary: 'start a worker: its worktree, a background session, a tab',
440
+ summary: 'start a worker: its worktree and a background session',
390
441
  usage: ['launch <item> [--project <name>] [--probe] [--prompt <text>] [--conductor <name>]'],
391
442
  },
392
443
  {
@@ -413,7 +464,10 @@ export const COMMANDS = [
413
464
  group: 'Used by work skills',
414
465
  name: 'lock',
415
466
  options: [
416
- ['--owner <id>', "who holds it; this checkout's worker's item by default"],
467
+ [
468
+ '--owner <id>',
469
+ "who holds it; this checkout's worker's item by default, else the item key in the worktree's name or branch",
470
+ ],
417
471
  ['--wait <minutes>', 'poll for the lock for up to that many minutes'],
418
472
  ],
419
473
  seeAlso: ['ports', 'status'],
@@ -438,7 +492,7 @@ export const COMMANDS = [
438
492
  },
439
493
  {
440
494
  arguments: [
441
- ['<item>', 'the item (ATK-312)'],
495
+ ['<item>', 'the item (ENG-312)'],
442
496
  ['<file>', 'the note, its heading first'],
443
497
  ],
444
498
  description: [
@@ -447,7 +501,7 @@ export const COMMANDS = [
447
501
  "With no conductor, it is posted from this checkout as its project's account, and the item moves the same way.",
448
502
  `The note must keep worker protocol ${PROTOCOL} (protocol/PROTOCOL.md in the package): a known phase (${PHASES.join(', ')}), a Handoff with a kind and one line (${HANDOFF_KINDS.join(', ')}), no kind on a phase that carries none, and a Plan with its **Size tier** and **Landing:** lines. One that breaks it is refused, with the rule, before anything is posted.`,
449
503
  ],
450
- examples: [['post the Plan note', 'note ATK-312 plan.md']],
504
+ examples: [['post the Plan note', 'note ENG-312 plan.md']],
451
505
  exitCodes: [
452
506
  [
453
507
  1,
@@ -466,14 +520,14 @@ export const COMMANDS = [
466
520
  usage: ['note <item> <file> [--worker <worker>]'],
467
521
  },
468
522
  {
469
- arguments: [['<item>', 'the item (ATK-312)']],
523
+ arguments: [['<item>', 'the item (ENG-312)']],
470
524
  description: [
471
525
  "The item's phase notes with their whole text, oldest first: what conduct brief lists as one line each. --phase and --kind keep the ones that match, and --last the newest of those, such as the Handoff an escalation is about.",
472
526
  "Read as conduct brief reads the item: by the conductor (no MCP), else here from this checkout's project, as its account.",
473
527
  ],
474
528
  examples: [
475
- ['every note on ATK-312', 'notes ATK-312'],
476
- ['the newest conductor Handoff', 'notes ATK-312 --phase Handoff --kind conductor --last'],
529
+ ['every note on ENG-312', 'notes ENG-312'],
530
+ ['the newest conductor Handoff', 'notes ENG-312 --phase Handoff --kind conductor --last'],
477
531
  ],
478
532
  exitCodes: [[1, 'refused, or nothing was read, as for conduct brief: the message says why']],
479
533
  group: 'Used by work skills',
@@ -509,7 +563,7 @@ export const COMMANDS = [
509
563
  group: 'Inbox and approvals',
510
564
  name: 'notify',
511
565
  options: [
512
- ['--channel remote-control|pushover', 'with test: push on that channel'],
566
+ ['--channel remote-control|pushover|webhook', 'with test: push on that channel'],
513
567
  ['--json', 'print the state as JSON'],
514
568
  ['--kind <kind>', 'with test: the kind of item (npm-otp by default)'],
515
569
  ['--raise', 'with test: put a real item in the inbox instead; it takes no --channel'],
@@ -520,7 +574,7 @@ export const COMMANDS = [
520
574
  usage: [
521
575
  'notify [--json]',
522
576
  'notify profile [<name>] [--until <when>]',
523
- 'notify test [--kind <kind>] [--channel remote-control|pushover] [--raise]',
577
+ 'notify test [--kind <kind>] [--channel remote-control|pushover|webhook] [--raise]',
524
578
  ],
525
579
  },
526
580
  {
@@ -528,7 +582,7 @@ export const COMMANDS = [
528
582
  description: ['No new launches in the project, or in every project without one, until <when> or conduct unpause.'],
529
583
  examples: [
530
584
  ['pause every project until tomorrow', 'pause --until tomorrow'],
531
- ['pause atk until you unpause it', 'pause atk'],
585
+ ['pause web until you unpause it', 'pause web'],
532
586
  ],
533
587
  group: 'Scheduling',
534
588
  name: 'pause',
@@ -557,27 +611,40 @@ export const COMMANDS = [
557
611
  },
558
612
  {
559
613
  commands: [
614
+ [
615
+ 'abandon <pr>',
616
+ "close the worker's PR unmerged (Azure DevOps abandons it), then post a closed `<skill> · Abandoned` note on it with --reason. Only the item's PR: its title and head branch carry the item key, and it is from the branch the checkout is on now (--force: from another branch of the item). A merged PR is refused; one closed already only gets the note if it lacks one, so it is safe to repeat",
617
+ ],
560
618
  [
561
619
  'create',
562
620
  "check the title carries the item key, the branch carries it too, the description fits the host, no PR is open from the branch, nothing is uncommitted, the branch is ahead of its base, and commitlint passes, all before anything is pushed. Then push and open the PR into the base branch (--repo: into the other repo's default branch, from its checkout)",
563
621
  ],
622
+ [
623
+ 'status <pr>',
624
+ "any PR's verdict, as land gives the worker's own: merged (with its mergeCommit, and noFastForward: whether that commit has two parents), build-failed, conflicts, changes-requested, review-comment, abandoned or waiting. It needs no checkout and checks no ownership, and arms nothing, so it reads a PR the item didn't open, such as one a skill publish opened in another repo. A read, so it runs here",
625
+ ],
564
626
  [
565
627
  'threads <pr>',
566
628
  "the PR's threads (on GitHub each comment and review), each with needsAnswer: a person's, open, with no note after it, and asking for something. A read, so it runs here",
567
629
  ],
568
630
  ],
569
631
  description: [
570
- "Opens the worker's PR, checked and pushed, or reads its threads.",
632
+ "Opens the worker's PR, checked and pushed, reads any PR's verdict or the worker's PR's threads, or abandons it.",
571
633
  "The description ends with the tracker's reference when it has one (AB#<id> for an ADO Boards item on a GitHub PR, so the Boards GitHub app links it), counted in its length.",
572
- 'With a conductor, the daemon opens it for the worker that owns this checkout, checking the ownership again, and records the PR on the worker. Without one (or an older one) it opens it here.',
634
+ 'With a conductor, the daemon opens or abandons it for the worker that owns this checkout, checking the ownership again, and records the PR on the worker. Without one (or an older one) it does it here.',
573
635
  'Prints JSON with "via": "daemon" or "local".',
574
636
  ],
575
637
  examples: [
576
638
  [
577
639
  'check everything, push nothing',
578
- 'pr create --title "feat(conductor): help sections (ATK-478)" --body-file pr.md --dry-run',
640
+ 'pr create --title "feat(web): help sections (ENG-478)" --body-file pr.md --dry-run',
579
641
  ],
580
642
  ["PR 1850's threads", 'pr threads 1850'],
643
+ [
644
+ 'a registry PR a skill publish opened: its verdict, and once merged its merge commit for conduct runs',
645
+ 'pr status 560 --repo github:EmergentSoftware/agentic-toolkit-registry',
646
+ ],
647
+ ['drop PR 1850, which another PR made redundant', 'pr abandon 1850 --reason "ENG-412\'s PR merged the same fix"'],
581
648
  ],
582
649
  exitCodes: [[1, 'refused or failed'], LOST_LOGIN],
583
650
  group: 'Used by work skills',
@@ -585,53 +652,83 @@ export const COMMANDS = [
585
652
  options: [
586
653
  ['--body-file <file>', 'with create: its description'],
587
654
  ['--dry-run', 'with create: stop before the push'],
655
+ ['--force', "with abandon: the item's PR from a branch the checkout isn't on"],
588
656
  ITEM,
657
+ ['--reason <why>', 'with abandon: why, in its note'],
589
658
  PR_REPO,
590
659
  ['--title <title>', 'with create: its title, with the item key'],
591
660
  ],
592
661
  seeAlso: ['land', 'reply', 'state'],
593
- summary: "open the worker's PR, checked and pushed; read its threads",
662
+ summary: "open or abandon the worker's PR; read a PR's verdict",
594
663
  usage: [
664
+ 'pr abandon <pr> --reason <why> [--repo <repo>] [--item <item>] [--force]',
595
665
  'pr create --title <title> --body-file <file> [--repo <repo>] [--item <item>] [--dry-run]',
666
+ 'pr status <pr> [--repo <repo>]',
596
667
  'pr threads <pr> [--repo <repo>]',
597
668
  ],
598
669
  },
670
+ {
671
+ arguments: [['<project>', 'a project added with conduct project add']],
672
+ description: [
673
+ "A project's profile as the conductor reads it: its machine profile (~/.conductor/projects/<project>.json) over the repo's .claude/conductor.json at origin/<base> in its clone, when there is one.",
674
+ "Objects merge key by key and the machine's wins; arrays are replaced whole; rules stack, the machine's first, so a machine rule shadows a repo rule with its id. Each field says whether it came from the machine, the repo or a default.",
675
+ 'Read here from the files and the clone as fetched last, with or without the daemon.',
676
+ ],
677
+ examples: [
678
+ ["web's profile and where each field came from", 'profile web'],
679
+ ['the same as JSON', 'profile web --json'],
680
+ ],
681
+ exitCodes: [[1, 'no clone of the project, or its profile is invalid (the message names the files)']],
682
+ group: 'Projects and workers',
683
+ name: 'profile',
684
+ options: [['--json', 'print the profile and its sources as JSON']],
685
+ seeAlso: ['project', 'rules'],
686
+ summary: "a project's profile, each field with its source",
687
+ usage: ['profile <project> [--json]'],
688
+ },
599
689
  {
600
690
  commands: [
601
- ['add <path>', 'register the project whose checkout holds .claude/conductor.json; works without the daemon'],
691
+ [
692
+ 'add <url | path>',
693
+ "clone the project's remote into ~/.conductor/projects/<name>/repo and register it. A path names a checkout whose origin is cloned: the folder itself is never cloned or touched again. The name is the one the repo's .claude/conductor.json gives, or --name. Adding a project again fetches its clone and updates the registration in place, and moves a project registered by its checkout to a clone. Works without the daemon",
694
+ ],
602
695
  ['list [--json]', 'the registered projects'],
603
696
  [
604
697
  'remove <name>',
605
- "drop a registration: a renamed project's old name, or a project no longer conducted. Resolves its open inbox items; refused while it has workers in flight. Works without the daemon",
698
+ 'drop a registration: a project no longer conducted. Resolves its open inbox items; refused while it has workers in flight. Its clone and machine profile stay. Works without the daemon',
606
699
  ],
607
700
  [
608
701
  'check <name>',
609
- 'whether the project can be conducted, before its first launch finds out: its profile (and what differs from the stored copy), tracker, code host and base branch, release pipelines, a throwaway worktree made and removed through its hooks, its installed skills, a free port slot and its health URLs. One ok, warn, fail or skip line each, with the fix',
702
+ 'whether the project can be conducted, before its first launch finds out: its profile (what differs from the stored copy, and fields newer than its conductor minimum), tracker, code host and base branch, release pipelines, a throwaway worktree made from the clone and removed, with its skills and Claude Code trust, the plugin skills, free ports and its health URLs. One ok, warn, fail or skip line each, with the fix',
610
703
  ],
611
704
  ],
612
705
  description: [
613
706
  'Registers a project, lists the registered ones, removes one, or checks one.',
614
- 'After that the daemon takes the profile from disk when it starts and each time the file is saved.',
615
- 'A project keeps the name it was registered under. To rename one, remove the old name, then add it again: with both registered, both would read the same queue.',
707
+ 'A project is a clone the conductor owns: its worktrees are made there (~/.conductor/projects/<name>/worktrees), never in a checkout of yours. The daemon fetches the clone every clones.fetchMinutes and takes the profile again when its .claude/conductor.json on the base branch changes, or when the machine profile (~/.conductor/projects/<name>.json) is saved. `conduct profile <name>` shows how the two merge.',
708
+ 'Claude Code trusts a worktree by its repository: run `claude` in a new clone once and accept the trust prompt before its first launch.',
616
709
  "check goes through the daemon, as its accounts, or runs here as the machine's when it isn't running. Only the worktree check writes, and it removes what it made.",
617
710
  ],
618
711
  examples: [
619
- ['register the checkout you are in', 'project add .'],
712
+ ['conduct the repo of the checkout you are in', 'project add .'],
713
+ [
714
+ 'conduct a repo by its URL, under a name of your own',
715
+ 'project add https://github.com/owner/repo.git --name mine',
716
+ ],
620
717
  ['the registered projects', 'project list'],
621
- ['drop the old name before adding the renamed project', 'project remove atk-old'],
622
- ['check atk before conducting it', 'project check atk'],
623
- ['the same without the worktree (its hook runs pnpm install)', 'project check atk --no-worktree'],
718
+ ['check web before conducting it', 'project check web'],
719
+ ['the same without the worktree (its setup runs pnpm install)', 'project check web --no-worktree'],
624
720
  ],
625
721
  group: 'Projects and workers',
626
722
  name: 'project',
627
723
  options: [
628
724
  ['--json', 'with list or check: print them as JSON'],
725
+ ['--name <name>', "with add: the project's name, when the repo's profile gives none or another"],
629
726
  ['--no-worktree', 'with check: skip the throwaway worktree'],
630
727
  ],
631
- seeAlso: ['launch', 'ports', 'status'],
728
+ seeAlso: ['init', 'profile', 'launch', 'ports', 'status'],
632
729
  summary: 'register a project, or list, remove or check them',
633
730
  usage: [
634
- 'project add <path>',
731
+ 'project add <url | path> [--name <name>]',
635
732
  'project list [--json]',
636
733
  'project remove <name>',
637
734
  'project check <name> [--no-worktree] [--json]',
@@ -674,9 +771,9 @@ export const COMMANDS = [
674
771
  {
675
772
  arguments: [WORKER],
676
773
  description: [
677
- "Stops the worker's session and removes its worktree. It refuses while the worker's turn runs or its worktree has unfinished work (uncommitted or unpushed).",
774
+ "Stops the worker's session and removes its worktree. It refuses while the worker's turn runs, while it is attached (open in a tab), or while its worktree has unfinished work (uncommitted or unpushed).",
678
775
  ],
679
- examples: [['retire ATK-309 once it is done', 'retire ATK-309']],
776
+ examples: [['retire ENG-309 once it is done', 'retire ENG-309']],
680
777
  group: 'Projects and workers',
681
778
  name: 'retire',
682
779
  options: [['--force', 'retire it anyway and throw that work away']],
@@ -689,7 +786,7 @@ export const COMMANDS = [
689
786
  description: ['The same report as conduct history, as Markdown.', 'Give a <range> or --since/--until, not both.'],
690
787
  examples: [
691
788
  ["yesterday's retro", 'retro yesterday'],
692
- ['a week of atk, to a file', 'retro 7d --project atk > retro.md'],
789
+ ['a week of web, to a file', 'retro 7d --project web > retro.md'],
693
790
  ],
694
791
  group: 'Logs and reports',
695
792
  name: 'retro',
@@ -700,13 +797,14 @@ export const COMMANDS = [
700
797
  },
701
798
  {
702
799
  arguments: [
703
- ['<item>', "the item (ATK-312), or the inbox item's id as '#12' (quoted: a shell reads #12 as a comment)"],
800
+ ['<item>', "the item (ENG-312), or the inbox item's id as '#12' (quoted: a shell reads #12 as a comment)"],
704
801
  ['<text>', 'what to change in the plan'],
705
802
  ],
706
803
  description: [
707
804
  'Posts "revise: <text>" on the item as you and wakes its worker. Every word after <item> is the text, quoted or not.',
805
+ "With no plan of the item in the inbox, it revises the item's approved plan: the conductor posts the revise, wakes its parked worker to re-plan (not once its PR has merged), and holds back the worker's next note until it does.",
708
806
  ],
709
- examples: [['ask for a smaller plan', 'revise ATK-312 put the web change in a PR of its own']],
807
+ examples: [['ask for a smaller plan', 'revise ENG-312 put the web change in a PR of its own']],
710
808
  group: 'Inbox and approvals',
711
809
  name: 'revise',
712
810
  seeAlso: ['approve', 'inbox'],
@@ -726,7 +824,7 @@ export const COMMANDS = [
726
824
  ],
727
825
  description: [
728
826
  'The rules in force, and a dry run of them on a sample. A sample for rules test:',
729
- { pre: ['{ "event": "pr.comment", "project": "atk",', ' "fields": { "wait.kind": "merge" } }'] },
827
+ { pre: ['{ "event": "pr.comment", "project": "web",', ' "fields": { "wait.kind": "merge" } }'] },
730
828
  ],
731
829
  examples: [
732
830
  ['the rules in force', 'rules'],
@@ -744,14 +842,24 @@ export const COMMANDS = [
744
842
  description: [
745
843
  "One look at a merge's runs: on Azure Pipelines for the project's Azure DevOps repo (the pipelines whose YAML trigger the merge fires, read in this worktree), on GitHub Actions for a GitHub repo (the runs the merge's push started). The outcome is succeeded, failed, cancelled, waiting-for-approval, missing, none (nothing ran: at once on Azure Pipelines, after 5 minutes on GitHub) or waiting (look again, or conduct wait merge).",
746
844
  "Each failed run comes with its failed tasks and the end of its log (logs). For the project's repo, each of the profile's releases whose run succeeded gives what it staged (stages): package, version, stageId, the npm stage approve line, and whether npm has it (published).",
747
- "On Azure Pipelines a cancelled run (a newer push's batch, or a person) gives way to a later run on the base whose commit contains the merge: that run is the merge's, with supersedes naming the cancelled one. So cancelled means no newer run carries the merge, and the note gives the --requeue line.",
748
- "--requeue <pipeline> queues that pipeline again on the base at its tip, for the item's own merge (its branch's PR merged as <sha>) when its run was cancelled and no newer run carries it; it refuses a run that is waiting, running, succeeded or failed, a pipeline the merge didn't trigger, a merge under 15 minutes old (Azure DevOps can still list a newer run), and GitHub. By the daemon for the worker that owns this checkout, else here. conduct wait merge <sha> then follows the new run.",
845
+ "On Azure Pipelines a cancelled run (a newer push's batch, or a person) gives way to a later run on the base whose commit contains the merge: that run is the merge's, with supersedes naming the cancelled one (or the failed one, for a run queued again for a failure: retryOf). So cancelled means no newer run carries the merge, and the note gives the --requeue line.",
846
+ "A batched pipeline (batch: true) holds the merge's push while its run on the base still goes, so a merge with no run yet waits as long as that run does and 2 minutes after (behind names it), not 15 minutes. Missing means no run, and none ahead of its batch, 15 minutes after the merge; the note gives the --requeue line.",
847
+ "--requeue <pipeline> queues that pipeline on the base at its tip, for the item's own merge (its branch's PR merged as <sha>) when its run was cancelled and no newer run carries it, when it failed, or when it is missing; it refuses a run that is waiting, running or succeeded, a batch still behind a run, a pipeline the merge didn't trigger, a cancelled or missing run under 15 minutes after the merge (Azure DevOps can still list a newer run). By the daemon for the worker that owns this checkout, else here. conduct wait merge <sha> then follows the new run.",
848
+ "On GitHub Actions (the project's repo, or one the item checked out under .scratch/repos, with --repo) --requeue re-runs the merge's run itself, at its own commit: the failed jobs of a failed run, all of a cancelled one. The run keeps its id, and conduct wait merge <sha> --repo <repo> follows its new attempt. It re-runs a run once (GitHub's run_attempt above 1 is refused), only while the run is its workflow's newest run on the base the PR merged into, of any event (re-running an older one would build an older commit after a newer one), and never a missing run, which has nothing to re-run.",
849
+ "A failed run is queued again once, for a flake its log shows that no change caused (a timeout in a test nothing touched, an agent or network error; not another merge's real failure); the note gives the line. A run queued by hand after the failed one stands in for it and names it (retryOf), so a second --requeue, of a run queued again that failed too, is refused. A newer push's run never stands in for a failed one.",
850
+ "--grep <pattern> searches every task log of the --for pipelines' runs, whatever their result, for a JavaScript regular expression (case-sensitive). grep.runs gives, for each run, the matching lines by stage and task (matches, at most 200 a task) and every task it searched with its line count (searched), so no match shows the run never printed it. A pipeline with no run, a run not finished or waiting on an approval, and a log that can't be read each say so in a note.",
749
851
  'Prints JSON. A read, so it runs here, except with --requeue.',
750
852
  ],
751
853
  examples: [
752
854
  ['the runs of the merge a1b2c3d', 'runs a1b2c3d'],
753
855
  ['its API deploy alone', 'runs a1b2c3d --for deploy-api'],
856
+ ['what its API deploy printed about deploying', 'runs a1b2c3d --for deploy-api --grep Deploying'],
754
857
  ['queue its cancelled conductor release again', 'runs a1b2c3d --requeue release-conductor'],
858
+ ['queue its CLI release again once, after a flaky test failed it', 'runs a1b2c3d --requeue release-cli'],
859
+ [
860
+ "re-run the registry merge's failed Build Registry once",
861
+ 'runs 9ad075d --requeue build-registry --repo github:contoso/skills-registry',
862
+ ],
755
863
  ],
756
864
  exitCodes: [[1, 'refused or failed'], LOST_LOGIN],
757
865
  group: 'Used by work skills',
@@ -765,12 +873,20 @@ export const COMMANDS = [
765
873
  '--repo <repo>',
766
874
  "github:<owner>/<repo> for another repo, such as the registry; the profile's code host by default",
767
875
  ],
768
- ['--requeue <pipeline>', "queue the merge's cancelled run of this pipeline again (Azure Pipelines)"],
876
+ ['--grep <pattern>', "with --for: the lines of those runs' logs that match, by task, whatever the run's result"],
877
+ [
878
+ '--requeue <pipeline>',
879
+ "queue the merge's cancelled, failed (once) or missing run of this pipeline; on GitHub Actions, re-run its failed or cancelled run once",
880
+ ],
769
881
  ['--item <KEY-n>', "with --requeue: the item whose merge it is, when the worktree's name has no key"],
770
882
  ],
771
- seeAlso: ['wait', 'land'],
883
+ seeAlso: ['wait', 'land', 'timeline'],
772
884
  summary: "a merge's runs, their verdict, failed logs and npm stages",
773
- usage: ['runs <sha> [--for <pipeline>[,<pipeline>…]] [--repo <repo>]', 'runs <sha> --requeue <pipeline>'],
885
+ usage: [
886
+ 'runs <sha> [--for <pipeline>[,<pipeline>…]] [--repo <repo>]',
887
+ 'runs <sha> --for <pipeline>[,<pipeline>…] --grep <pattern> [--repo <repo>]',
888
+ 'runs <sha> --requeue <pipeline> [--repo <repo>]',
889
+ ],
774
890
  },
775
891
  {
776
892
  arguments: [['<terms…>', 'the words to look for; an item matches only with every one']],
@@ -798,7 +914,7 @@ export const COMMANDS = [
798
914
  },
799
915
  {
800
916
  description: [
801
- 'Starts the logon task when it runs this build, else a detached conduct supervise --fail-fast, and waits until the daemon answers. Does nothing when one runs already.',
917
+ "Starts the logon startup (install-startup's task, agent or unit) when it runs this build, else a detached conduct supervise --fail-fast, and waits until the daemon answers. Does nothing when one runs already.",
802
918
  ],
803
919
  examples: [['start the daemon', 'start']],
804
920
  group: 'Daemon',
@@ -814,7 +930,7 @@ export const COMMANDS = [
814
930
  ],
815
931
  examples: [
816
932
  ['where this worktree stands', 'state'],
817
- ['the registry checkout alone', 'state --repo EmergentSoftware/agentic-toolkit-registry'],
933
+ ['the registry checkout alone', 'state --repo contoso/skills-registry'],
818
934
  ],
819
935
  exitCodes: [LOST_LOGIN],
820
936
  group: 'Used by work skills',
@@ -849,9 +965,9 @@ export const COMMANDS = [
849
965
  },
850
966
  {
851
967
  description: [
852
- 'Runs conduct serve and starts it again when it dies (a crash, a kill, a start that fails), after 1 s, 5 s, 15 s, 30 s, then every minute, and every 5 minutes once it has pushed. A daemon down 2 minutes sends one Pushover push, held through quiet hours. A stop (conduct stop, upgrade, Ctrl+C), or another daemon holding the lock, ends it. The logon task runs it.',
968
+ 'Runs conduct serve and starts it again when it dies (a crash, a kill, a start that fails), after 1 s, 5 s, 15 s, 30 s, then every minute, and every 5 minutes once it has pushed. A daemon down 2 minutes sends one Pushover push, held through quiet hours. A stop (conduct stop, upgrade, Ctrl+C), or another daemon holding the lock, ends it. The logon startup (install-startup) runs it.',
853
969
  ],
854
- examples: [['what the logon task runs', 'supervise']],
970
+ examples: [['what the logon startup runs', 'supervise']],
855
971
  group: 'Daemon',
856
972
  name: 'supervise',
857
973
  options: [['--fail-fast', 'end when the first serve exits before it comes up, as conduct start runs it']],
@@ -859,6 +975,49 @@ export const COMMANDS = [
859
975
  summary: 'run the daemon and restart it when it dies',
860
976
  usage: ['supervise [--fail-fast]'],
861
977
  },
978
+ {
979
+ arguments: [['<run>', 'a run id (an Azure Pipelines build, a GitHub Actions run)']],
980
+ description: [
981
+ "A run's tasks and when each ran: on Azure Pipelines each timeline task under its stage and job, on GitHub Actions each step under its job, in the order they started, with started, finished and seconds (null until a task has both times), and the host's own state and result. The run itself has the same times.",
982
+ "--for <pipeline> reads the last finished runs of one pipeline on a branch instead (the profile's base by default, 3 runs, at most 20), newest first, so a step can be measured across runs without their merge commits.",
983
+ "--task <regex> keeps the tasks whose name matches (a JavaScript regular expression, not case-sensitive), so Cache Next build also matches its Post-job: Cache Next build save. --grep <regex> (case-sensitive, with --task) gives those tasks' log lines that match, as runs --grep does: the matches by task (at most 200 a task) and every task it searched with its line count. A run not finished, a --task that matches nothing (it lists the run's tasks) and a log that can't be read each say so in a note.",
984
+ 'Prints JSON. A read, so it runs here.',
985
+ ],
986
+ examples: [
987
+ ['every task of build 8123 and how long it took', 'timeline 8123'],
988
+ [
989
+ 'the Next cache and export steps of the last 3 web deploys on develop, with what they printed',
990
+ 'timeline --for deploy-web --task "Cache Next build|Static export build" --grep "Cache restored|cache miss|Compiled successfully"',
991
+ ],
992
+ [
993
+ "the registry's last 5 Build Registry runs on main",
994
+ 'timeline --for build-registry --branch main --count 5 --repo github:contoso/skills-registry',
995
+ ],
996
+ ],
997
+ exitCodes: [[1, 'refused or failed'], LOST_LOGIN],
998
+ group: 'Used by work skills',
999
+ name: 'timeline',
1000
+ options: [
1001
+ [
1002
+ '--for <pipeline>',
1003
+ 'one pipeline (YAML file name such as deploy-web, its path, or its name): its last finished runs',
1004
+ ],
1005
+ ['--branch <branch>', "with --for: the runs on this branch; the profile's base by default"],
1006
+ ['--count <n>', 'with --for: how many runs, 1 to 20; 3 by default'],
1007
+ ['--task <regex>', 'only the tasks whose name matches, not case-sensitive'],
1008
+ ['--grep <regex>', "with --task: those tasks' log lines that match"],
1009
+ [
1010
+ '--repo <repo>',
1011
+ "github:<owner>/<repo> for another repo, such as the registry; the profile's code host by default",
1012
+ ],
1013
+ ],
1014
+ seeAlso: ['runs'],
1015
+ summary: "a run's tasks and their times; a pipeline's last runs",
1016
+ usage: [
1017
+ 'timeline <run> [--task <regex>] [--grep <regex>] [--repo <repo>]',
1018
+ 'timeline --for <pipeline> [--branch <branch>] [--count <n>] [--task <regex>] [--grep <regex>] [--repo <repo>]',
1019
+ ],
1020
+ },
862
1021
  {
863
1022
  arguments: [['<project>', "a registered project; without it, the checkout you're in"]],
864
1023
  description: [
@@ -867,7 +1026,7 @@ export const COMMANDS = [
867
1026
  ],
868
1027
  examples: [
869
1028
  ['what a train would take and leave out', 'train --dry-run'],
870
- ["merge atk's waiting publishes", 'train atk'],
1029
+ ["merge web's waiting publishes", 'train web'],
871
1030
  ],
872
1031
  group: 'Projects and workers',
873
1032
  name: 'train',
@@ -883,7 +1042,7 @@ export const COMMANDS = [
883
1042
  ],
884
1043
  examples: [
885
1044
  ['launch again everywhere', 'unpause'],
886
- ['launch again in atk', 'unpause atk'],
1045
+ ['launch again in web', 'unpause web'],
887
1046
  ],
888
1047
  group: 'Scheduling',
889
1048
  name: 'unpause',
@@ -940,7 +1099,7 @@ export const COMMANDS = [
940
1099
  "the project's login to the provider works again (projects.<name> in config.json says which account)",
941
1100
  ],
942
1101
  ['time <when>', 'such as 17:00 (the next one) or 2026-10-10T09:00 (local)'],
943
- ['<full form>', 'such as pr:ado:Emergent.AgenticToolkit#1850:merged'],
1102
+ ['<full form>', 'such as pr:ado:Contoso.Web#1850:merged'],
944
1103
  ],
945
1104
  description: [
946
1105
  "In a worker's worktree with the daemon running, registers the wait and exits 0 at once: end the turn, and the daemon resumes the session when the condition holds. Otherwise checks it here and blocks until it holds or --timeout passes.",
@@ -950,7 +1109,7 @@ export const COMMANDS = [
950
1109
  ['wait for PR 1850 to merge', 'wait pr 1850 merged'],
951
1110
  ["wait on PR 1850's merge, checks and comments at once", 'wait pr 1850 merged checks comment'],
952
1111
  ['wait for the plan approval', 'wait approval'],
953
- ['wait for a dev release on npm', 'wait npm 8.7.0-dev.8 --tag dev --package @detergent-software/atk'],
1112
+ ['wait for a dev release on npm', 'wait npm 8.7.0-dev.8 --tag dev --package @contoso/cli'],
954
1113
  ],
955
1114
  exitCodes: [
956
1115
  [0, 'the condition holds, or the daemon registered the wait'],
@@ -979,12 +1138,12 @@ export const COMMANDS = [
979
1138
  usage: ['wait <condition> [--local] [--timeout <minutes>] [--worker <worker>] [--item <item>]'],
980
1139
  },
981
1140
  {
982
- arguments: [['<event id | item>', 'an event id (4200) or an item (ATK-312)']],
1141
+ arguments: [['<event id | item>', 'an event id (4200) or an item (ENG-312)']],
983
1142
  description: [
984
1143
  "With an event id, that event's rule and the events that led to it; with an item, the same for each of its newest actions.",
985
1144
  ],
986
1145
  examples: [
987
- ['why the conductor acted on ATK-312', 'why ATK-312'],
1146
+ ['why the conductor acted on ENG-312', 'why ENG-312'],
988
1147
  ['the rule behind event 4200', 'why 4200'],
989
1148
  ],
990
1149
  group: 'Console and rules',
@@ -1003,7 +1162,7 @@ const HELP_ROWS = [
1003
1162
  ];
1004
1163
  const FOOTER = [
1005
1164
  'Run conduct help <command> for its options and examples.',
1006
- 'A <worker> is its item (ATK-309) or its name (probe-ATK-309).',
1165
+ 'A <worker> is its item (ENG-309) or its name (probe-ENG-309).',
1007
1166
  'Files live in ~/.conductor (CONDUCTOR_HOME overrides it).',
1008
1167
  ];
1009
1168
  // A placeholder, `conduct <command>`, or a flag: what prose styles.