vinta-ai-workflows 0.7.0-alpha34 → 0.7.0-alpha35
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 +45 -0
- package/package.json +1 -1
- package/schemas/vinta-ai-workflows-config.v1.schema.json +18 -2
- package/schemas/workflow.v1.schema.json +21 -3
- package/skills/vinta-bootstrap-ai-tools/SKILL.md +5 -2
- package/skills/vinta-derive-skills/resources/foundation-skills/plan-feature/SKILL.md +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,7 @@ 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-alpha35 on 2026-10-16 -->
|
|
10
11
|
<!-- pre-release: 0.7.0-alpha34 on 2026-10-16 -->
|
|
11
12
|
<!-- pre-release: 0.7.0-alpha33 on 2026-10-16 -->
|
|
12
13
|
<!-- pre-release: 0.7.0-alpha31 on 2026-10-09 -->
|
|
@@ -34,6 +35,26 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
34
35
|
|
|
35
36
|
### Added
|
|
36
37
|
|
|
38
|
+
- **`vinta-ai-maestro`: integration is visible while it happens.** A phase in
|
|
39
|
+
`integrate` — a merge, a suite on the merged tree, a push, none with an
|
|
40
|
+
agent — showed `running` over a silent transcript, and one queued behind it
|
|
41
|
+
looked the same. Now:
|
|
42
|
+
- The phase view has an **Integration** timeline: each merge, conflict fix
|
|
43
|
+
round, `verify`, wave gate, push and PR of this attempt, a live clock on
|
|
44
|
+
the one in progress, and the log of every step that has one.
|
|
45
|
+
- The run view has an **Integration worktree** panel: who holds it, the step
|
|
46
|
+
it is on and for how long, and who is queued behind it. The roster and
|
|
47
|
+
the phase header show each running phase's pipeline step.
|
|
48
|
+
- `status` prints the step beside each running phase and an `integration`
|
|
49
|
+
line (`a · wave 1 gate unit · 6m 13s · 1 queued (b)`); `status --json`
|
|
50
|
+
carries `nodes[].step` and `integration`.
|
|
51
|
+
- A conflict fixer's turn is also written to the transcript of the phase
|
|
52
|
+
being based or building the wave, not only to the incoming phase's.
|
|
53
|
+
|
|
54
|
+
Two additive journal events back it: `node_step` (the pipeline state an
|
|
55
|
+
attempt entered) and `integration_step` (a step started or finished in the
|
|
56
|
+
worktree, identifiers and a log path only). Older runs have neither and
|
|
57
|
+
show no timeline.
|
|
37
58
|
- **`vinta-ai-maestro`: `accept` on an unapproved review.** The review-budget
|
|
38
59
|
question offered `continue` or `stop`, and operators answered `stop` meaning
|
|
39
60
|
"take it as it is" — which fails the attempt and, under `--on-failure
|
|
@@ -638,6 +659,30 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
638
659
|
|
|
639
660
|
### Changed
|
|
640
661
|
|
|
662
|
+
- **`vinta-ai-maestro`: the full suite runs before a PR, and on every merged
|
|
663
|
+
tree.** Under `gate_scope: scoped`, a phase's gates ran their scoped form
|
|
664
|
+
everywhere, so a PR could carry a suite only a scoped run had seen, and most
|
|
665
|
+
phases were `done` before any full suite touched their code.
|
|
666
|
+
- A phase's gates run scoped until its review approves; `verify`, after the
|
|
667
|
+
review, runs every gate's full `cmd` on the phase branch. A red full run
|
|
668
|
+
goes back to a fixer and through the review again — more review rounds,
|
|
669
|
+
no failing suite in a PR. The fixer is told the gate failed in full, and
|
|
670
|
+
`vinta-ai-maestro gate <id> --full` runs the whole command for an agent.
|
|
671
|
+
- `defaults.wave_gates` now defaults to `every`: each wave's gates run in
|
|
672
|
+
full on the merged tree, so the next wave builds on a passing one. Set
|
|
673
|
+
`final` for the previous behaviour.
|
|
674
|
+
- A multi-dependency phase's `integ-<id>` base runs its dependencies' gates
|
|
675
|
+
in full before the phase starts, cached on the merged tree; red fails the
|
|
676
|
+
phase's setup with `BaseGateError`. A clean base merge used to run nothing.
|
|
677
|
+
- Wave and base gate failures now reach the journal with their gate and log,
|
|
678
|
+
not just their error name.
|
|
679
|
+
- Each full run can be skipped in a plan's `defaults` or the project's
|
|
680
|
+
`maestro.defaults` (`.vinta-ai-workflows.yaml`): `verify_gates: scoped`
|
|
681
|
+
keeps `verify` on the scoped form, `base_gates: off` leaves merged bases
|
|
682
|
+
unchecked, and `wave_gates: final` / `off` as before. Both new fields are
|
|
683
|
+
in `vinta-ai-workflows-config.v1.schema.json`, and the bootstrap asks when
|
|
684
|
+
the full suite should run. The run coordinator may tighten them, never
|
|
685
|
+
loosen them.
|
|
641
686
|
- **`vinta-ai-maestro`: a recycled lane no longer keeps the last phase's
|
|
642
687
|
ignored files.** A lane handed to the next phase kept everything gitignored,
|
|
643
688
|
and one kept `apps/api/.mypy_cache` and a deleted package's `__pycache__`,
|
package/package.json
CHANGED
|
@@ -339,7 +339,7 @@
|
|
|
339
339
|
"additionalProperties": false,
|
|
340
340
|
"properties": {
|
|
341
341
|
"defaults": {
|
|
342
|
-
"description": "Run defaults a plan's `defaults` overrides field by field: `harness`, `model`, `pipeline`, `chores`, `gates` (the gate ids every phase runs unless it names its own), `gate_scope` (`scoped` | `full`), `wave_gates` (`off` | `final` | `every`), `substitution` (`same_tier` | `up_one_tier` | `any`), `allow_ungated_phases`, `model_fallbacks`, `max_session_turns`, `max_spare_crew`, `pull_requests` (`phase` | `plan`).",
|
|
342
|
+
"description": "Run defaults a plan's `defaults` overrides field by field: `harness`, `model`, `pipeline`, `chores`, `gates` (the gate ids every phase runs unless it names its own), `gate_scope` (`scoped` | `full`), `verify_gates` (`full` | `scoped`), `base_gates` (`full` | `off`), `wave_gates` (`off` | `final` | `every`), `substitution` (`same_tier` | `up_one_tier` | `any`), `allow_ungated_phases`, `model_fallbacks`, `max_session_turns`, `max_spare_crew`, `pull_requests` (`phase` | `plan`).",
|
|
343
343
|
"type": "object",
|
|
344
344
|
"properties": {
|
|
345
345
|
"harness": {
|
|
@@ -379,6 +379,22 @@
|
|
|
379
379
|
"full"
|
|
380
380
|
]
|
|
381
381
|
},
|
|
382
|
+
"verify_gates": {
|
|
383
|
+
"type": "string",
|
|
384
|
+
"enum": [
|
|
385
|
+
"full",
|
|
386
|
+
"scoped"
|
|
387
|
+
],
|
|
388
|
+
"description": "What a phase's `verify` runs once its review approves. `full` (the default): every gate's whole command on the phase branch, so a PR never carries a suite only a scoped run saw. `scoped`: the scoped form there too, for a suite too slow to run once per phase; the merged-tree gates are then the first full run. No effect under `gate_scope: full`."
|
|
389
|
+
},
|
|
390
|
+
"base_gates": {
|
|
391
|
+
"type": "string",
|
|
392
|
+
"enum": [
|
|
393
|
+
"full",
|
|
394
|
+
"off"
|
|
395
|
+
],
|
|
396
|
+
"description": "Whether a multi-dependency phase's merged base is gated before the phase starts on it. `full` (the default): every command gate its dependencies declare, whole command, on the merged base; red fails the phase's setup. `off`: the phase starts on the merged base unchecked."
|
|
397
|
+
},
|
|
382
398
|
"substitution": {
|
|
383
399
|
"type": "string",
|
|
384
400
|
"enum": [
|
|
@@ -395,7 +411,7 @@
|
|
|
395
411
|
"final",
|
|
396
412
|
"every"
|
|
397
413
|
],
|
|
398
|
-
"description": "When the phases' gates run in full on a merged wave, in the integration worktree. `
|
|
414
|
+
"description": "When the phases' gates run in full on a merged wave, in the integration worktree. `every` (the default): a wave's gates on every wave, so the next wave builds on a passing tree, and every gate of the plan on the last wave before the plan PR. `final`: the last wave's, and a wave's gates only on a wave whose merge needed a conflict resolution. `off`: none of these (the full form of a `scoped_cmd` gate still runs per wave under `gate_scope: scoped`)."
|
|
399
415
|
},
|
|
400
416
|
"allow_ungated_phases": {
|
|
401
417
|
"type": "boolean",
|
|
@@ -420,7 +420,7 @@
|
|
|
420
420
|
},
|
|
421
421
|
"gate_scope": {
|
|
422
422
|
"default": "scoped",
|
|
423
|
-
"description": "`scoped` — the default — runs a gate’s `scoped_cmd` on phase gates and its full `cmd`
|
|
423
|
+
"description": "`scoped` — the default — runs a gate’s `scoped_cmd` on a phase’s gates up to and during its review, and its full `cmd` once the review approves (`verify`) and on every merged tree in the integration worktree. `full` runs `cmd` everywhere.",
|
|
424
424
|
"type": "string",
|
|
425
425
|
"enum": [
|
|
426
426
|
"scoped",
|
|
@@ -453,9 +453,27 @@
|
|
|
453
453
|
"minimum": 0,
|
|
454
454
|
"maximum": 9007199254740991
|
|
455
455
|
},
|
|
456
|
+
"verify_gates": {
|
|
457
|
+
"default": "full",
|
|
458
|
+
"description": "What `standard-phase`’s `verify` runs once the review approves. `full` — the default — runs every gate’s whole `cmd` on the phase branch, so a PR never carries a suite only a scoped run saw; a red full run goes back to a fixer and the review. `scoped` keeps the scoped form there too, for a suite too slow to run once per phase — the merged-tree gates are then the first full run. No effect under `gate_scope: full`.",
|
|
459
|
+
"type": "string",
|
|
460
|
+
"enum": [
|
|
461
|
+
"full",
|
|
462
|
+
"scoped"
|
|
463
|
+
]
|
|
464
|
+
},
|
|
465
|
+
"base_gates": {
|
|
466
|
+
"default": "full",
|
|
467
|
+
"description": "Whether a multi-dependency phase’s base (`integ-<id>`, its dependencies merged) is gated before the phase starts on it. `full` — the default — runs every command gate its dependencies declare, whole `cmd`, on the merged base, cached on its tree; red fails the phase’s setup. `off` starts the phase on the merged base unchecked.",
|
|
468
|
+
"type": "string",
|
|
469
|
+
"enum": [
|
|
470
|
+
"full",
|
|
471
|
+
"off"
|
|
472
|
+
]
|
|
473
|
+
},
|
|
456
474
|
"wave_gates": {
|
|
457
|
-
"default": "
|
|
458
|
-
"description": "When the phases’ gates run in full on a merged wave, in the integration worktree. Each phase passes its gates on its own branch, and two parallel phases can each be green and disagree with each other — a sender and a receiver of one signal, say — which only a merged tree shows. `
|
|
475
|
+
"default": "every",
|
|
476
|
+
"description": "When the phases’ gates run in full on a merged wave, in the integration worktree. Each phase passes its gates on its own branch, and two parallel phases can each be green and disagree with each other — a sender and a receiver of one signal, say — which only a merged tree shows. `every` — the default — runs the wave’s phases’ gates on every wave, so the next wave builds on a passing tree and a disagreement is caught at the wave that introduced it, and every gate of the plan once on the last wave before the plan PR opens. It costs one full suite per wave. `final` runs the last wave’s and any wave whose merge needed a conflict resolution only. `off` runs none of these. Under `gate_scope: scoped` the full form of a narrowed gate still runs on each wave whatever this says: that is where the suite the phases skipped is paid back.",
|
|
459
477
|
"type": "string",
|
|
460
478
|
"enum": [
|
|
461
479
|
"off",
|
|
@@ -101,7 +101,8 @@ These bleed across sub-skills, so capture once now:
|
|
|
101
101
|
On `Set project defaults`, capture:
|
|
102
102
|
- **Gates every phase runs.** Multi-select `AskUserQuestion` over the types the commands above give a command for: `typecheck` (from `commands.build`), `lint`, `test` (from `commands.test_unit`), and `e2e` only when `add-e2e-test` is enabled. → `maestro.defaults.gates`.
|
|
103
103
|
- **A different command for maestro.** `AskUserQuestion` per selected type: `Same as commands.* (Recommended)`, `Different for maestro (I'll give it)`. Teams pick a different one when lanes need a flag the inner loop does not, e.g. `pytest --reuse-db -n auto`. → `maestro.gates.<type>.cmd`. `implement-plan` keeps running `commands.*`.
|
|
104
|
-
- **Scoped gates.** Only when `test` (or `lint`) is selected: should a phase's gate run narrowed to the files the phase changed, with the full command run
|
|
104
|
+
- **Scoped gates.** Only when `test` (or `lint`) is selected: should a phase's gate run narrowed to the files the phase changed until its review approves, with the full command run after the review and on every merged tree? `AskUserQuestion`: `Yes — scoped until review, full after (Recommended)`, `No — full command every time`. On `Yes`, propose a template with `{changed_files}` for the detected runner (`vitest related {changed_files} --run`, `jest --findRelatedTests {changed_files}`, `pytest --testmon {changed_files}`, `ruff check {changed_files}`) and confirm it. It lands in `commands.test_unit_scoped` / `commands.lint_scoped`, where `implement-plan` reads it too. `No` sets `maestro.defaults.gate_scope: full`.
|
|
105
|
+
- **When the full suite runs.** Only on `Yes` above. `AskUserQuestion`: `After each review and on every merged tree (Recommended)`, `Only on merged trees`, `Only on merged waves`. The first is the default and emits nothing. `Only on merged trees` skips the per-phase full run after review (`maestro.defaults.verify_gates: scoped`), for a suite too slow to run once per phase. `Only on merged waves` also leaves multi-dependency bases unchecked (`verify_gates: scoped` and `base_gates: off`).
|
|
105
106
|
- **A test-suite pool.** `AskUserQuestion`: `One suite at a time (Recommended for DB-backed suites)`, `Two at a time`, `No limit`. A limit emits `maestro.resources.test-suite` (`kind: semaphore`, `capacity` 1 or 2) and `maestro.gates.test.requires: [test-suite]`. Then offer the runner's command patterns as the pool's `match` (`pytest*`, `uv run pytest*`, `pnpm test*`), which makes agents take the lease before running tests by hand.
|
|
106
107
|
- **Files git does not carry.** A maestro lane is a worktree and has only what git tracks. Read `.gitignore` for entries with a tracked `*.example` / `*.sample` / `*.template` sibling, the compose file's `env_file:` lines, and the gitignored settings module the framework imports (`DJANGO_SETTINGS_MODULE`'s local module, typically). Propose the list in a multi-select `AskUserQuestion` (header `Env files`), each path pre-selected; the user confirms or drops entries. → `maestro.project.env_files`. Every hook, gate and `manage.py` call in a lane depends on these, and a plan that omits them fails in ways that look like code problems. Nothing found → omit the key and say so.
|
|
107
108
|
|
|
@@ -366,7 +367,9 @@ run_options:
|
|
|
366
367
|
maestro:
|
|
367
368
|
defaults:
|
|
368
369
|
gates: <C.11 → gates every phase runs, e.g. [typecheck, lint, test]>
|
|
369
|
-
gate_scope: <C.11 → omit for "scoped" (the default); `full` on "No — full command every
|
|
370
|
+
gate_scope: <C.11 → omit for "scoped" (the default); `full` on "No — full command every time">
|
|
371
|
+
verify_gates: <C.11 → omit (the default, `full`); `scoped` on "Only on merged trees" or "Only on merged waves">
|
|
372
|
+
base_gates: <C.11 → omit (the default, `full`); `off` on "Only on merged waves">
|
|
370
373
|
gates:
|
|
371
374
|
test:
|
|
372
375
|
cmd: <C.11 → maestro-only test command; omit to use commands.test_unit>
|
|
@@ -608,7 +608,8 @@ First key in the file is `"$schema"`, pointing at `https://github.com/vintasoftw
|
|
|
608
608
|
| `chores.review-canvas` | **Emit only when `.vinta-ai-workflows.yaml` has `integrations.pr-review-canvas: enabled`.** An `after_pr` chore: maestro runs it once each phase's PR is open, and it posts a review canvas on that PR. Emit it exactly as shown under "The review-canvas chore" below. Never emit it when the integration is `disabled` or absent. The skill it names is installed only when the integration is enabled. |
|
|
609
609
|
| `defaults.chores` | `["review", "deslop"]`, plus `"review-canvas"` when that chore is emitted — or **omit the key** when `maestro.defaults.chores` already names the same list. The chores every phase runs unless it names its own. **Never write `"chores": []` to mean "the project's"**: an empty list *replaces* the project's list with nothing, and the run then runs no chore at all. |
|
|
610
610
|
| `defaults.substitution` | **Omit** — it defaults to `up_one_tier`: a busy member's phase may go to the next tier up the roster has, and a warm session never moves a phase up. Set `same_tier` when the top tier is a limited credit allowance that must not absorb other tiers' work. |
|
|
611
|
-
| `defaults.wave_gates` | **Omit** — it defaults to `
|
|
611
|
+
| `defaults.wave_gates` | **Omit** — it defaults to `every`: each wave's gates run in full on the merged tree, so the next wave builds on a passing one, and every gate of the plan once more before the plan PR opens. Set `final` only for a plan whose suite is too slow to run once per wave. Never `off` unless the project's suite cannot run in the integration worktree. |
|
|
612
|
+
| `defaults.verify_gates` / `defaults.base_gates` | **Omit** — both default to `full`: a phase runs its gates' full commands once its review approves, and a multi-dependency phase's merged base is gated before it starts. Set `verify_gates: scoped` or `base_gates: off` only when the human says the suite is too slow for it, and say so in the plan. |
|
|
612
613
|
| `defaults.gates` | The gate ids every phase runs. **Omit the key** when `maestro.defaults.gates` is already the list this plan wants; set it when most phases share a list the project does not name. A node with no `gates` key takes it. **Never `[]`**: that is a run with no gates. |
|
|
613
614
|
| `nodes[].chores` | **Omit the key** on almost every phase — absent means the run-wide default. Name a list only to give one phase a different set, and `[]` only to deliberately opt one phase out. A list *replaces* the default rather than adding to it; `[]` is "no chores", never "the default". |
|
|
614
615
|
| `nodes[]` | One per phase, in plan order. |
|
|
@@ -641,7 +642,7 @@ Rules the mapping depends on:
|
|
|
641
642
|
Read `.vinta-ai-workflows.yaml` before writing the document. Its `commands` and its `maestro:` section are laid **under** this file when maestro loads it: every value the project already supplies reaches this plan without being written here, and a value written here overrides it for this plan alone. So the document says what is particular to this plan and nothing else. A copy of a project value is not harmless — it freezes the value into the plan, and a later change to the project's file never reaches it.
|
|
642
643
|
|
|
643
644
|
- **Gates by type.** A gate typed `test`, `lint`, `typecheck` or `e2e` takes its command from the project — `maestro.gates.<type>`, else `commands.test_unit` / `lint` / `build` / `e2e`. Each type the project has a command for is available under the type's own name, so a node can list `"gates": ["typecheck", "test"]` with no `gates` table at all. Write an entry only to change something for this plan: `{ "type": "test", "timeout_s": 3600 }` keeps the project's command and extends its timeout; `{ "cmd": "…" }` (no type) replaces it outright.
|
|
644
|
-
- **`scoped_cmd`** is the same check narrowed to what a phase changed, with `{changed_files}` / `{touches}` in it. The project normally supplies it (`commands.test_unit_scoped`, `maestro.gates.<type>.scoped_cmd`).
|
|
645
|
+
- **`scoped_cmd`** is the same check narrowed to what a phase changed, with `{changed_files}` / `{touches}` in it. The project normally supplies it (`commands.test_unit_scoped`, `maestro.gates.<type>.scoped_cmd`). A phase's gates run it until its review approves; the full command runs after that, on the phase branch, and on every merged tree — each wave and each multi-dependency base. Set one here only for a plan whose phases need a different narrowing.
|
|
645
646
|
- **Pools, chores and the `project` block** merge per id: an entry here replaces the project's entry of the same id whole. Declare `resources.lane` (it is this plan's — one desk per implementer), and a pool, chore or database only when the project has none or this plan needs a different one.
|
|
646
647
|
- **`defaults`** merge field by field: omit what `maestro.defaults` already says.
|
|
647
648
|
- **Omitting a key inherits; writing `[]` replaces with nothing.** `nodes[].gates`, `defaults.gates`, `defaults.chores` and `nodes[].chores` are lists, and lists replace rather than merge. The only way to take the project's list is to leave the key out. `"gates": []` on a node is a phase with no gates, `"chores": []` in `defaults` is a run with no review and no comment pass — both silent at run time, and both exactly what the observed run did. When in doubt, omit the key and read what `validate --json` resolved.
|