vinta-ai-workflows 0.7.0-alpha25 → 0.7.0-alpha26

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 CHANGED
@@ -30,6 +30,95 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
30
30
 
31
31
  ### Added
32
32
 
33
+ - **Project defaults for maestro in `.vinta-ai-workflows.yaml`.** A new
34
+ `maestro:` section holds what every plan's `.workflow.json` used to repeat:
35
+ per-type gate defaults, resource pools, chores, run defaults and the
36
+ `project` block. Maestro layers each plan over it. The project's
37
+ `commands.*` come first, then `maestro.*`, then the plan, then the run's own
38
+ amendments. A plan now states only what is different, and editing the
39
+ project file reaches every plan that did not override it.
40
+ - **Gate types.** A gate with `"type": "test" | "lint" | "typecheck" |
41
+ "e2e"` takes its command from `maestro.gates.<type>`, else from
42
+ `commands.test_unit` / `lint` / `build` / `e2e`. A `maestro.gates.<type>.cmd`
43
+ gives maestro its own line, and `implement-plan` keeps running
44
+ `commands.*`. Every type the project has a command for is available under
45
+ the type's name, so a node can list `["typecheck", "test"]` with no gate
46
+ table.
47
+ - **`defaults.gates`**, the gates every phase runs unless it names its own.
48
+ `defaults.harness` and `defaults.pipeline` now default to `claude-code`
49
+ and `standard-phase`, and `base_branch` defaults to
50
+ `project.default_branch`.
51
+ - **The bootstrap asks for these** (interview item C.11) and writes the
52
+ section. `plan-feature` reads it and emits only plan-specific values.
53
+ - **Scoped and full gates.** A gate can carry a `scoped_cmd` with
54
+ `{changed_files}` / `{touches}`. Phase gates run it, and the full `cmd` runs
55
+ once on each wave's merged tree. A failure there is a regression between
56
+ phases, and it fails the merge (`defaults.gate_scope: scoped`, the default;
57
+ `full` runs `cmd` everywhere). `commands.test_unit_scoped` and the new
58
+ `commands.lint_scoped` are inherited as scoped commands when they contain a
59
+ placeholder. `implement-plan`'s scoped suite fills the same placeholders.
60
+ - **Every maestro run works on a plan branch, `plan/<workflow-id>/base`.**
61
+ It is cut from `base_branch` at start, and phases and waves build on it.
62
+ Pull requests still target `base_branch`. Commit a change to
63
+ `.vinta-ai-workflows.yaml` or the plan's `.workflow.json` on that branch,
64
+ and the running plan picks it up as a `config` amendment that names the
65
+ commit. A config change never undoes a change an operator or the monitor
66
+ made in the run, never rewrites a phase that has started, and ships with
67
+ the plan's PR. `run` warns when the checkout's config file differs from
68
+ what is committed on the plan branch.
69
+ - **The gate guard.** On claude-code, every maestro agent gets a
70
+ `PreToolUse` hook, in every permission mode, through the per-lane settings
71
+ file only. It refuses two things: a gate's full command typed by hand
72
+ (answer: `vinta-ai-maestro gate <id>`), and a command matching a pool's new
73
+ `match` patterns when run without the lease (answer:
74
+ `vinta-ai-maestro with <pool> --`). Refusals are journalled as
75
+ `bare_gate_blocked`. The hook fails open and never auto-approves anything.
76
+ On codex and opencode a matching command is recorded after the fact as
77
+ `bare_gate_detected`. `doctor` reports which you get as
78
+ `gate-guard:<harness>`.
79
+
80
+ - **Provision worktrees with your own script instead of the `prepare-worktree`
81
+ skill.** Set `commands.worktree_prepare` in `.vinta-ai-workflows.yaml` (and
82
+ optionally `commands.worktree_teardown`), and `implement-plan` runs that
83
+ command for the shared worktree, every lane and the integration worktree.
84
+ No LLM step and no `agent_models.worktree_prep` delegate are involved.
85
+ Worktrees, and therefore parallel phases, are now available when the skill
86
+ is enabled **or** the command is set. When both are set the command wins,
87
+ and the skill is offered as a fallback if the command fails.
88
+ - **The contract.** The command runs from the repo root with
89
+ `VINTA_WORKTREE_NAME`, `_PATH`, `_BRANCH`, `_BASE_REF`, `_KIND`
90
+ (`single` | `lane` | `integration`), `VINTA_MAIN_CHECKOUT`,
91
+ `VINTA_PLAN_PATH` and `VINTA_WORKTREE_SUMMARY` set. It must create a
92
+ runnable worktree at that path, on that new branch, and exit non-zero on
93
+ failure. The conductor then checks the result with git rather than
94
+ trusting the exit code: the right branch, the worktree registered, and
95
+ the main checkout's status unchanged. Writing the summary YAML is
96
+ optional. A summary carrying `reset_cmd`s lets a lane be reused across a
97
+ migration boundary. Without one the lane is re-provisioned (teardown,
98
+ then prepare again) instead. Lanes are provisioned one at a time, because
99
+ the command runs `git worktree add` itself.
100
+ - **Sandbox tier.** The conductor probes the tier itself. With the skill
101
+ disabled, its `sandbox-run.sh` is not installed, so the tier is `none` and
102
+ the review-phase stray-write check is the guard.
103
+ - **Bootstrap.** The `prepare-worktree` question gains a
104
+ `Yes — we provision with our own script/command` option.
105
+ `vinta-analyze-codebase` now records existing worktree scripts in
106
+ `commands.worktree_candidates`, and the interview offers them as the
107
+ command. Existing configs need no change.
108
+ - **The bootstrap can write the script for you.** A fourth answer,
109
+ `Yes — generate a provisioning script for this project`, adds an optional
110
+ step after `vinta-derive-skills`. It writes `prepare.sh`, `teardown.sh`
111
+ and a shared `lib.sh` (default `scripts/worktree/`) from bundled
112
+ templates, and points `commands.worktree_prepare` / `_teardown` at them.
113
+ The templates carry the contract: `--dry-run`, sanity checks, rollback of
114
+ a half-made worktree, generic compose isolation, the full summary YAML,
115
+ and a teardown that refuses a dirty worktree, drops only `*_wt_<name>`
116
+ databases and never runs `down -v`. They also refuse to fork or drop a
117
+ database on a non-local host. The bootstrap fills only the project's
118
+ dependency, env, database and service steps from the inventory, then
119
+ verifies with `bash -n`, a dry run, and an optional real smoke test. The
120
+ scripts are the project's to commit and edit; humans can run
121
+ `prepare.sh <name>` / `teardown.sh <name>` directly too.
33
122
  - **Agents stop for input with clickable questions instead of prose.** When a
34
123
  skill or a sub-agent needs a decision from you, it now asks through your
35
124
  harness's structured question tool, so you get the options as buttons plus
@@ -294,6 +383,17 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
294
383
 
295
384
  ### Changed
296
385
 
386
+ - **Maestro: every `workflow_amended` row carries `targets`.** Operator and
387
+ config amendments get them too, computed from the snapshot and the
388
+ proposal. Before, only monitor amendments had them.
389
+ - **Maestro: a gate command can be amended after a phase that uses it is
390
+ done.** Changing a gate table no longer counts as rewriting a finished
391
+ phase. Before, such an amendment was refused as `body_changed_after_done`.
392
+ - **Maestro: the editor saves only what you changed.** It shows the workflow
393
+ resolved over the project config, and on save it writes back only the
394
+ edited values. A first save no longer copies every default, or the
395
+ project's values, into the plan file.
396
+
297
397
  - **Maestro: the node view's right-hand column stays short.** Gate logs open
298
398
  in a dialog instead of an inline accordion. The dialog opens at the end of
299
399
  the log, keeps up with a running gate's output, numbers the lines, and has
@@ -393,6 +493,35 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
393
493
 
394
494
  ### Fixed
395
495
 
496
+ - **Maestro: wave merges again use the membership the executor counted.**
497
+ `RecordingIntegrator.mergeWave` dropped it, so in production a merge fell
498
+ back to the integrator's own reading of the wave. That reading could differ
499
+ from the count if an amendment landed in between.
500
+ - **Maestro: the gate run on a conflict resolution uses the amended gate
501
+ commands.** It used the workflow from the start of the run.
502
+ - **Maestro: the API serves a run's definition as amended.** It cached the
503
+ snapshot forever, so a monitor retune made in the run's own process never
504
+ reached the UI.
505
+ - **Maestro: an editor save from `ui` now reaches the run's job.** `ui`
506
+ is a separate process from the job hosting a run. A save to a running
507
+ plan's workflow used to replace the run's frozen snapshot from `ui` with no
508
+ runner: nothing adopted the change, and an amendment that needed a rebase
509
+ was refused. The job kept running the old definition until a resume. The
510
+ save is now sent to the job (`POST /api/runs/<id>/amend`), which applies it
511
+ under the usual amend rules, and `ui` writes the plan file only once the
512
+ job has accepted it. If the job does not answer, the save is refused
513
+ (`run_host_unreachable`) and nothing is written.
514
+ - **Maestro: saving in the editor during a run no longer reports a failure.**
515
+ The amendment response failed the client's schema check even though the
516
+ save had gone through.
517
+
518
+ - **`implement-plan`'s final report no longer suggests `docker compose down -v`
519
+ to tear down a lane.** `down -v` also deletes the compose volumes a worktree
520
+ deliberately shares with the main checkout (`shared_volumes`, such as a
521
+ dependency cache). The report now prints the same sequence the
522
+ `prepare-worktree` skill documents: `docker compose -p <project> down`, then
523
+ `docker volume rm` for each volume the worktree forked, then removal of the
524
+ generated compose override.
396
525
  - **`open-pr.sh` posts inline comments on macOS and reports why a comment
397
526
  failed.** Four bugs in the `open-pr-from-context` script, all seen while
398
527
  publishing a stacked plan from a Mac:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vinta-ai-workflows",
3
- "version": "0.7.0-alpha25",
3
+ "version": "0.7.0-alpha26",
4
4
  "description": "Bootstrap AI tooling (AGENTS.md, skills, sub-agents) across Claude Code, Codex, Cursor, and VS Code + GitHub Copilot.",
5
5
  "type": "module",
6
6
  "bin": {
package/schemas/README.md CHANGED
@@ -6,7 +6,7 @@ JSON Schema (Draft 2020-12) contracts for every YAML or JSON payload the vinta-a
6
6
 
7
7
  | Artifact | YAML location in target project | Schema file | Authored by | Read by |
8
8
  |---|---|---|---|---|
9
- | Project config | `.vinta-ai-workflows.yaml` (repo root) | [`vinta-ai-workflows-config.v1.schema.json`](vinta-ai-workflows-config.v1.schema.json) | `vinta-bootstrap-ai-tools` (initial) → `vinta-sync-ai-tools` (updates) | every builder skill, every template render, every meta-skill |
9
+ | Project config | `.vinta-ai-workflows.yaml` (repo root) | [`vinta-ai-workflows-config.v1.schema.json`](vinta-ai-workflows-config.v1.schema.json) | `vinta-bootstrap-ai-tools` (initial) → `vinta-sync-ai-tools` (updates) | every builder skill, every template render, every meta-skill ; `vinta-ai-maestro` reads `commands` + `maestro` and layers every workflow over them |
10
10
  | Sub-agent definition | `ai-tools/agents/<name>.yaml` | [`sub-agent.v1.schema.json`](sub-agent.v1.schema.json) | `vinta-derive-subagents` | `setup-ai-tools.mjs` (emits per-vendor copies) |
11
11
  | PR-context frontmatter | top-of-file YAML in `.vinta-ai-workflows/prs-context/{feature-kebab}/phase-{phase.id}.md` | [`prs-context-frontmatter.v1.schema.json`](prs-context-frontmatter.v1.schema.json) | `implement-plan` / `amend-plan` | `open-pr.sh` |
12
12
  | PR-context inline comments | YAML inside the ` ```yaml ... ``` ` fence under `# Comments` of the same file | [`prs-context-comments.v1.schema.json`](prs-context-comments.v1.schema.json) | `implement-plan` / `amend-plan` | `open-pr.sh` |
@@ -69,20 +69,35 @@
69
69
  "properties": {
70
70
  "lint": { "type": "string" },
71
71
  "format": { "type": "string" },
72
+ "lint_scoped": {
73
+ "description": "Lint narrowed to what a phase changed, as a template with `{changed_files}` or `{touches}` (e.g. `pnpm eslint {changed_files}`). `vinta-ai-maestro` inherits it as the `scoped_cmd` of `lint`-typed gates; see `test_unit_scoped` for how the placeholders are filled.",
74
+ "type": "string",
75
+ "minLength": 1
76
+ },
72
77
  "build": {
73
78
  "description": "Type-check / build gate. Often the same as the test command on Python projects.",
74
79
  "type": "string"
75
80
  },
76
81
  "test_unit": { "type": "string" },
77
82
  "test_unit_scoped": {
78
- "description": "Per-package or per-app scoped suite (e.g. `pnpm test:patient`).",
83
+ "description": "Per-package or per-app scoped suite (e.g. `pnpm test:patient`). `implement-plan` reads it as guidance for the outer gate's scoped run. When it contains `{changed_files}` (the files the phase changed against its base) or `{touches}` (the phase's Touch List), it is also a template: `implement-plan` substitutes them, and `vinta-ai-maestro` inherits it as the `scoped_cmd` of `test`-typed gates — e.g. `pnpm vitest related {changed_files} --run`. A line without a placeholder is not inherited by maestro, which has no agent to decide what to scope it to.",
79
84
  "type": "string"
80
85
  },
81
86
  "test_unit_new_pattern": {
82
87
  "description": "Pattern for running a single new test file in isolation. Use placeholders like `<pkg>` / `<new-test-path>`.",
83
88
  "type": "string"
84
89
  },
85
- "e2e": { "type": "string" }
90
+ "e2e": { "type": "string" },
91
+ "worktree_prepare": {
92
+ "description": "The project's own command for provisioning a runnable git worktree, used by `implement-plan` / `amend-plan` **instead of** the `prepare-worktree` skill. Set it when the team already has a script (`bin/new-worktree`, a Makefile target, `git gtr new`, …) or wants deterministic, LLM-free provisioning. Worktrees are available to the plan-execution family when this is set **or** `foundation_skills.prepare-worktree` is `enabled`; when both are set the command wins and the skill is offered as a fallback if the command fails. Runs from the main checkout root with `VINTA_WORKTREE_NAME`, `VINTA_WORKTREE_PATH`, `VINTA_WORKTREE_BRANCH`, `VINTA_WORKTREE_BASE_REF`, `VINTA_WORKTREE_KIND` (`single` | `lane` | `integration`), `VINTA_MAIN_CHECKOUT`, `VINTA_PLAN_PATH` and `VINTA_WORKTREE_SUMMARY` in its environment. It MUST create a worktree at `VINTA_WORKTREE_PATH` on a new branch `VINTA_WORKTREE_BRANCH` based on `VINTA_WORKTREE_BASE_REF`, and exit 0 only when that worktree is runnable. It MAY write the summary YAML at `VINTA_WORKTREE_SUMMARY` (the shape `prepare-worktree` writes); a summary carrying `reset_cmd`s lets a lane be reused across a migration boundary, and without one the conductor re-provisions the lane instead. The full contract is in the rendered `implement-plan` skill (Step 0.5). The bootstrap can generate a conforming `prepare.sh` / `teardown.sh` pair for the project (its `prepare-worktree` question, option `generate a provisioning script`).",
93
+ "type": "string",
94
+ "minLength": 1
95
+ },
96
+ "worktree_teardown": {
97
+ "description": "Optional counterpart to `worktree_prepare`: removes a worktree the prepare command created, plus any state it made outside git (forked DBs, compose volumes, caches). Receives the same `VINTA_WORKTREE_*` environment. Used when a lane is re-provisioned mid-run, when the user cancels at the worktree confirmation gate, and in the teardown commands the final report prints (never auto-run at the end of a run). Unset → teardown is `git worktree remove <path>`, which leaks anything the prepare command created outside the worktree; set it whenever the prepare command forks databases or volumes. Ignored when `worktree_prepare` is unset.",
98
+ "type": "string",
99
+ "minLength": 1
100
+ }
86
101
  }
87
102
  },
88
103
  "policies": {
@@ -209,7 +224,7 @@
209
224
  "enum": ["enabled", "disabled"]
210
225
  },
211
226
  "prepare-worktree": {
212
- "description": "Provision a fully-runnable git worktree for parallel feature work — gives each worktree its own copy of the dep dirs, copies env files, forks dev / test DBs, namespaces docker-compose project + network, drops a summary YAML for mechanical teardown. Copy-verbatim foundation skill (bucket A). When `enabled`, project-level defaults (worktree root, deps strategy, compose network strategy) live under `skills.prepare-worktree`. Consumed by `implement-plan` when its Step 0 question (c) opts in — the orchestrator runs `prepare-worktree` once at the start of a plan run and threads the worktree path through every subagent's prompt so phases all stack inside the same isolated checkout.",
227
+ "description": "Provision a fully-runnable git worktree for parallel feature work — gives each worktree its own copy of the dep dirs, copies env files, forks dev / test DBs, namespaces docker-compose project + network, drops a summary YAML for mechanical teardown. Copy-verbatim foundation skill (bucket A). When `enabled`, project-level defaults (worktree root, deps strategy, compose network strategy) live under `skills.prepare-worktree`. Consumed by `implement-plan` when its Step 0 question (c) opts in — the orchestrator runs `prepare-worktree` once at the start of a plan run and threads the worktree path through every subagent's prompt so phases all stack inside the same isolated checkout. Set `disabled` when the project provisions worktrees with its own command instead (`commands.worktree_prepare`) — worktrees stay available to `implement-plan` either way.",
213
228
  "type": "string",
214
229
  "enum": ["enabled", "disabled"]
215
230
  },
@@ -280,7 +295,7 @@
280
295
  "maximum": 4
281
296
  },
282
297
  "worktree_prep": {
283
- "description": "Tier for the mechanical worktree-provisioning step (`prepare-worktree`), which `implement-plan` / `amend-plan` run once at the start of a worktree-enabled run. When set, the conductor delegates the step to a subagent at this tier instead of running it inline in its own (usually pricier) session. Mechanical, precedent-driven work — Tier 1 is the usual default. Unset → conductor runs it inline. Irrelevant when `foundation_skills.prepare-worktree` is `disabled`.",
298
+ "description": "Tier for the mechanical worktree-provisioning step (`prepare-worktree`), which `implement-plan` / `amend-plan` run once at the start of a worktree-enabled run. When set, the conductor delegates the step to a subagent at this tier instead of running it inline in its own (usually pricier) session. Mechanical, precedent-driven work — Tier 1 is the usual default. Unset → conductor runs it inline. Irrelevant when `foundation_skills.prepare-worktree` is `disabled`, and when `commands.worktree_prepare` is set — a shell command needs no model, so the conductor runs it directly.",
284
299
  "type": "integer",
285
300
  "minimum": 1,
286
301
  "maximum": 4
@@ -307,6 +322,314 @@
307
322
  "uniqueItems": true,
308
323
  "default": []
309
324
  },
325
+ "maestro": {
326
+ "description": "Project-wide defaults for `vinta-ai-maestro` runs, layered UNDER every plan's `ai-plans/*.workflow.json`: a plan's own value wins, and a run's mid-run amendments win over both. Maps keyed by id (`resources`, `chores`, `project.databases`, `project.services`) merge per id with the plan's entry replacing the project's whole; a typed gate merges field by field; lists replace. Shapes are the workflow schema's (`workflow.v1.schema.json`) — maestro validates them strictly at load. A run follows its plan branch (`plan/<workflow-id>/base`): committing a change to this file on that branch applies it to the live run. Absent: every plan carries everything itself.",
327
+ "type": "object",
328
+ "additionalProperties": false,
329
+ "properties": {
330
+ "defaults": {
331
+ "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`), `reviewer_model`, `max_session_turns`.",
332
+ "type": "object",
333
+ "properties": {
334
+ "harness": {
335
+ "type": "string",
336
+ "enum": [
337
+ "claude-code",
338
+ "codex",
339
+ "opencode"
340
+ ]
341
+ },
342
+ "model": {
343
+ "type": "string",
344
+ "minLength": 1
345
+ },
346
+ "pipeline": {
347
+ "type": "string",
348
+ "pattern": "^[a-z0-9][a-z0-9-]*$"
349
+ },
350
+ "chores": {
351
+ "type": "array",
352
+ "items": {
353
+ "type": "string",
354
+ "pattern": "^[a-z0-9][a-z0-9-]*$"
355
+ }
356
+ },
357
+ "gates": {
358
+ "type": "array",
359
+ "items": {
360
+ "type": "string",
361
+ "pattern": "^[a-z0-9][a-z0-9-]*$"
362
+ }
363
+ },
364
+ "gate_scope": {
365
+ "type": "string",
366
+ "enum": [
367
+ "scoped",
368
+ "full"
369
+ ]
370
+ },
371
+ "reviewer_model": {
372
+ "type": "string",
373
+ "minLength": 1
374
+ },
375
+ "max_session_turns": {
376
+ "type": "integer",
377
+ "minimum": 1
378
+ }
379
+ },
380
+ "additionalProperties": false
381
+ },
382
+ "gates": {
383
+ "description": "Per gate type. Each type with a command is also available to every plan under the type's own name (`gates: [typecheck, test]` on a node, with no gate table).",
384
+ "type": "object",
385
+ "additionalProperties": false,
386
+ "properties": {
387
+ "test": {
388
+ "description": "Defaults a gate of this type inherits, over the matching `commands.*` line. Any field a plan's own gate sets wins over these.",
389
+ "type": "object",
390
+ "additionalProperties": false,
391
+ "properties": {
392
+ "cmd": {
393
+ "description": "The full check maestro runs for this type. Overrides the `commands.*` line for maestro only — `implement-plan` keeps running `commands.*`.",
394
+ "type": "string",
395
+ "minLength": 1
396
+ },
397
+ "scoped_cmd": {
398
+ "description": "The check narrowed to what a phase changed, with `{changed_files}` and/or `{touches}`. Run by phase gates under `gate_scope: scoped`; the full `cmd` runs once on each wave's merged tree.",
399
+ "type": "string",
400
+ "minLength": 1
401
+ },
402
+ "requires": {
403
+ "description": "Resource pools the gate holds while it runs, e.g. `[test-suite]`.",
404
+ "type": "array",
405
+ "items": {
406
+ "type": "string",
407
+ "pattern": "^[a-z0-9][a-z0-9-]*$"
408
+ }
409
+ },
410
+ "timeout_s": {
411
+ "type": "integer",
412
+ "minimum": 1
413
+ },
414
+ "tuning": {
415
+ "description": "Flags the monitor may add to `cmd` when it retunes the gate mid-run. Same shape as a workflow gate's `tuning`.",
416
+ "type": "object",
417
+ "properties": {
418
+ "allowed_flags": {
419
+ "type": "array",
420
+ "items": {
421
+ "type": "string",
422
+ "minLength": 1
423
+ },
424
+ "minItems": 1
425
+ }
426
+ },
427
+ "required": [
428
+ "allowed_flags"
429
+ ],
430
+ "additionalProperties": false
431
+ }
432
+ }
433
+ },
434
+ "lint": {
435
+ "description": "Defaults a gate of this type inherits, over the matching `commands.*` line. Any field a plan's own gate sets wins over these.",
436
+ "type": "object",
437
+ "additionalProperties": false,
438
+ "properties": {
439
+ "cmd": {
440
+ "description": "The full check maestro runs for this type. Overrides the `commands.*` line for maestro only — `implement-plan` keeps running `commands.*`.",
441
+ "type": "string",
442
+ "minLength": 1
443
+ },
444
+ "scoped_cmd": {
445
+ "description": "The check narrowed to what a phase changed, with `{changed_files}` and/or `{touches}`. Run by phase gates under `gate_scope: scoped`; the full `cmd` runs once on each wave's merged tree.",
446
+ "type": "string",
447
+ "minLength": 1
448
+ },
449
+ "requires": {
450
+ "description": "Resource pools the gate holds while it runs, e.g. `[test-suite]`.",
451
+ "type": "array",
452
+ "items": {
453
+ "type": "string",
454
+ "pattern": "^[a-z0-9][a-z0-9-]*$"
455
+ }
456
+ },
457
+ "timeout_s": {
458
+ "type": "integer",
459
+ "minimum": 1
460
+ },
461
+ "tuning": {
462
+ "description": "Flags the monitor may add to `cmd` when it retunes the gate mid-run. Same shape as a workflow gate's `tuning`.",
463
+ "type": "object",
464
+ "properties": {
465
+ "allowed_flags": {
466
+ "type": "array",
467
+ "items": {
468
+ "type": "string",
469
+ "minLength": 1
470
+ },
471
+ "minItems": 1
472
+ }
473
+ },
474
+ "required": [
475
+ "allowed_flags"
476
+ ],
477
+ "additionalProperties": false
478
+ }
479
+ }
480
+ },
481
+ "typecheck": {
482
+ "description": "Defaults a gate of this type inherits, over the matching `commands.*` line. Any field a plan's own gate sets wins over these.",
483
+ "type": "object",
484
+ "additionalProperties": false,
485
+ "properties": {
486
+ "cmd": {
487
+ "description": "The full check maestro runs for this type. Overrides the `commands.*` line for maestro only — `implement-plan` keeps running `commands.*`.",
488
+ "type": "string",
489
+ "minLength": 1
490
+ },
491
+ "scoped_cmd": {
492
+ "description": "The check narrowed to what a phase changed, with `{changed_files}` and/or `{touches}`. Run by phase gates under `gate_scope: scoped`; the full `cmd` runs once on each wave's merged tree.",
493
+ "type": "string",
494
+ "minLength": 1
495
+ },
496
+ "requires": {
497
+ "description": "Resource pools the gate holds while it runs, e.g. `[test-suite]`.",
498
+ "type": "array",
499
+ "items": {
500
+ "type": "string",
501
+ "pattern": "^[a-z0-9][a-z0-9-]*$"
502
+ }
503
+ },
504
+ "timeout_s": {
505
+ "type": "integer",
506
+ "minimum": 1
507
+ },
508
+ "tuning": {
509
+ "description": "Flags the monitor may add to `cmd` when it retunes the gate mid-run. Same shape as a workflow gate's `tuning`.",
510
+ "type": "object",
511
+ "properties": {
512
+ "allowed_flags": {
513
+ "type": "array",
514
+ "items": {
515
+ "type": "string",
516
+ "minLength": 1
517
+ },
518
+ "minItems": 1
519
+ }
520
+ },
521
+ "required": [
522
+ "allowed_flags"
523
+ ],
524
+ "additionalProperties": false
525
+ }
526
+ }
527
+ },
528
+ "e2e": {
529
+ "description": "Defaults a gate of this type inherits, over the matching `commands.*` line. Any field a plan's own gate sets wins over these.",
530
+ "type": "object",
531
+ "additionalProperties": false,
532
+ "properties": {
533
+ "cmd": {
534
+ "description": "The full check maestro runs for this type. Overrides the `commands.*` line for maestro only — `implement-plan` keeps running `commands.*`.",
535
+ "type": "string",
536
+ "minLength": 1
537
+ },
538
+ "scoped_cmd": {
539
+ "description": "The check narrowed to what a phase changed, with `{changed_files}` and/or `{touches}`. Run by phase gates under `gate_scope: scoped`; the full `cmd` runs once on each wave's merged tree.",
540
+ "type": "string",
541
+ "minLength": 1
542
+ },
543
+ "requires": {
544
+ "description": "Resource pools the gate holds while it runs, e.g. `[test-suite]`.",
545
+ "type": "array",
546
+ "items": {
547
+ "type": "string",
548
+ "pattern": "^[a-z0-9][a-z0-9-]*$"
549
+ }
550
+ },
551
+ "timeout_s": {
552
+ "type": "integer",
553
+ "minimum": 1
554
+ },
555
+ "tuning": {
556
+ "description": "Flags the monitor may add to `cmd` when it retunes the gate mid-run. Same shape as a workflow gate's `tuning`.",
557
+ "type": "object",
558
+ "properties": {
559
+ "allowed_flags": {
560
+ "type": "array",
561
+ "items": {
562
+ "type": "string",
563
+ "minLength": 1
564
+ },
565
+ "minItems": 1
566
+ }
567
+ },
568
+ "required": [
569
+ "allowed_flags"
570
+ ],
571
+ "additionalProperties": false
572
+ }
573
+ }
574
+ }
575
+ }
576
+ },
577
+ "resources": {
578
+ "description": "Capacity pools by id, e.g. a `test-suite` semaphore. `match` lists command patterns (`pytest*`) an agent must run under `vinta-ai-maestro with <pool> --`.",
579
+ "type": "object",
580
+ "propertyNames": {
581
+ "type": "string",
582
+ "pattern": "^[a-z0-9][a-z0-9-]*$"
583
+ },
584
+ "additionalProperties": {
585
+ "type": "object",
586
+ "required": [
587
+ "capacity",
588
+ "kind"
589
+ ],
590
+ "additionalProperties": false,
591
+ "properties": {
592
+ "capacity": {
593
+ "type": "integer",
594
+ "minimum": 1
595
+ },
596
+ "kind": {
597
+ "type": "string",
598
+ "enum": [
599
+ "worktree",
600
+ "semaphore"
601
+ ]
602
+ },
603
+ "match": {
604
+ "type": "array",
605
+ "items": {
606
+ "type": "string",
607
+ "minLength": 1
608
+ }
609
+ },
610
+ "description": {
611
+ "type": "string"
612
+ }
613
+ }
614
+ }
615
+ },
616
+ "chores": {
617
+ "description": "Chore definitions by id (`prompt` or `prompt_ref`, `skill`, `session`, `model`, `when`, `on_failure`) — the workflow schema's `chores` entries.",
618
+ "type": "object",
619
+ "propertyNames": {
620
+ "type": "string",
621
+ "pattern": "^[a-z0-9][a-z0-9-]*$"
622
+ },
623
+ "additionalProperties": {
624
+ "type": "object"
625
+ }
626
+ },
627
+ "project": {
628
+ "description": "The workflow schema's `project` block (`migrate_cmd`, `databases`, `env_files`, `commands`, `hooks`, `services`, `compose`, `prepare_cmd`, `setup_cmd`), merged under a plan's own field by field. `project.commands` additionally inherits `lint`, `typecheck` (from `commands.build`) and `test` (from `commands.test_unit`).",
629
+ "type": "object"
630
+ }
631
+ }
632
+ },
310
633
  "run_options": {
311
634
  "description": "Per-skill run-option defaults. Skills override via per-invocation prompts; values here are the defaults shown.",
312
635
  "type": "object",
@@ -324,12 +647,12 @@
324
647
  "default": false
325
648
  },
326
649
  "use_worktree": {
327
- "description": "Default answer to Step 0 question (c) — whether `implement-plan` should provision isolated git worktrees (via `prepare-worktree`) and run phase subagents inside them. False = run in the current checkout. True = provision at the start of the plan run: one shared worktree for a sequential run, or one lane per concurrent phase plus an integration worktree when `parallel_phases` is on. Per-run prompt still asks; this is the suggested default shown.",
650
+ "description": "Default answer to Step 0 question (c) — whether `implement-plan` should provision isolated git worktrees (via `commands.worktree_prepare` when set, else the `prepare-worktree` skill) and run phase subagents inside them. False = run in the current checkout. True = provision at the start of the plan run: one shared worktree for a sequential run, or one lane per concurrent phase plus an integration worktree when `parallel_phases` is on. Per-run prompt still asks; this is the suggested default shown.",
328
651
  "type": "boolean",
329
652
  "default": false
330
653
  },
331
654
  "parallel_phases": {
332
- "description": "Default answer to Step 0 question (e) — whether `implement-plan` implements independent phases concurrently, one git worktree lane per in-flight phase. The plan's per-phase `**Depends on**:` lines define the graph; a phase starts as soon as every phase it depends on is green. True (default) = run in parallel whenever the graph has a wave wider than one phase. False = one phase at a time. Requires `foundation_skills.prepare-worktree` enabled and `use_worktree` resolving true — several agents cannot share one working tree — and `implement-plan` refuses rather than silently degrading when that is not the case. Per-run prompt still asks; this is the suggested default shown.",
655
+ "description": "Default answer to Step 0 question (e) — whether `implement-plan` implements independent phases concurrently, one git worktree lane per in-flight phase. The plan's per-phase `**Depends on**:` lines define the graph; a phase starts as soon as every phase it depends on is green. True (default) = run in parallel whenever the graph has a wave wider than one phase. False = one phase at a time. Requires worktrees to be available (`foundation_skills.prepare-worktree` enabled or `commands.worktree_prepare` set) and `use_worktree` resolving true — several agents cannot share one working tree — and `implement-plan` refuses rather than silently degrading when that is not the case. Per-run prompt still asks; this is the suggested default shown.",
333
656
  "type": "boolean",
334
657
  "default": true
335
658
  },
@@ -421,7 +744,7 @@
421
744
  }
422
745
  },
423
746
  "prepare-worktree": {
424
- "description": "Configuration for the `prepare-worktree` foundation skill. Optional when `foundation_skills.prepare-worktree` is `enabled` — every field has a sensible default. Consumed by the skill at runtime to bias the per-worktree copy-vs-reinstall-vs-fork decisions.",
747
+ "description": "Configuration for the `prepare-worktree` foundation skill. Optional when `foundation_skills.prepare-worktree` is `enabled` — every field has a sensible default. Consumed by the skill at runtime to bias the per-worktree copy-vs-reinstall-vs-fork decisions. When the project provisions with `commands.worktree_prepare` instead, the plan-execution conductor still reads `worktree_root` and `summary_dir` from here to compute `VINTA_WORKTREE_PATH` / `VINTA_WORKTREE_SUMMARY`; the other fields are skill-only and ignored.",
425
748
  "type": "object",
426
749
  "additionalProperties": false,
427
750
  "properties": {