vinta-ai-workflows 0.7.0-alpha8 → 0.7.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/CHANGELOG.md +472 -595
- package/README.md +33 -19
- package/package.json +4 -1
- package/schemas/README.md +11 -3
- package/schemas/ai-models.v1.schema.json +5 -0
- package/schemas/interview-answers.v1.schema.json +122 -0
- package/schemas/interview-round.v1.schema.json +346 -0
- package/schemas/plan-review.v1.schema.json +342 -0
- package/schemas/postmortem.v1.schema.json +848 -3
- package/schemas/prs-context-comments.v1.schema.json +1 -1
- package/schemas/prs-context-frontmatter.v1.schema.json +18 -7
- package/schemas/vinta-ai-workflows-config.v1.schema.json +677 -18
- package/schemas/workflow.v1.schema.json +751 -26
- package/skills/vinta-analyze-codebase/SKILL.md +5 -0
- package/skills/vinta-bootstrap-ai-tools/SKILL.md +154 -31
- package/skills/vinta-bootstrap-ai-tools/resources/stacks/README.md +1 -1
- package/skills/vinta-bootstrap-ai-tools/resources/stacks/django/notes.md +36 -1
- package/skills/vinta-bootstrap-ai-tools/resources/worktree-command/README.md +85 -0
- package/skills/vinta-bootstrap-ai-tools/resources/worktree-command/lib-template.sh +160 -0
- package/skills/vinta-bootstrap-ai-tools/resources/worktree-command/prepare-template.sh +250 -0
- package/skills/vinta-bootstrap-ai-tools/resources/worktree-command/teardown-template.sh +96 -0
- package/skills/vinta-derive-skills/SKILL.md +23 -15
- package/skills/vinta-derive-skills/resources/dependency-license-block.md +8 -9
- package/skills/vinta-derive-skills/resources/foundation-skills/add-one-off-script/SKILL.md +1 -1
- package/skills/vinta-derive-skills/resources/foundation-skills/create-qa-use-cases/SKILL.md +3 -3
- package/skills/vinta-derive-skills/resources/foundation-skills/create-spec/SKILL.md +21 -2
- package/skills/vinta-derive-skills/resources/foundation-skills/handoff/SKILL.md +3 -3
- package/skills/vinta-derive-skills/resources/foundation-skills/interview-ui/SKILL.md +121 -0
- package/skills/vinta-derive-skills/resources/foundation-skills/interview-ui/resources/examples/docs/D4-concurrency.md +28 -0
- package/skills/vinta-derive-skills/resources/foundation-skills/interview-ui/resources/examples/round-01.json +60 -0
- package/skills/vinta-derive-skills/resources/foundation-skills/open-pr-from-context/SKILL.md +1 -1
- package/skills/vinta-derive-skills/resources/foundation-skills/open-pr-from-context/scripts/open-pr.sh +34 -7
- package/skills/vinta-derive-skills/resources/foundation-skills/plan-feature/SKILL.md +363 -142
- package/skills/vinta-derive-skills/resources/foundation-skills/plan-feature/resources/ai-models.yaml +19 -13
- package/skills/vinta-derive-skills/resources/foundation-skills/prepare-worktree/SKILL.md +39 -21
- package/skills/vinta-derive-skills/resources/foundation-skills/thermo-nuclear-code-quality-review/SKILL.md +8 -6
- package/skills/vinta-derive-skills/resources/foundation-skills/thermo-nuclear-review-loop/SKILL.md +181 -0
- package/skills/vinta-derive-skills/resources/plan-execution/README.md +40 -7
- package/skills/vinta-derive-skills/resources/plan-execution/partials/agent-models.md +14 -35
- package/skills/vinta-derive-skills/resources/plan-execution/partials/commit-strategy/stacked.md +21 -0
- package/skills/vinta-derive-skills/resources/plan-execution/partials/dispatched-agent.md +31 -0
- package/skills/vinta-derive-skills/resources/plan-execution/partials/implementer-prompt.md +67 -6
- package/skills/vinta-derive-skills/resources/plan-execution/partials/maestro-live-run.md +44 -0
- package/skills/vinta-derive-skills/resources/plan-execution/partials/model-pick.md +9 -3
- package/skills/vinta-derive-skills/resources/plan-execution/partials/parallel-lanes.md +95 -50
- package/skills/vinta-derive-skills/resources/plan-execution/partials/pr-context.md +4 -2
- package/skills/vinta-derive-skills/resources/plan-execution/partials/relay-questions.md +13 -0
- package/skills/vinta-derive-skills/resources/plan-execution/partials/review-loop.md +81 -0
- package/skills/vinta-derive-skills/resources/plan-execution/partials/worktree-seam.md +86 -17
- package/skills/vinta-derive-skills/resources/plan-execution/shell/amend-plan-template.md +35 -16
- package/skills/vinta-derive-skills/resources/plan-execution/shell/implement-phase-template.md +12 -1
- package/skills/vinta-derive-skills/resources/plan-execution/shell/implement-plan-template.md +49 -33
- package/skills/vinta-derive-skills/resources/plan-execution/shell/integrate-phase-template.md +2 -1
- package/skills/vinta-derive-skills/resources/plan-execution/shell/review-phase-template.md +19 -27
- package/skills/vinta-derive-skills/resources/prs-context-template.md +5 -4
- package/skills/vinta-derive-skills/resources/systematic-debugging-mcp-tools.md +1 -1
- package/skills/vinta-derive-skills/resources/systematic-debugging-template.md +8 -8
- package/skills/vinta-derive-skills/resources/write-unit-test-packs/stacks/django.md +4 -1
- package/skills/vinta-derive-skills/resources/write-unit-test-template.md +3 -0
- package/skills/vinta-derive-subagents/SKILL.md +25 -9
- package/skills/vinta-install-ai-tools-setup/SKILL.md +29 -2
- package/skills/vinta-migrate-plans-specs/SKILL.md +7 -7
- package/skills/vinta-sync-ai-tools/SKILL.md +19 -2
- package/skills/vinta-update-project-skills/SKILL.md +1 -0
- package/skills/vinta-write-agents-md/SKILL.md +10 -6
- package/skills/vinta-write-agents-md/resources/asking-the-human.md +56 -0
- package/skills/vinta-derive-skills/resources/plan-execution/partials/review-layers.md +0 -101
|
@@ -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": {
|
|
@@ -120,13 +135,13 @@
|
|
|
120
135
|
"type": "string"
|
|
121
136
|
},
|
|
122
137
|
"dependency_licenses": {
|
|
123
|
-
"description": "Third-party dependency license policy. Captured at bootstrap; rendered into the repo-root `AGENTS.md` (`## Dependency licenses` section) and the `implement-plan` / `amend-plan` skill bodies so the implementer
|
|
138
|
+
"description": "Third-party dependency license policy. Captured at bootstrap; rendered into the repo-root `AGENTS.md` (`## Dependency licenses` section) and the `implement-plan` / `amend-plan` skill bodies so the implementer agent checks a new dep's SPDX license against `forbidden_spdx` before running any install command (`npm add`, `pnpm add`, `pip install`, `poetry add`, `uv add`, `cargo add`, `go get`, etc.). When `enforcement: block`, the agent must refuse the install and surface the violation to the user; `warn` records the violation in the phase report but proceeds; `off` skips the check entirely.",
|
|
124
139
|
"type": "object",
|
|
125
140
|
"required": ["enforcement", "forbidden_spdx"],
|
|
126
141
|
"additionalProperties": false,
|
|
127
142
|
"properties": {
|
|
128
143
|
"enforcement": {
|
|
129
|
-
"description": "How the implementer
|
|
144
|
+
"description": "How the implementer agent reacts when a new dep's license is in `forbidden_spdx`. `block` (default) — refuse install, ask user to confirm override before proceeding. `warn` — proceed but flag in the phase report. `off` — skip the check.",
|
|
130
145
|
"type": "string",
|
|
131
146
|
"enum": ["block", "warn", "off"],
|
|
132
147
|
"default": "block"
|
|
@@ -139,7 +154,7 @@
|
|
|
139
154
|
"default": ["GPL-2.0-only", "GPL-3.0-only", "AGPL-3.0-only", "SSPL-1.0"]
|
|
140
155
|
},
|
|
141
156
|
"allowed_overrides": {
|
|
142
|
-
"description": "Explicit per-package exceptions to `forbidden_spdx`. Each entry whitelists one package + license pair the team has accepted (legal review, dual-license clause, in-house carve-out). The implementer agent skips the block when the candidate package + license matches an entry
|
|
157
|
+
"description": "Explicit per-package exceptions to `forbidden_spdx`. Each entry whitelists one package + license pair the team has accepted (legal review, dual-license clause, in-house carve-out). The implementer agent skips the block when the candidate package + license matches an entry, and treats the entry as load-bearing context (never silently drops it).",
|
|
143
158
|
"type": "array",
|
|
144
159
|
"items": {
|
|
145
160
|
"type": "object",
|
|
@@ -209,17 +224,27 @@
|
|
|
209
224
|
"enum": ["enabled", "disabled"]
|
|
210
225
|
},
|
|
211
226
|
"prepare-worktree": {
|
|
212
|
-
"description": "Provision a fully-runnable git worktree for parallel feature work —
|
|
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
|
},
|
|
216
231
|
"thermo-nuclear-code-quality-review": {
|
|
217
|
-
"description": "Opt-in deep structural-maintainability audit of a diff — abstraction quality, giant files, spaghetti-condition growth — harsher than the standard per-phase review. Copy-verbatim foundation skill (bucket A). Read-only; hands each fix to the `fixer` agent. Invoked deliberately by the user
|
|
232
|
+
"description": "Opt-in deep structural-maintainability audit of a diff — abstraction quality, giant files, spaghetti-condition growth — harsher than the standard per-phase review. Copy-verbatim foundation skill (bucket A). Read-only; hands each fix to the `fixer` agent. Invoked deliberately by the user; never auto-run on every diff. The per-phase review (`thermo-nuclear-review-loop`) already applies a structural-simplification lens; this skill is the deliberate deep audit.",
|
|
233
|
+
"type": "string",
|
|
234
|
+
"enum": ["enabled", "disabled"]
|
|
235
|
+
},
|
|
236
|
+
"thermo-nuclear-review-loop": {
|
|
237
|
+
"description": "Review-and-fix loop over a change: the running agent spawns one reviewer sub-agent, verifies its findings, fixes the justified ones and answers the rest, until the reviewer explicitly approves under a strict code-quality standard. Copy-verbatim foundation skill (bucket A), always shipped: it is the per-phase review on both execution paths. The `review-phase` skill runs it over each phase `implement-plan`, `amend-plan` and `systematic-debugging` produce, with the conductor as the loop's host; and every `vinta-ai-maestro` workflow `plan-feature` writes names it in its `review` chore, which runs on the implementer's session once a phase's gates are green. Set `disabled` only if a project deliberately opts out of phase review.",
|
|
238
|
+
"type": "string",
|
|
239
|
+
"enum": ["enabled", "disabled"]
|
|
240
|
+
},
|
|
241
|
+
"interview-ui": {
|
|
242
|
+
"description": "Run decision-heavy interviews (create-spec Step 0 today) as a full-screen browser form instead of a chat exchange: one decision per screen with context, Markdown/Mermaid explainers, and per-option consequences; the in-page chat is for questions to the agent, not decisions. Copy-verbatim foundation skill (bucket A), opt-in. The server and the page are `vinta-ai-maestro interview` (`start` / `wait` / `status` / `stop`; Node ≥ 22), rendered with maestro's design system. Rounds and answers are JSON (`interview-round.v1` / `interview-answers.v1`) under `.vinta-ai-workflows/interviews/<slug>/`. When `enabled`, `create-spec` offers the browser surface at the start of its interview.",
|
|
218
243
|
"type": "string",
|
|
219
244
|
"enum": ["enabled", "disabled"]
|
|
220
245
|
},
|
|
221
246
|
"deslop-comments": {
|
|
222
|
-
"description": "Rewrite comments and doc blocks touched during the current task into Simple English — strip AI-slop vocabulary and negative framing, comment-only (no renames, no behavior change). Copy-verbatim foundation skill (bucket A), always shipped: the `
|
|
247
|
+
"description": "Rewrite comments and doc blocks touched during the current task into Simple English — strip AI-slop vocabulary and negative framing, comment-only (no renames, no behavior change). Copy-verbatim foundation skill (bucket A), always shipped: `vinta-ai-maestro`'s `deslop` chore runs it on every phase once the review approves, and `integrate-phase` / `amend-plan` run it over the PR-context prose they write. Set `disabled` only if a project deliberately opts out of both comment passes.",
|
|
223
248
|
"type": "string",
|
|
224
249
|
"enum": ["enabled", "disabled"]
|
|
225
250
|
},
|
|
@@ -250,25 +275,38 @@
|
|
|
250
275
|
"fixer": { "type": "string", "enum": ["enabled", "disabled"] }
|
|
251
276
|
}
|
|
252
277
|
},
|
|
278
|
+
"integrations": {
|
|
279
|
+
"description": "Per-integration opt-in for external tools that ship their own skills, as opposed to foundation skills this package bundles. An integration's skill is installed by that tool's own CLI into `ai-tools/skills/<name>/`, carries the tool's own ownership marker, and is never copied, rendered or refreshed by `vinta-derive-skills` / `vinta-update-project-skills`. Use `enabled` / `disabled`; `disabled` is a sticky opt-out, as for `foundation_skills`. Absent means the integration was never offered (projects bootstrapped before it existed).",
|
|
280
|
+
"type": "object",
|
|
281
|
+
"additionalProperties": { "type": "string", "enum": ["enabled", "disabled"] },
|
|
282
|
+
"properties": {
|
|
283
|
+
"pr-review-canvas": {
|
|
284
|
+
"description": "PR Review Canvas (`@vintasoftware/pr-review-canvas`, CLI `pr-review`): a topic-grouped review canvas for each PR, posted as a PR comment and read in a local review app. When `enabled`: `vinta-install-ai-tools-setup` runs `pr-review install-skill` into `ai-tools/skills/` (the CLI itself is a global install the user does, never auto-installed); the `integrate-phase` PR step runs the `pr-review-canvas` skill after `open-pr.sh` publishes a PR; and `plan-feature` adds an `after_pr` `review-canvas` chore to the maestro workflow it writes. Posting the canvas comment follows the tool's own `sharing.canvasComment` setting in `pr-review.config.yml`.",
|
|
285
|
+
"type": "string",
|
|
286
|
+
"enum": ["enabled", "disabled"]
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
},
|
|
253
290
|
"agent_models": {
|
|
254
|
-
"description": "Per-role / per-task model selection for the plan-execution family, expressed as **tiers** (1–4) into the same table `plan-feature` uses — `ai-tools/skills/plan-feature/resources/ai-models.yaml`. Each consuming skill resolves a tier to a concrete model at runtime: take that tier's `models`, filter to the vendors the runtime exposes, pick the cheapest survivor. This keeps the config free of hard-coded model IDs (which go stale) — the nightly `check-ai-models` job keeps the tier table fresh. Every key is optional; an unset key (or the whole section absent) means the spawn uses the runtime's default model, i.e. today's behavior.
|
|
291
|
+
"description": "Per-role / per-task model selection for the plan-execution family, expressed as **tiers** (1–4) into the same table `plan-feature` uses — `ai-tools/skills/plan-feature/resources/ai-models.yaml`. Each consuming skill resolves a tier to a concrete model at runtime: take that tier's `models`, filter to the vendors the runtime exposes, pick the cheapest survivor. This keeps the config free of hard-coded model IDs (which go stale) — the nightly `check-ai-models` job keeps the tier table fresh. Every key is optional; an unset key (or the whole section absent) means the spawn uses the runtime's default model, i.e. today's behavior. The per-phase implementer model is NOT here — the plan owns it, through its **Crew** table and each phase's `**Assigned to**:` line. Neither is the review model: `review-phase` runs its reviewer one tier above the tier the phase's implementer actually ran at, and the phase's own implementer fixes the findings at its own tier. The conflict fixer and the mechanical steps (`worktree_prep`, `integrate`) are never plan-named.",
|
|
255
292
|
"type": "object",
|
|
256
293
|
"additionalProperties": false,
|
|
257
294
|
"properties": {
|
|
258
295
|
"reviewer": {
|
|
259
|
-
"description": "
|
|
296
|
+
"description": "**Deprecated since 0.7.0, and ignored.** The plan-execution review runs one tier above the phase's implementer (`review-phase` derives it), so no configured tier is read. Kept so existing configs still validate; remove it at your next edit.",
|
|
297
|
+
"deprecated": true,
|
|
260
298
|
"type": "integer",
|
|
261
299
|
"minimum": 1,
|
|
262
300
|
"maximum": 4
|
|
263
301
|
},
|
|
264
302
|
"fixer": {
|
|
265
|
-
"description": "
|
|
303
|
+
"description": "Tier for the merge-conflict fixer subagent (the project's `fixer` agent type) that `implement-plan` spawns when a wave integration or a dependent phase's merge conflicts, and that `amend-plan` spawns when a rewrite conflicts with a child phase. Narrow, well-specified edits — Tier 2 is the usual default. Review findings are not this role's: the phase's own implementer fixes them, and a cold fallback fixer runs at the implementer's tier. Unset → runtime default.",
|
|
266
304
|
"type": "integer",
|
|
267
305
|
"minimum": 1,
|
|
268
306
|
"maximum": 4
|
|
269
307
|
},
|
|
270
308
|
"worktree_prep": {
|
|
271
|
-
"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
|
|
309
|
+
"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.",
|
|
272
310
|
"type": "integer",
|
|
273
311
|
"minimum": 1,
|
|
274
312
|
"maximum": 4
|
|
@@ -295,6 +333,627 @@
|
|
|
295
333
|
"uniqueItems": true,
|
|
296
334
|
"default": []
|
|
297
335
|
},
|
|
336
|
+
"maestro": {
|
|
337
|
+
"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`, `codegen`, `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.",
|
|
338
|
+
"type": "object",
|
|
339
|
+
"additionalProperties": false,
|
|
340
|
+
"properties": {
|
|
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`), `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
|
+
"type": "object",
|
|
344
|
+
"properties": {
|
|
345
|
+
"harness": {
|
|
346
|
+
"type": "string",
|
|
347
|
+
"enum": [
|
|
348
|
+
"claude-code",
|
|
349
|
+
"codex",
|
|
350
|
+
"opencode"
|
|
351
|
+
]
|
|
352
|
+
},
|
|
353
|
+
"model": {
|
|
354
|
+
"type": "string",
|
|
355
|
+
"minLength": 1
|
|
356
|
+
},
|
|
357
|
+
"pipeline": {
|
|
358
|
+
"type": "string",
|
|
359
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
|
360
|
+
},
|
|
361
|
+
"chores": {
|
|
362
|
+
"type": "array",
|
|
363
|
+
"items": {
|
|
364
|
+
"type": "string",
|
|
365
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
"gates": {
|
|
369
|
+
"type": "array",
|
|
370
|
+
"items": {
|
|
371
|
+
"type": "string",
|
|
372
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
"gate_scope": {
|
|
376
|
+
"type": "string",
|
|
377
|
+
"enum": [
|
|
378
|
+
"scoped",
|
|
379
|
+
"full"
|
|
380
|
+
]
|
|
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
|
+
},
|
|
398
|
+
"substitution": {
|
|
399
|
+
"type": "string",
|
|
400
|
+
"enum": [
|
|
401
|
+
"same_tier",
|
|
402
|
+
"up_one_tier",
|
|
403
|
+
"any"
|
|
404
|
+
],
|
|
405
|
+
"description": "How far above the member the plan named a phase may be moved. `up_one_tier` (the default): a busy member's phase may go to the next tier up the roster has, and a warm session never moves a phase up. `same_tier`: a peer at the same tier or wait. `any`: any tier above, warm sessions included."
|
|
406
|
+
},
|
|
407
|
+
"wave_gates": {
|
|
408
|
+
"type": "string",
|
|
409
|
+
"enum": [
|
|
410
|
+
"off",
|
|
411
|
+
"final",
|
|
412
|
+
"every"
|
|
413
|
+
],
|
|
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`)."
|
|
415
|
+
},
|
|
416
|
+
"allow_ungated_phases": {
|
|
417
|
+
"type": "boolean",
|
|
418
|
+
"description": "Whether a phase that resolves to no gates is acceptable. Off (the default): `vinta-ai-maestro validate` refuses the workflow and `doctor` warns, because an ungated phase passes its gate step without running anything."
|
|
419
|
+
},
|
|
420
|
+
"model_fallbacks": {
|
|
421
|
+
"description": "Model id → the model to run instead once the first is out of quota or credits. A `quota` refusal on a listed model retries on the fallback instead of parking the harness; later spawns of that model go straight to the fallback until the vendor's stated reset, or for the rest of the run. A plan's own map replaces this one whole.",
|
|
422
|
+
"type": "object",
|
|
423
|
+
"additionalProperties": {
|
|
424
|
+
"type": "string",
|
|
425
|
+
"minLength": 1
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
"max_session_turns": {
|
|
429
|
+
"type": "integer",
|
|
430
|
+
"minimum": 1
|
|
431
|
+
},
|
|
432
|
+
"pull_requests": {
|
|
433
|
+
"type": "string",
|
|
434
|
+
"enum": [
|
|
435
|
+
"phase",
|
|
436
|
+
"plan"
|
|
437
|
+
],
|
|
438
|
+
"description": "Which pull requests a run opens. `phase` (the default): one per phase, one per integration branch, and the plan PR that lands them. `plan`: the plan PR alone, from the last wave branch; phases' `after_pr` chores are then skipped."
|
|
439
|
+
},
|
|
440
|
+
"max_spare_crew": {
|
|
441
|
+
"type": "integer",
|
|
442
|
+
"minimum": 0,
|
|
443
|
+
"description": "Crew members a run may take on beyond the plan's roster (default 2). When the member a phase was planned for is busy, the phase gets a new member at that member's tier and model, with its own worktree, instead of borrowing a member another pending phase is planned for or waiting. `0` keeps the roster to the plan's."
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
"additionalProperties": false
|
|
447
|
+
},
|
|
448
|
+
"gates": {
|
|
449
|
+
"description": "Keyed by gate type (`test`, `lint`, `typecheck`, `e2e`) or by a custom id. 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). Any other key is a custom project-wide gate — e.g. `django-check: { cmd: uv run python manage.py check --fail-level WARNING }` — that every plan has under that id and that `maestro.defaults.gates` names like a type. A custom id is lowercase kebab-case; `codegen` is reserved (it names a plan's codegen steps).",
|
|
450
|
+
"type": "object",
|
|
451
|
+
"additionalProperties": false,
|
|
452
|
+
"properties": {
|
|
453
|
+
"test": {
|
|
454
|
+
"description": "Defaults a gate of this type inherits, over the matching `commands.*` line. Any field a plan's own gate sets wins over these.",
|
|
455
|
+
"type": "object",
|
|
456
|
+
"additionalProperties": false,
|
|
457
|
+
"properties": {
|
|
458
|
+
"cmd": {
|
|
459
|
+
"description": "The full check maestro runs for this type. Overrides the `commands.*` line for maestro only — `implement-plan` keeps running `commands.*`.",
|
|
460
|
+
"type": "string",
|
|
461
|
+
"minLength": 1
|
|
462
|
+
},
|
|
463
|
+
"scoped_cmd": {
|
|
464
|
+
"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.",
|
|
465
|
+
"type": "string",
|
|
466
|
+
"minLength": 1
|
|
467
|
+
},
|
|
468
|
+
"fresh_cmd": {
|
|
469
|
+
"description": "The same check run from fresh state (the test database recreated, e.g. `pytest --create-db`). Run in place of `cmd` in the integration worktree whenever the state an earlier run left there may belong to another tree: the tree moved anywhere but forward, the gate has not run there yet in this process, its red output reads as a stale schema, or a conflict fixer reported `ENVIRONMENT_STALE`. Must check at least what `cmd` does.",
|
|
470
|
+
"type": "string",
|
|
471
|
+
"minLength": 1
|
|
472
|
+
},
|
|
473
|
+
"fresh_when": {
|
|
474
|
+
"description": "Globs, relative to the repository root, of the files the state `fresh_cmd` recreates is built from — the migrations, typically (e.g. `apps/*/migrations/*.py`). When a file that matched at the gate's last run in the integration worktree is gone or different now, the gate runs `fresh_cmd` even though the tree moved forward: a reused database keeps a migration that was rewritten or renamed under it. Files added since do not count. Ignored without `fresh_cmd`.",
|
|
475
|
+
"type": "array",
|
|
476
|
+
"items": {
|
|
477
|
+
"type": "string",
|
|
478
|
+
"minLength": 1
|
|
479
|
+
}
|
|
480
|
+
},
|
|
481
|
+
"cold_cmd": {
|
|
482
|
+
"description": "What a phase gate runs in place of `scoped_cmd` when the lane lacks a `scope_cache` file (e.g. `make test`, the suite in parallel, instead of a `--testmon` run that without `.testmondata` runs every test serially). Defaults to `cmd`. Must check at least what `scoped_cmd` does.",
|
|
483
|
+
"type": "string",
|
|
484
|
+
"minLength": 1
|
|
485
|
+
},
|
|
486
|
+
"scope_cache": {
|
|
487
|
+
"description": "Files `scoped_cmd` narrows by, relative to the lane (e.g. `apps/api/.testmondata`). When any is missing, a phase gate runs `cold_cmd` (or `cmd`) instead and journals why.",
|
|
488
|
+
"type": "array",
|
|
489
|
+
"items": { "type": "string", "minLength": 1 }
|
|
490
|
+
},
|
|
491
|
+
"requires": {
|
|
492
|
+
"description": "Resource pools the gate holds while it runs, e.g. `[test-suite]`.",
|
|
493
|
+
"type": "array",
|
|
494
|
+
"items": {
|
|
495
|
+
"type": "string",
|
|
496
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
|
497
|
+
}
|
|
498
|
+
},
|
|
499
|
+
"timeout_s": {
|
|
500
|
+
"type": "integer",
|
|
501
|
+
"minimum": 1
|
|
502
|
+
},
|
|
503
|
+
"queue_timeout_s": {
|
|
504
|
+
"description": "How long a phase gate may wait for its `requires` pools before the attempt fails, naming who held them. `timeout_s` counts only the command's own runtime. Absent, it waits as long as it takes.",
|
|
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
|
+
"lint": {
|
|
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
|
+
"fresh_cmd": {
|
|
544
|
+
"description": "The same check run from fresh state (the test database recreated, e.g. `pytest --create-db`). Run in place of `cmd` in the integration worktree whenever the state an earlier run left there may belong to another tree: the tree moved anywhere but forward, the gate has not run there yet in this process, its red output reads as a stale schema, or a conflict fixer reported `ENVIRONMENT_STALE`. Must check at least what `cmd` does.",
|
|
545
|
+
"type": "string",
|
|
546
|
+
"minLength": 1
|
|
547
|
+
},
|
|
548
|
+
"fresh_when": {
|
|
549
|
+
"description": "Globs, relative to the repository root, of the files the state `fresh_cmd` recreates is built from — the migrations, typically (e.g. `apps/*/migrations/*.py`). When a file that matched at the gate's last run in the integration worktree is gone or different now, the gate runs `fresh_cmd` even though the tree moved forward: a reused database keeps a migration that was rewritten or renamed under it. Files added since do not count. Ignored without `fresh_cmd`.",
|
|
550
|
+
"type": "array",
|
|
551
|
+
"items": {
|
|
552
|
+
"type": "string",
|
|
553
|
+
"minLength": 1
|
|
554
|
+
}
|
|
555
|
+
},
|
|
556
|
+
"cold_cmd": {
|
|
557
|
+
"description": "What a phase gate runs in place of `scoped_cmd` when the lane lacks a `scope_cache` file (e.g. `make test`, the suite in parallel, instead of a `--testmon` run that without `.testmondata` runs every test serially). Defaults to `cmd`. Must check at least what `scoped_cmd` does.",
|
|
558
|
+
"type": "string",
|
|
559
|
+
"minLength": 1
|
|
560
|
+
},
|
|
561
|
+
"scope_cache": {
|
|
562
|
+
"description": "Files `scoped_cmd` narrows by, relative to the lane (e.g. `apps/api/.testmondata`). When any is missing, a phase gate runs `cold_cmd` (or `cmd`) instead and journals why.",
|
|
563
|
+
"type": "array",
|
|
564
|
+
"items": { "type": "string", "minLength": 1 }
|
|
565
|
+
},
|
|
566
|
+
"requires": {
|
|
567
|
+
"description": "Resource pools the gate holds while it runs, e.g. `[test-suite]`.",
|
|
568
|
+
"type": "array",
|
|
569
|
+
"items": {
|
|
570
|
+
"type": "string",
|
|
571
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
|
572
|
+
}
|
|
573
|
+
},
|
|
574
|
+
"timeout_s": {
|
|
575
|
+
"type": "integer",
|
|
576
|
+
"minimum": 1
|
|
577
|
+
},
|
|
578
|
+
"queue_timeout_s": {
|
|
579
|
+
"description": "How long a phase gate may wait for its `requires` pools before the attempt fails, naming who held them. `timeout_s` counts only the command's own runtime. Absent, it waits as long as it takes.",
|
|
580
|
+
"type": "integer",
|
|
581
|
+
"minimum": 1
|
|
582
|
+
},
|
|
583
|
+
"tuning": {
|
|
584
|
+
"description": "Flags the monitor may add to `cmd` when it retunes the gate mid-run. Same shape as a workflow gate's `tuning`.",
|
|
585
|
+
"type": "object",
|
|
586
|
+
"properties": {
|
|
587
|
+
"allowed_flags": {
|
|
588
|
+
"type": "array",
|
|
589
|
+
"items": {
|
|
590
|
+
"type": "string",
|
|
591
|
+
"minLength": 1
|
|
592
|
+
},
|
|
593
|
+
"minItems": 1
|
|
594
|
+
}
|
|
595
|
+
},
|
|
596
|
+
"required": [
|
|
597
|
+
"allowed_flags"
|
|
598
|
+
],
|
|
599
|
+
"additionalProperties": false
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
},
|
|
603
|
+
"typecheck": {
|
|
604
|
+
"description": "Defaults a gate of this type inherits, over the matching `commands.*` line. Any field a plan's own gate sets wins over these.",
|
|
605
|
+
"type": "object",
|
|
606
|
+
"additionalProperties": false,
|
|
607
|
+
"properties": {
|
|
608
|
+
"cmd": {
|
|
609
|
+
"description": "The full check maestro runs for this type. Overrides the `commands.*` line for maestro only — `implement-plan` keeps running `commands.*`.",
|
|
610
|
+
"type": "string",
|
|
611
|
+
"minLength": 1
|
|
612
|
+
},
|
|
613
|
+
"scoped_cmd": {
|
|
614
|
+
"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.",
|
|
615
|
+
"type": "string",
|
|
616
|
+
"minLength": 1
|
|
617
|
+
},
|
|
618
|
+
"fresh_cmd": {
|
|
619
|
+
"description": "The same check run from fresh state (the test database recreated, e.g. `pytest --create-db`). Run in place of `cmd` in the integration worktree whenever the state an earlier run left there may belong to another tree: the tree moved anywhere but forward, the gate has not run there yet in this process, its red output reads as a stale schema, or a conflict fixer reported `ENVIRONMENT_STALE`. Must check at least what `cmd` does.",
|
|
620
|
+
"type": "string",
|
|
621
|
+
"minLength": 1
|
|
622
|
+
},
|
|
623
|
+
"fresh_when": {
|
|
624
|
+
"description": "Globs, relative to the repository root, of the files the state `fresh_cmd` recreates is built from — the migrations, typically (e.g. `apps/*/migrations/*.py`). When a file that matched at the gate's last run in the integration worktree is gone or different now, the gate runs `fresh_cmd` even though the tree moved forward: a reused database keeps a migration that was rewritten or renamed under it. Files added since do not count. Ignored without `fresh_cmd`.",
|
|
625
|
+
"type": "array",
|
|
626
|
+
"items": {
|
|
627
|
+
"type": "string",
|
|
628
|
+
"minLength": 1
|
|
629
|
+
}
|
|
630
|
+
},
|
|
631
|
+
"cold_cmd": {
|
|
632
|
+
"description": "What a phase gate runs in place of `scoped_cmd` when the lane lacks a `scope_cache` file (e.g. `make test`, the suite in parallel, instead of a `--testmon` run that without `.testmondata` runs every test serially). Defaults to `cmd`. Must check at least what `scoped_cmd` does.",
|
|
633
|
+
"type": "string",
|
|
634
|
+
"minLength": 1
|
|
635
|
+
},
|
|
636
|
+
"scope_cache": {
|
|
637
|
+
"description": "Files `scoped_cmd` narrows by, relative to the lane (e.g. `apps/api/.testmondata`). When any is missing, a phase gate runs `cold_cmd` (or `cmd`) instead and journals why.",
|
|
638
|
+
"type": "array",
|
|
639
|
+
"items": { "type": "string", "minLength": 1 }
|
|
640
|
+
},
|
|
641
|
+
"requires": {
|
|
642
|
+
"description": "Resource pools the gate holds while it runs, e.g. `[test-suite]`.",
|
|
643
|
+
"type": "array",
|
|
644
|
+
"items": {
|
|
645
|
+
"type": "string",
|
|
646
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
|
647
|
+
}
|
|
648
|
+
},
|
|
649
|
+
"timeout_s": {
|
|
650
|
+
"type": "integer",
|
|
651
|
+
"minimum": 1
|
|
652
|
+
},
|
|
653
|
+
"queue_timeout_s": {
|
|
654
|
+
"description": "How long a phase gate may wait for its `requires` pools before the attempt fails, naming who held them. `timeout_s` counts only the command's own runtime. Absent, it waits as long as it takes.",
|
|
655
|
+
"type": "integer",
|
|
656
|
+
"minimum": 1
|
|
657
|
+
},
|
|
658
|
+
"tuning": {
|
|
659
|
+
"description": "Flags the monitor may add to `cmd` when it retunes the gate mid-run. Same shape as a workflow gate's `tuning`.",
|
|
660
|
+
"type": "object",
|
|
661
|
+
"properties": {
|
|
662
|
+
"allowed_flags": {
|
|
663
|
+
"type": "array",
|
|
664
|
+
"items": {
|
|
665
|
+
"type": "string",
|
|
666
|
+
"minLength": 1
|
|
667
|
+
},
|
|
668
|
+
"minItems": 1
|
|
669
|
+
}
|
|
670
|
+
},
|
|
671
|
+
"required": [
|
|
672
|
+
"allowed_flags"
|
|
673
|
+
],
|
|
674
|
+
"additionalProperties": false
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
},
|
|
678
|
+
"e2e": {
|
|
679
|
+
"description": "Defaults a gate of this type inherits, over the matching `commands.*` line. Any field a plan's own gate sets wins over these.",
|
|
680
|
+
"type": "object",
|
|
681
|
+
"additionalProperties": false,
|
|
682
|
+
"properties": {
|
|
683
|
+
"cmd": {
|
|
684
|
+
"description": "The full check maestro runs for this type. Overrides the `commands.*` line for maestro only — `implement-plan` keeps running `commands.*`.",
|
|
685
|
+
"type": "string",
|
|
686
|
+
"minLength": 1
|
|
687
|
+
},
|
|
688
|
+
"scoped_cmd": {
|
|
689
|
+
"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.",
|
|
690
|
+
"type": "string",
|
|
691
|
+
"minLength": 1
|
|
692
|
+
},
|
|
693
|
+
"fresh_cmd": {
|
|
694
|
+
"description": "The same check run from fresh state (the test database recreated, e.g. `pytest --create-db`). Run in place of `cmd` in the integration worktree whenever the state an earlier run left there may belong to another tree: the tree moved anywhere but forward, the gate has not run there yet in this process, its red output reads as a stale schema, or a conflict fixer reported `ENVIRONMENT_STALE`. Must check at least what `cmd` does.",
|
|
695
|
+
"type": "string",
|
|
696
|
+
"minLength": 1
|
|
697
|
+
},
|
|
698
|
+
"fresh_when": {
|
|
699
|
+
"description": "Globs, relative to the repository root, of the files the state `fresh_cmd` recreates is built from — the migrations, typically (e.g. `apps/*/migrations/*.py`). When a file that matched at the gate's last run in the integration worktree is gone or different now, the gate runs `fresh_cmd` even though the tree moved forward: a reused database keeps a migration that was rewritten or renamed under it. Files added since do not count. Ignored without `fresh_cmd`.",
|
|
700
|
+
"type": "array",
|
|
701
|
+
"items": {
|
|
702
|
+
"type": "string",
|
|
703
|
+
"minLength": 1
|
|
704
|
+
}
|
|
705
|
+
},
|
|
706
|
+
"cold_cmd": {
|
|
707
|
+
"description": "What a phase gate runs in place of `scoped_cmd` when the lane lacks a `scope_cache` file (e.g. `make test`, the suite in parallel, instead of a `--testmon` run that without `.testmondata` runs every test serially). Defaults to `cmd`. Must check at least what `scoped_cmd` does.",
|
|
708
|
+
"type": "string",
|
|
709
|
+
"minLength": 1
|
|
710
|
+
},
|
|
711
|
+
"scope_cache": {
|
|
712
|
+
"description": "Files `scoped_cmd` narrows by, relative to the lane (e.g. `apps/api/.testmondata`). When any is missing, a phase gate runs `cold_cmd` (or `cmd`) instead and journals why.",
|
|
713
|
+
"type": "array",
|
|
714
|
+
"items": { "type": "string", "minLength": 1 }
|
|
715
|
+
},
|
|
716
|
+
"requires": {
|
|
717
|
+
"description": "Resource pools the gate holds while it runs, e.g. `[test-suite]`.",
|
|
718
|
+
"type": "array",
|
|
719
|
+
"items": {
|
|
720
|
+
"type": "string",
|
|
721
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
|
722
|
+
}
|
|
723
|
+
},
|
|
724
|
+
"timeout_s": {
|
|
725
|
+
"type": "integer",
|
|
726
|
+
"minimum": 1
|
|
727
|
+
},
|
|
728
|
+
"queue_timeout_s": {
|
|
729
|
+
"description": "How long a phase gate may wait for its `requires` pools before the attempt fails, naming who held them. `timeout_s` counts only the command's own runtime. Absent, it waits as long as it takes.",
|
|
730
|
+
"type": "integer",
|
|
731
|
+
"minimum": 1
|
|
732
|
+
},
|
|
733
|
+
"tuning": {
|
|
734
|
+
"description": "Flags the monitor may add to `cmd` when it retunes the gate mid-run. Same shape as a workflow gate's `tuning`.",
|
|
735
|
+
"type": "object",
|
|
736
|
+
"properties": {
|
|
737
|
+
"allowed_flags": {
|
|
738
|
+
"type": "array",
|
|
739
|
+
"items": {
|
|
740
|
+
"type": "string",
|
|
741
|
+
"minLength": 1
|
|
742
|
+
},
|
|
743
|
+
"minItems": 1
|
|
744
|
+
}
|
|
745
|
+
},
|
|
746
|
+
"required": [
|
|
747
|
+
"allowed_flags"
|
|
748
|
+
],
|
|
749
|
+
"additionalProperties": false
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
},
|
|
754
|
+
"patternProperties": {
|
|
755
|
+
"^(?!(?:test|lint|typecheck|e2e|codegen)$)[a-z0-9][a-z0-9-]*$": {
|
|
756
|
+
"description": "A custom gate every plan has under this id, untyped: nothing supplies its command but `cmd` here. A plan's own gate of the same id replaces it whole. Same fields as a gate type's entry.",
|
|
757
|
+
"type": "object",
|
|
758
|
+
"additionalProperties": false,
|
|
759
|
+
"required": ["cmd"],
|
|
760
|
+
"properties": {
|
|
761
|
+
"cmd": {
|
|
762
|
+
"description": "The full check. Required: only the four gate types inherit a command from `commands.*`.",
|
|
763
|
+
"type": "string",
|
|
764
|
+
"minLength": 1
|
|
765
|
+
},
|
|
766
|
+
"scoped_cmd": {
|
|
767
|
+
"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.",
|
|
768
|
+
"type": "string",
|
|
769
|
+
"minLength": 1
|
|
770
|
+
},
|
|
771
|
+
"fresh_cmd": {
|
|
772
|
+
"description": "The same check run from fresh state (the test database recreated, e.g. `pytest --create-db`). Run in place of `cmd` in the integration worktree whenever the state an earlier run left there may belong to another tree: the tree moved anywhere but forward, the gate has not run there yet in this process, its red output reads as a stale schema, or a conflict fixer reported `ENVIRONMENT_STALE`. Must check at least what `cmd` does.",
|
|
773
|
+
"type": "string",
|
|
774
|
+
"minLength": 1
|
|
775
|
+
},
|
|
776
|
+
"fresh_when": {
|
|
777
|
+
"description": "Globs, relative to the repository root, of the files the state `fresh_cmd` recreates is built from — the migrations, typically (e.g. `apps/*/migrations/*.py`). When a file that matched at the gate's last run in the integration worktree is gone or different now, the gate runs `fresh_cmd` even though the tree moved forward: a reused database keeps a migration that was rewritten or renamed under it. Files added since do not count. Ignored without `fresh_cmd`.",
|
|
778
|
+
"type": "array",
|
|
779
|
+
"items": {
|
|
780
|
+
"type": "string",
|
|
781
|
+
"minLength": 1
|
|
782
|
+
}
|
|
783
|
+
},
|
|
784
|
+
"cold_cmd": {
|
|
785
|
+
"description": "What a phase gate runs in place of `scoped_cmd` when the lane lacks a `scope_cache` file (e.g. `make test`, the suite in parallel, instead of a `--testmon` run that without `.testmondata` runs every test serially). Defaults to `cmd`. Must check at least what `scoped_cmd` does.",
|
|
786
|
+
"type": "string",
|
|
787
|
+
"minLength": 1
|
|
788
|
+
},
|
|
789
|
+
"scope_cache": {
|
|
790
|
+
"description": "Files `scoped_cmd` narrows by, relative to the lane (e.g. `apps/api/.testmondata`). When any is missing, a phase gate runs `cold_cmd` (or `cmd`) instead and journals why.",
|
|
791
|
+
"type": "array",
|
|
792
|
+
"items": { "type": "string", "minLength": 1 }
|
|
793
|
+
},
|
|
794
|
+
"requires": {
|
|
795
|
+
"description": "Resource pools the gate holds while it runs, e.g. `[test-suite]`.",
|
|
796
|
+
"type": "array",
|
|
797
|
+
"items": {
|
|
798
|
+
"type": "string",
|
|
799
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
|
800
|
+
}
|
|
801
|
+
},
|
|
802
|
+
"timeout_s": {
|
|
803
|
+
"type": "integer",
|
|
804
|
+
"minimum": 1
|
|
805
|
+
},
|
|
806
|
+
"queue_timeout_s": {
|
|
807
|
+
"description": "How long a phase gate may wait for its `requires` pools before the attempt fails, naming who held them. `timeout_s` counts only the command's own runtime. Absent, it waits as long as it takes.",
|
|
808
|
+
"type": "integer",
|
|
809
|
+
"minimum": 1
|
|
810
|
+
},
|
|
811
|
+
"tuning": {
|
|
812
|
+
"description": "Flags the monitor may add to `cmd` when it retunes the gate mid-run. Same shape as a workflow gate's `tuning`.",
|
|
813
|
+
"type": "object",
|
|
814
|
+
"properties": {
|
|
815
|
+
"allowed_flags": {
|
|
816
|
+
"type": "array",
|
|
817
|
+
"items": {
|
|
818
|
+
"type": "string",
|
|
819
|
+
"minLength": 1
|
|
820
|
+
},
|
|
821
|
+
"minItems": 1
|
|
822
|
+
}
|
|
823
|
+
},
|
|
824
|
+
"required": [
|
|
825
|
+
"allowed_flags"
|
|
826
|
+
],
|
|
827
|
+
"additionalProperties": false
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
},
|
|
833
|
+
"resources": {
|
|
834
|
+
"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> --`.",
|
|
835
|
+
"type": "object",
|
|
836
|
+
"propertyNames": {
|
|
837
|
+
"type": "string",
|
|
838
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
|
839
|
+
},
|
|
840
|
+
"additionalProperties": {
|
|
841
|
+
"type": "object",
|
|
842
|
+
"required": [
|
|
843
|
+
"capacity",
|
|
844
|
+
"kind"
|
|
845
|
+
],
|
|
846
|
+
"additionalProperties": false,
|
|
847
|
+
"properties": {
|
|
848
|
+
"capacity": {
|
|
849
|
+
"type": "integer",
|
|
850
|
+
"minimum": 1
|
|
851
|
+
},
|
|
852
|
+
"kind": {
|
|
853
|
+
"type": "string",
|
|
854
|
+
"enum": [
|
|
855
|
+
"worktree",
|
|
856
|
+
"semaphore"
|
|
857
|
+
]
|
|
858
|
+
},
|
|
859
|
+
"scope": {
|
|
860
|
+
"description": "`run` (the default) counts this run's holders only; `host` also counts every other maestro run on the machine holding a pool of the same name, so two runs on one laptop take turns at the full suite.",
|
|
861
|
+
"type": "string",
|
|
862
|
+
"enum": [
|
|
863
|
+
"run",
|
|
864
|
+
"host"
|
|
865
|
+
]
|
|
866
|
+
},
|
|
867
|
+
"match": {
|
|
868
|
+
"type": "array",
|
|
869
|
+
"items": {
|
|
870
|
+
"type": "string",
|
|
871
|
+
"minLength": 1
|
|
872
|
+
}
|
|
873
|
+
},
|
|
874
|
+
"description": {
|
|
875
|
+
"type": "string"
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
},
|
|
880
|
+
"chores": {
|
|
881
|
+
"description": "Chore definitions by id (`prompt` or `prompt_ref`, `skill`, `session`, `model`, `when`, `on_failure`) — the workflow schema's `chores` entries. `when` is `review` (runs once the phase's gates are green; the turn ends with `VERDICT: pass` or `VERDICT: fail` and the phase continues only on pass — e.g. a `thermo-nuclear-review-loop` chore), `after_review` (the default: runs after the review approved, before the final gate run — e.g. a `deslop-comments` chore) or `after_pr` (runs after the phase's PR is published).",
|
|
882
|
+
"type": "object",
|
|
883
|
+
"propertyNames": {
|
|
884
|
+
"type": "string",
|
|
885
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
|
886
|
+
},
|
|
887
|
+
"additionalProperties": {
|
|
888
|
+
"type": "object"
|
|
889
|
+
}
|
|
890
|
+
},
|
|
891
|
+
"codegen": {
|
|
892
|
+
"description": "Codegen steps by id (`cmd`, `outputs`, `inputs`, `after`, `requires`, `timeout_s`, `format`) — the workflow schema's `codegen` entries. Deterministic commands that write declared files: an OpenAPI schema, the client generated from it, a route tree, or a formatter scoped to the files a phase changed (`format: true`, `{changed_files}` in `cmd`). Maestro runs them in every lane before its gates and commits what they write, and in the integration worktree around every merge, where a conflict confined to their outputs is settled by running them instead of by a fixer agent. A failing step is a red gate.",
|
|
893
|
+
"type": "object",
|
|
894
|
+
"propertyNames": {
|
|
895
|
+
"type": "string",
|
|
896
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
|
897
|
+
},
|
|
898
|
+
"additionalProperties": {
|
|
899
|
+
"type": "object",
|
|
900
|
+
"required": [
|
|
901
|
+
"cmd",
|
|
902
|
+
"outputs"
|
|
903
|
+
],
|
|
904
|
+
"properties": {
|
|
905
|
+
"cmd": {
|
|
906
|
+
"type": "string",
|
|
907
|
+
"minLength": 1
|
|
908
|
+
},
|
|
909
|
+
"outputs": {
|
|
910
|
+
"type": "array",
|
|
911
|
+
"minItems": 1,
|
|
912
|
+
"items": {
|
|
913
|
+
"type": "string",
|
|
914
|
+
"minLength": 1
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
},
|
|
920
|
+
"append_only": {
|
|
921
|
+
"description": "Files every phase only appends to — a DI container, a URL route list, a registry of notification kinds, a beat schedule — as gitattributes patterns. Maestro merges them in the integration worktree with git's `union` driver, so two phases each adding an entry do not conflict; the merged tree is then gated as any other. A plan's own `append_only` replaces this list.",
|
|
922
|
+
"type": "array",
|
|
923
|
+
"items": {
|
|
924
|
+
"type": "string",
|
|
925
|
+
"minLength": 1
|
|
926
|
+
}
|
|
927
|
+
},
|
|
928
|
+
"post_merge": {
|
|
929
|
+
"description": "A command run in maestro's integration worktree after git merges a branch by itself, with `{files}` replaced by the files both sides changed — e.g. `python -m py_compile {files} && ruff check --fix --select I,F811,F401 {files} && ruff format {files}`. What it changes is committed on top of the merge; a non-zero exit is journalled and the merged tree's gates judge it. A plan's own `post_merge` replaces this one.",
|
|
930
|
+
"type": "object",
|
|
931
|
+
"additionalProperties": false,
|
|
932
|
+
"required": ["cmd"],
|
|
933
|
+
"properties": {
|
|
934
|
+
"cmd": { "type": "string", "minLength": 1 },
|
|
935
|
+
"timeout_s": { "type": "integer", "minimum": 1 }
|
|
936
|
+
}
|
|
937
|
+
},
|
|
938
|
+
"ci_only": {
|
|
939
|
+
"description": "CI checks deliberately left to CI, each with its reason (it needs credentials, a deploy, a hosted service). `vinta-ai-maestro doctor` warns about every CI command no gate runs; one listed here is a decision, not a gap. A plan's own `ci_only` replaces this list.",
|
|
940
|
+
"type": "array",
|
|
941
|
+
"items": {
|
|
942
|
+
"type": "object",
|
|
943
|
+
"additionalProperties": false,
|
|
944
|
+
"required": ["command", "reason"],
|
|
945
|
+
"properties": {
|
|
946
|
+
"command": { "type": "string", "minLength": 1, "description": "The CI command as CI runs it; wrappers like `uv run` are ignored when matching." },
|
|
947
|
+
"reason": { "type": "string", "minLength": 1 }
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
},
|
|
951
|
+
"project": {
|
|
952
|
+
"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`).",
|
|
953
|
+
"type": "object"
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
},
|
|
298
957
|
"run_options": {
|
|
299
958
|
"description": "Per-skill run-option defaults. Skills override via per-invocation prompts; values here are the defaults shown.",
|
|
300
959
|
"type": "object",
|
|
@@ -312,12 +971,12 @@
|
|
|
312
971
|
"default": false
|
|
313
972
|
},
|
|
314
973
|
"use_worktree": {
|
|
315
|
-
"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.",
|
|
974
|
+
"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.",
|
|
316
975
|
"type": "boolean",
|
|
317
976
|
"default": false
|
|
318
977
|
},
|
|
319
978
|
"parallel_phases": {
|
|
320
|
-
"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.",
|
|
979
|
+
"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.",
|
|
321
980
|
"type": "boolean",
|
|
322
981
|
"default": true
|
|
323
982
|
},
|
|
@@ -409,7 +1068,7 @@
|
|
|
409
1068
|
}
|
|
410
1069
|
},
|
|
411
1070
|
"prepare-worktree": {
|
|
412
|
-
"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
|
|
1071
|
+
"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.",
|
|
413
1072
|
"type": "object",
|
|
414
1073
|
"additionalProperties": false,
|
|
415
1074
|
"properties": {
|
|
@@ -419,10 +1078,10 @@
|
|
|
419
1078
|
"minLength": 1
|
|
420
1079
|
},
|
|
421
1080
|
"deps_strategy": {
|
|
422
|
-
"description": "Default strategy for dep dirs (`node_modules/`, `vendor/`, `venv/`)
|
|
1081
|
+
"description": "Default strategy for dep dirs (`node_modules/`, `vendor/`, `venv/`). Every worktree owns its dep dirs; they are never symlinked back to the main checkout. `copy` makes a copy-on-write clone of main's install, close to free on disk on APFS / btrfs / XFS; it is safe for pnpm-style relative-link stores and falls back to a plain copy elsewhere. `reinstall` runs the package manager fresh in the worktree. The skill always reinstalls virtualenvs and yarn PnP, because their trees store absolute paths into the main checkout, and it adds an install on top of the copy when the plan adds deps. `symlink` is deprecated and read as `copy`; it stays in the enum only so existing configs keep validating.",
|
|
423
1082
|
"type": "string",
|
|
424
|
-
"enum": ["
|
|
425
|
-
"default": "
|
|
1083
|
+
"enum": ["copy", "reinstall", "symlink"],
|
|
1084
|
+
"default": "copy"
|
|
426
1085
|
},
|
|
427
1086
|
"compose_network": {
|
|
428
1087
|
"description": "Default docker-compose networking strategy for the worktree. `per-worktree` spins a fresh isolated network (safest, doubles infra); `shared-external` joins an externally-declared network so the worktree can talk to main's compose services (queues, caches, search); `host` uses host networking when the project already does. Skill writes the chosen strategy into the worktree's `docker-compose.override.yml` (or equivalent) when `compose_change` is set.",
|