@detergent-software/conductor 3.0.0-dev.4 → 3.0.0-dev.41

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 (214) hide show
  1. package/CHANGELOG.md +352 -0
  2. package/README.md +274 -124
  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 +15 -10
  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/claude.js +48 -2
  12. package/build/claude.js.map +1 -1
  13. package/build/cli.js +225 -71
  14. package/build/cli.js.map +1 -1
  15. package/build/clones.js +92 -0
  16. package/build/clones.js.map +1 -0
  17. package/build/code-host-cli.js +172 -40
  18. package/build/code-host-cli.js.map +1 -1
  19. package/build/code-host-service.js +35 -2
  20. package/build/code-host-service.js.map +1 -1
  21. package/build/code-host.js +140 -16
  22. package/build/code-host.js.map +1 -1
  23. package/build/conditions.js +33 -16
  24. package/build/conditions.js.map +1 -1
  25. package/build/config.js +58 -28
  26. package/build/config.js.map +1 -1
  27. package/build/console.js +43 -27
  28. package/build/console.js.map +1 -1
  29. package/build/credentials.js +86 -54
  30. package/build/credentials.js.map +1 -1
  31. package/build/daemon.js +57 -66
  32. package/build/daemon.js.map +1 -1
  33. package/build/file-lock.js +155 -40
  34. package/build/file-lock.js.map +1 -1
  35. package/build/follow-ups.js +2 -2
  36. package/build/follow-ups.js.map +1 -1
  37. package/build/help.js +237 -82
  38. package/build/help.js.map +1 -1
  39. package/build/history.js +10 -4
  40. package/build/history.js.map +1 -1
  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 +46 -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 +6 -5
  70. package/build/in-process.js.map +1 -1
  71. package/build/inbox.js +57 -39
  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 +4 -3
  92. package/build/lib/providers/index.js.map +1 -1
  93. package/build/lib/providers/npm/stage.js +28 -5
  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 +131 -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 +323 -0
  112. package/build/npm-reads.js.map +1 -0
  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 +107 -51
  123. package/build/profile.js.map +1 -1
  124. package/build/project-check-cli.js +19 -19
  125. package/build/project-check-cli.js.map +1 -1
  126. package/build/project-check.js +194 -108
  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 +104 -47
  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 +89 -13
  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 -5
  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 +44 -20
  175. package/build/watchers/ado.js.map +1 -1
  176. package/build/watchers/github.js +21 -6
  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/npm.js +6 -4
  187. package/build/watchers/npm.js.map +1 -1
  188. package/build/watchers/source.js +5 -1
  189. package/build/watchers/source.js.map +1 -1
  190. package/build/webhook.js +80 -0
  191. package/build/webhook.js.map +1 -0
  192. package/build/why.js +1 -1
  193. package/build/why.js.map +1 -1
  194. package/build/worktrees.js +56 -93
  195. package/build/worktrees.js.map +1 -1
  196. package/package.json +61 -61
  197. package/plugin/.claude-plugin/plugin.json +1 -1
  198. package/plugin/hooks/model.ts +46 -6
  199. package/plugin/hooks/register.tsx +41 -2
  200. package/plugin/skills/conductor-console/SKILL.md +26 -27
  201. package/plugin/skills/work-item/SKILL.md +58 -54
  202. package/plugin/skills/work-item/trackers/ado-boards.md +2 -2
  203. package/plugin/skills/work-item/trackers/github-issues.md +1 -1
  204. package/plugin/skills/work-item/trackers/linear.md +2 -2
  205. package/plugin/types/index.d.ts +1 -1
  206. package/protocol/PROTOCOL.md +3 -9
  207. package/build/checkout-sync.js +0 -249
  208. package/build/checkout-sync.js.map +0 -1
  209. package/build/credential.js +0 -66
  210. package/build/credential.js.map +0 -1
  211. package/build/startup.js +0 -92
  212. package/build/startup.js.map +0 -1
  213. package/build/tab.js +0 -32
  214. package/build/tab.js.map +0 -1
@@ -9,7 +9,7 @@ export type ApiAnswer = { body: unknown; status: number };
9
9
 
10
10
  // What a Remote Control push came to: reached the phone (ok); not, as Remote Control is off
11
11
  // (inactive) or pushes are off in Claude Code's config (disabled); not sent to the phone on
12
- // purpose (skipped: Jason is at the terminal, or the answer says nothing about the phone); or the
12
+ // purpose (skipped: the operator is at the terminal, or the answer says nothing about the phone); or the
13
13
  // call failed (failed: it threw, was denied, or answered an error).
14
14
  export type PushOutcome = { detail: string; state: 'disabled' | 'failed' | 'inactive' | 'ok' | 'skipped' };
15
15
 
@@ -211,7 +211,7 @@ export type FleetRow = {
211
211
  };
212
212
 
213
213
  // A wait's condition key (conditions.ts's formatCondition) in words, the telling part first so a
214
- // truncated row keeps it: `PR #557 to merge (agentic-toolkit-registry)`, `npm 1.2.3 on dev (atk)`.
214
+ // truncated row keeps it: `PR #557 to merge (skills-registry)`, `npm 1.2.3 on dev (cli)`.
215
215
  // A kind this doesn't know, or a key it can't read, stays as it is.
216
216
  export function waitLabel(condition: string, now: number): string {
217
217
  const colon = condition.indexOf(':');
@@ -301,10 +301,13 @@ export function findPlan(inbox: readonly ConductorInboxItem[], ref: string): Fou
301
301
  const item = inbox.find((i) => i.id === Number(byId[1]));
302
302
  return item ? { found: item } : { error: `no open inbox item ${ref}` };
303
303
  }
304
- if (/^\d+$/.test(ref.trim()))
305
- return {
306
- error: `"${ref}" is ambiguous: name the item, such as ATK-${ref.trim()}, or the inbox id as #${ref.trim()}`,
307
- };
304
+ if (/^\d+$/.test(ref.trim())) {
305
+ const n = ref.trim();
306
+ // The waiting plans whose key ends in the number, else a placeholder: the project's key isn't known here.
307
+ const keys = inbox.flatMap((i) => (i.kind === 'plan' && i.item?.endsWith(`-${n}`) ? [i.item] : []));
308
+ const item = keys.length > 0 ? keys.join(' or ') : `<KEY>-${n}`;
309
+ return { error: `"${ref}" is ambiguous: name the item, such as ${item}, or the inbox id as #${n}` };
310
+ }
308
311
  const plans = inbox.filter((i) => i.kind === 'plan' && i.item?.toUpperCase() === ref.trim().toUpperCase());
309
312
  if (plans.length === 1 && plans[0]) return { found: plans[0] };
310
313
  if (plans.length === 0) return { error: `no plan of ${ref} waits in the inbox` };
@@ -553,6 +556,14 @@ export function answerText(action: 'approve' | 'done' | 'revise', id: number, an
553
556
  return `${action === 'approve' ? 'approved' : 'asked for a revision of'} ${key}: ${where}`;
554
557
  }
555
558
 
559
+ // The item a /revise names when no plan of it waits in the inbox, which `conduct revise` then revises
560
+ // as an approved plan (ATK-664); null for an inbox id, a bare number, or an item whose plan waits.
561
+ export function approvedPlanItem(inbox: readonly ConductorInboxItem[], ref: string): null | string {
562
+ const key = ref.trim().toUpperCase();
563
+ if (!/^[A-Z]+-\d+$/.test(key)) return null;
564
+ return inbox.some((i) => i.kind === 'plan' && i.item?.toUpperCase() === key) ? null : key;
565
+ }
566
+
556
567
  // The conductor this plugin folder belongs to: the CLI the mod runs, and the daemon's home. The
557
568
  // daemon's copy (<CONDUCTOR_HOME>/plugin) names both in conductor.json, written on each refresh.
558
569
  // The home matters because a `claude --bg` session doesn't see its launcher's environment: a worker
@@ -636,6 +647,35 @@ export function pushOutcome(answer: unknown): PushOutcome {
636
647
  return { detail: detail || 'PushNotification said nothing about the phone', state: 'skipped' };
637
648
  }
638
649
 
650
+ // POST /items/:item/revise's answer as the line to show, as `conduct revise` says it (reviseOutcome
651
+ // in src/cli.ts, which the mod doesn't import). A daemon from before ATK-664 has no such route (404).
652
+ export function reviseText(item: string, answer: ApiAnswer): string {
653
+ if (answer.status === 404)
654
+ return `not revised: no plan of ${item} waits in the inbox, and a conductor started before ATK-664 revises no approved plan: restart it for that`;
655
+ if (answer.status !== 200) {
656
+ const unknown = answer.status === 502 && isRecord(answer.body) && answer.body.posted === 'unknown';
657
+ return `not revised: ${errorOf(answer)}${unknown ? `; ${MAYBE_POSTED}` : ''}`;
658
+ }
659
+ const r = isRecord(answer.body) && isRecord(answer.body.revise) ? answer.body.revise : {};
660
+ const comment = isRecord(r.comment) ? r.comment : {};
661
+ const where =
662
+ typeof comment.url === 'string' ? comment.url : typeof comment.id === 'string' ? comment.id : 'comment posted';
663
+ const none = 'no worker is on it: one launched on it reads the revise in its brief';
664
+ const outcome =
665
+ typeof r.pending === 'string'
666
+ ? `nothing recorded yet (${r.pending}): ${r.worker === true ? 'the revise sweep records it and wakes its worker within 5 minutes' : none}`
667
+ : r.revised !== true
668
+ ? 'a revise of its plan was recorded already: its worker re-plans on the first one'
669
+ : typeof r.woken === 'number' && r.woken > 0
670
+ ? 'woke its worker to re-plan'
671
+ : r.landed === true
672
+ ? 'its PR has merged: its worker learns of it at its next note, for a follow-up PR'
673
+ : r.worker === true
674
+ ? 'its worker is running: its next note is held back, and it re-plans'
675
+ : none;
676
+ return `asked for a revision of ${item}'s approved plan: ${where}; ${outcome}`;
677
+ }
678
+
639
679
  // A `conduct` run (attach, approve, revise) as the line to show: what it printed when it succeeded
640
680
  // (`woke …`, `approved …`), else `failed`, then its error and details without the `conduct: `
641
681
  // prefix, and without anything node wrote before it (a warning).
@@ -8,6 +8,7 @@ import {
8
8
  age,
9
9
  answerText,
10
10
  type ApiAnswer,
11
+ approvedPlanItem,
11
12
  bandEntries,
12
13
  clearedText,
13
14
  CONSOLE_SKILL,
@@ -39,6 +40,7 @@ import {
39
40
  pushWarning,
40
41
  reaction,
41
42
  reportedState,
43
+ reviseText,
42
44
  runText,
43
45
  snapshotOf,
44
46
  spendToday,
@@ -65,6 +67,9 @@ const ATTACH_RUN_MS = 10 * 60_000;
65
67
  // An approve or a revise asks Linear twice, and `conduct approve|revise` allows that 60 s (ATK-508);
66
68
  // this adds node's start.
67
69
  const ANSWER_RUN_MS = 2 * 60_000;
70
+ // A revise of an approved plan reads the brief up to three times after it posts, and
71
+ // `conduct revise` allows that 3 min (ATK-664).
72
+ const REVISE_RUN_MS = 4 * 60_000;
68
73
  const NOT_RUNNING = 'the conductor is not running (conduct serve)';
69
74
 
70
75
  const snapshot = atom({ key: 'snapshot', plugin: 'conductor' } as const, null);
@@ -98,7 +103,7 @@ let isWindows = false;
98
103
 
99
104
  type Endpoint = { port: number; token: string };
100
105
 
101
- // Jason's answer to an inbox item, as `conduct approve|revise|done` posts it; the line to show.
106
+ // The operator's answer to an inbox item, as `conduct approve|revise|done` posts it; the line to show.
102
107
  // Approve and revise run `conduct` (ANSWER_RUN_MS), by inbox id. Without the CLI, the API, which
103
108
  // $.http.fetch cuts off after 30 s, possibly after the comment was posted. Done doesn't ask Linear.
104
109
  async function answer(
@@ -549,6 +554,38 @@ async function reportPlugin($: EngineInterface): Promise<void> {
549
554
  }
550
555
  }
551
556
 
557
+ // /revise of an item with no plan in the inbox: `conduct revise <item>` revises its approved plan
558
+ // (ATK-664), as `answer` runs it, or POST /items/:item/revise without the CLI.
559
+ async function reviseApproved($: EngineInterface, item: string, text: string): Promise<string> {
560
+ try {
561
+ const cli = await cliPath($);
562
+ if (await $.fs.exists(cli)) {
563
+ let run;
564
+ try {
565
+ run = await $.process.run(['node', cli, 'revise', item, text], {
566
+ ...(await cliInit($)),
567
+ timeoutMs: REVISE_RUN_MS,
568
+ });
569
+ } catch (error) {
570
+ return `not revised: ${error instanceof Error ? error.message : String(error)}`;
571
+ }
572
+ refreshSoon($);
573
+ return runText(run, { failed: 'not revised', ok: `asked for a revision of ${item}'s approved plan` });
574
+ }
575
+ const at = await endpoint($);
576
+ let result: ApiAnswer;
577
+ try {
578
+ result = await callApi($, 'POST', `/items/${encodeURIComponent(item)}/revise`, { text }, at);
579
+ } catch (error) {
580
+ return `not revised: ${error instanceof Error ? error.message : String(error)}; ${MAYBE_POSTED}`;
581
+ }
582
+ refreshSoon($);
583
+ return reviseText(item, result);
584
+ } catch (error) {
585
+ return error instanceof Error ? error.message : String(error);
586
+ }
587
+ }
588
+
552
589
  // `/notify <profile> [--until <when>]` and the pane's picker: switch the notification profile.
553
590
  async function switchProfile($: EngineInterface, name: string, until: null | string = null): Promise<string> {
554
591
  try {
@@ -671,7 +708,9 @@ export const register: Register = (on) => {
671
708
  const snap = await refresh($);
672
709
  if (snap.error !== null) return { text: snap.error };
673
710
  const plan = findPlan(snap.inbox, ref);
674
- return { text: plan.found ? await answer($, plan.found.id, { action: 'revise', text }) : plan.error };
711
+ if (plan.found) return { text: await answer($, plan.found.id, { action: 'revise', text }) };
712
+ const approved = approvedPlanItem(snap.inbox, ref);
713
+ return { text: approved === null ? plan.error : await reviseApproved($, approved, text) };
675
714
  });
676
715
 
677
716
  on('command.run', { command: 'attach' }, async ($, e) => {
@@ -1,39 +1,39 @@
1
1
  ---
2
2
  name: conductor-console
3
- description: Be the conductor console - the one always-open Claude session beside the conductor daemon (`conduct`). Wakes only for an escalation from the daemon's rules or for Jason. Handles escalations (a worker's conductor Handoff, a failed run, a stall, a vague item) and reports back through `conduct escalations done`. Answers Jason from `conduct status`, `inbox`, `queue` and `why`, and turns plain words into `conduct pause`, `focus`, `notify profile`, `approve` or `retire`. No loop, no ticks. Ships in the conductor plugin. Use for /conductor:conductor-console, "start the console", or a `[conductor] escalation …` wake-up.
3
+ description: Be the conductor console - the one always-open Claude session beside the conductor daemon (`conduct`). Wakes only for an escalation from the daemon's rules or for the operator. Handles escalations (a worker's conductor Handoff, a failed run, a stall, a vague item) and reports back through `conduct escalations done`. Answers the operator from `conduct status`, `inbox`, `queue` and `why`, and turns plain words into `conduct pause`, `focus`, `notify profile`, `approve` or `retire`. No loop, no ticks. Ships in the conductor plugin. Use for /conductor:conductor-console, "start the console", or a `[conductor] escalation …` wake-up.
4
4
  ---
5
5
 
6
6
  # conductor-console
7
7
 
8
- You are **the console**, the one Claude session that stays open beside **the daemon** (`conduct serve`, package `@detergent-software/conductor`). The daemon runs the work loop for every conducted project with no model in it. It picks items, launches and retires **workers** (one Claude session per item), parks and resumes them, raises an inbox of what waits on Jason, and pushes it to his phone. The **conductor mod** in this session does the plumbing in code: the status line, the inbox band, the pane, `/approve` `/revise` `/attach` `/pause` `/notify`, the Remote Control pushes. Your model is woken for two things only:
8
+ You are **the console**, the one Claude session that stays open beside **the daemon** (`conduct serve`, package `@detergent-software/conductor`). The daemon runs the work loop for every conducted project with no model in it. It picks items, launches and retires **workers** (one Claude session per item), parks and resumes them, raises an inbox of what waits on the operator, and pushes it to their phone. The **conductor mod** in this session does the plumbing in code: the status line, the inbox band, the pane, `/approve` `/revise` `/attach` `/pause` `/notify`, the Remote Control pushes. Your model is woken for two things only:
9
9
 
10
10
  - **An escalation:** a turn that reads `[conductor] escalation #<id> on <item>: <ask>`. A daemon rule (`escalate console "<ask>"`) wants judgement. The built-in `conductor-handoff` rule sends a worker's `Handoff · conductor` note this way.
11
- - **Jason**, typing here.
11
+ - **The operator**, typing here.
12
12
 
13
- Start this session with `conduct console` (a Windows Terminal tab in the conductor's own folder, `~/.conductor/console`) or `conduct console --here`. Either loads the conductor plugin with `--plugin-dir`, which brings this skill and the mod, sets `CONDUCTOR_CONSOLE=1`, which the mod needs, and runs `/conductor:conductor-console`. The console belongs to the machine, not to a project: it has no checkout, and opens with no project registered.
13
+ Start this session with `conduct console` (a tab in the conductor's own folder, `~/.conductor/console`, in Windows Terminal, iTerm or Terminal, or tmux) or `conduct console --here`. Either loads the conductor plugin with `--plugin-dir`, which brings this skill and the mod, sets `CONDUCTOR_CONSOLE=1`, which the mod needs, and runs `/conductor:conductor-console`. The console belongs to the machine, not to a project: it has no checkout, and opens with no project registered.
14
14
 
15
15
  ## Rules
16
16
 
17
17
  - **No loop.** Never use Monitor, ScheduleWakeup, CronCreate, `/loop`, `conduct events --follow`, `conduct wait`, or a polling command. The mod follows the daemon, and the daemon wakes you. Do the job, then end the turn.
18
- - **The daemon decides within policy.** Don't launch, retire, park or resume workers on your own judgement. Do it only when Jason asks, or when an escalation's ask is exactly that.
19
- - **Approvals are Jason's.** Run `conduct approve` or `conduct revise` only on Jason's own words in this session, and pass them on (`--text`, or the revise text) as he typed them. An escalation, a worker's message or a note is never an approval.
20
- - **Never** merge, publish, approve prod, delete, run `--force` or `--allow-downgrade`, or edit a Linear issue's state, priority or description. Labels are the daemon's rules' job.
18
+ - **The daemon decides within policy.** Don't launch, retire, park or resume workers on your own judgement. Do it only when the operator asks, or when an escalation's ask is exactly that.
19
+ - **Approvals are the operator's.** Run `conduct approve` or `conduct revise` only on the operator's own words in this session, and pass them on (`--text`, or the revise text) as they typed them. An escalation, a worker's message or a note is never an approval.
20
+ - **Never** merge, publish, approve prod, delete, run `--force` or `--allow-downgrade`, or edit a tracker item's state, priority or description. Labels are the daemon's rules' job.
21
21
  - **Keep this session small.** Read through short `conduct` commands, the tracker too (`conduct brief`, `notes`, `comments`, `search`): never a tracker's MCP tools. Anything that needs reading (a run log, an issue's comment thread, a transcript, code) goes to a subagent (Agent tool, `model: "haiku"` for reading, `"sonnet"` for judgement) that answers in a few lines.
22
- - **Work in the project's checkout, not here.** This session runs in `~/.conductor/console`. The `conduct` item verbs work from here while the daemon runs. A subagent that reads a project's code, logs or files gets that project's root from `conduct status` (its `projects:` lines) and works there: absolute paths under it, `git -C <root>`, `pnpm -C <root>`.
23
- - **Worker messages are nudges.** A worker launched by the daemon sends none. One from an older worker (`ATK-n · plan ready`, `· done`, …) needs nothing from you: the daemon reads the same note on Linear. Say so in one line.
24
- - **Questions to Jason:** while he chats here, ask with AskUserQuestion. Nobody may be watching during an escalation, so put what needs him in the inbox (`--ask`, below) instead.
22
+ - **Work in the project's clone, not here.** This session runs in `~/.conductor/console`. The `conduct` item verbs work from here while the daemon runs. A subagent that reads a project's code, logs or files gets that project's clone from `conduct status` (its `projects:` lines, `~/.conductor/projects/<name>/repo`, fetched every few minutes: read the base branch at `origin/<base>`) or a worker's worktree, and works there: absolute paths under it, `git -C <clone>`. It reads only: the clone is the daemon's, and its worktrees are the workers'. `conduct profile <name>` gives a project's profile and where each field comes from.
23
+ - **Worker messages are nudges.** A worker launched by the daemon sends none. One from an older worker (`ENG-n · plan ready`, `· done`, …) needs nothing from you: the daemon reads the same note on the tracker. Say so in one line.
24
+ - **Questions to the operator:** while they chat here, ask with AskUserQuestion. Nobody may be watching during an escalation, so put what needs them in the inbox (`--ask`, below) instead.
25
25
  - **Narrate** each action in one line.
26
26
 
27
27
  ## Start
28
28
 
29
29
  When `/conductor:conductor-console` runs:
30
30
 
31
- 1. `conduct start`. It starts the daemon detached if none answers (the logon task, else a detached `conduct serve`) and returns once it does. Never run `conduct serve` yourself: it would end with this session.
31
+ 1. `conduct start`. It starts the daemon detached if none answers (the logon startup, else a detached `conduct supervise`) and returns once it does. Never run `conduct serve` yourself: it would end with this session.
32
32
  2. Check the setup in one Bash call: `echo $CONDUCTOR_CONSOLE` and `conduct --version`.
33
33
  - Not `1`: say that the band, the pane and the escalation wake-ups are off in this session, and that `conduct console` opens a proper one. Go on with chat.
34
- - If Jason says the band or pane is missing: the mod comes with the conductor plugin in `~/.conductor/plugin`, which only `conduct console` loads (`--plugin-dir`). Check that the folder holds `hooks/register.tsx`, then run `/reload-plugins`; if it doesn't, `conduct start` (a daemon refreshes it as it starts), then close this session and run `conduct console`.
34
+ - If the operator says the band or pane is missing: the mod comes with the conductor plugin in `~/.conductor/plugin`, which only `conduct console` loads (`--plugin-dir`). Check that the folder holds `hooks/register.tsx`, then run `/reload-plugins`; if it doesn't, `conduct start` (a daemon refreshes it as it starts), then close this session and run `conduct console`.
35
35
  3. `conduct escalations`. These are escalations raised while no console was open. Handle each one, oldest first, as below.
36
- 4. Report in two or three lines from `conduct status`, `conduct inbox` and the first line of `conduct queue`: workers running and parked, what waits on Jason, and the scheduler's mode. If the mode is `observe`, say that the daemon launches nothing until `"scheduler": { "mode": "on" }` is set in `~/.conductor/config.json` and the daemon is restarted (`conduct stop`, then `conduct start`). That setting is only for a machine where conduct-atk's loop still runs.
36
+ 4. Report in two or three lines from `conduct status`, `conduct inbox` and the first line of `conduct queue`: workers running and parked, what waits on the operator, and the scheduler's mode. If the mode is `off`, say that the daemon launches nothing until `"scheduler": { "mode": "on" }` is set in `~/.conductor/config.json` and the daemon is restarted (`conduct stop`, then `conduct start`).
37
37
 
38
38
  Then end the turn.
39
39
 
@@ -43,25 +43,25 @@ Then end the turn.
43
43
 
44
44
  1. **What fired it:** `conduct why <item>` shows the rule and its trigger. `conduct escalations --json` has the rule's ref.
45
45
  2. **Do the job** within the rules above. Use a subagent for anything that needs reading:
46
- - **A worker's conductor Handoff** (`default:conductor-handoff`): read the newest one with `conduct notes <item> --phase Handoff --kind conductor --last`, which prints the note whole; never a tracker's MCP tools. `conduct comments <item> --since <its time>` shows what was said after it. Do what it asks when a `conduct` command does it. To reach a worker: `conduct status` shows whether it is `running` or `parked`. SendMessage goes only to a running, idle worker. A parked one is woken with `conduct attach <item>` (idle, in its tab), and gets the message once `conduct status` shows it running. Anything outside your remit goes to Jason with `--ask`.
46
+ - **A worker's conductor Handoff** (`default:conductor-handoff`): read the newest one with `conduct notes <item> --phase Handoff --kind conductor --last`, which prints the note whole; never a tracker's MCP tools. `conduct comments <item> --since <its time>` shows what was said after it. Do what it asks when a `conduct` command does it. To reach a worker: `conduct status` shows whether it is `running` or `parked`. SendMessage goes only to a running, idle worker, addressed by the name and ref ListAgents prints (`ENG-12 [b316bc]`), not the bare name: another session can carry the same name. A parked one is woken with `conduct attach <item>` (idle, in its tab), and gets the message once `conduct status` shows it running. Anything outside your remit goes to the operator with `--ask`.
47
47
  - **A failed run:** a subagent reads the run's log and says whether it is the change or the pipeline (flaky, infra), with the failing step and line.
48
48
  - **A stall:** `conduct status` (activity, waits, phase), `conduct inbox` (its `permission`, `stall` or `failed` item) and `conduct why <item>`. Say what it waits on and who can move it.
49
- - **A vague item:** a subagent reads it (`conduct brief <item>`, `conduct comments <item>`) and drafts a sharper description and a "done when". Put the draft in the `--ask` for Jason to adopt; never edit the description.
49
+ - **A vague item:** a subagent reads it (`conduct brief <item>`, `conduct comments <item>`) and drafts a sharper description and a "done when". Put the draft in the `--ask` for the operator to adopt; never edit the description.
50
50
  - **Anything else:** do what the ask says, if the rules allow it.
51
51
  3. **Report back, always**, also when there was nothing to do:
52
52
 
53
53
  ```bash
54
54
  conduct escalations done <id> "<what you found and what you did, one or two lines>"
55
- conduct escalations done <id> --ask "<what Jason must do, with the command or link>"
55
+ conduct escalations done <id> --ask "<what the operator must do, with the command or link>"
56
56
  ```
57
57
 
58
- `--ask` puts the finding in the inbox as a `console` item, which the daemon pushes to Jason's phone. Use it only when he must act. The report is logged with the escalation as its cause, so `conduct why` explains it later.
58
+ `--ask` puts the finding in the inbox as a `console` item, which the daemon pushes to the operator's phone. Use it only when they must act. The report is logged with the escalation as its cause, so `conduct why` explains it later.
59
59
 
60
60
  ## Chat
61
61
 
62
62
  Answer from the daemon, never from memory:
63
63
 
64
- | Jason asks | Run |
64
+ | The operator asks | Run |
65
65
  |---|---|
66
66
  | what's running, parked, stuck | `conduct status`, `conduct inbox` |
67
67
  | why isn't X started; what's next | `conduct queue` (`--fresh` reads the trackers now) |
@@ -72,17 +72,17 @@ Answer from the daemon, never from memory:
72
72
 
73
73
  Turn requests into commands, then show back what took effect: quote the line from `conduct rules` (its overrides) or `conduct notify` that proves it.
74
74
 
75
- | Jason says | Run |
75
+ | The operator says | Run |
76
76
  |---|---|
77
- | "pause Cadence until Monday" | `conduct pause cadence --until monday` |
77
+ | "pause portal until Monday" | `conduct pause portal --until monday` |
78
78
  | "stop all launches for now" | `conduct pause` (until `conduct unpause`) |
79
- | "resume ATK" | `conduct unpause atk` |
80
- | "put ATK first this afternoon" | `conduct focus atk --until 17:00` (`--slots <n>` or `--weight <n>` when he says so) |
79
+ | "resume web" | `conduct unpause web` |
80
+ | "put web first this afternoon" | `conduct focus web --until 17:00` (`--slots <n>` or `--weight <n>` when they say so) |
81
81
  | "I'm away until tomorrow" | `conduct notify profile away --until tomorrow` |
82
- | "approve ATK-12" / "ATK-12: change X" | `conduct approve ATK-12` / `conduct revise ATK-12 <his words>` |
83
- | "start ATK-40 now" | `conduct launch ATK-40` |
84
- | "show me ATK-12" | `conduct attach ATK-12` (opens its tab) |
85
- | "drop ATK-12's worker" | `conduct retire ATK-12`. On a refusal, report the unfinished work, and never add `--force` yourself |
82
+ | "approve ENG-12" / "ENG-12: change X" | `conduct approve ENG-12` / `conduct revise ENG-12 <their words>` |
83
+ | "start ENG-40 now" | `conduct launch ENG-40` |
84
+ | "show me ENG-12" | `conduct attach ENG-12` (opens its tab) |
85
+ | "drop ENG-12's worker" | `conduct retire ENG-12`. On a refusal, report the unfinished work, and never add `--force` yourself |
86
86
  | "always do X when Y" | a rule in `~/.conductor/rules.json` (`when` / `do`, see the conductor README's Rules). Edit the file, then `conduct rules`: a refused file shows there and in the inbox. Project rules change by PR in the project's `.claude/conductor.json`, which is work for a worker |
87
87
 
88
88
  `--until` takes `17:00` (the next one), `tomorrow`, a day such as `monday`, or a date and time. When a request is ambiguous (which project, until when), ask before running anything.
@@ -91,4 +91,3 @@ Turn requests into commands, then show back what took effect: quote the line fro
91
91
 
92
92
  - **This session closed, crashed or got slow:** run `conduct console` (or `/clear`, then `/conductor:conductor-console`). The daemon holds all the state, and step 3 of Start picks up the escalations raised meanwhile.
93
93
  - **The daemon is down** (`conduct status` says not running): `conduct start`. Workers are separate processes, and parked ones resume when their waits hold.
94
- - **Back to conduct-atk** (a rollback): `"scheduler": { "mode": "observe" }` in `~/.conductor/config.json`, `conduct stop`, `conduct start`, `atk install @agentic-toolkit/conduct-atk@1.7.5 --pin`, then close this console and run `/conduct-atk` as before.