@bluewombat/runtime 0.7.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 +126 -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 +2 -1
- package/dist/config/agent-shorthand.d.ts.map +1 -1
- package/dist/config/agent-shorthand.js +30 -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
|
|
@@ -219,22 +262,17 @@ agents:
|
|
|
219
262
|
adapter: cursor # or claude, or the path of an agent wrapper
|
|
220
263
|
home: ./.mason/agent-home # with apiKeyEnv: isolate the vendor (Cursor only)
|
|
221
264
|
apiKeyEnv: CURSOR_API_KEY
|
|
265
|
+
passEnv: [] # operator variables the agent also gets; it otherwise has a short list
|
|
266
|
+
denyShell: [] # commands refused to the agent, e.g. [gh, vercel]; ssh and scp always are
|
|
222
267
|
transcripts: ./.mason/transcripts
|
|
223
268
|
pluginsOut: ./.mason/plugins # where deck profiles are built
|
|
224
|
-
planner:
|
|
225
|
-
agent: cursor
|
|
226
|
-
prompt: ./prompts/planner.md
|
|
227
|
-
read: ./.mason/work-line # planner only
|
|
228
|
-
plugins: [./ai-plugins/core/planner]
|
|
229
|
-
profile: planner
|
|
230
|
-
args: [--plan] # the vendor CLI's own flags
|
|
231
|
-
timeoutMs: 600000
|
|
232
269
|
builder:
|
|
233
270
|
producer:
|
|
234
271
|
agent: cursor
|
|
235
272
|
prompt: ./prompts/builder.md
|
|
236
273
|
plugins: [./ai-plugins/core/builder]
|
|
237
274
|
profile: builder
|
|
275
|
+
args: [--mode, agent] # the vendor CLI's own flags
|
|
238
276
|
timeoutMs: 1200000
|
|
239
277
|
gates: { defaultTimeoutMs: 120000, gates: [] }
|
|
240
278
|
```
|
|
@@ -243,16 +281,15 @@ Host writes the `cmd` it stands for — `node <slots>/<role>.mjs --prompt-file
|
|
|
243
281
|
-- node <slots>/agents/cursor.mjs --transcript-dir … --plugin-dir … --profile
|
|
244
282
|
… --plugins-out … --agent-arg …` — with `<slots>` the
|
|
245
283
|
`node_modules/@bluewombat/slots` next to the config. Nothing past the config
|
|
246
|
-
knows a pass was written short. The roles: `
|
|
284
|
+
knows a pass was written short. The roles: `builder.producer`,
|
|
247
285
|
`builder.repair`, `assembly.fix`, `assembly.validate`, and `authority.describe`
|
|
248
|
-
(an argv
|
|
286
|
+
(an argv, or `{ agent, prompt?, plugins?, profile?, args? }`).
|
|
249
287
|
|
|
250
288
|
| Key | Meaning |
|
|
251
289
|
| --------- | --------------------------------------------------------------------------------------------------------- |
|
|
252
290
|
| `agent` | A name `agents` declares. With `cmd` beside it, the pass is refused |
|
|
253
291
|
| `prompt` | `--prompt-file` of the role slot. Absent: the role's built-in template |
|
|
254
292
|
| `rules` | `--rules-file` of the role slot |
|
|
255
|
-
| `read` | Planner only: the directory the Planner agent reads (`--read`) |
|
|
256
293
|
| `plugins` | Plugin folders of the Mason home, each a `--plugin-dir` |
|
|
257
294
|
| `profile` | The project's deck profile for this role. Needs the agent's `pluginsOut`. See the slots' § Agents/Plugins |
|
|
258
295
|
| `args` | Appended to the agent's own `args`, each an `--agent-arg` |
|
|
@@ -261,12 +298,12 @@ A `profile` is read in the project, not in the Mason home: the role gets the
|
|
|
261
298
|
base plugins and that profile, as the project's committed deck locks pin them.
|
|
262
299
|
`mason doctor` checks those locks in the work line without the network.
|
|
263
300
|
|
|
264
|
-
Every tracker field lives in `
|
|
301
|
+
Every tracker field lives in the `options` of its side. Host does not read them.
|
|
265
302
|
|
|
266
303
|
### Choosing `pollIntervalMs`
|
|
267
304
|
|
|
268
305
|
The sleep between two ticks, and nothing else. While a tick drives work — a
|
|
269
|
-
|
|
306
|
+
Builder, a validate — it runs to the end; the interval does not
|
|
270
307
|
touch it. It only sets how long `mason run` takes to notice:
|
|
271
308
|
|
|
272
309
|
- a new issue, or an edit to one;
|
|
@@ -274,7 +311,7 @@ touch it. It only sets how long `mason run` takes to notice:
|
|
|
274
311
|
that submitted (`docs/DECISIONS.md`, the Authority re-drive row), so on a
|
|
275
312
|
work line without CI the whole interval is waited for a Gate that answers in
|
|
276
313
|
two seconds;
|
|
277
|
-
- a `
|
|
314
|
+
- a `resume`, or an issue closed to cancel.
|
|
278
315
|
|
|
279
316
|
**What one tick costs**, with `@bluewombat/manager-github` (read in
|
|
280
317
|
`src/loop/tick.ts` `runOnce`, `src/loop/probe.ts` `abandonGone`, the manager's
|
|
@@ -285,8 +322,8 @@ against the token's budget.
|
|
|
285
322
|
| The tick | GitHub REST calls | Counted when nothing moved | Besides |
|
|
286
323
|
| --------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- | ---------------------------------------------- |
|
|
287
324
|
| Nothing to do | 1: the issues updated since the Cursor, 100 per page | 0 (304) | none: no fetch |
|
|
288
|
-
| A
|
|
289
|
-
| 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` | |
|
|
290
327
|
|
|
291
328
|
Reports to the tracker (a comment, a label move: 2 to 4 calls each) happen
|
|
292
329
|
when the work moves, not per tick, and each changes the listing: the read
|
|
@@ -296,7 +333,7 @@ after a report is a full one.
|
|
|
296
333
|
(GitHub's primary rate limit). It is shared by every caller using that token:
|
|
297
334
|
the reports, `ci-green`, `gh`, and every other Mason home pointed at it.
|
|
298
335
|
|
|
299
|
-
| `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) |
|
|
300
337
|
| ---------------- | ------------------- | ---------------------------------------------- | ---------------------------------------- |
|
|
301
338
|
| 30000 | ~0 /h | 360 /h (7 %) | 600 /h (12 %) |
|
|
302
339
|
| 15000 | ~0 /h | 720 /h (14 %) | 1,200 /h (24 %) |
|
|
@@ -310,14 +347,14 @@ listing. Without conditional reads an idle tick counted one call (360 /h at
|
|
|
310
347
|
**The floor.** An idle tick takes 1 to 1.5 s, almost all of it the `listen`
|
|
311
348
|
call (measured on `tilap/orangemonkey-site`, October 2026). Below 2 to 3 s
|
|
312
349
|
the loop never sleeps. Below 10 s nothing a person notices is gained: a
|
|
313
|
-
|
|
350
|
+
Ticket takes minutes, and 10 s against 30 s saves about 20 s per Ticket,
|
|
314
351
|
mostly the post-Submission wait (30 s of a 5 min 40 s run, measured). Going
|
|
315
|
-
lower spends the token while a
|
|
352
|
+
lower spends the token while a Ticket is submitted, for seconds nobody
|
|
316
353
|
notices.
|
|
317
354
|
|
|
318
|
-
**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
|
|
319
356
|
budget, so the quota is not what holds the floor: usefulness is, and a
|
|
320
|
-
submitted
|
|
357
|
+
submitted Ticket still is (its judgement counts). Several homes on the same
|
|
321
358
|
token add up: multiply the `submitted` and worst-case columns by their count
|
|
322
359
|
and stay under half the budget. The journal is not a reason either way: quiet
|
|
323
360
|
ticks are folded into one `idle` line a minute (`src/loop/journal.ts`).
|
|
@@ -328,7 +365,7 @@ settle or its timeout ends the attempt.
|
|
|
328
365
|
|
|
329
366
|
## Slots
|
|
330
367
|
|
|
331
|
-
Commands mason spawns and never imports: the
|
|
368
|
+
Commands mason spawns and never imports: the Builder, each Gate,
|
|
332
369
|
and — when an Authority is enabled — the Publisher and the Refresher. Every one
|
|
333
370
|
reads argv and answers with **one JSON object on stdout**; an exit code alone is
|
|
334
371
|
not the contract. mason does not pick a producer, and a slot may be written in
|
|
@@ -339,10 +376,6 @@ the shipped roles and agents (Cursor CLI, Claude Code), the shipped Gates, and
|
|
|
339
376
|
their options. What follows is what Host guarantees them.
|
|
340
377
|
|
|
341
378
|
```json
|
|
342
|
-
"planner": {
|
|
343
|
-
"cmd": ["node", "./node_modules/@bluewombat/slots/planners/one-subtask.mjs"],
|
|
344
|
-
"timeoutMs": 600000
|
|
345
|
-
},
|
|
346
379
|
"builder": {
|
|
347
380
|
"producer": {
|
|
348
381
|
"cmd": [
|
|
@@ -360,8 +393,8 @@ composition with `--` is the same.
|
|
|
360
393
|
|
|
361
394
|
### Builder
|
|
362
395
|
|
|
363
|
-
Spawned in the
|
|
364
|
-
`--
|
|
396
|
+
Spawned in the workspace with `--intention`, `--id`, `--attempt`, and
|
|
397
|
+
`--context`. On a retry it also gets `--report` and
|
|
365
398
|
`--report-from`: what refused the last pass, and which Gate said it. Exit 0
|
|
366
399
|
means the Gates may run.
|
|
367
400
|
|
|
@@ -371,11 +404,11 @@ hides the change from them.
|
|
|
371
404
|
|
|
372
405
|
The config always names a producer (and a repair). Implementer can still run a
|
|
373
406
|
Task as its Gate sequence alone — that is the first judgement of the assembled
|
|
374
|
-
|
|
407
|
+
ticket, which makes nothing.
|
|
375
408
|
|
|
376
409
|
### Assembly fix
|
|
377
410
|
|
|
378
|
-
Spawned in the
|
|
411
|
+
Spawned in the ticket workspace when a judgement of the whole refused it
|
|
379
412
|
(`--report`, `--report-from`). Same argv as a Builder otherwise. Host hands
|
|
380
413
|
Implementer `assembly.fix` as that pass's only agent: there is no first-pass
|
|
381
414
|
producer at this moment. The refusal it repairs may have come from an
|
|
@@ -383,7 +416,7 @@ Authority or from `assembly.validate`.
|
|
|
383
416
|
|
|
384
417
|
### Assembly validate
|
|
385
418
|
|
|
386
|
-
Spawned in the
|
|
419
|
+
Spawned in the ticket workspace after align, with or without an Authority —
|
|
387
420
|
`--intention`, `--id`, `--attempt`, `--context`. No `--report`: it is a
|
|
388
421
|
read-only review, not a repair, and takes nothing a producer would. Optional.
|
|
389
422
|
Its verdict is not the exit code alone: the slot reads what the agent itself
|
|
@@ -392,10 +425,10 @@ that completes cleanly but finds a problem is still a refusal.
|
|
|
392
425
|
|
|
393
426
|
### Gates
|
|
394
427
|
|
|
395
|
-
|
|
428
|
+
Four independent sequences, one per role — `builder.producer`,
|
|
396
429
|
`builder.repair`, `assembly.fix`, `assembly.validate` — plus `assembly.gates`
|
|
397
430
|
for the one judgement-only pass with no producer of its own (re-checking the
|
|
398
|
-
assembled
|
|
431
|
+
assembled ticket; `ci-green` reads the checks the work line ran on what the
|
|
399
432
|
Publisher placed, so it belongs there). No sharing, no dispatch choosing
|
|
400
433
|
between two buckets: a check right for one pass is not necessarily right for
|
|
401
434
|
another, even within the same stage. `builder.repair` is the sharpest edge —
|
|
@@ -403,13 +436,10 @@ it does not inherit `builder.producer.gates`, so a repair Attempt with no
|
|
|
403
436
|
Gate of its own runs ungated.
|
|
404
437
|
|
|
405
438
|
Implementer's Gates are told `--stage unit` or `--stage assembly` alongside
|
|
406
|
-
`--id`, `--attempt`, `--gate-id
|
|
439
|
+
`--id`, `--attempt`, `--gate-id` and `--intention`.
|
|
407
440
|
Most have no use for it. `workspace-changed` does: "nothing changed" means
|
|
408
441
|
nothing was done in a unit, and is the correct outcome for an assembly that
|
|
409
|
-
needed nothing.
|
|
410
|
-
`--key` and `--gate-id` — no Attempt counter, no `--stage`, no
|
|
411
|
-
`--definition-of-done` — so a Gate written for Implementer's shape is not a
|
|
412
|
-
drop-in for `planner.gates`.
|
|
442
|
+
needed nothing.
|
|
413
443
|
|
|
414
444
|
`init` writes an empty list on `builder.producer` and `builder.repair`; add a
|
|
415
445
|
Gate when the Project has a check.
|
|
@@ -417,10 +447,10 @@ Gate when the Project has a check.
|
|
|
417
447
|
Every child carries its own ceiling and no other. A Gate entry may name a
|
|
418
448
|
`timeoutMs`; without one it takes its sequence's `defaultTimeoutMs`, and a Gate
|
|
419
449
|
that ends up with neither is refused when the config loads. Nothing is derived
|
|
420
|
-
from what another child left behind, so a slow producer
|
|
450
|
+
from what another child left behind, so a slow producer cannot leave its
|
|
421
451
|
Gates a millisecond to answer in.
|
|
422
452
|
|
|
423
|
-
What bounds
|
|
453
|
+
What bounds the unit is therefore what you wrote:
|
|
424
454
|
`builder.maxAttempts × (builder.producer.timeoutMs + Σ builder.producer.gates timeouts)`
|
|
425
455
|
for a first pass, and the same shape with `repair` in place of `producer` once
|
|
426
456
|
a Gate has refused one.
|
|
@@ -441,16 +471,9 @@ is bounded the same way from `assembly.maxAttempts` and `assembly.fix`.
|
|
|
441
471
|
}
|
|
442
472
|
```
|
|
443
473
|
|
|
444
|
-
### Planner
|
|
445
|
-
|
|
446
|
-
FeatureStandard in, a Plan out. It is given `--key`, `--intention`,
|
|
447
|
-
`--title` and `--max-units`. `init` writes the
|
|
448
|
-
bootstrap Planner — one Subtask that is the intention — from
|
|
449
|
-
`@bluewombat/slots/planners/one-subtask.mjs`.
|
|
450
|
-
|
|
451
474
|
### Describer
|
|
452
475
|
|
|
453
|
-
How a delivered
|
|
476
|
+
How a delivered ticket describes itself — the words the manager puts on the
|
|
454
477
|
Submission and on the fold — is the Project's, not Host's. Three levels, one
|
|
455
478
|
key, `authority.describe`:
|
|
456
479
|
|
|
@@ -458,10 +481,10 @@ key, `authority.describe`:
|
|
|
458
481
|
| -------------------------------------- | --------------------------------------------------------------------------------------- | ------------------------- |
|
|
459
482
|
| not set | the manager's own default: the issue's title, its body as the human wrote it | none |
|
|
460
483
|
| `messages/conventional.mjs` | `<type>: <title>` (`--scope`, `--type`), the body as written | none |
|
|
461
|
-
| `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 |
|
|
462
485
|
|
|
463
486
|
It is an argv like `publish` and `refresh`, bounded by the global `timeoutMs`.
|
|
464
|
-
Host spawns it once per
|
|
487
|
+
Host spawns it once per ticket, in the ticket workspace, when the work is
|
|
465
488
|
offered — with `--id`, `--title`, `--intention` and `--target` (the work line
|
|
466
489
|
it lands on) — and takes one line back: `{ "subject": "…", "body": "…" }`.
|
|
467
490
|
Host hands that description to the manager as is; what it becomes is the
|
|
@@ -469,12 +492,9 @@ manager's business (for GitHub: the squash's title and message, the pull
|
|
|
469
492
|
request's first paragraph). A slot that fails is skipped and the journal says
|
|
470
493
|
so.
|
|
471
494
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
else its first sentence cut at a word, no markdown. That headline is also what
|
|
476
|
-
the tracker's Plan, the progress comments and the Submission's change list
|
|
477
|
-
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.
|
|
478
498
|
|
|
479
499
|
### Write another slot
|
|
480
500
|
|
|
@@ -484,8 +504,8 @@ otherwise repeat is [`@bluewombat/slot-kit`](../slot-kit/README.md).
|
|
|
484
504
|
|
|
485
505
|
## Submissions
|
|
486
506
|
|
|
487
|
-
Without an Authority, a finished
|
|
488
|
-
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
|
|
489
509
|
outside judge first, and only an `accepted` verdict lets it into the work line.
|
|
490
510
|
|
|
491
511
|
It is **declared**, never inferred:
|
|
@@ -520,7 +540,7 @@ strategy does not know, a branch the remote does not have, a `workLine.branch`
|
|
|
520
540
|
that disagrees with the reference, or a `workLine.stable` that is not a copy of
|
|
521
541
|
it each stop `mason run` at boot, and `mason doctor` reports the same offline
|
|
522
542
|
(`reference`, `work line`). Without a reference, `workLine.stable` is required
|
|
523
|
-
and is the operator's directory
|
|
543
|
+
and is the operator's directory.
|
|
524
544
|
|
|
525
545
|
```
|
|
526
546
|
assembled → align → assembly.validate (optional, local)
|
|
@@ -542,12 +562,12 @@ Isolation must start from that version, not from a copy left behind.
|
|
|
542
562
|
|
|
543
563
|
A refusal is not a second failure path: its report reaches `assembly.fix`
|
|
544
564
|
exactly as a Gate's report reaches `builder.repair`. After `maxRefusals`
|
|
545
|
-
refusals the
|
|
565
|
+
refusals the ticket escalates with that report as its Trace, and `done` names
|
|
546
566
|
the Submission rather than a directory on the machine that ran.
|
|
547
567
|
|
|
548
568
|
## Write another manager
|
|
549
569
|
|
|
550
|
-
Host loads whatever `
|
|
570
|
+
Host loads whatever `featureTracker.package` and `ticketTracker.package` name, as long as it exports `createManager`. The
|
|
551
571
|
contract and a worked example are in
|
|
552
572
|
[`@bluewombat/manager-kit`](../manager-kit/README.md). Nothing in Host changes.
|
|
553
573
|
|
|
@@ -557,14 +577,20 @@ contract and a worked example are in
|
|
|
557
577
|
import { openHost } from "@bluewombat/runtime";
|
|
558
578
|
|
|
559
579
|
const host = await openHost({
|
|
560
|
-
|
|
561
|
-
|
|
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
|
+
},
|
|
562
588
|
// …paths and slots
|
|
563
589
|
});
|
|
564
590
|
await host.runOnce();
|
|
565
591
|
```
|
|
566
592
|
|
|
567
|
-
`
|
|
593
|
+
Each `package` also takes an already-loaded module, which is how a test drives Host
|
|
568
594
|
without resolving a package.
|
|
569
595
|
|
|
570
596
|
## Stack
|
|
@@ -616,7 +642,7 @@ change that breaks it does not merge.
|
|
|
616
642
|
Host's code names no plugin. A manager, an isolation strategy, a persistence
|
|
617
643
|
backend, the shipped slots: each is loaded by the name a config gives, through
|
|
618
644
|
`plugins/`, never imported. The names Host falls back to — the two isolation
|
|
619
|
-
strategies `init` writes, the default `persist
|
|
645
|
+
strategies `init` writes, the default `persist` — are
|
|
620
646
|
strings in `config/defaults.ts` and nowhere else; `check-host.mjs` refuses an
|
|
621
647
|
import of any of them and a spelled-out name anywhere else. Host's
|
|
622
648
|
`package.json` declares exactly those defaults, so a config `init` wrote runs
|
|
@@ -665,6 +691,6 @@ src/
|
|
|
665
691
|
config/ argv, JSON config, config discovery → HostOptions; defaults: the plugin names Host ships with
|
|
666
692
|
plugins/ load: the one loader; manager, isolation, persist: one shape each; discover
|
|
667
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
|
|
668
|
-
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
|
|
669
695
|
fixtures/ stand-in slots for the loop's tests
|
|
670
696
|
```
|