vinta-ai-workflows 0.7.0-alpha12 → 0.7.0-alpha14
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/CHANGELOG.md +195 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,8 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
|
|
8
8
|
## [0.7.0] — YYYY-MM-DD
|
|
9
9
|
|
|
10
|
+
<!-- pre-release: 0.7.0-alpha14 on 2026-09-16 -->
|
|
11
|
+
<!-- pre-release: 0.7.0-alpha13 on 2026-09-16 -->
|
|
10
12
|
<!-- pre-release: 0.7.0-alpha12 on 2026-09-15 -->
|
|
11
13
|
<!-- pre-release: 0.7.0-alpha11 on 2026-09-15 -->
|
|
12
14
|
<!-- pre-release: 0.7.0-alpha10 on 2026-09-15 -->
|
|
@@ -22,6 +24,18 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
22
24
|
|
|
23
25
|
### Added
|
|
24
26
|
|
|
27
|
+
- **`vinta-ai-maestro gate <gate-id>` runs a declared gate from inside an agent
|
|
28
|
+
turn.** A phase used to run its full gate suite five or six times a round —
|
|
29
|
+
implementer, reviewer, fixer, reviewer again, then the authoritative `gate`
|
|
30
|
+
node — and only the last of those consulted the gate cache or the resource
|
|
31
|
+
pool. Agents now ask the daemon for a gate by id: the result is cached on the
|
|
32
|
+
same `(gate id, lane tree hash)` key the `gate` node reads, the gate's
|
|
33
|
+
resources are held by the daemon rather than by whichever agent remembered to
|
|
34
|
+
wrap the command, and the id resolves to the plan's own command so a scoped
|
|
35
|
+
approximation cannot be reported as the gate. Each run is journalled as a
|
|
36
|
+
`gate_result` event and a `gate_run` transcript entry under the GATE band,
|
|
37
|
+
whoever asked for it.
|
|
38
|
+
|
|
25
39
|
- **A project declares what makes a lane runnable.** `project.env_files` copies
|
|
26
40
|
ignored configuration into each worktree, `project.setup_cmd` runs an
|
|
27
41
|
idempotent setup hook on provisioning and recycle, and the fixed
|
|
@@ -184,10 +198,33 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
184
198
|
claimed per review turn rather than per phase — it has one session ledger and
|
|
185
199
|
two concurrent reviews would collide over it — so one reviewer on a three-lane
|
|
186
200
|
plan is a queue at the review step and not a serialised run.
|
|
201
|
+
- **"Cheapest qualified" has one exception, and it is about sessions.** A
|
|
202
|
+
member who already holds a session this phase would genuinely resume takes
|
|
203
|
+
it ahead of a cheaper member who would have to start cold — even when they
|
|
204
|
+
are more senior than the phase needs, and even when the member the plan
|
|
205
|
+
named is free. What it buys is the context a cold session spends its first
|
|
206
|
+
turn rebuilding; what it costs is the dearer model for that phase, which is
|
|
207
|
+
the smaller of the two bills. **The tier floor is untouched**: warmth
|
|
208
|
+
reorders the members who already qualify and never widens them, so a warm
|
|
209
|
+
junior still cannot take a Tier 3 phase.
|
|
210
|
+
- **Only when a session is genuinely already up.** "Warm" means the scheduler
|
|
211
|
+
asked its own session-reuse rules and got a yes — same pinned lane, same
|
|
212
|
+
harness, under the turn ceiling, not poisoned by a failed phase. A member
|
|
213
|
+
who has merely run before is not warm, because a promotion bought on a
|
|
214
|
+
resume that is then refused pays the senior's rate *and* cold-starts
|
|
215
|
+
anyway. With nobody warm, staffing is exactly what it was: a session is
|
|
216
|
+
being opened either way, and the plan's own level wins.
|
|
217
|
+
- An operator who picks the member by hand on a retry gets that member. A
|
|
218
|
+
saving nobody asked for does not overrule an explicit answer.
|
|
187
219
|
- The run view reports who actually worked against who the plan said would.
|
|
188
220
|
`substituted` is the figure to read beside a cost that overran: every
|
|
189
221
|
substitution ran at or above the budgeted tier, so a run can be entirely green
|
|
190
|
-
and still have been staffed dearer than planned.
|
|
222
|
+
and still have been staffed dearer than planned. The phases promoted to reuse
|
|
223
|
+
a warm session are counted **within** that figure and reported apart from it —
|
|
224
|
+
a peer covering for a busy member costs what the plan budgeted, while a warm
|
|
225
|
+
promotion is the scheduler deliberately trading model rate against cold
|
|
226
|
+
starts, and folded together a run that promoted everything to the top tier
|
|
227
|
+
would read as an ordinary busy wave.
|
|
191
228
|
|
|
192
229
|
- **`implement-plan` runs independent phases in parallel.** The plan now carries a
|
|
193
230
|
dependency graph and the conductor schedules against it: a phase starts as soon as
|
|
@@ -282,8 +319,63 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
282
319
|
**generated** from a zod source rather than hand-written — see
|
|
283
320
|
[`schemas/README.md`](schemas/README.md).
|
|
284
321
|
|
|
322
|
+
- **The monitor keeps thinking when you look away, and thinks out loud.**
|
|
323
|
+
Asking used to be one long HTTP request that produced the whole answer inside
|
|
324
|
+
it, which made the turn's lifetime the browser's connection: switching view,
|
|
325
|
+
reloading or letting a laptop sleep killed the monitor mid-thought and left a
|
|
326
|
+
question with no answer and no record that one had been attempted. The daemon
|
|
327
|
+
owns the turn now — `POST` answers `202`, and the monitor journals each
|
|
328
|
+
thought and each sentence as it produces them, so the conversation is
|
|
329
|
+
readable while it is being written and by any tab that opens it. The panel
|
|
330
|
+
renders through the same rows a phase's transcript uses, which is what the
|
|
331
|
+
API always claimed and the UI never did.
|
|
332
|
+
|
|
333
|
+
- **A phase's transcript says which agent wrote each line, and holds the gates.**
|
|
334
|
+
Every spawn on a node appends to one file whatever its role, so a phase that
|
|
335
|
+
took two fix rounds held five agents' output in one undifferentiated stream —
|
|
336
|
+
the role was in scope at the append and simply not written down. Each line now
|
|
337
|
+
carries the role and the session slot that produced it, the view bands the
|
|
338
|
+
list where one agent stops and the next starts, and gate runs are entries in
|
|
339
|
+
it rather than only in a log beside it. The operator's own steering stays the
|
|
340
|
+
operator's (§7), even though the adapter echoes it back on the agent's event
|
|
341
|
+
stream. Transcripts written before this render exactly as they did, with no
|
|
342
|
+
bands. The band stays pinned to the top of the scroller while its own run of
|
|
343
|
+
rows goes past, so the agent you are reading is named without scrolling back
|
|
344
|
+
to where it started — in the phase transcript and in the monitor conversation
|
|
345
|
+
alike.
|
|
346
|
+
|
|
285
347
|
### Changed
|
|
286
348
|
|
|
349
|
+
- **A session cannot inherit a machine's decision to stop compacting.** All
|
|
350
|
+
three harnesses compact automatically when their context fills — there was
|
|
351
|
+
never a flag to turn on — but each honours an environment variable that turns
|
|
352
|
+
it off, and an agent spawned on a machine carrying one would run a long phase
|
|
353
|
+
straight into a wall it was supposed to be able to survive. Those variables
|
|
354
|
+
are now stripped from every child the daemon spawns, and claude-code's own
|
|
355
|
+
setting is reasserted in the per-lane file beside its permission rules. The
|
|
356
|
+
window itself is left alone: an operator who narrowed theirs compacts earlier,
|
|
357
|
+
which is not the failure this guards against. A harness that compacts declares
|
|
358
|
+
it, and a compaction the harness reports is a transcript row like any other.
|
|
359
|
+
|
|
360
|
+
One consequence worth knowing: `max_session_turns` used to be a proxy for "this
|
|
361
|
+
session is nearing a context window it will die on". That death no longer
|
|
362
|
+
happens, so the ceiling now guards a different thing — a session whose memory
|
|
363
|
+
was replaced by a summary of itself, and which answers just as confidently.
|
|
364
|
+
|
|
365
|
+
- **Agent prompts name gates by id rather than printing their commands.** The
|
|
366
|
+
implementer's step 4 was descriptive — "Outer gate… These run against your
|
|
367
|
+
lane:" followed by the gate commands — and implementers were observed reading
|
|
368
|
+
it as a note about what would run later, finishing the scoped inner loop and
|
|
369
|
+
never running a gate at all. It is imperative now, and every role that runs a
|
|
370
|
+
gate (implementer, reviewer, fixer, and the continuation of each) is pointed
|
|
371
|
+
at `vinta-ai-maestro gate <id>`. The fixer prompts no longer say to re-run the
|
|
372
|
+
gates "until they are green", which contradicted the commit protocol directly
|
|
373
|
+
below them and left fixers running out the turn with the work uncommitted;
|
|
374
|
+
they now say to commit and report FAILURE when a gate cannot be turned green.
|
|
375
|
+
Implementers and fixers report which gates they ran and what each returned —
|
|
376
|
+
a record for the reviewer to check against, explicitly not a licence for the
|
|
377
|
+
reviewer to skip running them itself.
|
|
378
|
+
|
|
287
379
|
- **Phase branches base on their dependencies, not on the previous phase.** A phase
|
|
288
380
|
with no dependencies cuts from the default branch; one with a single dependency
|
|
289
381
|
cuts from that phase's branch; one with several cuts from a
|
|
@@ -337,8 +429,110 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
337
429
|
is only as good as the `healthcheck` a service declares: without one, compose
|
|
338
430
|
returns as soon as the container starts and `createdb` races the server.
|
|
339
431
|
|
|
432
|
+
- **A merge conflict goes to the most senior member who wrote one of its
|
|
433
|
+
sides.** The conflict fixer was staffed from `defaults` and ignored the roster
|
|
434
|
+
entirely, so on a tiered crew a collision between two Tier 4 phases was handed
|
|
435
|
+
to a default-tier agent that had read neither of them — the hardest merge in
|
|
436
|
+
the run going to the least contextualised agent available, and resolved by
|
|
437
|
+
guessing which side looked more finished.
|
|
438
|
+
|
|
439
|
+
`Integrator` already knows which nodes own the contested paths, and `node_crew`
|
|
440
|
+
already records who took each one; this is the join. Highest tier among them
|
|
441
|
+
wins, on that member's own `model` and `harness`, and a tier tie breaks on
|
|
442
|
+
member id the way roster substitution breaks its own. An unstaffed workflow
|
|
443
|
+
still resolves through `defaults`, unchanged, and so does a conflict whose
|
|
444
|
+
nodes cannot be resolved to a member.
|
|
445
|
+
|
|
446
|
+
What is carried is the member's **capability, not their session**. A phase's
|
|
447
|
+
session ran in that phase's lane; the fixer runs in the integration worktree,
|
|
448
|
+
where the files in dispute are half-merged and unlike anything that session
|
|
449
|
+
saw — resuming there would give the agent confident, false memories of exactly
|
|
450
|
+
the files it is merging. The prompt tells the fixer which side is its own, and
|
|
451
|
+
in the same breath that it is a fresh session and must read rather than
|
|
452
|
+
recall.
|
|
453
|
+
|
|
340
454
|
### Fixed
|
|
341
455
|
|
|
456
|
+
- **An agent taking a lease left the resource panel showing the one before it.**
|
|
457
|
+
The scheduler's own gate-pool transitions are journalled as `gate_pool`
|
|
458
|
+
events, so the browser re-reads the snapshot when one lands. An agent's lease,
|
|
459
|
+
taken through `vinta-ai-maestro with`, was only a row in the `leases` table —
|
|
460
|
+
correct in the daemon's projection and announced to nobody. A projection
|
|
461
|
+
nobody is told changed is a projection nobody sees change, so the panel showed
|
|
462
|
+
whatever holders it had last time some unrelated event happened to arrive, and
|
|
463
|
+
the waits it was stalest about were the agent ones, which are the long ones.
|
|
464
|
+
The broker now journals `agent_lease` on both edges. A renewal writes nothing:
|
|
465
|
+
it is a heartbeat on a lease already reported, and journalling it would bury
|
|
466
|
+
the two rows that are transitions under a liveness log.
|
|
467
|
+
|
|
468
|
+
- **An agent waiting for a semaphore could be overtaken without bound.** A
|
|
469
|
+
`vinta-ai-maestro with` wait is served in fifteen-second hops so no client
|
|
470
|
+
timeout has an opinion about it, and each hop used to abort the underlying
|
|
471
|
+
`pools.acquire`. Aborting leaves the pool queue, and the next POST re-entered
|
|
472
|
+
it — at the tail, behind every waiter that had arrived in the meantime. Since
|
|
473
|
+
a gate run holds a capacity-1 semaphore for minutes, an agent lost that race
|
|
474
|
+
on hop after hop while the scheduler's own in-process waiters, which never
|
|
475
|
+
leave the queue, did not. The pool's aging rule could not help: aging reserves
|
|
476
|
+
against waiters *behind* the aged one, and the waiters that overtook it are in
|
|
477
|
+
front of it. A `202` now carries a `waitToken` naming the wait, the client
|
|
478
|
+
sends it back, and the daemon keeps the one queue entry — one arrival time,
|
|
479
|
+
one place in line — across the whole wait. A parked wait whose client stops
|
|
480
|
+
hopping is reaped after a minute, releasing the slot if one was granted to it
|
|
481
|
+
while nobody was watching.
|
|
482
|
+
|
|
483
|
+
- **The monitor's conversation could never be written on Windows.** It is kept
|
|
484
|
+
under a reserved node id that becomes a directory, and that id was
|
|
485
|
+
`monitor:conversation` — a colon, chosen because no phase id may contain one,
|
|
486
|
+
and the drive separator on Windows. `mkdir` failed with `ENOENT`, so every
|
|
487
|
+
question threw on its first append and the endpoint reported the monitor
|
|
488
|
+
unavailable. A colon is legal in a macOS or Linux filename, which is why no
|
|
489
|
+
machine the feature was built on ever saw it. The id is now
|
|
490
|
+
`_monitor-conversation`: still unrepresentable as a phase id, and legal
|
|
491
|
+
everywhere. Conversations recorded under the old id are not migrated.
|
|
492
|
+
|
|
493
|
+
- **An implementer was told both to commit and never to commit.** The prompt
|
|
494
|
+
carried "never commit while a gate is red" beside "the turn is not complete
|
|
495
|
+
until `git status --porcelain` is empty of your work" — a contradiction
|
|
496
|
+
whenever the gate could not be turned green inside the turn, which is most of
|
|
497
|
+
why fix rounds exist. Agents obeyed the `never`, and the reviewer one node
|
|
498
|
+
later raised the BLOCKER it is told to raise for uncommitted work, spending a
|
|
499
|
+
fix round re-implementing code that was already on disk. A red gate now
|
|
500
|
+
changes the report and never the decision to commit: commit, and report
|
|
501
|
+
FAILURE saying what is still red.
|
|
502
|
+
|
|
503
|
+
The reviewer's side was a false BLOCKER independently of that. Any unclean
|
|
504
|
+
tree was a finding, and a lane's tree is never clean — the pool copies
|
|
505
|
+
configuration in, links dependency trees, and the gates leave build output
|
|
506
|
+
behind, none of which the implementer is allowed to stage. It is scoped to
|
|
507
|
+
the failure it was written for now: work that is in the tree and missing from
|
|
508
|
+
the diff.
|
|
509
|
+
- **A live transcript stops following at entry sixty.** The effect that kept the
|
|
510
|
+
box on the newest row was keyed on how many rows were *shown*, which is
|
|
511
|
+
`min(entries, window)` — so it stopped changing the moment a transcript
|
|
512
|
+
outgrew one window, and the following died silently and permanently, including
|
|
513
|
+
after the operator scrolled back to the bottom to ask for it. Which is roughly
|
|
514
|
+
minute two of any real phase. It follows on the entry count now, growing the
|
|
515
|
+
window keeps the reader on the row they were reading instead of teleporting
|
|
516
|
+
them, and a **Jump to latest** button says so out loud rather than leaving a
|
|
517
|
+
60px band at the bottom of a scroller as the only way back in.
|
|
518
|
+
|
|
519
|
+
- **The transcript spends its space on the noisiest rows.** An agent's answer,
|
|
520
|
+
its private reasoning and four hundred characters of tool-call JSON all
|
|
521
|
+
rendered as the same two lines at the same weight. Thinking is now small and
|
|
522
|
+
quiet, and a streamed thought is one row rather than the dozen events it
|
|
523
|
+
arrived as; tool calls and their results fold to the argument that says what
|
|
524
|
+
they did — a command, a path — and open individually or a whole kind at a time
|
|
525
|
+
from the panel header. Prose is untouched and never folds.
|
|
526
|
+
|
|
527
|
+
- **A panel's expand control did nothing on the node view.** It expanded by
|
|
528
|
+
taking `col-span-full`, which on the run view bought a strip a third wider and
|
|
529
|
+
on the node view matched nothing at all — those panels sit in a flex column,
|
|
530
|
+
not a grid, so the only thing the button changed was the height of the
|
|
531
|
+
scroller inside it. It now opens the panel over the whole page through a
|
|
532
|
+
portal, so no scrolling ancestor can clip it, with Escape to leave and the
|
|
533
|
+
page behind it held still. A transcript that was following stays on its newest
|
|
534
|
+
row across the change.
|
|
535
|
+
|
|
342
536
|
- **`doctor` checks that the shared servers answer.** It verified that binaries
|
|
343
537
|
existed and disk fitted, and never looked at a `server_url` — so a project
|
|
344
538
|
whose Postgres lives in another checkout's compose stack passed the preflight
|
|
@@ -1178,7 +1372,6 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
1178
1372
|
**Consumers**: re-sync to pick up the opt-in questions. E2E-disabled projects
|
|
1179
1373
|
are unaffected (the e2e regions strip out as before).
|
|
1180
1374
|
|
|
1181
|
-
|
|
1182
1375
|
<!-- pre-release: 0.2.0-alpha6 on 2026-07-13 -->
|
|
1183
1376
|
|
|
1184
1377
|
### Changed
|
|
@@ -1215,7 +1408,6 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
1215
1408
|
|
|
1216
1409
|
### Added
|
|
1217
1410
|
|
|
1218
|
-
|
|
1219
1411
|
- **`handoff` foundation skill — session-continuation handoff docs between
|
|
1220
1412
|
agents.** Write mode captures the current task (goal, verified-vs-unverified
|
|
1221
1413
|
state, decisions + rejected alternatives, landmines, single concrete next
|
package/package.json
CHANGED