vinta-ai-workflows 0.6.1 → 0.7.0-alpha2

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.
Files changed (25) hide show
  1. package/CHANGELOG.md +288 -0
  2. package/README.md +21 -13
  3. package/package.json +2 -1
  4. package/schemas/README.md +5 -1
  5. package/schemas/postmortem.v1.schema.json +339 -0
  6. package/schemas/vinta-ai-workflows-config.v1.schema.json +13 -1
  7. package/schemas/workflow.v1.schema.json +833 -0
  8. package/skills/vinta-bootstrap-ai-tools/SKILL.md +9 -1
  9. package/skills/vinta-derive-skills/SKILL.md +6 -2
  10. package/skills/vinta-derive-skills/resources/foundation-skills/plan-feature/SKILL.md +622 -32
  11. package/skills/vinta-derive-skills/resources/foundation-skills/prepare-worktree/SKILL.md +24 -2
  12. package/skills/vinta-derive-skills/resources/plan-execution/README.md +21 -4
  13. package/skills/vinta-derive-skills/resources/plan-execution/partials/agent-models.md +30 -3
  14. package/skills/vinta-derive-skills/resources/plan-execution/partials/commit-strategy/modular.md +27 -14
  15. package/skills/vinta-derive-skills/resources/plan-execution/partials/commit-strategy/stacked.md +12 -18
  16. package/skills/vinta-derive-skills/resources/plan-execution/partials/implementer-prompt.md +19 -9
  17. package/skills/vinta-derive-skills/resources/plan-execution/partials/model-pick.md +25 -9
  18. package/skills/vinta-derive-skills/resources/plan-execution/partials/parallel-lanes.md +240 -0
  19. package/skills/vinta-derive-skills/resources/plan-execution/partials/review-layers.md +56 -5
  20. package/skills/vinta-derive-skills/resources/plan-execution/partials/worktree-seam.md +13 -6
  21. package/skills/vinta-derive-skills/resources/plan-execution/shell/amend-plan-template.md +17 -12
  22. package/skills/vinta-derive-skills/resources/plan-execution/shell/implement-phase-template.md +5 -3
  23. package/skills/vinta-derive-skills/resources/plan-execution/shell/implement-plan-template.md +94 -57
  24. package/skills/vinta-derive-skills/resources/plan-execution/shell/integrate-phase-template.md +2 -1
  25. package/skills/vinta-derive-skills/resources/plan-execution/shell/review-phase-template.md +16 -5
@@ -19,8 +19,9 @@ The output is a worktree that is the **same shape as the main checkout** from th
19
19
 
20
20
  - A plan / spec that takes hours-to-days where parallel work in the main checkout would be disruptive (a long migration, a refactor, a feature you want to experiment on while still serving customer support out of `main`).
21
21
  - Two-or-more concurrent plans where each needs its own running app + own DB state.
22
+ - **A lane pool for one plan** — [implement-plan](../implement-plan/SKILL.md) implements independent phases concurrently and calls this skill once per lane (plus once for an integration worktree). See **Provisioning a pool** below.
22
23
  - A risky migration where the user wants the migration to run against a forked DB, then walk the diff before promoting.
23
- - [implement-plan](../implement-plan/SKILL.md) Step 0 (c) — when the user opts in, that orchestrator runs this skill once before phase 1, captures the resulting path, and threads it through every subagent's prompt.
24
+ - [implement-plan](../implement-plan/SKILL.md) Step 0 (c) — when the user opts in, that orchestrator runs this skill before the first phase (once for a sequential run, once per lane plus one integration worktree for a parallel run), captures the resulting paths, and threads each lane's through its own subagent prompts.
24
25
 
25
26
  ## When NOT to use
26
27
 
@@ -28,6 +29,19 @@ The output is a worktree that is the **same shape as the main checkout** from th
28
29
  - The project has no ignored runnable state (rare — usually means the project is so simple a worktree adds friction with no upside).
29
30
  - The user is on a filesystem that doesn't support symlinks (Windows non-NTFS volumes, some corporate fileshares). Fall back to copy-only and warn the user up front.
30
31
 
32
+ ## Provisioning a pool (several worktrees for one plan)
33
+
34
+ A caller that needs N isolated lanes invokes this skill N times — once per lane, with distinct names (`plan-<id>-lane-1`, `plan-<id>-lane-2`, …, plus `plan-<id>-integ` for merges). Nothing about the flow changes per invocation, but four things must hold across them:
35
+
36
+ 1. **Names are the isolation key.** Every forked DB name, compose project name, redis index, and S3 prefix already derives from `<worktree-name>` — distinct names give distinct everything. Never provision two lanes with the same name.
37
+ 2. **Answer the interview once, reuse the answers.** The caller passes the same plan and the same strategy answers to every lane. Don't re-interview per lane.
38
+ 3. **Provision lanes concurrently when the caller asks for it** — the expensive part of a lane (dependency install or link, DB clone, summary write) shares nothing between lanes and should overlap. But **two steps must be serialized**, and skipping either corrupts something:
39
+ - **`git worktree add` itself.** Git rewrites `.git/worktrees/` metadata on every add, and concurrent adds against one repository clobber each other's entries. Add the worktrees one at a time, then do the per-lane work in parallel. This is forced by git, not a choice.
40
+ - **The DB template.** Create or refresh the template DB once, then let each lane clone from it — that clone is what makes N lanes cost N cheap copies instead of N full provisions.
41
+ 4. **Record a `reset_cmd`** for each forked DB (see the summary schema). A pooled lane gets reused for a later phase on a different base, and the caller must be able to return its DB to a fresh state without re-provisioning. A lane whose DBs have no `reset_cmd` is single-use — say so in the report so the caller re-provisions instead of reusing it.
42
+
43
+ Disk is the real constraint: N lanes means N dep trees and N DB copies. Run the **Sanity checks** disk probe against `N ×` the estimate, not `1 ×`, and warn the caller before the first lane if the pool won't fit.
44
+
31
45
  ## Inputs (Step 0 — interview)
32
46
 
33
47
  Use `AskUserQuestion` for every finite-choice question. Open prose only when the answer is genuinely free-form.
@@ -344,11 +358,17 @@ state:
344
358
  strategy: fork | share | stub
345
359
  forked_name: <forked db name> # null when share / stub
346
360
  connection_url_var: DATABASE_URL
361
+ reset_cmd: <shell command that returns this DB to the state of a fresh checkout>
362
+ # e.g. dropdb <forked> && createdb -T <template> <forked>
363
+ # rm -f <path>/db.sqlite3 && <migrate cmd>
364
+ # null when the engine / setup has no safe reset — callers must then re-provision
365
+ # instead of reusing this worktree across a migration boundary.
347
366
  test_db:
348
367
  engine: ...
349
368
  strategy: fork | share
350
369
  forked_name: ...
351
370
  connection_url_var: TEST_DATABASE_URL
371
+ reset_cmd: <same idea, for the test DB> # null when not resettable
352
372
  compose:
353
373
  project_name: <repo>_<worktree-name>
354
374
  network_strategy: per-worktree | shared-external | host
@@ -371,7 +391,9 @@ state:
371
391
  # claude-hook → in-process (claude-code) Layer A hook only (file tools)
372
392
  # claude-native-sandbox → in-process (claude-code) Layer A hook + Layer B OS sandbox
373
393
  # null → tier=none (no guard wired)
374
- deny: [<main-checkout-root>] # subtree(s) made read-only inside the cage
394
+ deny: [<main-checkout-root>, <worktree-root>] # subtree(s) made read-only inside the cage
395
+ # <worktree-root> is the dir that holds the worktrees — denying it blocks writes into
396
+ # SIBLING lanes when a pool is provisioned; the allow entry below re-opens only this one.
375
397
  allow: [<worktree-path>, <main-checkout-root>/.git, <.vinta-ai-workflows-dir>] # writable exceptions
376
398
  notes: |
377
399
  <freeform — anything the user / agent should know>
@@ -3,7 +3,7 @@
3
3
  Source-of-truth fragments for the **plan-execution skill family** that
4
4
  `vinta-derive-skills` renders into a target project's `ai-tools/skills/`:
5
5
 
6
- - `implement-plan` (conductor) — parse → classify → resolve `WORKROOT` → per-phase loop → track → report.
6
+ - `implement-plan` (conductor) — parse → classify → build the dependency graph → resolve a `WORKROOT` per lane → scheduler loop (several phases at a time) → wave integration → track → report.
7
7
  - `implement-phase` — compose prompt + pick model + spawn implementer (one phase).
8
8
  - `review-phase` — three-layer review + fix loop (shared by all three conductors).
9
9
  - `integrate-phase` — push + open PR via context file (commit-strategy-resolved).
@@ -31,12 +31,29 @@ Partials and shells are **not** `SKILL.md` files, so they legitimately keep `{{.
31
31
 
32
32
  ## The `WORKROOT` seam (why worktree branching is gone)
33
33
 
34
- The conductor resolves three values **once** (see `partials/worktree-seam.md#WORKROOT_RESOLUTION`) and passes them to every sub-skill as data:
34
+ The conductor resolves three values **once per lane** (see `partials/worktree-seam.md#WORKROOT_RESOLUTION`) and passes them to every sub-skill as data:
35
35
 
36
36
  | Value | `use_worktree = false` | `use_worktree = true` |
37
37
  |---|---|---|
38
- | `WORKROOT` | `<main_checkout>` | `<worktree_path>` |
38
+ | `WORKROOT` | `<main_checkout>` | `<worktree_path>` — this lane's, when a pool is provisioned |
39
39
  | `BASE_BRANCH` | `{{DEFAULT_BRANCH}}` | `<worktree_branch>` |
40
- | `SANDBOX_TIER` | `none` | `enforced` \| `none` (probed by prepare-worktree) |
40
+ | `SANDBOX_TIER` | `none` | `enforced` \| `none` (probed by prepare-worktree, per lane) |
41
41
 
42
42
  Every `git` / lint / test / build call in every sub-skill uses `git -C <WORKROOT>` **uniformly** — no `if use_worktree` inside them. Only two genuine conditionals remain, each local and data-driven: the `SANDBOX_TIER`-gated spawn wrap in `implement-phase`, and the `WORKROOT != main_checkout`-gated stray-write check in `review-phase`.
43
+
44
+ ## The parallel-lanes seam (`partials/parallel-lanes.md`)
45
+
46
+ The plan gives every phase a `**Depends on**:` line. The conductor turns those into a DAG and dispatches a phase the moment its dependencies are green and a lane is free. Six blocks:
47
+
48
+ | Block | Consumed by | What it owns |
49
+ |---|---|---|
50
+ | `DAG_PARSE` | `implement-plan` Step 0 | graph build, wave derivation, cycle / unknown-id / file-overlap validation |
51
+ | `LANE_WORKTREE_POOL` | `implement-plan` Step 0.5 | pool sizing + provisioning, lane reuse + DB reset, teardown; the hard refusal when worktrees are unavailable |
52
+ | `LANE_TOPOLOGY` | `implement-plan` (linked, not included, from `integrate-phase`) | per-phase base branch from `depends_on`, `integ-{id}` merge bases, `wave-{N}` integration branches, merge-conflict handling |
53
+ | `LANE_SCHEDULER` | `implement-plan` Step 1 | the dispatch loop, tie-breaking, failure containment, the pause gate under concurrency |
54
+ | `TRACKING_DIR` | `implement-plan` | the `TRACKING_{plan-id}/` directory + its ownership rules |
55
+ | `SIBLING_LANE_ISOLATION` | `worktree-seam.md#STRAY_WRITE_CHECK` → `review-phase` | the stray-write guard extended across sibling lanes |
56
+
57
+ **Sequential execution is `max_parallel_lanes = 1`**, running the same blocks — there is no separate sequential code path to keep in sync.
58
+
59
+ **Why tracking is a directory.** Lanes commit on branches that later merge. One shared file would conflict at every wave merge for no reason. `run.md` is conductor-owned, `phase-{id}.md` is written only by the lane that ran that phase, on that phase's own branch — so no two branches ever touch the same path and the merges are clean by construction.
@@ -1,16 +1,43 @@
1
- <!-- Partial: agent-models — resolves the `.vinta-ai-workflows.yaml` `agent_models` section (tier per role/task) to a concrete spawn model, and the mechanical-step delegation pattern. Blocks: TIER_RESOLVE (review-phase reviewer/fixer + implement-plan mechanical steps), MECHANICAL_DELEGATION (implement-plan worktree/integrate steps). The implementer model is NOT here — that stays plan-owned via model-pick. -->
1
+ <!-- Partial: agent-models — resolves the `.vinta-ai-workflows.yaml` `agent_models` section (tier per role/task) to a concrete spawn model, the reviewer's tier-above-the-author derivation, and the mechanical-step delegation pattern. Blocks: TIER_RESOLVE (review-phase reviewer/fixer + implement-plan mechanical steps), MECHANICAL_DELEGATION (implement-plan worktree/integrate steps). The implementer model is NOT here — that stays plan-owned via model-pick. -->
2
2
 
3
3
  <!-- block-begin: TIER_RESOLVE -->
4
4
  ## Resolve an `agent_models` tier to a spawn model
5
5
 
6
6
  `.vinta-ai-workflows.yaml` may carry an `agent_models` section mapping a role/task (`reviewer`, `fixer`, `worktree_prep`, `integrate`) to a **tier** (1–4) into the same table the per-phase implementer suggestion uses — [`ai-tools/skills/plan-feature/resources/ai-models.yaml`](../plan-feature/resources/ai-models.yaml). `agent_models` is the **project default** for these roles; for `reviewer` / `fixer`, a plan phase's optional `**Review models**:` line may override the tier for that one phase (the caller resolves that precedence and hands this block the effective tier). The mechanical steps (`worktree_prep`, `integrate`) are never plan-named. To turn a tier into the model a spawn actually uses:
7
7
 
8
- 1. Determine the **effective tier** for the role: for `reviewer` / `fixer`, a per-phase override the conductor passed wins over `agent_models.<role>`; for the mechanical steps, it's simply `agent_models.<role>`.
8
+ 1. Determine the **effective tier** for the role. For the mechanical steps it is simply `agent_models.<role>`. For `reviewer` / `fixer` there are now three sources, in this order:
9
+ 1. a per-phase `**Review models**:` override the conductor passed;
10
+ 2. **the cheapest reviewer on the plan's Crew table at or above the phase's tier** (see [Who reviews](#who-reviews-a-member-not-a-tier) below);
11
+ 3. `agent_models.<role>`.
9
12
  2. **No effective tier (override absent AND key unset, or the whole `agent_models` section absent) → do not force a model.** Spawn with the runtime's default model (today's behavior). Skip the rest.
10
13
  3. Open [`ai-tools/skills/plan-feature/resources/ai-models.yaml`](../plan-feature/resources/ai-models.yaml), take that tier's `models`, **filter to the vendors the runtime actually exposes**, pick the cheapest/fastest survivor, and translate it to the runner's spawn form — the same resolution [implement-phase](../implement-phase/SKILL.md) runs for the implementer, only keyed by a config tier instead of a plan line.
11
14
  4. `ai-models.yaml` missing, or the tier has no runtime-available vendor → fall back to the runtime default and surface the fallback once. Never hard-fail a phase over a model-selection miss.
12
15
 
13
- Record the **model actually used** in tracking: for `reviewer` / `fixer`, alongside the review note; for the mechanical steps, in the phase's tracking row next to the branch/PR fields.
16
+ ### Who reviews: a member, not a tier
17
+
18
+ **Reviewers are their own members on the plan's Crew table**, with `role: reviewer`, and they never take phases. That is what makes an agent reviewing its own work impossible rather than merely unlikely — and it replaces an earlier rule that resolved a reviewer *model* one tier above the author, which was a proxy for independence and failed in both directions: a phase covered by the top-tier implementer had nobody above it and fell back to being read at its own tier, and a tier says nothing about *who* once a member is a durable agent rather than a model id.
19
+
20
+ Resolve it from the roster: the **cheapest reviewer at or above the phase's tier**. A reviewer's tier is a floor in the same way an implementer's is — it reads work at or below its own capability, never above it.
21
+
22
+ Three consequences worth knowing:
23
+
24
+ - **A reviewer is claimed, not borrowed.** It has one session ledger, so two reviews running as the same reviewer would collide over it; a phase whose reviewer is busy waits. That cannot deadlock — reviewers never take phases, so the wait is always on a review already running.
25
+ - **A reviewer reads the lane it is reviewing**, uncommitted changes and all, so findings are fixed before the commit. It has no worktree of its own, and therefore keeps a session only when consecutive reviews land in the same lane.
26
+ - **No reviewer on the roster → fall through to `agent_models.reviewer`**, cold, one session per phase. That is what every plan did before, and the one thing a roster-less plan leaves on the table.
27
+
28
+ A plan with no **Crew** table skips this step entirely and resolves `agent_models.<role>` as it always did.
29
+
30
+ ### What `fixer` still governs
31
+
32
+ `fixer` governs fewer rounds than it used to. A finding goes back to the phase's
33
+ own implementer — the same agent, in the same session — which fixes at the tier
34
+ of the crew member that took the phase
35
+ because it *is* that member; `agent_models.fixer` applies to the cold cases
36
+ only — a runtime that cannot continue a sub-agent, and the last round before
37
+ giving up, which is deliberately handed to an agent that has not seen the work.
38
+ See the fix loop in [review-phase](../review-phase/SKILL.md).
39
+
40
+ Record the **model actually used** in tracking, **and which of the three sources it came from** — a review that quietly fell through to the project default because the roster had nobody above the author is a fact worth being able to read later. For `reviewer` / `fixer`, alongside the review note; for the mechanical steps, in the phase's tracking row next to the branch/PR fields.
14
41
  <!-- block-end: TIER_RESOLVE -->
15
42
 
16
43
  <!-- block-begin: MECHANICAL_DELEGATION -->
@@ -1,26 +1,36 @@
1
- <!-- Partial: commit-strategy / modular-commits. Folds in the former implement-plan-template-modular-substitutions.md. Blocks consumed by implement-phase (PER_PHASE_COMMIT) + integrate-phase (BRANCH_NAMING, PR_OPEN_TIMING) + conductor (CHECKLIST). All git calls use `git -C <WORKROOT>`; the first executed phase branches off `<BASE_BRANCH>` — both resolved once by the conductor (see worktree-seam.md#WORKROOT_RESOLUTION). The rendering-guidance appendix at the bottom is read by derive-skills to resolve the {{MODULAR_*}} placeholders; it is NOT part of any shipped block. -->
1
+ <!-- Partial: commit-strategy / modular-commits. Folds in the former implement-plan-template-modular-substitutions.md. Blocks consumed by implement-phase (PER_PHASE_COMMIT) + integrate-phase (BRANCH_NAMING, PR_OPEN_TIMING) + conductor (CHECKLIST). All git calls use `git -C <WORKROOT>`; each phase branches off its own dependency-derived `<phase.base_branch>` — all resolved by the conductor (see worktree-seam.md#WORKROOT_RESOLUTION + parallel-lanes.md#LANE_TOPOLOGY). The rendering-guidance appendix at the bottom is read by derive-skills to resolve the {{MODULAR_*}} placeholders; it is NOT part of any shipped block. -->
2
2
 
3
3
  <!-- block-begin: BRANCH_NAMING -->
4
4
  Branch naming: `plan/{plan-id-kebab}` (one branch for the whole plan — no per-phase suffix).
5
5
 
6
- **First executed phase** (branches from `<BASE_BRANCH>`, already made current by the conductor):
6
+ **Sequential run** (`max_parallel_lanes = 1`) — every phase commits straight onto the plan branch:
7
7
 
8
8
  ```bash
9
- git -C <WORKROOT> checkout <BASE_BRANCH>
10
- git -C <WORKROOT> checkout -b plan/{plan-id-kebab}
9
+ git -C <WORKROOT> checkout plan/{plan-id-kebab} # created from <BASE_BRANCH> on the first phase
11
10
  # subagent's atomic unit commits land on this branch
12
11
  git -C <WORKROOT> push -u origin plan/{plan-id-kebab}
13
12
  ```
14
13
 
15
- **Subsequent phases** (stay on the same plan branch — no new branch):
14
+ **Parallel run** — one branch cannot take concurrent writers, so each lane commits its atomic units on a **lane branch** and the conductor merges those into the plan branch at each wave boundary:
16
15
 
17
16
  ```bash
18
- git -C <WORKROOT> checkout plan/{plan-id-kebab}
19
- # subagent's atomic unit commits land on this branch
20
- git -C <WORKROOT> push origin plan/{plan-id-kebab}
17
+ git -C <WORKROOT> checkout <phase.base_branch>
18
+ git -C <WORKROOT> checkout -b plan/{plan-id-kebab}/lane-{phase.id}
19
+ # subagent's atomic unit commits land on this lane branch
20
+ git -C <WORKROOT> push -u origin plan/{plan-id-kebab}/lane-{phase.id}
21
21
  ```
22
22
 
23
- The branch carries every phase's commits in plan order. Reviewers read the commit log top-to-bottom as a table of contents of the implementation.
23
+ then, once every phase at that wave is green, in the integration worktree:
24
+
25
+ ```bash
26
+ git -C <integ.workroot> checkout plan/{plan-id-kebab}
27
+ git -C <integ.workroot> merge --no-ff plan/{plan-id-kebab}/lane-{phase.id} # once per lane, in plan order
28
+ git -C <integ.workroot> push origin plan/{plan-id-kebab}
29
+ ```
30
+
31
+ `--no-ff` is what preserves the atomic units: the plan branch keeps every individual unit commit, grouped by the merge commit that names its phase. `plan/{plan-id-kebab}` **is** the wave integration branch under this strategy — there is no separate `wave-{N}` branch. Reviewers still read the commit log top-to-bottom as a table of contents; parallel phases appear as adjacent groups rather than one flat sequence.
32
+
33
+ **Never squash a lane merge.** Squashing collapses the unit commits this whole strategy exists to preserve.
24
34
  <!-- block-end: BRANCH_NAMING -->
25
35
 
26
36
  <!-- block-begin: PER_PHASE_COMMIT -->
@@ -72,24 +82,27 @@ Tests for a unit belong **in the same commit** as that unit. Never commit tests
72
82
  <!-- block-end: PER_PHASE_COMMIT -->
73
83
 
74
84
  <!-- block-begin: PR_OPEN_TIMING -->
75
- **PR opens once — after Phase 1 passes review.** Subsequent phases push their atomic unit commits to the same plan branch (`plan/{plan-id-kebab}`); the orchestrator re-runs [open-pr.sh](../open-pr-from-context/scripts/open-pr.sh) against the same plan-level prs-context file at `.vinta-ai-workflows/prs-context/{feature-kebab}/plan.md`. The script is idempotent for already-open PRs — it updates the body, appends new inline comments, and posts a `Phase {N} complete — pushed M commits` PR comment.
85
+ **PR opens once — after the first phase passes review.** Subsequent phases land their atomic unit commits on the same plan branch (`plan/{plan-id-kebab}`) — directly when sequential, through a wave merge when parallel; the orchestrator re-runs [open-pr.sh](../open-pr-from-context/scripts/open-pr.sh) against the same plan-level prs-context file at `.vinta-ai-workflows/prs-context/{feature-kebab}/plan.md`. The script is idempotent for already-open PRs — it updates the body, appends new inline comments, and posts a `Phase {N} complete — pushed M commits` PR comment.
86
+
87
+ Under a parallel run, the PR comment goes up **after the wave merge**, not when the lane branch is pushed — before the merge those commits are not on the branch the PR tracks.
76
88
  <!-- block-end: PR_OPEN_TIMING -->
77
89
 
78
90
  <!-- block-begin: CHECKLIST -->
79
91
  - [ ] Commit units listed upfront before any staging.
80
92
  - [ ] Each commit covers exactly one logical unit (no "and" in commit messages).
81
93
  - [ ] Tests landed in the same commit as the code they cover (never a separate test-only commit).
82
- - [ ] All unit commits pushed to `plan/{plan-id-kebab}` at end of phase.
94
+ - [ ] All unit commits pushed at end of phase — to `plan/{plan-id-kebab}` when sequential, to `plan/{plan-id-kebab}/lane-{phase.id}` when parallel.
95
+ - [ ] Parallel runs only: lane branch merged into `plan/{plan-id-kebab}` with `--no-ff` at the wave boundary; never squashed.
83
96
  <!-- block-end: CHECKLIST -->
84
97
 
85
98
  <!-- Single-line values (derive-skills substitutes these into the shells directly):
86
99
  BRANCH_PUSH_HEADING = Push to plan branch
87
- BRANCH_NAMING_PATTERN_SUMMARY = plan branch (one branch for whole plan: `plan/{plan-id-kebab}`)
100
+ BRANCH_NAMING_PATTERN_SUMMARY = plan branch (one branch for whole plan: `plan/{plan-id-kebab}`; parallel runs add per-lane branches `plan/{plan-id-kebab}/lane-{phase-id}` merged in at each wave boundary)
88
101
  PRS_CONTEXT_FILE_PATH = a single `.vinta-ai-workflows/prs-context/{feature-kebab}/plan.md` file (one PR per plan, not per phase)
89
102
  TRACKING_BRANCH_FIELD = top-level `plan_branch:` field
90
103
  TRACKING_PHASE_BRANCH_FIELD = (empty — no per-phase branch under modular)
91
- FINAL_REPORT_BRANCH_SUMMARY = single plan branch `plan/{plan-id-kebab}` with commit log organized by phase
92
- BRANCH_CHECKLIST_LINE = Plan branch updated with phase commits; pushed. -->
104
+ FINAL_REPORT_BRANCH_SUMMARY = single plan branch `plan/{plan-id-kebab}` with commit log organized by phase (parallel runs: plus the lane branches merged into it, per wave)
105
+ BRANCH_CHECKLIST_LINE = Plan branch updated with phase commits (directly, or via the lane branch's wave merge); pushed. -->
93
106
 
94
107
  <!-- ===================================================================== -->
95
108
  <!-- rendering-guidance (read by derive-skills; NOT shipped in any block) -->
@@ -1,29 +1,22 @@
1
- <!-- Partial: commit-strategy / stacked-branches. Blocks consumed by implement-phase (PER_PHASE_COMMIT) + integrate-phase (BRANCH_NAMING, PR_OPEN_TIMING) + conductor (CHECKLIST). All git calls use `git -C <WORKROOT>`; the first executed phase branches off `<BASE_BRANCH>` — both resolved once by the conductor (see worktree-seam.md#WORKROOT_RESOLUTION). -->
1
+ <!-- Partial: commit-strategy / stacked-branches. Blocks consumed by implement-phase (PER_PHASE_COMMIT) + integrate-phase (BRANCH_NAMING, PR_OPEN_TIMING) + conductor (CHECKLIST). All git calls use `git -C <WORKROOT>`; each phase branches off its own dependency-derived `<phase.base_branch>` — all resolved by the conductor (see worktree-seam.md#WORKROOT_RESOLUTION + parallel-lanes.md#LANE_TOPOLOGY). -->
2
2
 
3
3
  <!-- block-begin: BRANCH_NAMING -->
4
- Branch naming: `plan/{plan-id-kebab}/phase-{phase.id}` (one branch + one PR per phase, stacked).
4
+ Branch naming: `plan/{plan-id-kebab}/phase-{phase.id}` (one branch + one PR per phase, stacked on its **dependencies** rather than on plan order).
5
5
 
6
- **First executed phase** (branches from `<BASE_BRANCH>`, already made current by the conductor):
6
+ Each phase branches from `<phase.base_branch>` — the branch the conductor computed from that phase's `**Depends on**:` set (see [Lane branch topology](../implement-plan/SKILL.md#lane-branch-topology)): `<BASE_BRANCH>` for a phase with no dependencies, the single dependency's phase branch for one, `plan/{plan-id-kebab}/integ-{phase.id}` for several. The conductor creates the branch when it assigns the phase to a lane:
7
7
 
8
8
  ```bash
9
- git -C <WORKROOT> checkout <BASE_BRANCH>
9
+ git -C <WORKROOT> checkout <phase.base_branch>
10
10
  git -C <WORKROOT> checkout -b plan/{plan-id-kebab}/phase-{phase.id}
11
11
  # subagent's commits land on this branch
12
12
  git -C <WORKROOT> push -u origin plan/{plan-id-kebab}/phase-{phase.id}
13
13
  ```
14
14
 
15
- **Subsequent phases** (stacked on the previous phase's branch):
15
+ A chain-shaped plan reproduces the classic stack exactly — each phase depends on the one before it, so `<phase.base_branch>` *is* the previous phase's branch. A plan with independent phases produces several stacks rooted at `<BASE_BRANCH>`, reunited by the wave integration branches.
16
16
 
17
- ```bash
18
- git -C <WORKROOT> checkout plan/{plan-id-kebab}/phase-{prev.id}
19
- git -C <WORKROOT> checkout -b plan/{plan-id-kebab}/phase-{phase.id}
20
- git -C <WORKROOT> push -u origin plan/{plan-id-kebab}/phase-{phase.id}
21
- ```
22
-
23
- **PR base per phase** (the `base` field written into the prs-context frontmatter — this is what `gh pr create --base` / `glab mr create --target-branch` opens the PR against; getting it wrong makes every stacked PR target `<BASE_BRANCH>` instead of its parent phase):
17
+ **PR base per phase** (the `base` field written into the prs-context frontmatter — this is what `gh pr create --base` / `glab mr create --target-branch` opens the PR against; getting it wrong makes the PR diff include every upstream phase and the review unusable):
24
18
 
25
- - **First executed phase** → `base = <BASE_BRANCH>`.
26
- - **Subsequent phases** → `base = plan/{plan-id-kebab}/phase-{prev.id}` (the previous phase's branch, **not** `<BASE_BRANCH>`). The PR must open against its parent phase so the diff shows only this phase's changes and the stack reviews cleanly.
19
+ - `base = <phase.base_branch>`, always. Never `<BASE_BRANCH>` for a phase that has dependencies.
27
20
  <!-- block-end: BRANCH_NAMING -->
28
21
 
29
22
  <!-- block-begin: PER_PHASE_COMMIT -->
@@ -38,14 +31,15 @@ One PR per phase — the [Open PR via context file](#open-pr-via-context-file) s
38
31
  <!-- block-end: PR_OPEN_TIMING -->
39
32
 
40
33
  <!-- block-begin: CHECKLIST -->
41
- <!-- stacked adds no extra commit-discipline checklist items beyond the branch line -->
34
+ - [ ] Phase branch created from `<phase.base_branch>` (dependency-derived), not from plan order.
35
+ - [ ] PR `base` in the prs-context frontmatter equals `<phase.base_branch>`.
42
36
  <!-- block-end: CHECKLIST -->
43
37
 
44
38
  <!-- Single-line values (derive-skills substitutes these into the shells directly):
45
39
  BRANCH_PUSH_HEADING = Push stacked branch
46
- BRANCH_NAMING_PATTERN_SUMMARY = branch naming pattern (default: `plan/{plan-id-kebab}/phase-{phase-id}`)
40
+ BRANCH_NAMING_PATTERN_SUMMARY = branch naming pattern (default: `plan/{plan-id-kebab}/phase-{phase-id}`, each based on its dependencies; wave integration branches `plan/{plan-id-kebab}/wave-{N}`)
47
41
  PRS_CONTEXT_FILE_PATH = `.vinta-ai-workflows/prs-context/{feature-kebab}/phase-{phase.id}.md`
48
42
  TRACKING_BRANCH_FIELD = (empty — per-phase branch lives inline under TRACKING_PHASE_BRANCH_FIELD)
49
43
  TRACKING_PHASE_BRANCH_FIELD = , branch, base
50
- FINAL_REPORT_BRANCH_SUMMARY = branches pushed (with bases, in stack order)
51
- BRANCH_CHECKLIST_LINE = Stacked branch created; pushed. -->
44
+ FINAL_REPORT_BRANCH_SUMMARY = branches pushed (with bases, grouped by wave)
45
+ BRANCH_CHECKLIST_LINE = Phase branch created from its dependency-derived base; pushed. -->
@@ -1,4 +1,4 @@
1
- <!-- Partial: implementer-prompt — the token-efficient per-phase prompt. FULL = the forward-implementation prompt used by implement-phase. INNER_OUTER_LOOP = the read→edit→inner→outer verification steps (1–6), reused verbatim by amend-plan's 4b (which appends its own amend-specific commit / no-push tail instead of the commit-strategy block). The {If run_options.use_worktree = true:} markers are runtime gates the agent reads at execution time; derive-skills strips them entirely when foundation_skills.prepare-worktree is disabled (use_worktree can only ever be false). -->
1
+ <!-- Partial: implementer-prompt — the token-efficient per-phase prompt. FULL = the forward-implementation prompt used by implement-phase. INNER_OUTER_LOOP = the read→edit→inner→outer verification steps (1–6), reused verbatim by amend-plan's 4b (which appends its own amend-specific commit / no-push tail instead of the commit-strategy block). The {If run_options.use_worktree = true:} and {If run_options.parallel_phases = true:} markers are runtime gates the agent reads at execution time; derive-skills strips both entirely when foundation_skills.prepare-worktree is disabled (use_worktree can only ever be false, and parallel execution requires a worktree). -->
2
2
 
3
3
  <!-- block-begin: FULL -->
4
4
  ```
@@ -14,11 +14,18 @@ every lint / test / build / migrate call runs there.
14
14
  `<WORKROOT>` is an isolated git worktree — do NOT touch the main checkout; its DB,
15
15
  env, and compose stack are intentionally separated. See `<WORKROOT>/WORKTREE.md` for
16
16
  what's forked vs shared (deps, dev DB, test DB, compose project name, env file).
17
- {If run_options.sandbox_tier = enforced:} Writes to the main checkout are OS-blocked —
18
- if you see `Operation not permitted` / `EROFS` on a write, you used a main-checkout
19
- path by mistake; redo it against this worktree path.
20
- Branch base for this phase: `<phase-specific base>` — the orchestrator already created
21
- your phase branch there; commit straight to it.
17
+ {If run_options.sandbox_tier = enforced:} Writes outside this worktree are OS-blocked —
18
+ if you see `Operation not permitted` / `EROFS` on a write, you used a path outside
19
+ `<WORKROOT>` by mistake; redo it against this worktree path.
20
+ {If run_options.parallel_phases = true:}
21
+ Other phases of this plan are being implemented **right now**, in sibling worktrees
22
+ next to yours. Never read or write any path outside `<WORKROOT>` — a sibling's tree is
23
+ mid-edit and mid-test, and a write there corrupts someone else's phase. Anything you
24
+ need from another phase is either already in your base branch or is a dependency the
25
+ plan failed to declare — say so in your report rather than reaching for it.
26
+ Branch base for this phase: `<phase.base_branch>` — derived from this phase's
27
+ **Depends on** set, not from plan order. The orchestrator already created your phase
28
+ branch there; commit straight to it.
22
29
 
23
30
  ## Read first
24
31
  1. AGENTS.md — repo conventions.
@@ -32,8 +39,11 @@ your phase branch there; commit straight to it.
32
39
  Feature flag: `{flag-key}` — scope `{per-tenant|per-request}`, default `{false|true}`.
33
40
  Wire reads + writes per the plan's **Guiding Decisions** entry. Off-flag path = byte-for-byte pre-feature behavior.
34
41
 
35
- ## What was already implemented in prior phases
36
- {Tracking file "Completed Phases" section. First executed phase: "Nothing yet — this is the first phase."}
42
+ ## What your phase builds on
43
+ {The `phase-{id}.md` tracking summaries for this phase's transitive dependencies, in
44
+ wave order. No dependencies: "Nothing yet — this phase starts from `<BASE_BRANCH>`."
45
+ Sibling phases running in parallel are deliberately NOT listed: their work is not in
46
+ your base branch and you must not code against it.}
37
47
 
38
48
  ## Your tasks (Phase {id} only)
39
49
  {phase.body verbatim, including Goal / Spec use-case / Feature flag / Changes / Tests / Acceptance lines}
@@ -57,7 +67,7 @@ Project skills available: {{PROJECT_SKILLS_LIST}}
57
67
  - Anything you couldn't do (with explanation).
58
68
  ```
59
69
 
60
- **Don't** dump the full plan into every prompt. Tracking summaries replace prior phases as context. Always include the **Goals + Non-goals** and **Guiding Decisions** sections plus the relevant **Data Model Changes** subsection — load-bearing decisions; phases reach back frequently.
70
+ **Don't** dump the full plan into every prompt. Dependency-closure tracking summaries replace prior phases as context. Always include the **Goals + Non-goals** and **Guiding Decisions** sections plus the relevant **Data Model Changes** subsection — load-bearing decisions; phases reach back frequently.
61
71
  <!-- block-end: FULL -->
62
72
 
63
73
  <!-- block-begin: INNER_OUTER_LOOP -->
@@ -1,19 +1,35 @@
1
1
  <!-- Partial: model-pick — the plan-owns-model-selection rules. Included by implement-phase; referenced (linked, not included) by amend-plan's Tier-4 rule. -->
2
2
  <!-- block-begin: MODEL_PICK -->
3
- ## Pick the model from the plan's per-phase suggestion
3
+ ## Pick the model from the phase's crew assignment
4
4
 
5
- **The plan owns the *implementer* model — this skill does not re-derive tiers and doesn't assume a vendor.** Each phase carries a `**Suggested AI model**:` line listing one model per vendor. (The reviewer / fixer models default to `.vinta-ai-workflows.yaml`'s `agent_models` section, though a phase's optional `**Review models**:` line can override them for that phase; the mechanical-step models are `agent_models`-only. All of that is handled by `review-phase` / the conductor, not this implementer step.)
5
+ **The plan owns the *implementer* model — this skill does not re-derive tiers and doesn't assume a vendor.** It owns it as a **roster**: the plan's **Crew** table names the agents it is staffed with and the tier each is staffed at, and every phase carries an `**Assigned to**:` line naming one of them.
6
6
 
7
7
  Pick:
8
8
 
9
- 1. Read the line, parse out **all** vendor suggestions.
10
- 2. **Filter to what's actually available in the runtime.** Different harnesses expose different sets.
11
- 3. From the surviving suggestions, **pick the cheapest / fastest** the runner can use.
12
- 4. Translate the chosen model to whatever form the runner's spawning tool expects.
13
- 5. Phase suggestion straddles tiers → pick the higher-tier suggestion.
14
- 6. Line missing / malformed → **ask the user**. Don't silently re-derive tier.
9
+ 1. Read the phase's `**Assigned to**:` line for the crew id, then that id's row in the plan's **Crew** table for the tier.
10
+ 2. Open the tier in [`ai-tools/skills/plan-feature/resources/ai-models.yaml`](../plan-feature/resources/ai-models.yaml) and take its models.
11
+ 3. **Filter to what's actually available in the runtime.** Different harnesses expose different sets.
12
+ 4. From the survivors, **pick the cheapest / fastest** the runner can use, and translate it to whatever form the runner's spawning tool expects.
13
+ 5. Tier with no runtime-available vendor → step one tier up and say so once. Never hard-fail a phase over a model-selection miss.
14
+ 6. `**Assigned to**:` missing or naming an agent the **Crew** table does not list → **ask the user**. Don't silently re-derive a tier from the phase body; the roster is the plan's arithmetic about how many agents this feature needs, and inventing a member changes it.
15
+
16
+ **A legacy plan carries `**Suggested AI model**:` and no Crew table.** Read the tier straight off that line and continue — same resolution, one less indirection. Don't invent a roster for it.
17
+
18
+ ### Reuse the agent the plan staffed
19
+
20
+ **A crew member is an agent, and it is still alive.** If this member has already taken a phase on this run, continue that sub-agent rather than spawning a new one: it is standing in the same worktree — a member keeps one for the whole run — and it already knows where this codebase keeps things, how its suite is run and what its conventions are. Rediscovering that is most of what a cold agent's first turn costs.
21
+
22
+ Because it is new work, the continuation gets the phase's **full brief**, not a delta. Precede it with the re-orientation described in [Re-orienting a member after the reset](../implement-plan/SKILL.md#re-orienting-a-member-after-the-reset): same agent and same directory, whether the previous phase's work is in this tree, and which files differ from what it last saw.
23
+
24
+ Start cold instead when any of these hold:
25
+
26
+ - the member has taken no phase yet on this run;
27
+ - **their previous phase failed** — that session is the context that failed with it;
28
+ - the runtime cannot continue a finished sub-agent at all.
29
+
30
+ Record which of those applied, so a phase that was unexpectedly slow can be read later without guessing.
15
31
 
16
32
  **Retry escalation (no user prompt):** the picked model fails on a clear capability gap → step **one tier up** and retry once. After Tier 4 fails, STOP. Update tracking with `❌`, post the agent's report to the user, ask how to proceed.
17
33
 
18
- Record the **model actually used** + the **plan's suggested tier** in tracking.
34
+ Record the **model actually used**, the **crew member** it came from, and **whether that member is the one the plan assigned** — a phase run by a covering peer is the difference between a run that cost what the plan said and one that did not.
19
35
  <!-- block-end: MODEL_PICK -->