@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.
- package/README.md +124 -100
- package/SPECS.md +103 -84
- package/dist/cli.js +32 -34
- package/dist/cli.js.map +1 -1
- package/dist/config/agent-shorthand.d.ts +0 -1
- package/dist/config/agent-shorthand.d.ts.map +1 -1
- package/dist/config/agent-shorthand.js +1 -9
- package/dist/config/agent-shorthand.js.map +1 -1
- package/dist/config/defaults.d.ts +0 -2
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +0 -2
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/find-config.d.ts +3 -2
- package/dist/config/find-config.d.ts.map +1 -1
- package/dist/config/find-config.js +4 -4
- package/dist/config/find-config.js.map +1 -1
- package/dist/config/home.js +2 -2
- package/dist/config/home.js.map +1 -1
- package/dist/config/load-config.d.ts +2 -2
- package/dist/config/load-config.d.ts.map +1 -1
- package/dist/config/load-config.js +46 -29
- package/dist/config/load-config.js.map +1 -1
- package/dist/config/parse-args.d.ts.map +1 -1
- package/dist/config/parse-args.js +50 -48
- package/dist/config/parse-args.js.map +1 -1
- package/dist/config/types.d.ts +40 -24
- package/dist/config/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/loop/authority.d.ts +3 -4
- package/dist/loop/authority.d.ts.map +1 -1
- package/dist/loop/authority.js +27 -22
- package/dist/loop/authority.js.map +1 -1
- package/dist/loop/context.d.ts +8 -3
- package/dist/loop/context.d.ts.map +1 -1
- package/dist/loop/deliveries.d.ts +16 -16
- package/dist/loop/deliveries.d.ts.map +1 -1
- package/dist/loop/deliveries.js +35 -187
- package/dist/loop/deliveries.js.map +1 -1
- package/dist/loop/describe.d.ts +4 -6
- package/dist/loop/describe.d.ts.map +1 -1
- package/dist/loop/describe.js +2 -2
- package/dist/loop/describe.js.map +1 -1
- package/dist/loop/drive.d.ts +4 -6
- package/dist/loop/drive.d.ts.map +1 -1
- package/dist/loop/drive.js +9 -33
- package/dist/loop/drive.js.map +1 -1
- package/dist/loop/features.d.ts +23 -0
- package/dist/loop/features.d.ts.map +1 -0
- package/dist/loop/features.js +571 -0
- package/dist/loop/features.js.map +1 -0
- package/dist/loop/journal.d.ts +1 -1
- package/dist/loop/journal.js +2 -2
- package/dist/loop/journal.js.map +1 -1
- package/dist/loop/lock.d.ts +1 -1
- package/dist/loop/lock.js +1 -1
- package/dist/loop/open-host.d.ts.map +1 -1
- package/dist/loop/open-host.js +23 -24
- package/dist/loop/open-host.js.map +1 -1
- package/dist/loop/probe.d.ts +1 -1
- package/dist/loop/probe.d.ts.map +1 -1
- package/dist/loop/probe.js +51 -22
- package/dist/loop/probe.js.map +1 -1
- package/dist/loop/process-tree.d.ts +1 -1
- package/dist/loop/process-tree.js +1 -1
- package/dist/loop/report.d.ts +9 -7
- package/dist/loop/report.d.ts.map +1 -1
- package/dist/loop/report.js +30 -99
- package/dist/loop/report.js.map +1 -1
- package/dist/loop/streams.d.ts +5 -5
- package/dist/loop/streams.d.ts.map +1 -1
- package/dist/loop/streams.js +3 -3
- package/dist/loop/streams.js.map +1 -1
- package/dist/loop/tick.d.ts +6 -4
- package/dist/loop/tick.d.ts.map +1 -1
- package/dist/loop/tick.js +50 -78
- package/dist/loop/tick.js.map +1 -1
- package/dist/loop/trace.d.ts +5 -5
- package/dist/loop/trace.d.ts.map +1 -1
- package/dist/loop/trace.js +5 -14
- package/dist/loop/trace.js.map +1 -1
- package/dist/loop/transformers.d.ts +3 -13
- package/dist/loop/transformers.d.ts.map +1 -1
- package/dist/loop/transformers.js +3 -53
- package/dist/loop/transformers.js.map +1 -1
- package/dist/loop/warm.d.ts +3 -3
- package/dist/loop/warm.js +3 -3
- package/dist/loop/work-line.d.ts +1 -1
- package/dist/operator/agent-plugins.d.ts +11 -0
- package/dist/operator/agent-plugins.d.ts.map +1 -1
- package/dist/operator/agent-plugins.js +3 -3
- package/dist/operator/agent-plugins.js.map +1 -1
- package/dist/operator/board.d.ts +3 -8
- package/dist/operator/board.d.ts.map +1 -1
- package/dist/operator/board.js +2 -11
- package/dist/operator/board.js.map +1 -1
- package/dist/operator/cancel.d.ts +2 -2
- package/dist/operator/cancel.js +6 -6
- package/dist/operator/cancel.js.map +1 -1
- package/dist/operator/doctor.d.ts +9 -0
- package/dist/operator/doctor.d.ts.map +1 -1
- package/dist/operator/doctor.js +32 -25
- package/dist/operator/doctor.js.map +1 -1
- package/dist/operator/explain.d.ts +76 -0
- package/dist/operator/explain.d.ts.map +1 -0
- package/dist/operator/explain.js +556 -0
- package/dist/operator/explain.js.map +1 -0
- package/dist/operator/film.d.ts +3 -11
- package/dist/operator/film.d.ts.map +1 -1
- package/dist/operator/film.js +8 -90
- package/dist/operator/film.js.map +1 -1
- package/dist/operator/init.d.ts.map +1 -1
- package/dist/operator/init.js +41 -49
- package/dist/operator/init.js.map +1 -1
- package/dist/operator/live.js +1 -1
- package/dist/operator/live.js.map +1 -1
- package/dist/operator/log.js +3 -4
- package/dist/operator/log.js.map +1 -1
- package/dist/operator/release.d.ts +2 -2
- package/dist/operator/release.js +7 -7
- package/dist/operator/release.js.map +1 -1
- package/dist/operator/run.d.ts +25 -0
- package/dist/operator/run.d.ts.map +1 -0
- package/dist/operator/run.js +70 -0
- package/dist/operator/run.js.map +1 -0
- package/dist/operator/setup.d.ts.map +1 -1
- package/dist/operator/setup.js +20 -16
- package/dist/operator/setup.js.map +1 -1
- package/dist/plugins/manager.d.ts +33 -2
- package/dist/plugins/manager.d.ts.map +1 -1
- package/dist/plugins/manager.js +67 -0
- package/dist/plugins/manager.js.map +1 -1
- 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
|
-
|
|
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
|
|
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
|
|
63
|
-
| `mason
|
|
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
|
|
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 `
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
`--
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
| `
|
|
170
|
-
| `
|
|
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 `
|
|
174
|
-
| `workLine.warm` | Optional `cmd` / `timeoutMs`. Runs
|
|
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
|
|
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
|
-
| `
|
|
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
|
|
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
|
|
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>/<
|
|
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
|
|
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: `
|
|
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
|
|
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 `
|
|
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
|
-
|
|
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 `
|
|
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
|
|
291
|
-
| A
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
366
|
-
`--
|
|
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
|
-
|
|
407
|
+
ticket, which makes nothing.
|
|
377
408
|
|
|
378
409
|
### Assembly fix
|
|
379
410
|
|
|
380
|
-
Spawned in the
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
475
|
-
|
|
476
|
-
|
|
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
|
|
490
|
-
and that is the end of it. With one, the assembled
|
|
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
|
|
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
|
|
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 `
|
|
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
|
-
|
|
563
|
-
|
|
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
|
-
`
|
|
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
|
|
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
|
```
|