@bluewombat/runtime 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/README.md +124 -100
  2. package/SPECS.md +103 -84
  3. package/dist/cli.js +32 -34
  4. package/dist/cli.js.map +1 -1
  5. package/dist/config/agent-shorthand.d.ts +0 -1
  6. package/dist/config/agent-shorthand.d.ts.map +1 -1
  7. package/dist/config/agent-shorthand.js +1 -9
  8. package/dist/config/agent-shorthand.js.map +1 -1
  9. package/dist/config/defaults.d.ts +0 -2
  10. package/dist/config/defaults.d.ts.map +1 -1
  11. package/dist/config/defaults.js +0 -2
  12. package/dist/config/defaults.js.map +1 -1
  13. package/dist/config/find-config.d.ts +3 -2
  14. package/dist/config/find-config.d.ts.map +1 -1
  15. package/dist/config/find-config.js +4 -4
  16. package/dist/config/find-config.js.map +1 -1
  17. package/dist/config/home.js +2 -2
  18. package/dist/config/home.js.map +1 -1
  19. package/dist/config/load-config.d.ts +2 -2
  20. package/dist/config/load-config.d.ts.map +1 -1
  21. package/dist/config/load-config.js +46 -29
  22. package/dist/config/load-config.js.map +1 -1
  23. package/dist/config/parse-args.d.ts.map +1 -1
  24. package/dist/config/parse-args.js +50 -48
  25. package/dist/config/parse-args.js.map +1 -1
  26. package/dist/config/types.d.ts +40 -24
  27. package/dist/config/types.d.ts.map +1 -1
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +1 -1
  31. package/dist/index.js.map +1 -1
  32. package/dist/loop/authority.d.ts +3 -4
  33. package/dist/loop/authority.d.ts.map +1 -1
  34. package/dist/loop/authority.js +27 -22
  35. package/dist/loop/authority.js.map +1 -1
  36. package/dist/loop/context.d.ts +8 -3
  37. package/dist/loop/context.d.ts.map +1 -1
  38. package/dist/loop/deliveries.d.ts +16 -16
  39. package/dist/loop/deliveries.d.ts.map +1 -1
  40. package/dist/loop/deliveries.js +35 -187
  41. package/dist/loop/deliveries.js.map +1 -1
  42. package/dist/loop/describe.d.ts +4 -6
  43. package/dist/loop/describe.d.ts.map +1 -1
  44. package/dist/loop/describe.js +2 -2
  45. package/dist/loop/describe.js.map +1 -1
  46. package/dist/loop/drive.d.ts +4 -6
  47. package/dist/loop/drive.d.ts.map +1 -1
  48. package/dist/loop/drive.js +9 -33
  49. package/dist/loop/drive.js.map +1 -1
  50. package/dist/loop/features.d.ts +23 -0
  51. package/dist/loop/features.d.ts.map +1 -0
  52. package/dist/loop/features.js +571 -0
  53. package/dist/loop/features.js.map +1 -0
  54. package/dist/loop/journal.d.ts +1 -1
  55. package/dist/loop/journal.js +2 -2
  56. package/dist/loop/journal.js.map +1 -1
  57. package/dist/loop/lock.d.ts +1 -1
  58. package/dist/loop/lock.js +1 -1
  59. package/dist/loop/open-host.d.ts.map +1 -1
  60. package/dist/loop/open-host.js +23 -24
  61. package/dist/loop/open-host.js.map +1 -1
  62. package/dist/loop/probe.d.ts +1 -1
  63. package/dist/loop/probe.d.ts.map +1 -1
  64. package/dist/loop/probe.js +51 -22
  65. package/dist/loop/probe.js.map +1 -1
  66. package/dist/loop/process-tree.d.ts +1 -1
  67. package/dist/loop/process-tree.js +1 -1
  68. package/dist/loop/report.d.ts +9 -7
  69. package/dist/loop/report.d.ts.map +1 -1
  70. package/dist/loop/report.js +30 -99
  71. package/dist/loop/report.js.map +1 -1
  72. package/dist/loop/streams.d.ts +5 -5
  73. package/dist/loop/streams.d.ts.map +1 -1
  74. package/dist/loop/streams.js +3 -3
  75. package/dist/loop/streams.js.map +1 -1
  76. package/dist/loop/tick.d.ts +6 -4
  77. package/dist/loop/tick.d.ts.map +1 -1
  78. package/dist/loop/tick.js +50 -78
  79. package/dist/loop/tick.js.map +1 -1
  80. package/dist/loop/trace.d.ts +5 -5
  81. package/dist/loop/trace.d.ts.map +1 -1
  82. package/dist/loop/trace.js +5 -14
  83. package/dist/loop/trace.js.map +1 -1
  84. package/dist/loop/transformers.d.ts +3 -13
  85. package/dist/loop/transformers.d.ts.map +1 -1
  86. package/dist/loop/transformers.js +3 -53
  87. package/dist/loop/transformers.js.map +1 -1
  88. package/dist/loop/warm.d.ts +3 -3
  89. package/dist/loop/warm.js +3 -3
  90. package/dist/loop/work-line.d.ts +1 -1
  91. package/dist/operator/agent-plugins.d.ts +11 -0
  92. package/dist/operator/agent-plugins.d.ts.map +1 -1
  93. package/dist/operator/agent-plugins.js +3 -3
  94. package/dist/operator/agent-plugins.js.map +1 -1
  95. package/dist/operator/board.d.ts +3 -8
  96. package/dist/operator/board.d.ts.map +1 -1
  97. package/dist/operator/board.js +2 -11
  98. package/dist/operator/board.js.map +1 -1
  99. package/dist/operator/cancel.d.ts +2 -2
  100. package/dist/operator/cancel.js +6 -6
  101. package/dist/operator/cancel.js.map +1 -1
  102. package/dist/operator/doctor.d.ts +9 -0
  103. package/dist/operator/doctor.d.ts.map +1 -1
  104. package/dist/operator/doctor.js +32 -25
  105. package/dist/operator/doctor.js.map +1 -1
  106. package/dist/operator/explain.d.ts +76 -0
  107. package/dist/operator/explain.d.ts.map +1 -0
  108. package/dist/operator/explain.js +556 -0
  109. package/dist/operator/explain.js.map +1 -0
  110. package/dist/operator/film.d.ts +3 -11
  111. package/dist/operator/film.d.ts.map +1 -1
  112. package/dist/operator/film.js +8 -90
  113. package/dist/operator/film.js.map +1 -1
  114. package/dist/operator/init.d.ts.map +1 -1
  115. package/dist/operator/init.js +41 -49
  116. package/dist/operator/init.js.map +1 -1
  117. package/dist/operator/live.js +1 -1
  118. package/dist/operator/live.js.map +1 -1
  119. package/dist/operator/log.js +3 -4
  120. package/dist/operator/log.js.map +1 -1
  121. package/dist/operator/release.d.ts +2 -2
  122. package/dist/operator/release.js +7 -7
  123. package/dist/operator/release.js.map +1 -1
  124. package/dist/operator/run.d.ts +25 -0
  125. package/dist/operator/run.d.ts.map +1 -0
  126. package/dist/operator/run.js +70 -0
  127. package/dist/operator/run.js.map +1 -0
  128. package/dist/operator/setup.d.ts.map +1 -1
  129. package/dist/operator/setup.js +20 -16
  130. package/dist/operator/setup.js.map +1 -1
  131. package/dist/plugins/manager.d.ts +33 -2
  132. package/dist/plugins/manager.d.ts.map +1 -1
  133. package/dist/plugins/manager.js +67 -0
  134. package/dist/plugins/manager.js.map +1 -1
  135. package/package.json +15 -16
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Host: the process you run, `@bluewombat/runtime`, binary `mason`. It listens,
4
4
  admits, calls Conductor, and reports. It does not know a tracker: it loads one
5
- FeatureManager package and hands it the options it never reads. Contract:
5
+ TicketTracker package and hands it the options it never reads. Contract:
6
6
  [SPECS.md](./SPECS.md).
7
7
 
8
8
  ## Install
@@ -24,12 +24,11 @@ npx mason run
24
24
  npx mason watch
25
25
  ```
26
26
 
27
- A script gets the same result with no questions — `--manager` turns them off:
27
+ A script gets the same result with no questions — `--manager` turns them off (it names the one package that answers both sides):
28
28
 
29
29
  ```bash
30
30
  mason init --manager @bluewombat/manager-github \
31
31
  --manager-option repo=owner/name \
32
- --manager-option labels=mason \
33
32
  --work-line-stable ./work-line-stable \
34
33
  --clone git@github.com:owner/name.git --branch dev
35
34
  mason setup --apply
@@ -52,15 +51,43 @@ package's README — Host does not grow a `--repo` flag for it.
52
51
 
53
52
  | Command | Job |
54
53
  | --------------- | -------------------------------------------------------------------------------------- |
55
- | `mason run` | Drain the FeatureManager, run Conductor, report |
54
+ | `mason run` | Drain the TicketTracker, run Conductor, report |
56
55
  | `mason watch` | Snapshot the ledger and follow the journal. Ctrl-C leaves the worker running |
57
56
  | `mason status` | Snapshot the ledger, then exit. `--json` for scripts |
58
57
  | `mason log` | Replay the journal, with the reason a phase stopped. `--problems` for just those |
59
58
  | `mason init` | Set this directory up: asks, writes the config and the Builder stub, then runs `setup` |
60
59
  | `mason setup` | Prepare the tracker. A plan by default; `--apply` writes. Exit 1 on a blocked step |
61
60
  | `mason doctor` | Check the config, the slots, and the manager. Exit 1 on any failure |
62
- | `mason cancel` | Abandon a Feature by key, when the tracker cannot say it is gone |
63
- | `mason release` | Drop a held Subtask without waiting for the bail clock |
61
+ | `mason explain` | Say what an agent role starts with: prompt, plugins, skills, the project's profile. Read-only, offline. Exit 1 on a setup every attempt would fail on |
62
+ | `mason cancel` | Abandon a Ticket by key, when the tracker cannot say it is gone |
63
+ | `mason release` | Drop a held unit without waiting for the bail clock |
64
+
65
+ ### What an agent role starts with
66
+
67
+ ```bash
68
+ mason explain builder.producer # one role; no role names all of them
69
+ mason explain --json # the same facts for a script
70
+ ```
71
+
72
+ It reads the config, the role's prompt file, the plugin folders of the home, and — for the
73
+ project's side — the deck requests and locks of the work line as it was last refreshed. It runs
74
+ no agent and fetches nothing. Each line says where it comes from: `[home]` for the role you wrote
75
+ in the Mason home, `[base]` and `[profile]` for the project's deck setup, read from the
76
+ `ai-plugin.lock.json` the project committed (which lists the skills, agents, hooks and MCP servers
77
+ of each plugin, so the plugin does not have to be fetched to be described).
78
+
79
+ What cannot be known is said, not guessed:
80
+
81
+ - before the work line exists, the project's side is "not known yet";
82
+ - a request no committed lock pins, a prompt that does not place a required `{{placeholder}}` or
83
+ uses one the role does not fill, an unreadable prompt file, a missing plugin folder: `FAIL`
84
+ (exit 1), because every attempt of that role would fail the same way;
85
+ - a lock of a version it does not read, a missing profile, two plugins bringing a skill of the
86
+ same name: `warn`;
87
+ - the key of the agent is never printed, only whether its variable is set;
88
+ - a role written as a plain command is said to be one;
89
+ - the final prompt of a ticket, and what the agent's own tool reads from the checkout, are listed
90
+ as not covered.
64
91
 
65
92
  One `run` per ledger: `run` writes `<ledger>/lock` with its pid and a second
66
93
  `run` on the same home refuses to start while that process lives (two runs
@@ -74,15 +101,33 @@ steps it is handed. A manager without `setupManager` says it has nothing to do.
74
101
  `init` takes `--manager NAME` (which turns the questions off), `--manager-option KEY=VALUE`,
75
102
  `--work-line-stable DIR`, `--clone REMOTE`, `--branch NAME`, `--force` and `--interactive`.
76
103
 
104
+ `mason run` speaks before it does anything, so a terminal is never blank: it says that it
105
+ is starting, then the config, the trackers, the ledger and the poll interval, then that it is
106
+ opening the host and that it has started. A tick with work prints one line per step; a loop
107
+ with nothing to do says once a minute that it is polling; a tracker that cannot be read is
108
+ named on every poll. The last line says that it stopped and with which exit code, after the
109
+ error message on stderr when there was one.
110
+
111
+ ```
112
+ 10:28:50 run starting
113
+ 10:28:50 config /path/to/home
114
+ 10:28:50 trackers features @bluewombat/manager-github, tickets @bluewombat/manager-github
115
+ 10:28:50 ledger /path/to/home/.mason/ledger
116
+ 10:28:50 poll every 10s
117
+ 10:28:50 opening ledger, lock, work line and trackers
118
+ 10:28:51 started pid 4242, Ctrl-C to stop
119
+ 10:29:51 waiting nothing to do: 6 poll(s) in 60s
120
+ ```
121
+
77
122
  Leave `mason run` going in one terminal. In another:
78
123
 
79
124
  ```bash
80
125
  mason watch
81
126
  ```
82
127
 
83
- That is the operator surface: the durable state of every Feature, then the film
128
+ That is the operator surface: the durable state of every Ticket, then the film
84
129
  of the current step (`submitted` included). It does not talk to the tracker, and
85
- it cannot `ready` or claim. `status` is the same snapshot without the
130
+ it cannot `resume` or claim. `status` is the same snapshot without the
86
131
  follow. `--json` prints that snapshot as JSON.
87
132
 
88
133
  When a run only printed `unavailable:<key>`, the reason is already in the
@@ -95,19 +140,18 @@ mason log --problems
95
140
  `--all` keeps the idle polls. `--tail N` limits the text film (`0` shows every
96
141
  kept line). `--json` prints every kept line; with `--tail`, a truncated reply
97
142
  names how many were kept and how many are shown. The closing tally counts each
98
- distinct failure. A pause with no planner exit code is counted apart from a
99
- non-zero exit. If a slot was started with `--transcript-dir`, the newest
143
+ distinct failure. If a slot was started with `--transcript-dir`, the newest
100
144
  transcript files are named underneath, with the agent exit and duration read
101
145
  from the start of each file.
102
146
 
103
- To abandon a Feature the tracker can no longer mention (a deleted issue, a
147
+ To abandon a Ticket the tracker can no longer mention (a deleted issue, a
104
148
  manager with no `probe`), stop `run` if it holds the ledger lock, then:
105
149
 
106
150
  ```bash
107
151
  mason cancel github:owner/name#19
108
152
  ```
109
153
 
110
- After a crash left a Subtask `running` with nobody on it, stop `run` if it
154
+ After a crash left a unit `running` with nobody on it, stop `run` if it
111
155
  holds the lock, then:
112
156
 
113
157
  ```bash
@@ -122,7 +166,7 @@ crash — the ledger is. The file can grow; there is no rotation yet.
122
166
  `mason.config.yaml`, found by walking up from the working directory. `--config
123
167
  FILE` names another one. Relative paths resolve against the file; relative
124
168
  flag paths resolve against the working directory. Flags override the file, and
125
- `--manager-option` overrides one manager option without dropping the others.
169
+ `--feature-tracker-option` and `--ticket-tracker-option` override one option of that side without dropping the others.
126
170
  Parsed with the `yaml` package (YAML 1.2 core schema), so a repeated key is
127
171
  refused rather than silently keeping the last one, and `no` / `on` / `off`
128
172
  stay plain strings — never coerced to a boolean the way YAML 1.1 would. A
@@ -130,22 +174,22 @@ value that starts with `@`, like every `@bluewombat/...` package name, needs
130
174
  quotes: `@` is a reserved YAML indicator at the start of a plain scalar.
131
175
 
132
176
  ```yaml
133
- manager: "@bluewombat/manager-fake"
134
- managerOptions:
135
- source: ./.mason/source
136
- target: ./.mason/threads
177
+ featureTracker:
178
+ package: "@bluewombat/manager-fake"
179
+ options:
180
+ source: ./.mason/source
181
+ target: ./.mason/threads
182
+ ticketTracker:
183
+ package: "@bluewombat/manager-fake"
184
+ options:
185
+ source: ./.mason/source
186
+ target: ./.mason/threads
137
187
  workLine:
138
188
  stable: ./work-line-stable
139
189
  isolation: "@bluewombat/isolation-copy"
140
190
  warm:
141
191
  cmd: [pnpm, install, --frozen-lockfile]
142
192
  timeoutMs: 600000
143
- planner:
144
- cmd:
145
- - node
146
- - ./node_modules/@bluewombat/slots/planners/one-subtask.mjs
147
- timeoutMs: 600000
148
- gates: { defaultTimeoutMs: 120000, gates: [] }
149
193
  builder:
150
194
  producer:
151
195
  cmd: [node, ./mason-builder.mjs]
@@ -166,35 +210,34 @@ pollIntervalMs: 10000
166
210
 
167
211
  | Field | Meaning |
168
212
  | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
169
- | `manager` | Package name or path that exports `createManager` |
170
- | `managerOptions` | Opaque to Host. What it holds is the manager's own documentation |
213
+ | `featureTracker` | `package` (a name or path that exports `createManager`) and `options`: where Features are written and signalled |
214
+ | `ticketTracker` | Same shape: where the Tickets of a Feature are, and the Authority that holds the lines. May name the same package as `featureTracker`, or another |
171
215
  | `workLine.stable` | Existing directory the work folds into. Optional when the manager names a reference work line: Host then keeps its own copy at `<home>/work-line` |
172
216
  | `workLine.isolation` | Package name or path exporting `strategy` — required. Host loads it like a manager; Isolator/Integrator do not sniff |
173
- | `workLine.isolationOptions` | What that strategy is told, unread by Host — like `managerOptions`. `isolation-git` reads `exclude`, the paths a Child never gets (default `.env`, `.env.*`). A strategy without `createStrategy` refuses any |
174
- | `workLine.warm` | Optional `cmd` / `timeoutMs`. Runs once in the Feature workspace after Isolation, before any Subtask is copied from it — typically `pnpm install --frozen-lockfile`. Absent: Subtasks inherit a cold Feature |
217
+ | `workLine.isolationOptions` | What that strategy is told, unread by Host — like a manager's `options`. `isolation-git` reads `exclude`, the paths a Child never gets (default `.env`, `.env.*`). A strategy without `createStrategy` refuses any |
218
+ | `workLine.warm` | Optional `cmd` / `timeoutMs`. Runs in the workspace after Isolation, before the Builder — typically `pnpm install --frozen-lockfile`. Absent: the Builder gets a cold tree |
175
219
  | `workLine.branch` | The work line a fold lands on. Without it, what the reference names, or else whatever is checked out |
176
220
  | `authority` | `enabled`, the `publish` / `refresh` slots, and the optional `describe` slot (§ Describer). Absent: the fold is local |
177
221
  | `home` | Where Host keeps what is its own — default `./.mason` |
178
- | `workspaceRoot` | Isolated feature / Subtask directories (created). Default `<home>/workspaces` |
222
+ | `workspaceRoot` | Isolated directories (created). Default `<home>/workspaces` |
179
223
  | `ledger` | WorkLedger root (created). The Cursor is a file inside it. Default `<home>/ledger` |
180
224
  | `persist` | Package name or path exporting `openPersist({ ledgerRoot })`: how the ledger is stored under that root. Default `@bluewombat/persist-fs`; `@bluewombat/persist-sqlite` ships too. `watch` reads through the same backend |
181
225
  | `agents` | Agents a pass names instead of writing `cmd` (§ Agent passes written short) |
182
- | `planner` | `cmd` / `timeoutMs` / `gates`. FeatureStandard in, a Plan out. Its own `gates` judges `workLineStable` once a Plan is otherwise accepted — not where the Planner agent itself reads from |
183
- | `builder.producer` | `cmd` / `timeoutMs` / `gates`. Spawned in the Subtask workspace. Exit 0 runs its own `gates` |
226
+ | `builder.producer` | `cmd` / `timeoutMs` / `gates`. Spawned in the workspace. Exit 0 runs its own `gates` |
184
227
  | `builder.repair` | The same, for a pass a Gate refused. **Required**, and never inherited — including its `gates`: a repair with none of its own runs ungated, even when `builder.producer.gates` is not empty |
185
228
  | `builder.maxAttempts` | Attempts one Task may start. Default 3 |
186
229
  | `assembly.fix` | `cmd` / `timeoutMs` / `gates`. Spawned when a judgement of the whole refused it — by an Authority, by `assembly.validate`, or by both. Judged by its own `gates` |
187
- | `assembly.validate` | `cmd` / `timeoutMs` / `gates`. Optional. A local, read-only judge of the assembled feature, run after align, with or without an Authority. A refusal is repaired by `assembly.fix` the same as an Authority's. Judged by its own `gates`, never `builder`'s or `assembly.fix`'s |
230
+ | `assembly.validate` | `cmd` / `timeoutMs` / `gates`. Optional. A local, read-only judge of the assembled ticket, run after align, with or without an Authority. A refusal is repaired by `assembly.fix` the same as an Authority's. Judged by its own `gates`, never `builder`'s or `assembly.fix`'s |
188
231
  | `assembly.maxAttempts` | Attempts that one fix may start. Default 3 |
189
- | `assembly.gates` | `defaultTimeoutMs` and `gates`: the produce:false judgement-only pass — no producer of its own, re-checking the assembled feature. Empty: the Authority judges alone. Independent of `assembly.fix.gates` / `assembly.validate.gates` — never shared with either |
232
+ | `assembly.gates` | `defaultTimeoutMs` and `gates`: the produce:false judgement-only pass — no producer of its own, re-checking the assembled ticket. Empty: the Authority judges alone. Independent of `assembly.fix.gates` / `assembly.validate.gates` — never shared with either |
190
233
  | `timeoutMs` | How long a child **outside** a Task may run: manager, isolations |
191
234
  | `maxRefusals` | Times the work may be sent back before it escalates, by an Authority, by `assembly.validate`, or by both — one shared budget. Default 3 |
192
235
  | `pollIntervalMs` | Set it and the process keeps draining until SIGINT. Absent: one tick. Pick it with § Choosing `pollIntervalMs` — 10000 is the floor worth having |
193
- | `observability.streams` | `enabled`, `dir`, `keep`. Films what every child says, as it says it — one file per child under `<dir>/<feature>/`, named in the journal by a `stream-opened` line. `dir` resolves against the config file; default `<home>/streams`. `keep` is `stdout` / `stderr`, default both. Off unless `enabled` is true: a stream is the Project's own code and prompts in the clear |
236
+ | `observability.streams` | `enabled`, `dir`, `keep`. Films what every child says, as it says it — one file per child under `<dir>/<ticket>/`, named in the journal by a `stream-opened` line. `dir` resolves against the config file; default `<home>/streams`. `keep` is `stdout` / `stderr`, default both. Off unless `enabled` is true: a stream is the Project's own code and prompts in the clear |
194
237
 
195
238
  Every `cmd` is named where it is used, and nothing falls back to a neighbour: a
196
239
  `repair` with no command of its own is refused rather than quietly running the
197
- first-pass agent again. `builder` makes a Subtask. `assembly` judges the whole
240
+ first-pass agent again. `builder` makes the unit of work. `assembly` judges the whole
198
241
  and, when that judgement refuses it, runs `assembly.fix` — not a second first-pass.
199
242
  `assembly.validate`, when declared, is a second, local judge of the whole: it
200
243
  runs after align, before the Authority sees the work (or before the final
@@ -223,20 +266,13 @@ agents:
223
266
  denyShell: [] # commands refused to the agent, e.g. [gh, vercel]; ssh and scp always are
224
267
  transcripts: ./.mason/transcripts
225
268
  pluginsOut: ./.mason/plugins # where deck profiles are built
226
- planner:
227
- agent: cursor
228
- prompt: ./prompts/planner.md
229
- read: ./.mason/work-line # planner only
230
- plugins: [./ai-plugins/core/planner]
231
- profile: planner
232
- args: [--plan] # the vendor CLI's own flags
233
- timeoutMs: 600000
234
269
  builder:
235
270
  producer:
236
271
  agent: cursor
237
272
  prompt: ./prompts/builder.md
238
273
  plugins: [./ai-plugins/core/builder]
239
274
  profile: builder
275
+ args: [--mode, agent] # the vendor CLI's own flags
240
276
  timeoutMs: 1200000
241
277
  gates: { defaultTimeoutMs: 120000, gates: [] }
242
278
  ```
@@ -245,16 +281,15 @@ Host writes the `cmd` it stands for — `node <slots>/<role>.mjs --prompt-file
245
281
  -- node <slots>/agents/cursor.mjs --transcript-dir … --plugin-dir … --profile
246
282
  … --plugins-out … --agent-arg …` — with `<slots>` the
247
283
  `node_modules/@bluewombat/slots` next to the config. Nothing past the config
248
- knows a pass was written short. The roles: `planner`, `builder.producer`,
284
+ knows a pass was written short. The roles: `builder.producer`,
249
285
  `builder.repair`, `assembly.fix`, `assembly.validate`, and `authority.describe`
250
- (an argv as before, or `{ agent, prompt?, plugins?, profile?, args? }`).
286
+ (an argv, or `{ agent, prompt?, plugins?, profile?, args? }`).
251
287
 
252
288
  | Key | Meaning |
253
289
  | --------- | --------------------------------------------------------------------------------------------------------- |
254
290
  | `agent` | A name `agents` declares. With `cmd` beside it, the pass is refused |
255
291
  | `prompt` | `--prompt-file` of the role slot. Absent: the role's built-in template |
256
292
  | `rules` | `--rules-file` of the role slot |
257
- | `read` | Planner only: the directory the Planner agent reads (`--read`) |
258
293
  | `plugins` | Plugin folders of the Mason home, each a `--plugin-dir` |
259
294
  | `profile` | The project's deck profile for this role. Needs the agent's `pluginsOut`. See the slots' § Agents/Plugins |
260
295
  | `args` | Appended to the agent's own `args`, each an `--agent-arg` |
@@ -263,12 +298,12 @@ A `profile` is read in the project, not in the Mason home: the role gets the
263
298
  base plugins and that profile, as the project's committed deck locks pin them.
264
299
  `mason doctor` checks those locks in the work line without the network.
265
300
 
266
- Every tracker field lives in `managerOptions`. Host does not read them.
301
+ Every tracker field lives in the `options` of its side. Host does not read them.
267
302
 
268
303
  ### Choosing `pollIntervalMs`
269
304
 
270
305
  The sleep between two ticks, and nothing else. While a tick drives work — a
271
- Planner, a Builder, a validate — it runs to the end; the interval does not
306
+ Builder, a validate — it runs to the end; the interval does not
272
307
  touch it. It only sets how long `mason run` takes to notice:
273
308
 
274
309
  - a new issue, or an edit to one;
@@ -276,7 +311,7 @@ touch it. It only sets how long `mason run` takes to notice:
276
311
  that submitted (`docs/DECISIONS.md`, the Authority re-drive row), so on a
277
312
  work line without CI the whole interval is waited for a Gate that answers in
278
313
  two seconds;
279
- - a `ready`, or an issue closed to cancel.
314
+ - a `resume`, or an issue closed to cancel.
280
315
 
281
316
  **What one tick costs**, with `@bluewombat/manager-github` (read in
282
317
  `src/loop/tick.ts` `runOnce`, `src/loop/probe.ts` `abandonGone`, the manager's
@@ -287,8 +322,8 @@ against the token's budget.
287
322
  | The tick | GitHub REST calls | Counted when nothing moved | Besides |
288
323
  | --------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- | ---------------------------------------------- |
289
324
  | Nothing to do | 1: the issues updated since the Cursor, 100 per page | 0 (304) | none: no fetch |
290
- | A Feature in flight | + 1 per Feature that can still be abandoned: is its issue still there | 0 (304) | a `git fetch` of the work line copy (not REST) |
291
- | A Feature `submitted` | + the judgement: `ci-green` asks for the pull request, its check runs and its statuses (about 3) | about 3: `ci-green` is its own process and keeps no `etag` | |
325
+ | A Ticket in flight | + 1 per Ticket that can still be abandoned: is its issue still there | 0 (304) | a `git fetch` of the work line copy (not REST) |
326
+ | A Ticket `submitted` | + the judgement: `ci-green` asks for the pull request, its check runs and its statuses (about 3) | about 3: `ci-green` is its own process and keeps no `etag` | |
292
327
 
293
328
  Reports to the tracker (a comment, a label move: 2 to 4 calls each) happen
294
329
  when the work moves, not per tick, and each changes the listing: the read
@@ -298,7 +333,7 @@ after a report is a full one.
298
333
  (GitHub's primary rate limit). It is shared by every caller using that token:
299
334
  the reports, `ci-green`, `gh`, and every other Mason home pointed at it.
300
335
 
301
- | `pollIntervalMs` | Idle, nothing moved | A Feature `submitted` (about 3 counted a tick) | Worst case, every read changed (about 5) |
336
+ | `pollIntervalMs` | Idle, nothing moved | A Ticket `submitted` (about 3 counted a tick) | Worst case, every read changed (about 5) |
302
337
  | ---------------- | ------------------- | ---------------------------------------------- | ---------------------------------------- |
303
338
  | 30000 | ~0 /h | 360 /h (7 %) | 600 /h (12 %) |
304
339
  | 15000 | ~0 /h | 720 /h (14 %) | 1,200 /h (24 %) |
@@ -312,14 +347,14 @@ listing. Without conditional reads an idle tick counted one call (360 /h at
312
347
  **The floor.** An idle tick takes 1 to 1.5 s, almost all of it the `listen`
313
348
  call (measured on `tilap/orangemonkey-site`, October 2026). Below 2 to 3 s
314
349
  the loop never sleeps. Below 10 s nothing a person notices is gained: a
315
- Feature takes minutes, and 10 s against 30 s saves about 20 s per Feature,
350
+ Ticket takes minutes, and 10 s against 30 s saves about 20 s per Ticket,
316
351
  mostly the post-Submission wait (30 s of a 5 min 40 s run, measured). Going
317
- lower spends the token while a Feature is submitted, for seconds nobody
352
+ lower spends the token while a Ticket is submitted, for seconds nobody
318
353
  notices.
319
354
 
320
- **So:** 10000 for one Mason home on a token. Idle no longer spends the
355
+ **So:** 10000 for one Mason home on a token. Idle does not spend the
321
356
  budget, so the quota is not what holds the floor: usefulness is, and a
322
- submitted Feature still is (its judgement counts). Several homes on the same
357
+ submitted Ticket still is (its judgement counts). Several homes on the same
323
358
  token add up: multiply the `submitted` and worst-case columns by their count
324
359
  and stay under half the budget. The journal is not a reason either way: quiet
325
360
  ticks are folded into one `idle` line a minute (`src/loop/journal.ts`).
@@ -330,7 +365,7 @@ settle or its timeout ends the attempt.
330
365
 
331
366
  ## Slots
332
367
 
333
- Commands mason spawns and never imports: the Planner, the Builder, each Gate,
368
+ Commands mason spawns and never imports: the Builder, each Gate,
334
369
  and — when an Authority is enabled — the Publisher and the Refresher. Every one
335
370
  reads argv and answers with **one JSON object on stdout**; an exit code alone is
336
371
  not the contract. mason does not pick a producer, and a slot may be written in
@@ -341,10 +376,6 @@ the shipped roles and agents (Cursor CLI, Claude Code), the shipped Gates, and
341
376
  their options. What follows is what Host guarantees them.
342
377
 
343
378
  ```json
344
- "planner": {
345
- "cmd": ["node", "./node_modules/@bluewombat/slots/planners/one-subtask.mjs"],
346
- "timeoutMs": 600000
347
- },
348
379
  "builder": {
349
380
  "producer": {
350
381
  "cmd": [
@@ -362,8 +393,8 @@ composition with `--` is the same.
362
393
 
363
394
  ### Builder
364
395
 
365
- Spawned in the Subtask workspace with `--intention`, `--definition-of-done`,
366
- `--id`, `--attempt`, and `--context`. On a retry it also gets `--report` and
396
+ Spawned in the workspace with `--intention`, `--id`, `--attempt`, and
397
+ `--context`. On a retry it also gets `--report` and
367
398
  `--report-from`: what refused the last pass, and which Gate said it. Exit 0
368
399
  means the Gates may run.
369
400
 
@@ -373,11 +404,11 @@ hides the change from them.
373
404
 
374
405
  The config always names a producer (and a repair). Implementer can still run a
375
406
  Task as its Gate sequence alone — that is the first judgement of the assembled
376
- feature, which makes nothing.
407
+ ticket, which makes nothing.
377
408
 
378
409
  ### Assembly fix
379
410
 
380
- Spawned in the feature workspace when a judgement of the whole refused it
411
+ Spawned in the ticket workspace when a judgement of the whole refused it
381
412
  (`--report`, `--report-from`). Same argv as a Builder otherwise. Host hands
382
413
  Implementer `assembly.fix` as that pass's only agent: there is no first-pass
383
414
  producer at this moment. The refusal it repairs may have come from an
@@ -385,7 +416,7 @@ Authority or from `assembly.validate`.
385
416
 
386
417
  ### Assembly validate
387
418
 
388
- Spawned in the feature workspace after align, with or without an Authority —
419
+ Spawned in the ticket workspace after align, with or without an Authority —
389
420
  `--intention`, `--id`, `--attempt`, `--context`. No `--report`: it is a
390
421
  read-only review, not a repair, and takes nothing a producer would. Optional.
391
422
  Its verdict is not the exit code alone: the slot reads what the agent itself
@@ -394,10 +425,10 @@ that completes cleanly but finds a problem is still a refusal.
394
425
 
395
426
  ### Gates
396
427
 
397
- Five independent sequences, one per role — `planner`, `builder.producer`,
428
+ Four independent sequences, one per role — `builder.producer`,
398
429
  `builder.repair`, `assembly.fix`, `assembly.validate` — plus `assembly.gates`
399
430
  for the one judgement-only pass with no producer of its own (re-checking the
400
- assembled feature; `ci-green` reads the checks the work line ran on what the
431
+ assembled ticket; `ci-green` reads the checks the work line ran on what the
401
432
  Publisher placed, so it belongs there). No sharing, no dispatch choosing
402
433
  between two buckets: a check right for one pass is not necessarily right for
403
434
  another, even within the same stage. `builder.repair` is the sharpest edge —
@@ -405,13 +436,10 @@ it does not inherit `builder.producer.gates`, so a repair Attempt with no
405
436
  Gate of its own runs ungated.
406
437
 
407
438
  Implementer's Gates are told `--stage unit` or `--stage assembly` alongside
408
- `--id`, `--attempt`, `--gate-id`, `--intention` and `--definition-of-done`.
439
+ `--id`, `--attempt`, `--gate-id` and `--intention`.
409
440
  Most have no use for it. `workspace-changed` does: "nothing changed" means
410
441
  nothing was done in a unit, and is the correct outcome for an assembly that
411
- needed nothing. FeatureBreakdown's Gates (`planner.gates`) are told only
412
- `--key` and `--gate-id` — no Attempt counter, no `--stage`, no
413
- `--definition-of-done` — so a Gate written for Implementer's shape is not a
414
- drop-in for `planner.gates`.
442
+ needed nothing.
415
443
 
416
444
  `init` writes an empty list on `builder.producer` and `builder.repair`; add a
417
445
  Gate when the Project has a check.
@@ -419,10 +447,10 @@ Gate when the Project has a check.
419
447
  Every child carries its own ceiling and no other. A Gate entry may name a
420
448
  `timeoutMs`; without one it takes its sequence's `defaultTimeoutMs`, and a Gate
421
449
  that ends up with neither is refused when the config loads. Nothing is derived
422
- from what another child left behind, so a slow producer can no longer leave its
450
+ from what another child left behind, so a slow producer cannot leave its
423
451
  Gates a millisecond to answer in.
424
452
 
425
- What bounds a Subtask is therefore what you wrote:
453
+ What bounds the unit is therefore what you wrote:
426
454
  `builder.maxAttempts × (builder.producer.timeoutMs + Σ builder.producer.gates timeouts)`
427
455
  for a first pass, and the same shape with `repair` in place of `producer` once
428
456
  a Gate has refused one.
@@ -443,16 +471,9 @@ is bounded the same way from `assembly.maxAttempts` and `assembly.fix`.
443
471
  }
444
472
  ```
445
473
 
446
- ### Planner
447
-
448
- FeatureStandard in, a Plan out. It is given `--key`, `--intention`,
449
- `--title` and `--max-units`. `init` writes the
450
- bootstrap Planner — one Subtask that is the intention — from
451
- `@bluewombat/slots/planners/one-subtask.mjs`.
452
-
453
474
  ### Describer
454
475
 
455
- How a delivered feature describes itself — the words the manager puts on the
476
+ How a delivered ticket describes itself — the words the manager puts on the
456
477
  Submission and on the fold — is the Project's, not Host's. Three levels, one
457
478
  key, `authority.describe`:
458
479
 
@@ -460,10 +481,10 @@ key, `authority.describe`:
460
481
  | -------------------------------------- | --------------------------------------------------------------------------------------- | ------------------------- |
461
482
  | not set | the manager's own default: the issue's title, its body as the human wrote it | none |
462
483
  | `messages/conventional.mjs` | `<type>: <title>` (`--scope`, `--type`), the body as written | none |
463
- | `messages/git-producer.mjs -- <agent>` | an agent reads the git diff and writes both under `--rules-file` — the team's guideline | one agent run per feature |
484
+ | `messages/git-producer.mjs -- <agent>` | an agent reads the git diff and writes both under `--rules-file` — the team's guideline | one agent run per ticket |
464
485
 
465
486
  It is an argv like `publish` and `refresh`, bounded by the global `timeoutMs`.
466
- Host spawns it once per feature, in the feature workspace, when the work is
487
+ Host spawns it once per ticket, in the ticket workspace, when the work is
467
488
  offered — with `--id`, `--title`, `--intention` and `--target` (the work line
468
489
  it lands on) — and takes one line back: `{ "subject": "…", "body": "…" }`.
469
490
  Host hands that description to the manager as is; what it becomes is the
@@ -471,12 +492,9 @@ manager's business (for GitHub: the squash's title and message, the pull
471
492
  request's first paragraph). A slot that fails is skipped and the journal says
472
493
  so.
473
494
 
474
- Subtasks are never described: their folds are folded again into the
475
- feature's, so their message is the Subtask's intention — its headline when
476
- the Planner wrote one (a line, a blank line, the rest: the shape of a commit),
477
- else its first sentence cut at a word, no markdown. That headline is also what
478
- the tracker's Plan, the progress comments and the Submission's change list
479
- show, so a Planner is asked to write one.
495
+ The commit that takes up what the Builder made is worded from the title of the
496
+ issue (or the headline of its intention: a line, a blank line, the rest — the
497
+ shape of a commit), else its first sentence cut at a word, no markdown.
480
498
 
481
499
  ### Write another slot
482
500
 
@@ -486,8 +504,8 @@ otherwise repeat is [`@bluewombat/slot-kit`](../slot-kit/README.md).
486
504
 
487
505
  ## Submissions
488
506
 
489
- Without an Authority, a finished feature is folded straight into WorkLineStable
490
- and that is the end of it. With one, the assembled feature is **offered** to an
507
+ Without an Authority, a finished ticket is folded straight into WorkLineStable
508
+ and that is the end of it. With one, the assembled ticket is **offered** to an
491
509
  outside judge first, and only an `accepted` verdict lets it into the work line.
492
510
 
493
511
  It is **declared**, never inferred:
@@ -522,7 +540,7 @@ strategy does not know, a branch the remote does not have, a `workLine.branch`
522
540
  that disagrees with the reference, or a `workLine.stable` that is not a copy of
523
541
  it each stop `mason run` at boot, and `mason doctor` reports the same offline
524
542
  (`reference`, `work line`). Without a reference, `workLine.stable` is required
525
- and is the operator's directory, as before.
543
+ and is the operator's directory.
526
544
 
527
545
  ```
528
546
  assembled → align → assembly.validate (optional, local)
@@ -544,12 +562,12 @@ Isolation must start from that version, not from a copy left behind.
544
562
 
545
563
  A refusal is not a second failure path: its report reaches `assembly.fix`
546
564
  exactly as a Gate's report reaches `builder.repair`. After `maxRefusals`
547
- refusals the feature escalates with that report as its Trace, and `done` names
565
+ refusals the ticket escalates with that report as its Trace, and `done` names
548
566
  the Submission rather than a directory on the machine that ran.
549
567
 
550
568
  ## Write another manager
551
569
 
552
- Host loads whatever `manager` names, as long as it exports `createManager`. The
570
+ Host loads whatever `featureTracker.package` and `ticketTracker.package` name, as long as it exports `createManager`. The
553
571
  contract and a worked example are in
554
572
  [`@bluewombat/manager-kit`](../manager-kit/README.md). Nothing in Host changes.
555
573
 
@@ -559,14 +577,20 @@ contract and a worked example are in
559
577
  import { openHost } from "@bluewombat/runtime";
560
578
 
561
579
  const host = await openHost({
562
- manager: "@bluewombat/manager-fake",
563
- managerOptions: { source: "./.mason/source", target: "./.mason/threads" },
580
+ featureTracker: {
581
+ package: "@bluewombat/manager-fake",
582
+ options: { source: "./.mason/source", target: "./.mason/threads" },
583
+ },
584
+ ticketTracker: {
585
+ package: "@bluewombat/manager-fake",
586
+ options: { source: "./.mason/source", target: "./.mason/threads" },
587
+ },
564
588
  // …paths and slots
565
589
  });
566
590
  await host.runOnce();
567
591
  ```
568
592
 
569
- `manager` also takes an already-loaded module, which is how a test drives Host
593
+ Each `package` also takes an already-loaded module, which is how a test drives Host
570
594
  without resolving a package.
571
595
 
572
596
  ## Stack
@@ -618,7 +642,7 @@ change that breaks it does not merge.
618
642
  Host's code names no plugin. A manager, an isolation strategy, a persistence
619
643
  backend, the shipped slots: each is loaded by the name a config gives, through
620
644
  `plugins/`, never imported. The names Host falls back to — the two isolation
621
- strategies `init` writes, the default `persist`, the bootstrap Planner — are
645
+ strategies `init` writes, the default `persist` — are
622
646
  strings in `config/defaults.ts` and nowhere else; `check-host.mjs` refuses an
623
647
  import of any of them and a spelled-out name anywhere else. Host's
624
648
  `package.json` declares exactly those defaults, so a config `init` wrote runs
@@ -667,6 +691,6 @@ src/
667
691
  config/ argv, JSON config, config discovery → HostOptions; defaults: the plugin names Host ships with
668
692
  plugins/ load: the one loader; manager, isolation, persist: one shape each; discover
669
693
  loop/ open-host (composition), tick (the loop), deliveries, drive, probe, report, authority, work-line, cursor, lock, journal (the film), streams (what a child said), trace, transformers
670
- operator/ init, setup, doctor, live (watch / status), log, film, cancel, release, board, prompt, git-remote
694
+ operator/ run, init, setup, doctor, explain, live (watch / status), log, film, cancel, release, board, prompt, git-remote
671
695
  fixtures/ stand-in slots for the loop's tests
672
696
  ```