@detergent-software/conductor 3.0.0-dev.2 → 3.0.0-dev.20

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 (133) hide show
  1. package/CHANGELOG.md +161 -0
  2. package/README.md +154 -42
  3. package/build/brief-cli.js +1 -1
  4. package/build/brief-cli.js.map +1 -1
  5. package/build/broker-cli.js +24 -25
  6. package/build/broker-cli.js.map +1 -1
  7. package/build/broker.js +66 -92
  8. package/build/broker.js.map +1 -1
  9. package/build/claude.js +50 -7
  10. package/build/claude.js.map +1 -1
  11. package/build/cli.js +119 -54
  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 +95 -22
  16. package/build/code-host-cli.js.map +1 -1
  17. package/build/code-host.js +13 -8
  18. package/build/code-host.js.map +1 -1
  19. package/build/config.js +31 -12
  20. package/build/config.js.map +1 -1
  21. package/build/console.js +40 -24
  22. package/build/console.js.map +1 -1
  23. package/build/credentials.js +26 -24
  24. package/build/credentials.js.map +1 -1
  25. package/build/daemon.js +35 -21
  26. package/build/daemon.js.map +1 -1
  27. package/build/help.js +138 -28
  28. package/build/help.js.map +1 -1
  29. package/build/host/credential-manager.js +109 -0
  30. package/build/host/credential-manager.js.map +1 -0
  31. package/build/host/keychain.js +44 -0
  32. package/build/host/keychain.js.map +1 -0
  33. package/build/host/libsecret.js +40 -0
  34. package/build/host/libsecret.js.map +1 -0
  35. package/build/host/macos-terminal.js +63 -0
  36. package/build/host/macos-terminal.js.map +1 -0
  37. package/build/host/platform.js +4 -0
  38. package/build/host/platform.js.map +1 -0
  39. package/build/host/secrets.js +46 -0
  40. package/build/host/secrets.js.map +1 -0
  41. package/build/host/shell.js +26 -0
  42. package/build/host/shell.js.map +1 -0
  43. package/build/host/terminal.js +46 -0
  44. package/build/host/terminal.js.map +1 -0
  45. package/build/host/tmux.js +39 -0
  46. package/build/host/tmux.js.map +1 -0
  47. package/build/host/windows-terminal.js +46 -0
  48. package/build/host/windows-terminal.js.map +1 -0
  49. package/build/in-process.js +6 -5
  50. package/build/in-process.js.map +1 -1
  51. package/build/inbox.js +50 -5
  52. package/build/inbox.js.map +1 -1
  53. package/build/init.js +508 -0
  54. package/build/init.js.map +1 -0
  55. package/build/lib/providers/ado/pipelines.js +79 -13
  56. package/build/lib/providers/ado/pipelines.js.map +1 -1
  57. package/build/lib/providers/github/actions.js +85 -2
  58. package/build/lib/providers/github/actions.js.map +1 -1
  59. package/build/lib/providers/index.js +2 -1
  60. package/build/lib/providers/index.js.map +1 -1
  61. package/build/lib/providers/npm/stage.js +14 -4
  62. package/build/lib/providers/npm/stage.js.map +1 -1
  63. package/build/lib/providers/timing.js +10 -0
  64. package/build/lib/providers/timing.js.map +1 -0
  65. package/build/local-files.js +95 -0
  66. package/build/local-files.js.map +1 -0
  67. package/build/manager.js +171 -47
  68. package/build/manager.js.map +1 -1
  69. package/build/note.js +1 -1
  70. package/build/note.js.map +1 -1
  71. package/build/npm-reads.js +323 -0
  72. package/build/npm-reads.js.map +1 -0
  73. package/build/paths.js +44 -1
  74. package/build/paths.js.map +1 -1
  75. package/build/plugin.js +10 -0
  76. package/build/plugin.js.map +1 -1
  77. package/build/profile-fields.js +149 -0
  78. package/build/profile-fields.js.map +1 -0
  79. package/build/profile-layers.js +264 -0
  80. package/build/profile-layers.js.map +1 -0
  81. package/build/profile.js +60 -38
  82. package/build/profile.js.map +1 -1
  83. package/build/project-check-cli.js +18 -10
  84. package/build/project-check-cli.js.map +1 -1
  85. package/build/project-check.js +179 -97
  86. package/build/project-check.js.map +1 -1
  87. package/build/pushover.js +5 -5
  88. package/build/pushover.js.map +1 -1
  89. package/build/registry.js +195 -36
  90. package/build/registry.js.map +1 -1
  91. package/build/rule-actions.js +3 -1
  92. package/build/rule-actions.js.map +1 -1
  93. package/build/rules-service.js +101 -44
  94. package/build/rules-service.js.map +1 -1
  95. package/build/rules.js +11 -2
  96. package/build/rules.js.map +1 -1
  97. package/build/runs.js +49 -0
  98. package/build/runs.js.map +1 -1
  99. package/build/scheduler.js +11 -1
  100. package/build/scheduler.js.map +1 -1
  101. package/build/server.js +3 -24
  102. package/build/server.js.map +1 -1
  103. package/build/spend.js +4 -0
  104. package/build/spend.js.map +1 -1
  105. package/build/store.js +82 -25
  106. package/build/store.js.map +1 -1
  107. package/build/timeline.js +104 -0
  108. package/build/timeline.js.map +1 -0
  109. package/build/tracker-reads-cli.js +4 -5
  110. package/build/tracker-reads-cli.js.map +1 -1
  111. package/build/train-cli.js +6 -5
  112. package/build/train-cli.js.map +1 -1
  113. package/build/upgrade.js +16 -1
  114. package/build/upgrade.js.map +1 -1
  115. package/build/wait.js +6 -6
  116. package/build/wait.js.map +1 -1
  117. package/build/watchers/ado.js +3 -2
  118. package/build/watchers/ado.js.map +1 -1
  119. package/build/watchers/github.js +3 -2
  120. package/build/watchers/github.js.map +1 -1
  121. package/build/watchers/npm.js +6 -4
  122. package/build/watchers/npm.js.map +1 -1
  123. package/build/worktrees.js +199 -92
  124. package/build/worktrees.js.map +1 -1
  125. package/package.json +61 -61
  126. package/plugin/skills/conductor-console/SKILL.md +3 -3
  127. package/plugin/skills/work-item/SKILL.md +5 -3
  128. package/build/checkout-sync.js +0 -249
  129. package/build/checkout-sync.js.map +0 -1
  130. package/build/credential.js +0 -66
  131. package/build/credential.js.map +0 -1
  132. package/build/tab.js +0 -32
  133. package/build/tab.js.map +0 -1
package/README.md CHANGED
@@ -10,12 +10,18 @@ conduct start start the daemon detached and wait until it an
10
10
  conduct stop stop the running daemon
11
11
  conduct supervise [--fail-fast] run the daemon and restart it when it dies (see Restarts)
12
12
  conduct status [--json] the daemon's pid, port, projects, workers and held locks
13
- conduct project add <path> register the project whose checkout holds .claude/conductor.json
13
+ conduct init [<path>] [--name <name>] [--base <branch>] [--tracker <kind>] [--key <KEY>] [--team <key>]
14
+ [--query <query>] [--shared] [--yes]
15
+ onboard a repo: a starter profile, then project add and check (see Projects)
16
+ conduct project add <url | path> [--name <name>]
17
+ clone the project's remote into ~/.conductor/projects/<name>/repo and register it
14
18
  conduct project list [--json] the registered projects
15
19
  conduct project remove <name> drop a registration (a renamed project's old name), resolving its inbox items
16
20
  conduct project check <name> [--no-worktree] [--json]
17
21
  whether the project can be conducted, before a launch finds out
18
- conduct launch <item> start a worker: worktree, background session, tab
22
+ conduct profile <project> [--json]
23
+ the project's profile, machine over repo, each field with its source (see Projects)
24
+ conduct launch <item> start a worker: worktree and background session (a tab with workers.tab)
19
25
  [--project <name>] [--probe] [--prompt <text>] [--conductor <name>]
20
26
  conduct retire <worker> [--force] stop a worker, remove its worktree and session
21
27
  conduct attach <worker> wake a parked worker (no event text) and open it in a tab
@@ -38,7 +44,7 @@ conduct focus <project> [--slots <n>] [--weight <n>] --until <when>
38
44
  conduct why <event id | item> [--json]
39
45
  the rule behind an action, and the events that led to it
40
46
  conduct console [--here]
41
- open the console in a Windows Terminal tab, or in this terminal (see Console)
47
+ open the console in a tab (Windows Terminal, iTerm or Terminal, tmux), or in this terminal (see Console)
42
48
  conduct escalations [--json] what rules escalated to the console and it hasn't handled
43
49
  conduct escalations done <id> [--ask] <text>
44
50
  the console's finding on an escalation; --ask puts it in the inbox
@@ -76,12 +82,17 @@ conduct reply <pr> [<thread>] --body-file <file> [--repo <repo>]
76
82
  answer on the worker's PR, headed as a note
77
83
  conduct runs <sha> [--for <pipeline>[,<pipeline>…]] [--repo <repo>]
78
84
  a merge's runs, their verdict, failed logs and npm stages (see Worker verbs)
85
+ conduct runs <sha> --for <pipeline>[,<pipeline>…] --grep <pattern> [--repo <repo>]
86
+ the same, with the lines of those runs' logs that match, whatever their result
79
87
  conduct runs <sha> --requeue <pipeline>
80
88
  queue the item's merge's cancelled run again on the base (see Worker verbs)
89
+ conduct timeline <run> [--task <regex>] [--grep <regex>] [--repo <repo>]
90
+ a run's tasks with their times, and the named tasks' log lines that match (see Worker verbs)
91
+ conduct timeline --for <pipeline> [--branch <branch>] [--count <n>] [--task <regex>] [--grep <regex>] [--repo <repo>]
92
+ the same for a pipeline's last finished runs on a branch
81
93
  conduct train [<project>] [--dry-run]
82
94
  merge the waiting skill publishes into one registry PR (see Skill trains)
83
- conduct ports [<path>] [--prefer <slot>] [--json]
84
- a checkout's dev ports from the port broker, or every worktree's (see Broker)
95
+ conduct ports [<path>] [--json] a conducted worktree's dev ports from the port broker, or every worktree's (see Broker)
85
96
  conduct lock acquire|release|status <name> [--owner <id>] [--wait <minutes>]
86
97
  a lock every project shares, such as chrome (see Broker)
87
98
  conduct events [--since <id>] [--follow] [--console]
@@ -100,11 +111,27 @@ A `<worker>` is its item (`ATK-309`) or its name (`probe-ATK-309`).
100
111
 
101
112
  The session manager owns the `claude --bg` sessions it launches, and only those:
102
113
 
103
- - **launch:** the worktree comes first, through the project's `.claude/hooks/worktree-hooks.mjs`. In a repo with `.atk-lock.json`, the profile's work and verify skills must match the lockfile (`atk install` fixes them when it can). Then `claude --bg --worktree <name> -n <name> --plugin-dir <home>/plugin --disallowedTools EnterPlanMode ExitPlanMode --permission-mode auto -- <prompt>` runs from the main checkout (see Plugin). A work or verify skill named `conductor:<skill>` comes from the plugin, not the lockfile: the launch checks that the plugin holds it. A profile with `"workers": { "tab": true }` also gets a Windows Terminal tab attached to the session.
114
+ - **launch:** the worktree comes first, made by the daemon itself (design note v2, section 2; ATK-526), with no hooks:
115
+ 1. the broker gives it a port for each name in the profile's `ports` (see Broker);
116
+ 2. `git worktree add`, run in the project's clone (see Projects), makes `~/.conductor/projects/<project>/worktrees/<name>` on `worktree-<name>` from `origin/<base>`, fetched first (after `git worktree prune`, and on Windows with `core.longpaths` on). It doesn't fetch, pull, add worktrees to or change a checkout of yours (a `localFilesFrom` checkout is only read). A worktree git still reads there is reused, its own changes and all; one with a `.git` git can't read is never deleted, and fails the launch. A `worktree-<name>` branch that is left is checked out again, with any commits it kept;
117
+ 3. with `localFilesFrom` (an absolute path to a checkout the operator keeps), the gitignored files there that match its `.worktreeinclude` are copied in, as they are now;
118
+ 4. the profile's `setup` commands run in order in the worktree, through the shell, with `CONDUCTOR_PORT_<NAME>` (such as `CONDUCTOR_PORT_WEB=41000`), `CONDUCTOR_ITEM`, `CONDUCTOR_PROJECT` and `CONDUCTOR_WORKTREE` set. They build its gitignored files from what the repo commits (ATK's: `pnpm install`, `atk setup --tool claude-code --yes`, `node scripts/dev-ports.mjs assign`, `atk install`). The first that fails fails the launch, with the end of its output. So does a setup that leaves changes git sees, such as an `.atk-lock.json` that `atk install` rewrote: the worker would take them for its own;
119
+ 5. the ports go into the worktree's `.claude/settings.local.json` as `env`, merged into what the file had. A `claude --bg` session doesn't inherit the environment it is started from, but Claude Code applies that file's `env` to every session in the folder and to each resume;
120
+ 6. the profile's work and verify skills must be there: a `conductor:<skill>` in the plugin, any other in the worktree's `.claude/skills` or `~/.claude/skills`.
121
+
122
+ A launch that fails removes the worktree it made when it is clean, with its branch while that still has the launch's name; a worktree that was there before the launch stays.
123
+
124
+ Then `claude --bg -n <name> --plugin-dir <home>/plugin --disallowedTools EnterPlanMode ExitPlanMode --permission-mode auto -- <prompt>` runs with its cwd in the worktree (see Plugin), never `--worktree`. Workers run headless. A machine whose `config.json` sets `"workers": { "tab": true }` also gets a tab attached to each session, `claude attach <session>`, in the terminal `workers.terminal` names (see Tabs); `conduct attach` opens one either way. A tab that fails to open is a `worker.tab-failed` event and never fails the launch.
104
125
  - **park:** a worker with a wait (`POST /waits`) is stopped once `claude agents` shows its turn has ended. Its status becomes `parked`, and its tab closes.
105
126
  - **resume:** when a wait resolves, the daemon lets the stop settle (`sessions.settleSeconds`). It checks the process has exited, then runs `claude --bg --resume <session> -- "[conductor] event: …"`. The session keeps its name, model, permission mode and disallowed tools. A resume of a session that still runs starts a copy; the daemon stops and removes the copy, then tries again.
106
127
  - **compact:** a parked worker with no resolved wait, whose context the rules find too big (the default `compact-on-park`: past `sessions.compactTokens`, 300k), is resumed with `/compact <what to keep>` once its stop has settled (`worker.compacting`). It runs until its transcript shows the compaction's boundary (`worker.compacted`, with the context before it and the conversation it kept), then parks again on its waits, which resume it as usual. Each turn of a session re-reads its whole context from cache, so a worker left to grow pays for it every turn (ATK-454 reached 883k). A resume that starts a copy is tried again on a later sweep (`worker.compact-deferred`), as a resume is. A compaction whose resume fails, or whose turn ends with no boundary 10 minutes on, logs `worker.compact-failed`, which raises a `context` item in the inbox. The worker still parks, and the daemon doesn't try it again until it restarts or the session compacts some other way: any boundary in its transcript, Claude Code's own included, logs `worker.compacted` and resolves that item. A worker whose context is unknown is never compacted, so even a rule with no threshold can't compact it on every park.
107
- - **retire:** refuses uncommitted or unpushed work, and a worker whose turn still runs, unless `--force`. It never retires a session that is still starting. Then it stops the session, removes the worktree and runs `claude rm`. If the stop fails, nothing is removed.
128
+ - **retire:** refuses a worker whose turn still runs, unless `--force`, and never retires a session that is still starting. What happens to the worktree depends on the worker's PR (design note v2, section 2):
129
+ - **merged** (read from the code host): it refuses uncommitted or unpushed work unless `--force`, then stops the session, removes the worktree and deletes its local branch, and runs `claude rm`;
130
+ - **no PR, and nothing uncommitted or unpushed** (a canceled item, a worker retired before its first commit): as merged, with nothing to lose;
131
+ - **not merged** (abandoned or closed, or no PR with work in it): it stops and removes the session and frees the ports, and keeps the worktree and its branch, so nothing the PR didn't land is lost. `worker.retired` names it under `kept`, which raises one `failed` inbox item with the path, the branch and the commands that remove them. A PR the project's code host can't read at all counts as not merged;
132
+ - **unread** (the code host didn't answer): it refuses, as a refusal that passes on its own, and the scheduler tries again.
133
+
134
+ A probe's worktree and a `--force` retire's always go. The removal moves the worktree aside, has git forget it, deletes the branch and then the directory with Node, which unlinks pnpm's junctions without following them (`git worktree remove` leaves them on Windows). The delete is asynchronous, so the API goes on answering through a minute of `node_modules`. It works in the repository the worktree's own `.git` names, so a worker launched before the daemon owned clones retires from the checkout its worktree was made in; it removes only a linked worktree that repository lists, never a main checkout. With the directory gone already, it deletes the `worktree-<name>` branch in the project's clone only when none of its commits is unpushed. If the stop fails, nothing is removed.
108
135
  - **restarts:** a launch the daemon was stopped in adopts its session if one was started, and otherwise fails and removes its clean worktree.
109
136
  - **attach:** a parked worker is resumed with no event text, so it wakes idle and keeps running when its tab closes. An attached worker isn't parked until it registers a new wait, or until its turn has been over `sessions.idleMinutes` (`worker.detached`). The daemon can't see the tab, so this also delivers a wait that resolved while it was attached. A wait that resolves after the attach, on a worker whose transcript shows no turn since then, is delivered at once: the worker is detached (`reason: wait resolved`), parked, which closes its tab, and resumed with the event. A worker someone woke outside the daemon counts as attached since its stop, so the turn that woke it counts. One that took a turn since the attach (or has no transcript to tell), or whose wait resolved before the attach, keeps it until the idle release, logs `worker.resume-held` (`reason: attached`) once, and `conduct status` shows it as `idle, holding resolved waits for the attached session`.
110
137
  - **park failures:** a session whose process outlives `claude stop` by 30 s logs one `worker.park-failed` per spell, which raises a `stall` in the inbox (see Inbox), and the park is tried again every 5 minutes.
@@ -115,6 +142,19 @@ The session manager owns the `claude --bg` sessions it launches, and only those:
115
142
 
116
143
  Worker statuses: `launching`, `running`, `parked`, `stopped-unexpectedly`, `failed`, `exited`. Every step is an event (`worker.launched`, `worker.parked`, `worker.resumed`, …) on `GET /events`.
117
144
 
145
+ ### Tabs
146
+
147
+ Workers are background sessions, and a tab is only a view of one: the session runs without it, and a tab closes when its worker parks. `~/.conductor/config.json` says whether each launch opens one and where tabs open:
148
+
149
+ ```jsonc
150
+ { "workers": { "tab": true, "terminal": "auto" } }
151
+ ```
152
+
153
+ - `tab` (false): open a tab on each launch. `conduct attach <worker>` opens one whatever it says. It was the profile's `workers.tab` until ATK-529: a profile may still set it, for older daemons, but it is ignored, and `conduct project check` warns about it. Set it in `config.json` on each machine that wants tabs.
154
+ - `terminal` (`auto`): `windows-terminal` (`wt.exe`, a window per project, "Conductor · <project>"), `iterm` (a tab in its front window), `terminal` (macOS Terminal, a window per tab) or `tmux` (a detached session per window, such as `conductor-atk`, and a tmux window per tab). `auto` is Windows Terminal on Windows, iTerm on macOS where it is installed and Terminal where not, and tmux elsewhere.
155
+
156
+ A tmux tab runs where no desktop is, so `conduct attach` and `conduct console` print the `tmux attach -t <session>` that reaches it. With no terminal to open in (no tmux on a server), `conduct attach` prints the `claude attach <session>` to run yourself, and `conduct console` refuses with `conduct console --here --force` (`--force` because the refused start is claimed for a minute). A worker's tab whose `claude attach` fails stays open on the failure, until Enter, so you can read it. Tabs on macOS and tmux run their command through `sh -c`, whatever the login shell. macOS asks once whether the conductor may control Terminal or iTerm (Automation, in Privacy & Security). Terminal opens a window per tab, and closes it when the tab's shell exits only if the profile's "When the shell exits" says so (Settings, Profiles, Shell); otherwise a parked worker leaves its window behind.
157
+
118
158
  ## Notes
119
159
 
120
160
  A worker writes each phase note (`## <work skill> · <Phase>[ · <kind>: <one line>]`, such as `## work-issue · PR opened`) with `conduct note <item> <file>`. The daemon posts the file as a comment on the item in the tracker, then records the phase at once: on the worker (`phase` in `GET /fleet` and `conduct status`), on the item, and as a `note.posted` event. A PR opened note also records the worker's PR (`pr`, such as `ado:Emergent.AgenticToolkit#1850` or `github:<owner>/<repo>#458`) from its first PR link, replacing an earlier one; until then, the worker's first `pr:` wait records it. `conduct status` and the console's fleet pane show it. The worker is `--worker <worker>`, else the one whose worktree is the current checkout, else the project's live worker on that item. The project is the worker's, else the one whose tracker key (the Linear team, or the Boards or GitHub Issues `key`) is the item's key prefix.
@@ -194,7 +234,12 @@ Protocol 2's verbs on git and the code host (providers design note, section 4),
194
234
  - **A cancelled run (ATK-547).** On Azure Pipelines a canceled build is `cancelled`, not `failed`. A later run on the base whose commit contains the merge stands in for it: the first that wasn't cancelled is the merge's run, with `supersedes` naming the cancelled one. So `cancelled` means no newer run carries the merge, and the note gives the `--requeue` line. GitHub reads runs by the merge's SHA alone, so its `cancelled` says nothing about newer runs.
195
235
  - **`--requeue <pipeline>`.** It queues that pipeline again on the base at its tip (`POST build/builds` with the tip as `sourceVersion`), after checking that the tip contains the merge. It is a write, for the item's own merge only: the checkout's branch carries the item's key, and that branch's PR merged as `<sha>`. It refuses a run that is waiting, running, succeeded or failed, so a run already listed is never queued twice. It also refuses a merge under 15 minutes old, since Azure DevOps can still list a newer run that carries it. A newer merge's batched run that ADO hasn't listed yet isn't caught. It refuses a pipeline the merge didn't trigger and a GitHub repo. The daemon queues it for the worker that owns the checkout (`POST /workers/:id/requeues`) and logs `code-host.run-requeued`; with no daemon it runs here. `conduct wait merge <sha>` then follows the new run, which carries the merge.
196
236
  - **`--for`.** It settles on the named pipelines alone, by YAML file name, path or name, and lists the rest under `others`. Azure Pipelines refuses a name no pipeline answers to.
237
+ - **`--grep <pattern>` (ATK-622).** With `--for`, it reads every task log of those pipelines' runs, succeeded or not (`Ci.taskLogs`: Azure Pipelines' timeline tasks under their stage, through the reader `failureLog` uses; GitHub Actions' `gh run view --log` steps under their job). It tests each line against a JavaScript regular expression, case-sensitive. `grep.runs` gives each run's `matches` by stage and task, at most 200 lines a task with `truncated` beyond that, and `searched`, each task with its line count. So a dev proof can show that a run never printed a line. Some runs carry a note saying why they were searched in part or not at all: a pipeline with no run yet (`run: null`), a run still queued or running, one waiting on an approval (its later stages haven't run), and a log the provider won't give. A transient failure or a lost login is thrown instead.
197
238
  - **Logs and stages.** Each failed run comes with its failed tasks and log tail (`logs`). For the project's repo, each of the profile's `releases` whose run succeeded gives what it staged (`stages.<key>`): package, version, `stageId`, the `npm stage approve` line, and `published`.
239
+ - `conduct timeline` (ATK-623) reads when a run's tasks ran, so a worker can measure a step (a cache that has to pay for itself) without a merge commit. It is a read, so it runs here.
240
+ - **One run.** `conduct timeline <run>` gives the run's start, finish and `seconds`, and each task in the order it started, with its `stage`, `job`, `started`, `finished`, `seconds` (null until it has both times), and the host's `state` and `result` (`Ci.timeline`: Azure Pipelines' timeline `Task` records under their stage and job; GitHub Actions' jobs API steps under their job, with no stage).
241
+ - **A pipeline's last runs.** `conduct timeline --for <pipeline>` reads the last finished runs of one pipeline on a branch instead, newest first (`Ci.recentRuns`): the profile's base and 3 runs by default, `--branch` and `--count` (at most 20) to change them. The pipeline is named as `runs --for` names one, and a name no pipeline, or more than one, answers to is refused. A branch with fewer runs says so in a note.
242
+ - **`--task <regex>` and `--grep <regex>`.** `--task` keeps the tasks whose name matches, not case-sensitive, so `Cache Next build` also keeps its `Post-job: Cache Next build` save. One that matches nothing says so and lists the run's tasks. `--grep`, which needs `--task`, reads only those tasks' logs (`Ci.taskLogs` with `only`) and gives `grep` in `runs --grep`'s shape: `matches` and `searched` by task, with a note for a log the provider won't give. A run not finished says its tasks may be partial.
198
243
  - `conduct wait merge <sha> [--for …] [--repo …]` parks the worker until that verdict isn't `waiting` (see Waits), on either CI, so no worker polls with `wait time`. It absorbs ATK-430, ATK-246 and ATK-182.
199
244
 
200
245
  ## Writes
@@ -229,7 +274,7 @@ The `inbox` table holds everything that waits on the operator, across projects.
229
274
  - the exact commands, and its links, each named (`{ label, href }`);
230
275
  - when it was raised.
231
276
 
232
- The console gives each link a button of its own, `open <label>`, and `conduct inbox` and `/inbox` print it as `<label>: <href>`. The daemon names the links it knows: a run is `run <n>`, a conflict's PR is `PR <n>`, a refused file is `rules` or `profile`, a checkout-sync item's root is `checkout`, a train's are `<repo> PRs` and `train PR <n>`. Every other link is named from its shape:
277
+ The console gives each link a button of its own, `open <label>`, and `conduct inbox` and `/inbox` print it as `<label>: <href>`. The daemon names the links it knows: a run is `run <n>`, a conflict's PR is `PR <n>`, a refused file is `rules` or `profile`, a train's are `<repo> PRs` and `train PR <n>`. Every other link is named from its shape:
233
278
 
234
279
  - A pull request is `PR <n>`, or `<repo> PR <n>` when it isn't the project's repo.
235
280
  - An Azure Pipelines or GitHub Actions run is `run <n>`.
@@ -278,7 +323,7 @@ If the tracker refuses the comment, nothing is resolved. Only a plan takes appro
278
323
  The notifier routes each new inbox item to the phone, on two channels:
279
324
 
280
325
  - **Remote Control:** the daemon appends `notify.requested` (`channel: "remote-control"`), and the conductor mod in the console pushes it with PushNotification. It reaches the phone only while the console is connected to Remote Control (see Mod). On Claude Code 2.1.296 these pushes are reported sent but never reach the phone (ATK-359), so the built-in `default` and `focus` also send to Pushover until a Claude Code release fixes it.
281
- - **Pushover:** sent from the daemon. The keys are `PUSHOVER_TOKEN` and `PUSHOVER_USER`, or else the Windows generic credential `atk-conductor-pushover` (`notify.pushover.credential`): its **user name is your Pushover user key** and its **password is the application's API token**. Save it with `cmdkey /generic:atk-conductor-pushover /user:<user key> /pass:<app token>` or in Credential Manager. A credential saved while the daemon runs is read on the next push. The keys are never logged or stored. Only `~/.conductor` falls back to `atk-conductor-pushover`: a daemon on another `CONDUCTOR_HOME` (a scratch home for a test) reads a credential only when its `config.json` names `notify.pushover.credential`, so it pushes to your phone only with that or with `PUSHOVER_TOKEN` and `PUSHOVER_USER` in its environment (ATK-506).
326
+ - **Pushover:** sent from the daemon. The keys are `PUSHOVER_TOKEN` and `PUSHOVER_USER`, or else the credential `conductor-pushover` in the machine's secret store (`notify.pushover.credential`; see Accounts): its **user name is your Pushover user key** and its **password is the application's API token**. Save it with `cmdkey /generic:conductor-pushover /user:<user key> /pass` on Windows, `security add-generic-password -s conductor-pushover -a <user key> -w` on macOS, or `secret-tool store --label=conductor-pushover service conductor target conductor-pushover user <user key>` on Linux; each asks for the token. On macOS and Linux, delete an older item first (`conduct project check` prints the line that does). A credential saved while the daemon runs is read on the next push. The keys are never logged or stored. Only `~/.conductor` falls back to `conductor-pushover`: a daemon on another `CONDUCTOR_HOME` (a scratch home for a test) reads a credential only when its `config.json` names `notify.pushover.credential`, so it pushes to your phone only with that or with `PUSHOVER_TOKEN` and `PUSHOVER_USER` in its environment (ATK-506).
282
327
 
283
328
  **Profiles** pick the channels. A profile is a list of rules, and the first rule that matches an item says where it goes; when none matches, the item stays in the inbox, unpushed. Three are built in, and `notify.profiles` in `config.json` replaces one by name or adds more:
284
329
 
@@ -326,11 +371,11 @@ Rules say what the conductor does when something happens (design note, section 9
326
371
  ]
327
372
  ```
328
373
 
329
- - **Sources, in order:** the item's project's `rules` (in its `.claude/conductor.json`, changed by PR), then `~/.conductor/rules.json`, then the built-in defaults: conduct-atk's behavior written as rules (`launch`, `retire-closed`, `park-on-wait`, `resume-on-wait`, `compact-on-park`, `runaway`, `daily-cap`, `ready-to-release`, `queue-drained`, `triage`, which raises a new item that waits on the profile's triage label in the inbox, `conductor-handoff`, which escalates a worker's `Handoff · conductor` note to the console, and `hold-pre-start-handoff`, which adds the human label when a worker hands off as `human`, `operator`, `blocked` or `scope` before its `Started` note, so the scheduler never launches work no worker can do again; remove the label if the item should be picked later). A rule with an `id` replaces the rule with the same id further down, so a file holds only the differences.
330
- - **when:** `and`, `or`, `not` and parentheses over comparisons (`==`, `!=`, `<`, `<=`, `>`, `>=`, `in [a, b]`, `<label> in item.labels`, `Started in item.phases`) and events. An event rule fires when one of its events happens: `note`, `plan`, `wait.resolved`, `run.failed` (a failed launch, a session that stopped unexpectedly, or a PR's red checks: `pr.checks-failed`), `worker.idle`, `worker.exited`, `worker.permission`, `worker.waiting`, `worker.parked` (a park; the session manager also asks it of each parked worker on a sweep, for `compact`), `inbox.raised`, `pr.comment`, `item.unblocked`, `item.closed`, `provider.login-failed` (a project's login lost, once per spell; see Accounts), `queue.pick`, `queue.drained`, `queue.ready-to-release`, `queue.triage`. A rule without one is a state rule, checked on each scheduler tick against each wait, inbox item, worker or project, or once for the machine, by the fields it reads. Fields: `project`, `item.id/area/labels/tier/priority`, `item.phases` (the phases of every note the item has had, the one being posted too), `plan.tier/landing`, `note.phase/kind`, `wait.kind/age`, `inbox.kind/age`, `worker.retries/phase`, `worker.context` (the session's context in tokens, see Workers), `spend.worker/item/project/today` (input, output and cache-write tokens, without cache reads: the worker's and the item's in all, the project's and the machine's today), `time`, `day`, `notify.profile`. Values carry units: `15m`, `2h`, `500k`, `2M`, `22:00`, `saturday`.
374
+ - **Sources, in order:** the item's project's `rules`, its machine profile's (`~/.conductor/projects/<project>.json`, named `project.<project>.machine:<id>`) before its repo's (`.claude/conductor.json`, changed by PR, named `project.<project>:<id>`; see Projects), then `~/.conductor/rules.json`, then the built-in defaults: conduct-atk's behavior written as rules (`launch`, `retire-closed`, `park-on-wait`, `resume-on-wait`, `compact-on-park`, `runaway`, `daily-cap`, `ready-to-release`, `queue-drained`, `triage`, which raises a new item that waits on the profile's triage label in the inbox, `conductor-handoff`, which escalates a worker's `Handoff · conductor` note to the console, and `hold-pre-start-handoff`, which adds the human label when a worker hands off as `human`, `operator`, `blocked` or `scope` before its `Started` note, so the scheduler never launches work no worker can do again; remove the label if the item should be picked later), and `release-pre-start-hold`, which takes that label off again when the worker clears the hold itself (its `Resumed`, or its `Started` after the hold), and leaves a human label the hold didn't add (ATK-575). A rule with an `id` replaces the rule with the same id further down, so a file holds only the differences, and a machine-profile rule replaces the repo's rule of its id (`"do": "none"` switches it off).
375
+ - **when:** `and`, `or`, `not` and parentheses over comparisons (`==`, `!=`, `<`, `<=`, `>`, `>=`, `in [a, b]`, `<label> in item.labels`, `Started in item.phases`) and events. An event rule fires when one of its events happens: `note`, `plan`, `wait.resolved`, `run.failed` (a failed launch, a session that stopped unexpectedly, or a PR's red checks: `pr.checks-failed`), `worker.idle`, `worker.exited`, `worker.permission`, `worker.waiting`, `worker.parked` (a park; the session manager also asks it of each parked worker on a sweep, for `compact`), `inbox.raised`, `pr.comment`, `item.unblocked`, `item.closed`, `provider.login-failed` (a project's login lost, once per spell; see Accounts), `queue.pick`, `queue.drained`, `queue.ready-to-release`, `queue.triage`. A rule without one is a state rule, checked on each scheduler tick against each wait, inbox item, worker or project, or once for the machine, by the fields it reads. Fields: `project`, `item.id/area/labels/tier/priority`, `item.phases` (the phases of every note the item has had, the one being posted too), `item.labelled-by` (the ids of the rules whose label add still stands on the item: a label they added, not one it had already, that no rule removed since), `plan.tier/landing`, `note.phase/kind`, `wait.kind/age`, `inbox.kind/age`, `worker.retries/phase`, `worker.context` (the session's context in tokens, see Workers), `spend.worker/item/project/today` (input, output and cache-write tokens, without cache reads: the worker's and the item's in all, the project's and the machine's today), `time`, `day`, `notify.profile`. Values carry units: `15m`, `2h`, `500k`, `2M`, `22:00`, `saturday`.
331
376
  - **do:** `launch`, `retire`, `park`, `resume worker`, `retry`, `pause launches [in <project>] [until <when> | for <duration>]`, `pause all launches …`, `unpause launches`, `focus [<project>] weight|slots <n> until <when>`, `auto-approve now`, `auto-approve after <duration>`, `inbox <kind> ["<text>"]`, `remind operator`, `notify <channel> ["<text>"]`, `notify profile <name> [until <when>]`, `label add|remove human|triage|shipped-open`, `flag shipped-open`, `escalate console "<ask>"`, `none`. One string, or a list.
332
377
  - **Guardrails:** rules act inside Area locks, slots, quiet hours and config.json's limits. A rule that would go past one is refused when it loads: `focus … slots` over `scheduler.slots`, an override with no end or one over 14 days, `retire` on anything but `item.closed`, `launch` outside `queue.pick` / `item.unblocked`, `park` outside `worker.waiting`, `resume` outside `wait.resolved` / `pr.comment`, `compact` outside `worker.parked`, `retry` outside `run.failed`. `merge`, `push`, `publish`, `approve`, `delete` and `run` aren't in the vocabulary: rules never merge, push, publish, approve prod, delete or run commands, and the daemon writes to a code host only when the owning worker asks (see Writes).
333
- - **Reload:** saving `rules.json` or a project's profile reloads its rules. A profile save, or a profile changed while the daemon was down, is taken whole: the daemon stores it and logs `project.updated` with the fields that `changed`, and the scheduler, watchers and the rest use it from then on. A profile that renames the project is refused: a project keeps the name it was registered under. To rename one, `conduct project remove <old name>`, then `conduct project add` it under the new name (in that order: with both registered, both would read the same queue and could launch the same item). The remove drops the old registration and its queue read, resolves its open inbox items (the refusal's among them) and logs `project.removed`, on which the daemon drops its rules and its watch of the file. It is refused while the project has workers in flight, and works without the daemon. A file the conductor refuses leaves its last good rules (for a profile, the whole last good profile) in force, logs `rules.rejected` and raises a `failed` inbox item until it loads again (`rules.loaded`), including after a restart. `conduct project add` refuses a profile whose rules don't load, with or without the daemon.
378
+ - **Reload:** saving `rules.json` or a project's machine profile reloads its rules, and so does a fetch of its clone that brings another `.claude/conductor.json` on the base branch. A profile changed either way, or while the daemon was down, is taken whole: the daemon stores it and logs `project.updated` with the fields that `changed`, and the scheduler, watchers and the rest use it from then on. A project keeps the name its folder gives it: the repo's `name` is only what `project add` takes when no `--name` is given, and a machine profile that names another project is refused. To rename one, `conduct project remove <old name>`, then `conduct project add <url> --name <new name>` (in that order: with both registered, both would read the same queue and could launch the same item). The remove drops the old registration and its queue read, resolves its open inbox items (the refusal's among them) and logs `project.removed`, on which the daemon drops its rules and its watch of the file. It is refused while the project has workers in flight, and works without the daemon. A file the conductor refuses leaves its last good rules (for a profile, the whole last good profile) in force, logs `rules.rejected` and raises a `failed` inbox item until it loads again (`rules.loaded`), including after a restart. `conduct project add` refuses a profile whose rules don't load, with or without the daemon.
334
379
  - **Checking:** `conduct rules` lists the rules in force (`project.atk:#2`, `machine:runaway`, `default:launch`) and what replaces what. `conduct rules test <file>` dry-runs a sample, such as `{ "event": "pr.comment", "project": "atk", "fields": { "wait.kind": "merge", "wait.age": "3h" } }` (leave out `event` for a state rule), and shows what fires, each action's guardrail, and why every other rule of the trigger didn't. Both read the files directly when the daemon isn't running.
335
380
 
336
381
  - **Why:** every action the conductor takes is an event that names its rule, directly (`rule`) or through the event that caused it (`data.cause`). `conduct why <event id>` follows that chain back and shows the rule as it fired; `conduct why ATK-315` does it for the item's newest actions.
@@ -386,15 +431,47 @@ The scheduler moves conduct-atk's tick into the daemon (design note, section 8).
386
431
 
387
432
  **Overrides** end on their own: `conduct pause atk --until 17:00`, `conduct pause --until tomorrow` (every project), `conduct unpause atk`, `conduct focus atk --slots 3 --until monday`. `--until` takes `17:00` (the next one), `tomorrow`, a day, or a date and time. Each is an `override.set` event, which `conduct why` attributes to the command, and they show in `conduct rules`.
388
433
 
389
- ## Skill bumps reach the main checkout
434
+ ## Projects
435
+
436
+ A conducted project is a clone the daemon owns (design note v2, sections 2 and 7; ATK-527). Everything of it lives under `~/.conductor/projects`:
437
+
438
+ | Path | Holds |
439
+ |---|---|
440
+ | `<name>.json` | its machine profile: what this machine says about the project, which wins over the repo's |
441
+ | `<name>/repo` | the clone of its remote, which the daemon fetches and adds worktrees to |
442
+ | `<name>/worktrees/<item>` | a worker's worktree (see Workers) |
443
+
444
+ **Your first conducted project.** `conduct init` takes a repo from a checkout to a passing `conduct project check` with no hand-written JSON (ATK-528). The repo is on GitHub or Azure DevOps and has at least one commit on its base branch.
445
+
446
+ 1. Install the conductor (see On PATH) and sign in to the code host and tracker (see Accounts).
447
+ 2. In a checkout of the repo, run `conduct init`. It shows what it detected:
448
+ - the code host from `origin`;
449
+ - CI as the code host's own (a hint when the pipeline files are another's);
450
+ - the base branch from `origin/HEAD`;
451
+ - `setup` from the lockfile at the root (`pnpm install --frozen-lockfile`, `npm ci`, `yarn install`, `bun install`, `uv sync`, `poetry install` or `go mod download`);
452
+ - a `verify-*` skill in `.claude/skills`;
453
+ - the item key most recent commit subjects carry.
454
+
455
+ Then it asks for the rest, each detected value the default: the name, the base, the tracker (the code host's own issues or Boards, or Linear), its key, team or query, `setup` and the verify skill. `--yes` asks nothing and refuses, with each one's flag, what it couldn't detect. Without `--yes` it needs a terminal to ask in: node sees none in Git Bash's mintty, so use Windows Terminal there, or `--yes`.
456
+ 3. It writes a starter profile to `~/.conductor/projects/<name>.json`: the code host, CI, base, tracker, `conductor:work-item` and the verify skill, 2 slots, the plan and merge gates, a release handoff and `setup`, with the `conductor` minimum its fields need. `--shared` writes `.claude/conductor.json` in the checkout instead, which the conductor reads only on `origin/<base>`: commit it, push it and run `conduct init` again. A profile file that is there is never overwritten, and a repo profile on `origin/<base>` that names the project means nothing is written; one only in the working tree stops `init` until it is pushed.
457
+ 4. It runs `conduct project add` on the checkout. For a new clone it prints the trust step: run `claude` in the clone once and accept the prompt. In a terminal it waits for Enter; with `--yes` it stops there.
458
+ 5. It runs `conduct project check`. With no verify skill, the worktree check fails as a launch would, and `init` points at the conductor plugin's `/conductor:create-verification-skill`, which loads only with the plugin: run `claude --plugin-dir <the plugin>` in the checkout (`init` prints the folder), make the skill under the name the profile's `skills.verify` gives, commit it and push it.
459
+ 6. Run `conduct init` again after each step: it keeps what is done, fetches the clone and checks again. On a project that is set up, ATK among them, it writes nothing and only fetches and checks. Once the check passes, give the tracker's projects a priority (Linear) or label items `conduct` (GitHub Issues), and `conduct launch <item>`.
460
+
461
+ **Adding one.** `conduct project add <url | path> [--name <name>]` clones the remote into `<name>/repo`, in the CLI's own process, so its output shows and no API timeout applies. Given a path, it reads that checkout's `origin` and clones from the remote: the folder itself is never cloned, and nothing the conductor does touches it again. The name is `--name`, else the `name` the repo's `.claude/conductor.json` gives on its default branch; a repo with no profile needs `--name`. The clone is made in a staging folder first, so one that fails leaves nothing. Adding a project again fetches its clone (its origin must be the same remote) and updates the registration in place: its inbox, items and workers stay. Then the daemon registers it (or the store, with none running). Claude Code trusts a worktree by its repository, and nobody has opened a new clone in Claude Code yet, so `add` ends with the one step that trusts it: run `claude` in the clone once and accept the trust prompt, then `conduct project check <name>`.
462
+
463
+ **Its profile** comes in two layers, merged as the files are written, before the schema reads them:
390
464
 
391
- A worker's worktree branches from `origin/<base>` and installs its own pins. The main checkout is different: it keeps the pins it was last pulled at, and the worktree hooks and the skills a new worktree copies come from there. The console's skill doesn't: it comes with the conductor plugin (see Plugin). So the daemon checks each conducted project that has an `.atk-lock.json`, at most every `checkout.intervalMinutes` (10):
465
+ - the **machine profile**, `<name>.json` (JSONC), optional beside a repo profile. A project with no repo profile keeps a whole profile here;
466
+ - the **repo profile**, `.claude/conductor.json` at `origin/<base>` in the clone, optional, changed by PR and shared by the team. `<base>` is the machine profile's `baseBranch`, else the remote's default branch (`origin/HEAD`); when the file there names another `baseBranch`, it is read once more at that one.
392
467
 
393
- 1. It runs `git fetch origin <base>` in the main checkout and compares the pins (asset type, name and version) at `HEAD` with those at `origin/<base>`. When they match and nothing is left to install, nothing more happens.
394
- 2. When they differ, it records the pins as pending (a `checkout.pending` event). With the main checkout on `<base>` and no local changes to `.atk-lock.json`, it then runs `git merge --ff-only origin/<base>`.
395
- 3. Once `HEAD` has the pins, whether by this pull or yours, it runs `atk install` for the pending assets. A `checkout.updated` event lists each `name old → new`. An install that fails or leaves drift stays pending, and the next check tries it again, in this daemon or the next.
468
+ Objects merge key by key and the machine's value wins; arrays (`ports`, `setup`, `approvers`, `gates`, …) are replaced whole. `rules` stack instead: the machine profile's first, then the repo's, then `rules.json`, then the defaults, so a machine rule replaces the repo's rule of its id (see Rules). Each layer's `conductor` minimum is checked on its own, and `protocol` on the merge. `name` is the registered one: a machine profile may repeat it, not change it.
396
469
 
397
- The checkout isn't touched in these cases: it is on another branch, its lockfile has local changes, or git refuses the fast-forward. Instead one `operator` item gives the commands (`git -C <root> pull --ff-only`, `atk install -P <root>`). The same item stays open while an install leaves drift, and it resolves itself once the pins are installed. A worktree create waits for a check that is running, and a check waits while one of the project's workers is launching, so a new worktree never copies a half-updated checkout. A failed fetch is only logged. `checkout.mode` is `update` (the default), `notify` (the item only, with no git or atk run) or `off`.
470
+ `conduct profile <name>` prints the merged profile from the files and the clone as fetched last, one line per field with its value and its source (`machine`, `repo` or `default`), then each rule with its layer; `--json` gives `{ profile, sources }`. It works with or without the daemon.
471
+
472
+ **Keeping it current.** When the daemon starts and every `clones.fetchMinutes` (10) after, it runs `git fetch --quiet --prune origin` in each clone and then reads the profile again, so a changed `.claude/conductor.json` on the base branch is in force as a saved machine profile is (a watch on `<name>.json` takes that at once). A worktree create waits out a fetch that is running, and the fetches pass a clone by while a create works in it, so the two never write the clone's refs at once. A fetch can't prompt for credentials (`GIT_TERMINAL_PROMPT=0`) and gives up after 2 minutes. A failed fetch is logged once a spell, and the profile stays as it was. Nothing is pulled, installed or fast-forwarded anywhere else: a worktree's `setup` installs what its branch pins.
473
+
474
+ **From a project registered by its checkout** (before ATK-527): the daemon conducts such a row no longer. Its profile is refused with the step that moves it, `conduct project add "<that checkout>"`, which clones the checkout's origin and keeps the registration, and the scheduler launches none of its items meanwhile. Workers in flight keep their worktrees in that checkout, and retire from it: that retire is the one time the conductor runs git there (`git worktree prune`, and `git branch -D` of the worker's branch). A profile refusal of the project, whichever file it named, resolves once the project's profile loads.
398
475
 
399
476
  ## Skill trains
400
477
 
@@ -453,11 +530,23 @@ Accounts belong to the person running the daemon, not to the repo, so each proje
453
530
 
454
531
  | Order | Source | Azure DevOps (PRs, runs, Boards) | GitHub (reads, and writes such as `conduct train`'s) | Linear (waits, notes, labels, queue, briefs) |
455
532
  |---|---|---|---|---|
456
- | 1 | **project token**: a generic credential (Credential Manager) the project names | `projects.<name>.ado.token`: a PAT, sent as Basic auth | `projects.<name>.github.token`: a token, as `GH_TOKEN` | `projects.<name>.linear.credential`: an API key |
457
- | 2 | **machine token**: a conductor-only env var, else a generic credential | `CONDUCTOR_ADO_TOKEN`, else `conductor-ado` | `CONDUCTOR_GITHUB_TOKEN`, else `conductor-github` | `CONDUCTOR_LINEAR_KEY` or `LINEAR_API_KEY`, else `atk-conductor-linear` (`ATK_CONDUCT_LINEAR_CREDENTIAL` names another) |
533
+ | 1 | **project token**: a credential in the machine's secret store that the project names | `projects.<name>.ado.token`: a PAT, sent as Basic auth | `projects.<name>.github.token`: a token, as `GH_TOKEN` | `projects.<name>.linear.credential`: an API key |
534
+ | 2 | **machine token**: a conductor-only env var, else a credential in the store | `CONDUCTOR_ADO_TOKEN`, else `conductor-ado` | `CONDUCTOR_GITHUB_TOKEN`, else `conductor-github` | `CONDUCTOR_LINEAR_KEY` or `LINEAR_API_KEY`, else `conductor-linear` (`CONDUCTOR_LINEAR_CREDENTIAL` names another) |
458
535
  | 3 | **CLI login**, last: it usually carries the widest permissions | `az account get-access-token --resource 499b84ac-…`, with `--tenant <tenant>` when `ado.tenant` names one | `gh auth token`, with `--user <user>` when `github.user` names one, so gh's active account doesn't change | none |
459
536
 
460
- Only the conductor's own env names count: another tool's `AZURE_DEVOPS_PAT` or `GITHUB_TOKEN` never changes what the conductor signs in as. Save a token with `cmdkey /generic:<target> /user:pat /pass` (Linear's with `/user:linear`); a token scoped to one project wants:
537
+ **The secret store** is the platform's own:
538
+
539
+ | Platform | Store | Save a token (each asks for the secret) |
540
+ |---|---|---|
541
+ | Windows | Credential Manager (generic credentials) | `cmdkey /generic:<target> /user:pat /pass` |
542
+ | macOS | the login keychain (generic passwords, the target as service) | `security delete-generic-password -s <target>; security add-generic-password -s <target> -a pat -w` |
543
+ | Linux | libsecret (the Secret Service: GNOME Keyring, KeePassXC …), attributes `service=conductor target=<target>` | `secret-tool clear service conductor target <target>; secret-tool store --label=<target> service conductor target <target> user pat` |
544
+
545
+ Linear's key is saved with the user name `linear` instead of `pat`. On macOS and Linux the old item is deleted first: an item there is kept per user name (macOS) or per set of attributes (Linux), so saving under another user name would leave two. `conduct project check` prints the line for its platform. **Env fallback:** where the store has no such credential, or can't be read (`secret-tool` missing, or a headless Linux box with no D-Bus session or keyring), the conductor reads `CONDUCTOR_SECRET_<TARGET>` instead: the target in upper snake case, so `conductor-atk-ado` is `CONDUCTOR_SECRET_CONDUCTOR_ATK_ADO`, with its user name, when one is needed (Pushover), in the same name plus `_USER`. Targets that differ only in punctuation (`a.b`, `a-b`) share a variable, so give them names that differ in letters or digits.
546
+
547
+ **The names lost their ATK prefix in ATK-529:** the machine's Linear key is `conductor-linear` (it was `atk-conductor-linear`), Pushover's `conductor-pushover` (it was `atk-conductor-pushover`), and `CONDUCTOR_LINEAR_CREDENTIAL` replaces `ATK_CONDUCT_LINEAR_CREDENTIAL`, which is no longer read. On Windows, the first read of a new name that finds none copies the old Credential Manager entry to it, with its user name and secret, and leaves the old one in place for an older conductor; after that the new one is found, so the old name is never read again. Delete the old ones with `cmdkey /delete:atk-conductor-linear` and `cmdkey /delete:atk-conductor-pushover` once no older conductor runs.
548
+
549
+ Only the conductor's own env names count: another tool's `AZURE_DEVOPS_PAT` or `GITHUB_TOKEN` never changes what the conductor signs in as. A token scoped to one project wants:
461
550
  - **Azure DevOps:** Code (read & write) and Build (read & execute), plus Work Items (read & write) for Boards;
462
551
  - **GitHub:** a fine-grained token on the repo with Contents, Pull requests and Issues (read & write) and Actions (read);
463
552
  - **Linear:** an API key limited to the project's team.
@@ -466,7 +555,7 @@ Only the conductor's own env names count: another tool's `AZURE_DEVOPS_PAT` or `
466
555
 
467
556
  A project whose entry names its CLI account (`ado.tenant`, `github.user`) keeps that account ahead of the machine's token, which is another identity and may not reach the project's organization. One machine ADO PAT serves every other project, so a project in another organization than the PAT's gets a token of its own.
468
557
 
469
- Found means there: a project token that is named but missing, or any token that is there but refused, is a lost login (below), never a quiet fall back to a wider credential. A refused PAT is read again once, so a replaced one is tried; the same one refused again is the lost login. The machine credential is optional: one that `cmdkey /list` says isn't saved (no PowerShell started then), or that can't be read, is passed over.
558
+ Found means there: a project token that is named but missing, or any token that is there but refused, is a lost login (below), never a quiet fall back to a wider credential. A refused PAT is read again once, so a replaced one is tried; the same one refused again is the lost login. The machine credential is optional: one that the store says isn't saved (on Windows `cmdkey /list`, so no PowerShell starts), or that can't be read, is passed over.
470
559
 
471
560
  Each credential is kept per account: an az token 20 minutes, renewed when ADO answers 401 or 203; a token read again every 20 minutes, so a replaced or removed one is seen; a gh token asked again once on a 401; a Linear key until Linear answers 401, when it is read again once. Projects on the same account share it. The secrets are never logged, stored or put on a command line.
472
561
 
@@ -542,14 +631,11 @@ Everything goes through the project's gh account (`projects.<name>.github.user`,
542
631
 
543
632
  The broker shares what every project on the machine uses (ATK-318).
544
633
 
545
- **Ports.** Each profile declares its dev servers' base ports by name, such as ATK's `"ports": { "web": 3000, "api": 7071, "maxSlot": 50 }` or `{ "web": 3000 }`.
546
- - A main checkout serves on the base ports (slot 0).
547
- - Each worktree gets a slot from 1 to `maxSlot` (default 50) and serves on base + slot. `conduct ports <path>` gives it the first slot whose ports no other checkout of any registered project has and nothing listens on, `--prefer` first. It's the same answer each time after that.
548
- - A retired worker's worktree frees its slot, and so does a worktree whose directory is gone (at the next assignment).
549
- - Ports are compared, not slots, so projects with different bases stay apart too.
550
- - A project's dev scripts read the assignment with `--json`, as ATK's `scripts/dev-ports.mjs assign` does. They keep their own scheme when it exits 1 (`not brokered`): no daemon, an older one, or a checkout in no registered project.
551
- - The broker knows only the slots it gave out. A slot a script picked on its own while no daemon answered stays unknown until that worktree asks the broker; until then only the listening probe keeps the slot clear. So `--prefer` is the slot the script would pick itself (`dev-ports.mjs` passes the checkout's own slot or its own free-slot scan's). The preferred slot is taken without the listening probe, because the checkout's own servers may be what listens there.
552
- - A stored assignment follows its project's profile: when the base ports or `maxSlot` change, the worktree moves, its old slot first.
634
+ **Ports.** Each profile names the ports a worktree's dev servers need, such as ATK's `"ports": ["web", "api"]` (design note v2, section 2; ATK-526).
635
+ - A launch gives the worktree one port per name from the machine's pool, `ports.first` to `ports.last` in config.json (41000 to 41999): each the pool's first port that no other worktree of any project holds, nothing listens on (IPv4 or IPv6 loopback), and that binds, which also skips a range Windows reserves. They reach `setup` and the worker as `CONDUCTOR_PORT_<NAME>` (see Workers).
636
+ - The pool sits away from the usual dev ports and their slot schemes, such as ATK's 3000+N and 7071+N for a person's own worktrees, so those never take a port a worker was given.
637
+ - A worktree keeps its ports while the profile names the same ports; a changed list gives it new ones. Retiring the worker frees them, and so does a worktree whose directory is gone (at the next assignment).
638
+ - `conduct ports` lists the assignments, and `conduct ports <path>` gives one worktree's (`--json` for either). Only a launch assigns. `conduct project check` previews the ports a new worktree would get, saving nothing.
553
639
 
554
640
  **Locks.** `conduct lock acquire chrome` takes the lock every project's verify runs share. It answers the work-issue helper's JSON (`acquired`, `heldBy`, `since`, `refreshed`; `released` for a release; `verdict` for a status).
555
641
  - The owner is `--owner`, else the item of the worker whose worktree this is.
@@ -597,7 +683,8 @@ Everything lives in `~/.conductor` (`CONDUCTOR_HOME` overrides it):
597
683
 
598
684
  | File | Holds |
599
685
  |---|---|
600
- | `config.json` | machine settings, JSONC (comments allowed), validated at startup; `inbox.runawayTokens` (1500000, the `runaway` rule's number); `notify` and `quietHours` (see Notifications); `scheduler` holds `mode` (`on`, `observe` or `off`), `slots` (4, across projects, and the most any rule can give one project), `dailyTokens` (20000000, the `daily-cap` rule's number) and `tickSeconds` (120); `sessions` holds `pollSeconds` (10), `settleSeconds` (5), `permissionMinutes` (5), `idleMinutes` (20), `compactTokens` (300000, the `compact-on-park` rule's number); `watchers` holds `ado`, `github`, `health`, `linear` and `npm`, each `{ intervalSeconds, perMinute }` (30/60, 30/30, 30/30, 30/10, 20/30), `statsMinutes` (10) and `conflictMinutes` (30) |
686
+ | `projects/` | each conducted project's machine profile, clone and worktrees (see Projects) |
687
+ | `config.json` | machine settings, JSONC (comments allowed), validated at startup; `clones.fetchMinutes` (10, see Projects); `inbox.runawayTokens` (1500000, the `runaway` rule's number); `notify` and `quietHours` (see Notifications); `scheduler` holds `mode` (`on`, `observe` or `off`), `slots` (4, across projects, and the most any rule can give one project), `dailyTokens` (20000000, the `daily-cap` rule's number) and `tickSeconds` (120); `sessions` holds `pollSeconds` (10), `settleSeconds` (5), `permissionMinutes` (5), `idleMinutes` (20), `compactTokens` (300000, the `compact-on-park` rule's number); `watchers` holds `ado`, `github`, `health`, `linear` and `npm`, each `{ intervalSeconds, perMinute }` (30/60, 30/30, 30/30, 30/10, 20/30), `statsMinutes` (10) and `conflictMinutes` (30); `workers` holds `tab` (false: workers run headless) and `terminal` (`auto`; see Tabs) |
601
688
  | `rules.json` | machine rules, JSONC, reloaded on save (see Rules) |
602
689
  | `token` | the API token, readable by this user only; every request sends `Authorization: Bearer <token>` |
603
690
  | `conductor.pid`, `port` | the single-instance lock and where the API listens (`127.0.0.1`) |
@@ -606,7 +693,7 @@ Everything lives in `~/.conductor` (`CONDUCTOR_HOME` overrides it):
606
693
 
607
694
  ## API
608
695
 
609
- - `GET /projects`: the registered projects. `POST /projects` with `{ "path": "<absolute path>" }` registers one. `DELETE /projects/<name>` removes one: `{ project, resolved }` (the inbox items it resolved), 404 for a name no project is registered under, or 409 naming its workers in flight. `POST /projects/<name>/check` with `{ "worktree": false }` or `{}` runs `conduct project check` as the daemon's accounts: `{ project, results: [{ check, status, summary, details, fix }] }`, or 404 for a name no project is registered under.
696
+ - `GET /projects`: the registered projects, each with its `clone`, `url`, profile and `sources`. `POST /projects` with `{ "name": "<name>" }` registers the clone `conduct project add` made at `~/.conductor/projects/<name>/repo` (400 when there is none, or its profile doesn't read). `DELETE /projects/<name>` removes one: `{ project, resolved }` (the inbox items it resolved), 404 for a name no project is registered under, or 409 naming its workers in flight. `POST /projects/<name>/check` with `{ "worktree": false }` or `{}` runs `conduct project check` as the daemon's accounts: `{ project, results: [{ check, status, summary, details, fix }] }`, or 404 for a name no project is registered under.
610
697
  - `GET /events`: the event log as server-sent events. Add `?since=<id>` (or send `Last-Event-ID`) to replay from an id. Without either, the stream starts at the live end. `conduct events` prints it one JSON event per line: the events after `--since` (all of them without it), or with `--follow` everything from there on (live without `--since`). `--follow` reconnects with `Last-Event-ID` when the daemon goes away, so a restart loses nothing, and prints the stream's state as lines without an id: `{"kind":"conduct.connected"}` and, once per outage, `{"kind":"conduct.disconnected","error":…}`. `?console=1` (`conduct events --follow --console`, which the conductor mod runs, or `conduct events --follow` with `CONDUCTOR_CONSOLE=1`, as a mod from before `--console` runs it until `/reload-plugins`) marks the console's stream: while one is open, escalations have a console to wake (see Console).
611
698
  - `POST /shutdown`: a clean stop (`conduct stop`).
612
699
  - `GET /console/escalations`: the open escalations, oldest first (see Console).
@@ -616,7 +703,7 @@ Everything lives in `~/.conductor` (`CONDUCTOR_HOME` overrides it):
616
703
  - `GET /fleet`: the workers in flight, with session activity, phase, PR, waits and spend (today, total).
617
704
  - `POST /workers` with `{ "item": "ATK-309", "project"?, "probe"?, "prompt"?, "conductor"? }`: launch; answers 202 with the `launching` worker. `GET /workers/:id` shows it with its latest events.
618
705
  - `DELETE /workers/:id` (`?force=true`): retire; 409 with the unfinished work (the worktree's, and each `.scratch/repos` checkout's under `checkouts`) when it refuses.
619
- - `POST /workers/:id/attach`: wake if parked, mark attached, open the tab.
706
+ - `POST /workers/:id/attach`: wake if parked, mark attached, open the tab; `tab` is why none opened, else null, and `hint` how to reach one off the desktop (`tmux attach -t <session>`).
620
707
  - `POST /workers/:id/prs` with `{ "title", "body", "repo"? }`: open the worker's PR after the ownership checks (see Worker verbs); 201 with the PR, 409 refused, 503 a lost login (with `login.provider` and `login.command`), 502 the host failed.
621
708
  - `POST /workers/:id/landings` with `{ "pr", "reason", "mode"?, "rearm"?, "repo"? }`: `conduct land` for the worker; 200 with the landing and its verdict. `POST /workers/:id/replies` with `{ "pr", "body", "thread"?, "repo"? }`: `conduct reply`; 201. Both answer 409, 503 and 502 as `/prs` does.
622
709
  - `POST /items/:id/notes` with `{ "body": "## work-issue · …", "worker"?: 1 }`: post a phase note (see Notes); 201 with the note and the worker. 409 when it won't post it; 502 when the tracker didn't take it, with `posted: "no"` or `"unknown"`.
@@ -659,24 +746,49 @@ Install the package globally, next to `atk`. `dev` follows `develop`; `latest` f
659
746
  ```bash
660
747
  npm install --global @detergent-software/conductor@dev
661
748
  conduct install-startup
662
- conduct project add <path to the project's main checkout>
749
+ conduct project add <the project's remote URL, or a checkout of it>
663
750
  ```
664
751
 
665
- `conduct project add` walks up from the path it is given to the directory that holds `.claude/conductor.json`, and maps a worktree to its main checkout. After that the daemon takes the whole profile from disk when it starts and each time the file is saved, so a `git pull` that changes `slots` or `skills.work` needs no `conduct project add`. An older daemon refuses a profile with fields it doesn't know, so upgrade the daemon before a profile that uses new ones lands. After an `--allow-downgrade` to a version without those fields, the stored copy no longer validates either: the project shows `the stored profile no longer validates` and isn't conducted until its file, saved without them, is read again.
752
+ `conduct project add` clones the remote into `~/.conductor/projects/<name>/repo` (see Projects). After that the daemon reads the profile again when it starts, when the machine profile is saved and after each fetch of the clone, so a merge that changes `slots` or `skills.work` needs no `conduct project add`. An older daemon refuses a profile with fields it doesn't know, so upgrade the daemon before a profile that uses new ones lands.
753
+
754
+ A profile that uses new fields says which conductor reads them: `"conductor": "3.0.0-dev.9"`, the version that first read the newest of them (a `-dev.N` while it is only on `dev`; a stable minimum such as `3.0.0` is newer than every `3.0.0-dev.N`, as semver orders them). Every conductor from the one that knows this key (ATK-573) checks it before the rest of the profile, and an older one refuses the file with one line instead of a list of fields: `conductor: needs 3.0.0-dev.9 or newer; this is 3.0.0-dev.7: run \`conduct upgrade --tag dev\`` (`--tag latest` for a stable minimum). The worker verbs that read the profile in a worktree (`conduct state`, `conduct branch`, `conduct search`, a lock with no daemon) say the same and exit 1, and the daemon's inbox item carries the line and the upgrade command. While a project's profile on disk doesn't read (a minimum above this conductor, a schema problem, another protocol), the scheduler launches none of the project's items: each waits in `conduct queue` as `profile refused: <its first problem>`, since a new worktree would hold the same file and its verbs would refuse it. A profile that reads but whose rules are refused, or that renames the project, keeps the last good profile and launches as before. Workers already running carry on, and launches resume on the first tick after the file loads.
755
+
756
+ `src/profile-fields.ts` records the conductor that first read each field as it is written today (`FIELD_SINCE`, ATK-577), and its type makes a schema field without a record a typecheck error. Fields that 2.0.0 read, the first conductor that reads protocol 2, need no minimum: an older one refuses the profile on `protocol` first. `minimumProblems` reads a profile as written, so a field a default fills in doesn't count. It names each field the profile writes that is newer than its minimum, or newer than 2.0.0 when the profile sets none. A conductor test holds ATK's `.claude/conductor.json` to it, and `atk-conductor-ci` runs on changes to that file. Any other project hears it from `conduct project check`, as a `warn` on its profile check.
757
+
758
+ A PR that adds or reshapes a field can't know the number semantic-release will give it, so it takes the next one:
759
+
760
+ 1. Find the newest conductor tag: `git tag -l 'conductor-v*' --sort=-v:refname` (after a `git fetch --tags`). On `develop` the next release is its `-dev.N` plus one, such as `3.0.0-dev.12` after `3.0.0-dev.11`, unless the PR's commits make a bigger bump than that series: after a stable release, the first `-dev.1` of the version its commit type makes (a fix's patch, a feature's minor), and for a breaking change the next major's `-dev.1`, as `2.2.0-dev.3` was followed by `3.0.0-dev.1`.
761
+ 2. Record that version for the field in `FIELD_SINCE`. If ATK's profile writes the field in the same PR, raise its `conductor` to it too. Its launches are then held, with the upgrade line, until the daemon runs that release (`conduct upgrade --tag dev`, once Jason has approved its stage).
762
+ 3. After the merge, `conduct runs <merge>` gives the version `atk-conductor-release` staged. If another conductor PR took the number first, the record and the minimum are one too low: fix both in a follow-up. Too low lets the version before the field read the profile, and fail with the field list this key replaces. Too high holds launches until that version exists.
763
+
764
+ A `test`, `chore` or `docs` change stages no release and records nothing.
765
+
766
+ After an `--allow-downgrade` to a version without those fields, the stored copy no longer validates either: the project shows `the stored profile no longer validates` and isn't conducted until its file, saved without them, is read again.
666
767
 
667
768
  Then `conduct project check <name>` says whether the project can be conducted, before its first launch finds out. Each check prints one line, `ok`, `warn`, `fail` or `skip`, with a fix under a warn or a fail, and the command exits 1 when any check fails (`--json` prints the same as data):
668
769
 
669
- - **profile:** the file reads with this build's schema and keeps the registered name; a `warn` lists the fields that differ from the daemon's stored copy, which it takes on the next save or start. The later checks use the file when it reads, else the stored copy; with neither they are `skip`.
670
- - **auth:** which credential each provider the project uses signs in with (project token, machine token or CLI login; see Accounts), probed as the daemon would. For each that isn't the project's own token, a detail line gives the scopes, the `cmdkey` line and the config key that would scope it; that is advice, and the check passes. A token that is there but refused, or no credential at all, fails.
770
+ - **profile:** the layers (see Projects) read with this build's schema; a `warn` lists the fields that differ from the daemon's stored copy, which it takes on the next save, fetch or start, and each field a file writes that is newer than its `conductor` minimum (`minimumProblems`, above), with the version to raise it to (ATK-580). A project still registered by a checkout fails, with the `conduct project add` that moves it to a clone. The later checks use the resolved profile when it reads, else the stored copy; with neither they are `skip`.
771
+ - **auth:** which credential each provider the project uses signs in with (project token, machine token or CLI login; see Accounts), probed as the daemon would. For each that isn't the project's own token, a detail line gives the scopes, the line that saves a token in the platform's store (`cmdkey`, `security` or `secret-tool`) and the config key that would scope it; that is advice, and the check passes. A token that is there but refused, or no credential at all, fails.
671
772
  - **tracker:** the tracker's login answers, and the queue reads (Linear: the team, and whether any of its projects has a priority; Boards: the saved query; GitHub Issues: the labelled issues).
672
773
  - **code-host** and **ci:** the code host's login answers and the base branch exists; each release's `pipeline` names exactly one of the repo's pipelines.
673
- - **worktree:** the launch's first steps on a throwaway `conduct-check-<time>`: the worktree hooks create it, its skills match `.atk-lock.json`, and it is removed, whatever happened. The one check that writes; `--no-worktree` skips it, since the create hook runs `pnpm install`.
674
- - **skills:** `skills.work` is there and declares `protocol: 2` in its SKILL.md frontmatter (worker protocol 2), `skills.verify` is there, and `atk audit` finds the installed ones unchanged; a missing alias is a `warn`. A skill named `conductor:<skill>` is read from this package's plugin and isn't audited, and beside a plugin work skill the aliases only name older notes' headings, so they aren't checked; any other is read from the main checkout.
675
- - **ports:** the broker has a free slot for a new worktree, up to `ports.maxSlot`, saving nothing.
774
+ - **worktree:** the launch's worktree steps on a throwaway `conduct-check-<time>` in the project's worktrees folder: `git worktree add` in the clone from `origin/<base>`, `localFilesFrom`'s files, the ports the broker would give, and `setup`. Then the profile's skills must be there after it, and a `warn` says when git doesn't ignore `.claude/settings.local.json`, where the ports go. A `claude --bg` with no prompt then checks that Claude Code would start a session there: it starts idle, costs no tokens and is removed at once. Claude Code keeps workspace trust per repository, so a clone nobody has opened in Claude Code fails here with the one step that trusts it, `claude` run in the clone once with its trust prompt accepted (ATK-571). It is removed with its branch, whatever happened. The one check that writes; `--no-worktree` skips it, since setup can take a while (ATK's runs `pnpm install`).
775
+ - **skills:** a `conductor:<skill>` is in this package's plugin, and `skills.work` declares `protocol: 2` in its SKILL.md frontmatter (worker protocol 2). A project's own skills arrive through its `setup` (ATK's runs `atk install`), not in the clone, so the worktree check looks for them.
776
+ - **ports:** the machine's pool has a free port for each of the profile's `ports`, saving nothing; `skip` for a profile with none.
676
777
  - **health:** each `health` URL answers; a `warn` at most, since an environment can be down.
677
778
 
678
779
  With the daemon running it checks through the API, as the daemon's own accounts; without it, here, as the machine's.
679
780
 
781
+ A new worktree's local files come from the profile (design note v2, section 2; see Workers):
782
+
783
+ ```jsonc
784
+ // The dev ports a worktree needs, by name: CONDUCTOR_PORT_WEB and CONDUCTOR_PORT_API.
785
+ "ports": ["web", "api"],
786
+ // Run in order in each new worktree; they build its gitignored files from what the repo commits.
787
+ "setup": ["pnpm install --frozen-lockfile", "node scripts/dev-ports.mjs assign"],
788
+ // Optional: copy the .worktreeinclude files of a checkout you keep, for local files made by hand.
789
+ "localFilesFrom": "C:\\Users\\you\\src\\project"
790
+ ```
791
+
680
792
  The profile's optional `work` section is for the project's work skill; the daemon only checks it:
681
793
 
682
794
  ```jsonc
@@ -696,7 +808,7 @@ conduct upgrade
696
808
 
697
809
  It takes the tag the installed version came from (`dev` for an `X.Y.Z-dev.N`, `latest` otherwise; `--tag` picks one), and does nothing when that tag's version is already installed. When the tag points at an older version (semver, so `1.2.0-dev.4` is older than `1.2.0`), it refuses before it stops anything and names that version; `--allow-downgrade` installs it anyway and reports `downgraded`. Otherwise it stops the daemon, runs `npm install --global @detergent-software/conductor@<the tag's version>` (the exact version it compared, in case the tag moves) and starts the daemon again: through the `Conductor` logon task when the task runs this `cli.js`, else as a detached `conduct supervise --fail-fast`. A supervisor waiting to restart a daemon that keeps dying is stopped the same way before npm runs (see Restarts), so it can't restart `serve` from the `cli.js` npm is replacing, and the conductor starts again on the new version. A daemon that wasn't running stays stopped. If npm fails, the daemon still starts again on whatever npm left in place, and `upgrade` exits 1 with npm's output. A linked build (below) refuses: its `cli.js` isn't under npm's global `node_modules`.
698
810
 
699
- **From a checkout instead (development).** `npm link` puts the main checkout's build on PATH, so every worktree and the logon task run that build. Run it from the main checkout, and upgrade by pulling `develop`, building, then `conduct stop` and `conduct serve`:
811
+ **From a checkout instead (development).** `npm link` puts a checkout's build on PATH, so every worktree and the logon task run that build. Run it from your own checkout of the conductor's repo, and upgrade by pulling `develop`, building, then `conduct stop` and `conduct serve`:
700
812
 
701
813
  ```bash
702
814
  pnpm install
@@ -714,7 +826,7 @@ The console (design note, section 11) is the one Claude session that stays open
714
826
  The console belongs to the machine, not to a project (design note v2, section 1): it runs in `<home>/console` (`~/.conductor/console`), a folder of the conductor's own, and opens with no project registered. It reads items through the `conduct` verbs, which find the project from the item while the daemon runs, and a subagent that reads a project's code or logs works in that project's checkout, from `conduct status`.
715
827
 
716
828
  ```bash
717
- conduct console # a tab in Windows Terminal (window "conductor"), in ~/.conductor/console
829
+ conduct console # a tab in ~/.conductor/console: Windows Terminal (window "conductor"), iTerm or Terminal, or tmux (session conductor)
718
830
  conduct console --here # the same session in this terminal
719
831
  ```
720
832
 
@@ -114,7 +114,7 @@ async function briefHere(paths, item, io, why) {
114
114
  if (!ITEM.test(item))
115
115
  throw new ConductorError(`"${item}" is not a tracker item, such as ATK-311`);
116
116
  const key = item.toUpperCase();
117
- const here = await checkoutProject(io.cwd, key, why, 'read it from');
117
+ const here = await checkoutProject(paths, io.cwd, key, why, 'read it from');
118
118
  if ('refusal' in here)
119
119
  return notBriefed(here.refusal);
120
120
  const { profile } = here;
@@ -1 +1 @@
1
- {"version":3,"file":"brief-cli.js","sourceRoot":"","sources":["../src/brief-cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"brief-cli.js","sourceRoot":"","sources":["../src/brief-cli.ts"],"names":[],"mappings":"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"}