vinta-ai-workflows 0.2.0-alpha3 → 0.2.0-alpha5

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 (31) hide show
  1. package/CHANGELOG.md +162 -0
  2. package/README.md +5 -2
  3. package/package.json +1 -1
  4. package/schemas/vinta-ai-workflows-config.v1.schema.json +57 -0
  5. package/skills/vinta-analyze-codebase/SKILL.md +1 -1
  6. package/skills/vinta-bootstrap-ai-tools/SKILL.md +37 -8
  7. package/skills/vinta-derive-skills/SKILL.md +92 -39
  8. package/skills/vinta-derive-skills/resources/foundation-skills/deslop-comments/SKILL.md +148 -0
  9. package/skills/vinta-derive-skills/resources/foundation-skills/handoff/SKILL.md +100 -0
  10. package/skills/vinta-derive-skills/resources/foundation-skills/prepare-worktree/SKILL.md +39 -4
  11. package/skills/vinta-derive-skills/resources/foundation-skills/prepare-worktree/scripts/claude-worktree-write-guard.py +118 -0
  12. package/skills/vinta-derive-skills/resources/foundation-skills/prepare-worktree/scripts/gen-claude-sandbox-settings.sh +167 -0
  13. package/skills/vinta-derive-skills/resources/foundation-skills/prepare-worktree/scripts/sandbox-run.sh +3 -1
  14. package/skills/vinta-derive-skills/resources/foundation-skills/thermo-nuclear-code-quality-review/SKILL.md +129 -0
  15. package/skills/vinta-derive-skills/resources/handoff-to-client-template.md +107 -0
  16. package/skills/vinta-derive-skills/resources/plan-execution/README.md +42 -0
  17. package/skills/vinta-derive-skills/resources/{implement-plan-template-modular-substitutions.md → plan-execution/partials/commit-strategy/modular.md} +38 -70
  18. package/skills/vinta-derive-skills/resources/plan-execution/partials/commit-strategy/stacked.md +46 -0
  19. package/skills/vinta-derive-skills/resources/plan-execution/partials/implementer-prompt.md +78 -0
  20. package/skills/vinta-derive-skills/resources/plan-execution/partials/model-pick.md +19 -0
  21. package/skills/vinta-derive-skills/resources/plan-execution/partials/pr-context.md +61 -0
  22. package/skills/vinta-derive-skills/resources/plan-execution/partials/review-layers.md +50 -0
  23. package/skills/vinta-derive-skills/resources/plan-execution/partials/worktree-seam.md +68 -0
  24. package/skills/vinta-derive-skills/resources/{amend-plan-template.md → plan-execution/shell/amend-plan-template.md} +48 -42
  25. package/skills/vinta-derive-skills/resources/plan-execution/shell/implement-phase-template.md +47 -0
  26. package/skills/vinta-derive-skills/resources/plan-execution/shell/implement-plan-template.md +186 -0
  27. package/skills/vinta-derive-skills/resources/plan-execution/shell/integrate-phase-template.md +30 -0
  28. package/skills/vinta-derive-skills/resources/plan-execution/shell/review-phase-template.md +25 -0
  29. package/skills/vinta-derive-skills/resources/systematic-debugging-template.md +7 -3
  30. package/skills/vinta-update-project-skills/SKILL.md +1 -1
  31. package/skills/vinta-derive-skills/resources/implement-plan-template.md +0 -436
@@ -1,36 +1,29 @@
1
- # Modular-commits substitutions for `implement-plan-template.md`
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. -->
2
2
 
3
- This file holds the substitution bodies for the `{{COMMIT_STRATEGY_*}}` placeholder family when `policies.commit_strategy = modular-commits`. The `stacked-branches` substitutions are inline in the parent placeholder table in [SKILL.md](../SKILL.md). The `ask` variant emits **both** the stacked and the modular bodies gated by inline runtime markers — see [Phase 4 ask-mode substitutions](#ask-mode-substitutions) at the bottom.
4
-
5
- Each section below is delimited by `<!-- substitution: {{PLACEHOLDER}} -->` markers so derive-skills can extract the block by name. The block's content is everything between the open and close markers, **excluding** the markers themselves.
6
-
7
- ## `{{BRANCH_NAMING_BLOCK}}` (modular)
8
-
9
- <!-- substitution-begin: BRANCH_NAMING_BLOCK -->
3
+ <!-- block-begin: BRANCH_NAMING -->
10
4
  Branch naming: `plan/{plan-id-kebab}` (one branch for the whole plan — no per-phase suffix).
11
5
 
12
- **First executed phase** (branches from `{{DEFAULT_BRANCH}}`):
6
+ **First executed phase** (branches from `<BASE_BRANCH>`, already made current by the conductor):
7
+
13
8
  ```bash
14
- git checkout {{DEFAULT_BRANCH}}
15
- git pull --ff-only
16
- git checkout -b plan/{plan-id-kebab}
9
+ git -C <WORKROOT> checkout <BASE_BRANCH>
10
+ git -C <WORKROOT> checkout -b plan/{plan-id-kebab}
17
11
  # subagent's atomic unit commits land on this branch
18
- git push -u origin plan/{plan-id-kebab}
12
+ git -C <WORKROOT> push -u origin plan/{plan-id-kebab}
19
13
  ```
20
14
 
21
15
  **Subsequent phases** (stay on the same plan branch — no new branch):
16
+
22
17
  ```bash
23
- git checkout plan/{plan-id-kebab}
18
+ git -C <WORKROOT> checkout plan/{plan-id-kebab}
24
19
  # subagent's atomic unit commits land on this branch
25
- git push origin plan/{plan-id-kebab}
20
+ git -C <WORKROOT> push origin plan/{plan-id-kebab}
26
21
  ```
27
22
 
28
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.
29
- <!-- substitution-end: BRANCH_NAMING_BLOCK -->
24
+ <!-- block-end: BRANCH_NAMING -->
30
25
 
31
- ## `{{PER_PHASE_COMMIT_BLOCK}}` (modular)
32
-
33
- <!-- substitution-begin: PER_PHASE_COMMIT_BLOCK -->
26
+ <!-- block-begin: PER_PHASE_COMMIT -->
34
27
  7. **Plan commit units before staging.** List the logical units this phase produces (e.g. `3 services + 1 use case update + 1 init export`). Each unit = **one** commit. Tests for that unit travel **in the same commit** as the code they test — never a separate commit.
35
28
  8. For each unit, in order:
36
29
  a. Stage exactly that unit's files: `git add <explicit paths>` (NEVER `git add -A` — {{ANTI_GIT_ADD_ALL_REASON}}). Tests for the unit go in the same `git add`.
@@ -76,11 +69,35 @@ Tests for a unit belong **in the same commit** as that unit. Never commit tests
76
69
  | "The user can squash later" | Squashing destroys the logical history this discipline exists to preserve. |
77
70
  | "It's faster to do one commit" | Planning units takes 2 minutes; reviewing a 2000-line blob takes much longer. |
78
71
  | "The changes are all related" | Related ≠ same unit. Services that depend on each other still get separate commits. |
79
- <!-- substitution-end: PER_PHASE_COMMIT_BLOCK -->
72
+ <!-- block-end: PER_PHASE_COMMIT -->
73
+
74
+ <!-- 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.
76
+ <!-- block-end: PR_OPEN_TIMING -->
77
+
78
+ <!-- block-begin: CHECKLIST -->
79
+ - [ ] Commit units listed upfront before any staging.
80
+ - [ ] Each commit covers exactly one logical unit (no "and" in commit messages).
81
+ - [ ] 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.
83
+ <!-- block-end: CHECKLIST -->
84
+
85
+ <!-- Single-line values (derive-skills substitutes these into the shells directly):
86
+ BRANCH_PUSH_HEADING = Push to plan branch
87
+ BRANCH_NAMING_PATTERN_SUMMARY = plan branch (one branch for whole plan: `plan/{plan-id-kebab}`)
88
+ PRS_CONTEXT_FILE_PATH = a single `.vinta-ai-workflows/prs-context/{feature-kebab}/plan.md` file (one PR per plan, not per phase)
89
+ TRACKING_BRANCH_FIELD = top-level `plan_branch:` field
90
+ 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. -->
93
+
94
+ <!-- ===================================================================== -->
95
+ <!-- rendering-guidance (read by derive-skills; NOT shipped in any block) -->
96
+ <!-- ===================================================================== -->
80
97
 
81
98
  ### Conditional example messages (driven by `policies.commit_style`)
82
99
 
83
- derive-skills resolves the six `{{MODULAR_EXAMPLE_*}}` placeholders + the `{{MODULAR_COMMIT_MESSAGE_FORMAT_BLOCK}}` from this table when rendering `{{PER_PHASE_COMMIT_BLOCK}}`:
100
+ derive-skills resolves the six `{{MODULAR_EXAMPLE_*}}` placeholders + the `{{MODULAR_COMMIT_MESSAGE_FORMAT_BLOCK}}` from this table when rendering the `PER_PHASE_COMMIT` block above:
84
101
 
85
102
  | Placeholder | `commit_style = conventional` | `commit_style = imperative` | `commit_style = other` |
86
103
  |---|---|---|---|
@@ -147,52 +164,3 @@ WIP
147
164
  add stuff
148
165
  Implement full record copy feature ← too broad, should be split
149
166
  ```
150
-
151
- ## `{{PR_OPEN_TIMING_BLOCK}}` (modular)
152
-
153
- <!-- substitution-begin: PR_OPEN_TIMING_BLOCK -->
154
- **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](../foundation-skills/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 an `Phase {N} complete — pushed M commits` PR comment.
155
-
156
- <!-- substitution-end: PR_OPEN_TIMING_BLOCK -->
157
-
158
- ## `{{COMMIT_STRATEGY_CHECKLIST_BLOCK}}` (modular)
159
-
160
- <!-- substitution-begin: COMMIT_STRATEGY_CHECKLIST_BLOCK -->
161
- - [ ] Commit units listed upfront before any staging.
162
- - [ ] Each commit covers exactly one logical unit (no "and" in commit messages).
163
- - [ ] Tests landed in the same commit as the code they cover (never a separate test-only commit).
164
- - [ ] All unit commits pushed to `plan/{plan-id-kebab}` at end of phase.
165
- <!-- substitution-end: COMMIT_STRATEGY_CHECKLIST_BLOCK -->
166
-
167
- ## Other modular substitutions (single-line — listed for completeness)
168
-
169
- | Placeholder | Modular substitution |
170
- |---|---|
171
- | `{{BRANCH_PUSH_HEADING}}` | `Push to plan branch` |
172
- | `{{BRANCH_NAMING_PATTERN_SUMMARY}}` | ``plan branch (one branch for whole plan: `plan/{plan-id-kebab}`)`` |
173
- | `{{PRS_CONTEXT_FILE_PATH_DESCRIPTION}}` | `` a single `.vinta-ai-workflows/prs-context/{feature-kebab}/plan.md` file (one PR per plan, not per phase) `` |
174
- | `{{TRACKING_BRANCH_FIELD}}` | `top-level \`plan_branch:\` field` |
175
- | `{{TRACKING_PHASE_BRANCH_FIELD}}` | empty string (no per-phase branch under modular) |
176
- | `{{FINAL_REPORT_BRANCH_SUMMARY}}` | ``single plan branch `plan/{plan-id-kebab}` with commit log organized by phase`` |
177
- | `{{BRANCH_CHECKLIST_LINE}}` | `Plan branch updated with phase commits; pushed.` |
178
- | `{{COMMIT_STRATEGY_STEP0_QUESTION}}` | empty string (modular is set as the project default; nothing to ask) |
179
- | `{{COMMIT_STRATEGY_STEP0_TRAILER}}` | empty string |
180
- | `{{COMMIT_STRATEGY_CONFIRM_NOTE}}` | empty string |
181
-
182
- ## Ask-mode substitutions
183
-
184
- When `policies.commit_strategy = ask`, derive-skills renders **both** the stacked-branches and the modular-commits bodies for each multi-line placeholder, gated by inline runtime markers the agent reads at execution time:
185
-
186
- ```markdown
187
- **If `run_options.commit_strategy_resolved = "modular-commits"`:**
188
-
189
- <modular substitution body here>
190
-
191
- **Else (`run_options.commit_strategy_resolved = "stacked-branches"`):**
192
-
193
- <stacked substitution body here>
194
- ```
195
-
196
- Single-line placeholders under ask use the same gating pattern but inline (`If modular: <a> · Else (stacked): <b>`).
197
-
198
- For the Step 0 question itself (`{{COMMIT_STRATEGY_STEP0_QUESTION}}`), the ask substitution is the AskUserQuestion block documented in the parent placeholder table in [SKILL.md](../SKILL.md) — same content used to populate the resolved value.
@@ -0,0 +1,46 @@
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). -->
2
+
3
+ <!-- block-begin: BRANCH_NAMING -->
4
+ Branch naming: `plan/{plan-id-kebab}/phase-{phase.id}` (one branch + one PR per phase, stacked).
5
+
6
+ **First executed phase** (branches from `<BASE_BRANCH>`, already made current by the conductor):
7
+
8
+ ```bash
9
+ git -C <WORKROOT> checkout <BASE_BRANCH>
10
+ git -C <WORKROOT> checkout -b plan/{plan-id-kebab}/phase-{phase.id}
11
+ # subagent's commits land on this branch
12
+ git -C <WORKROOT> push -u origin plan/{plan-id-kebab}/phase-{phase.id}
13
+ ```
14
+
15
+ **Subsequent phases** (stacked on the previous phase's branch):
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
+ <!-- block-end: BRANCH_NAMING -->
23
+
24
+ <!-- block-begin: PER_PHASE_COMMIT -->
25
+ 7. Stage the right files (NEVER `git add -A` — {{ANTI_GIT_ADD_ALL_REASON}}). Stage explicitly: `git add {{STAGE_PATTERN}}`.
26
+ 8. Commit with the repo's style — look at `git log -10 --oneline` first. {{COMMIT_STYLE_LINE}}.
27
+ 9. {{COAUTHOR_INSTRUCTION_LINE}}
28
+ 10. {{PUSH_INSTRUCTION_LINE}}
29
+ <!-- block-end: PER_PHASE_COMMIT -->
30
+
31
+ <!-- block-begin: PR_OPEN_TIMING -->
32
+ One PR per phase — the [Open PR via context file](#open-pr-via-context-file) step runs after this phase passes review, writing `.vinta-ai-workflows/prs-context/{feature-kebab}/phase-{phase.id}.md`.
33
+ <!-- block-end: PR_OPEN_TIMING -->
34
+
35
+ <!-- block-begin: CHECKLIST -->
36
+ <!-- stacked adds no extra commit-discipline checklist items beyond the branch line -->
37
+ <!-- block-end: CHECKLIST -->
38
+
39
+ <!-- Single-line values (derive-skills substitutes these into the shells directly):
40
+ BRANCH_PUSH_HEADING = Push stacked branch
41
+ BRANCH_NAMING_PATTERN_SUMMARY = branch naming pattern (default: `plan/{plan-id-kebab}/phase-{phase-id}`)
42
+ PRS_CONTEXT_FILE_PATH = `.vinta-ai-workflows/prs-context/{feature-kebab}/phase-{phase.id}.md`
43
+ TRACKING_BRANCH_FIELD = (empty — per-phase branch lives inline under TRACKING_PHASE_BRANCH_FIELD)
44
+ TRACKING_PHASE_BRANCH_FIELD = , branch, base
45
+ FINAL_REPORT_BRANCH_SUMMARY = branches pushed (with bases, in stack order)
46
+ BRANCH_CHECKLIST_LINE = Stacked branch created; pushed. -->
@@ -0,0 +1,78 @@
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). -->
2
+
3
+ <!-- block-begin: FULL -->
4
+ ```
5
+ You are implementing {phase.id}: {phase.title} of plan {plan.id}.
6
+
7
+ ## Repo
8
+ {{PROJECT_NAME}} ({{STACK_SUMMARY}}).
9
+
10
+ ## Working location
11
+ Work entirely inside `<WORKROOT>`. `cd` into it before any command. Every `git`,
12
+ every lint / test / build / migrate call runs there.
13
+ {If run_options.use_worktree = true:}
14
+ `<WORKROOT>` is an isolated git worktree — do NOT touch the main checkout; its DB,
15
+ env, and compose stack are intentionally separated. See `<WORKROOT>/WORKTREE.md` for
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.
22
+
23
+ ## Read first
24
+ 1. AGENTS.md — repo conventions.
25
+ 2. {{PLAN_DIR}}/{plan-filename}, the **Goals + Non-goals**, **Guiding Decisions**, **Data Model Changes** sections and YOUR phase body inside **Phased Rollout**.
26
+ {If run_options.use_worktree = true:} 3. `WORKTREE.md` at the worktree root — fork map (which dirs symlink to main vs are independent copies).
27
+
28
+ ## Plan-level decisions (from Goals + Non-goals + Guiding Decisions)
29
+ {Goals + Non-goals verbatim}
30
+ {Guiding Decisions table verbatim}
31
+ {If feature flag declared:}
32
+ Feature flag: `{flag-key}` — scope `{per-tenant|per-request}`, default `{false|true}`.
33
+ Wire reads + writes per the plan's **Guiding Decisions** entry. Off-flag path = byte-for-byte pre-feature behavior.
34
+
35
+ ## What was already implemented in prior phases
36
+ {Tracking file "Completed Phases" section. First executed phase: "Nothing yet — this is the first phase."}
37
+
38
+ ## Your tasks (Phase {id} only)
39
+ {phase.body verbatim, including Goal / Spec use-case / Feature flag / Changes / Tests / Acceptance lines}
40
+
41
+ ## Reusable skills you SHOULD invoke
42
+ {phase.reusable_skills — for each, instruct the agent to first read ai-tools/skills/{name}/SKILL.md, then follow that pattern.}
43
+
44
+ Project skills available: {{PROJECT_SKILLS_LIST}}
45
+
46
+ {{DEPENDENCY_LICENSE_BLOCK}}
47
+
48
+ <!-- include: partials/implementer-prompt.md#INNER_OUTER_LOOP -->
49
+ {{PER_PHASE_COMMIT_BLOCK}}
50
+
51
+ ## Required output (single final report)
52
+ - Status: SUCCESS or FAILURE (and why).
53
+ - Files created/modified (paths only).
54
+ - 5–15 line summary of what you implemented and key decisions.
55
+ {{E2E_REPORT_FIELD}}
56
+ - Deviations from the plan body and reasoning.
57
+ - Anything you couldn't do (with explanation).
58
+ ```
59
+
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.
61
+ <!-- block-end: FULL -->
62
+
63
+ <!-- block-begin: INNER_OUTER_LOOP -->
64
+ ## Working instructions
65
+ 1. Read existing code paths your changes touch — do not write before reading.
66
+ 2. Implement using Read/Edit/Write. Match existing patterns.
67
+ 3. **Inner loop — fast iteration.** Scoped to files/apps you touched:
68
+ a. `{{LINT_CMD}}` until clean.
69
+ b. {{NEW_TEST_CMD_PATTERN}} for new tests individually.
70
+ c. Scoped suite: {{SCOPED_TEST_PATTERN}}.
71
+ 4. Iterate 2–3 until **new tests pass individually** and the scoped suite is green. Do **not** advance to step 5 with red scoped tests.
72
+ 5. **Outer gate — local verification, only after step 4 is green.** All MUST pass before staging:
73
+ a. **Type / build:** `{{BUILD_CMD}}` — repo-wide, always.
74
+ b. **Tests:** by default run only the **scoped suite** `{{SCOPED_TEST_PATTERN}}` for the apps/files you touched — the new tests already passed individually in step 4b, so this re-confirms the touched surface without paying for the whole repo.
75
+ {If run_options.full_test_suite = true:} run the **full test suite** `{{TEST_CMD}}` instead of the scoped suite — this phase guards against regressions in untouched code too.
76
+ {{E2E_OUTER_GATE_LINE}}
77
+ 6. Outer gate fails → return step 2 (fix regression), re-run inner loop, then 5a/5b/5c. **Never** commit, push, or proceed while any gate is red.
78
+ <!-- block-end: INNER_OUTER_LOOP -->
@@ -0,0 +1,19 @@
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
+ <!-- block-begin: MODEL_PICK -->
3
+ ## Pick the model from the plan's per-phase suggestion
4
+
5
+ **The plan owns model selection — 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.
6
+
7
+ Pick:
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.
15
+
16
+ **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
+
18
+ Record the **model actually used** + the **plan's suggested tier** in tracking.
19
+ <!-- block-end: MODEL_PICK -->
@@ -0,0 +1,61 @@
1
+ <!-- Partial: pr-context — the "Open PR via context file" body (former 1f), decoupled from commit-strategy. Included by integrate-phase. The commit-strategy-specific PR-open timing + prs-context file path come from commit-strategy/<resolved>.md (PR_OPEN_TIMING block + PRS_CONTEXT_FILE_PATH value). generate_inline_comments is a runtime flag whose only effect is localized here (whether the `# Comments` block is populated). -->
2
+
3
+ <!-- block-begin: PR_CONTEXT -->
4
+ This is the **only** PR-creation path. PRs always go through {{PRS_CONTEXT_FILE_PATH}} + the bundled [open-pr.sh](../open-pr-from-context/scripts/open-pr.sh) script — even when inline comments are not requested. The file is the durable record; the script is the publisher. Subagents never open PRs themselves; the orchestrator does, after review passes.
5
+
6
+ {{PR_OPEN_TIMING_BLOCK}}
7
+
8
+ Two project-level signals decide the actual behavior:
9
+
10
+ | `{{PR_POLICY_BLOCK}}` policy | `run_options.generate_inline_comments` | What this step does |
11
+ |---|---|---|
12
+ | agents create PRs | false | Write minimal context file (`# Title`, `# Description`, empty `# Comments`). Run `open-pr.sh` → PR opened, no inline comments. |
13
+ | agents create PRs | true | Write full context file (title + description + 3–10 inline comments). Run `open-pr.sh` → PR opened, all comments posted. |
14
+ | branches only | false | **Skip this step entirely.** Human will open the PR manually from the pushed branch. |
15
+ | branches only | true | Write full context file (durable record). **Don't run `open-pr.sh`.** Human can publish later from a CLI-equipped session via [open-pr-from-context](../open-pr-from-context/SKILL.md). Surface this in the user update. |
16
+
17
+ ### Steps
18
+
19
+ 1. **Skip if neither column applies** (policy = branches only AND `generate_inline_comments = false`). Return to the conductor's tracking step.
20
+
21
+ 2. **Honor existing PR / MR templates.** Read `project.pr_template_paths` from `.vinta-ai-workflows.yaml`. For each entry:
22
+ - **One template** → load it; the prs-context `# Description` body must follow that template's section structure verbatim. Fill each section with phase-specific content drawn from the plan's **Goals + Non-goals**, **Guiding Decisions**, and the phase body. Preserve any `<!-- HTML comments -->` placeholders; do not strip the template's checklists. Sections you can't fill from phase data → leave the template's placeholder/prompt untouched (don't fabricate).
23
+ - **Multiple templates** (`PULL_REQUEST_TEMPLATE/` directory) → ask once via `AskUserQuestion`: list each template + its filename, ask which to use for this run. Cache the choice in tracking under `run_options.pr_template_used` so subsequent phases of the same plan use the same one without re-asking.
24
+ - **Empty array** → free-form description. Default sections: `## Summary` (1–3 sentences), `## Plan reference` (link / phase id), `## Test plan` (commands the reviewer can run).
25
+
26
+ When the project's PR template includes a checkbox checklist (e.g. `- [ ] Tests added`, `- [ ] Docs updated`), tick the boxes the phase's diff actually satisfies and leave unsatisfied ones unticked — never auto-tick everything.
27
+
28
+ GitHub also honors `?template=<name>` in the PR-create URL when the project has a multi-template directory. `gh pr create --body-file` writes the body directly so the URL trick isn't needed; the body must match the chosen template's structure regardless.
29
+
30
+ 3. **Pick comment targets** (only when `generate_inline_comments = true`). Read the phase diff via `git -C <WORKROOT> diff <BASE_BRANCH>...HEAD` (or the previous phase branch for stacked phases). Select 3–10 spots that benefit from a one-paragraph context note — typically:
31
+ - A subtle invariant the diff relies on (cite the plan's **Goals + Non-goals** / **Guiding Decisions** entries — by name, never use `§` shorthand).
32
+ - A workaround for a known framework / library limitation.
33
+ - A naming choice driven by an upstream contract.
34
+ - The off-flag short-circuit when a feature flag is in **Guiding Decisions**.
35
+ - Why a seemingly-cleaner refactor wasn't made (out of scope per **Goals + Non-goals**).
36
+ - Cross-phase coupling (this hook is consumed by phase N+k).
37
+
38
+ Skip lint/format churn, boilerplate matching nearby files, standard patterns from AGENTS.md, and self-explanatory test names. **A clean phase produces few comments — that's fine. Don't pad.**
39
+
40
+ When `generate_inline_comments = false`: skip this step. The file's `# Comments` block stays empty.
41
+
42
+ 4. **Write the prs-context file** at {{PRS_CONTEXT_FILE_PATH}}, following [resources/prs-context-template.md](../../prs-context-template.md). Frontmatter: `plan_id`, `feature_name`, `phase_id`, `phase_title`, `branch`, `base`, `created_at`, `status: pending`, empty `pr_url`. Body sections: `# Title` (single-line PR title), `# Description` (Markdown body — uses the project's PR template structure from step 2 when one exists), `# Comments` (YAML list of `{file, start_line, end_line?, side, body}` — empty list when comments are off).
43
+
44
+ 5. **Confirm `.vinta-ai-workflows/prs-context/` is in `.gitignore`.** [vinta-install-ai-tools-setup](../../../vinta-install-ai-tools-setup/SKILL.md) runs the multi-vendor setup script which appends `.vinta-ai-workflows/prs-context/` on its first invocation. If an older bootstrap missed it, append it now.
45
+
46
+ 6. **Run `open-pr.sh`** (only when policy = agents create PRs). Detect a usable CLI (`gh` for GitHub, `glab` for GitLab) plus the script's other deps (`yq`, `jq`):
47
+
48
+ ```bash
49
+ bash ai-tools/skills/open-pr-from-context/scripts/open-pr.sh {{PRS_CONTEXT_FILE_PATH}}
50
+ ```
51
+
52
+ The script opens the PR (or detects an existing one), posts each inline comment, rewrites the file's frontmatter to `status: published` + populated `pr_url`, appends a publish log. Exit codes:
53
+
54
+ - `0` — PR up, all comments (if any) posted. Capture `pr_url` for the user update.
55
+ - `1` — PR up, ≥1 comment failed. Surface the failed `(file:line)` list to the user; continue to the tracking step.
56
+ - `2` — Hard failure (deps missing, branch not pushed, CLI unauthed, file invalid). Surface the script's stderr; treat the phase as having no PR. The file stays `status: pending` so the user can re-run after fixing the gap.
57
+
58
+ When policy = "branches only": **don't run the script.** File stays `status: pending`.
59
+
60
+ 7. **Skill wrapper** — [open-pr-from-context](../open-pr-from-context/SKILL.md) is available for ad-hoc invocation (after the run, on a different machine, etc.). The orchestrator can call the script directly here; the skill is for humans.
61
+ <!-- block-end: PR_CONTEXT -->
@@ -0,0 +1,50 @@
1
+ <!-- Partial: review-layers — the three-layer review + fix loop. Included by review-phase. amend-plan and systematic-debugging reuse it by INVOKING review-phase (not by including this partial). The orchestrator running review-phase never edits code itself — every issue surfaces as a fix-up subagent task. -->
2
+
3
+ <!-- block-begin: LAYERS -->
4
+ Three layers, all required, in order. The reviewing orchestrator never edits — every issue surfaces as a fix-up subagent task.
5
+
6
+ ## Layer 1 — Mechanical checks
7
+
8
+ 1. `git -C <WORKROOT> status` + `git -C <WORKROOT> diff --stat`: confirm the file list matches the agent's report.
9
+ 2. **Read the full diff** for every changed file using `git -C <WORKROOT> diff`. Spot-checking is not enough.
10
+ 3. **Verify the outer gate** ran + green. By default that is `{{BUILD_CMD}}` (repo-wide) AND the scoped suite `{{SCOPED_TEST_PATTERN}}` covering the touched apps. {If run_options.full_test_suite = true:} the outer gate runs `{{BUILD_CMD}}` AND the full `{{TEST_CMD}}` instead — verify that. Look in the report for explicit confirmation the applicable gate was executed + passed{{E2E_LAYER1_NOTE}}. Vague confirmation → **re-run yourself** (in `<WORKROOT>`).
11
+ 4. **Scope creep**: file touched outside the expected surface area? Unrelated formatting churn? Surface it.
12
+ 5. **No-secrets scan**: `git -C <WORKROOT> diff` for `password|secret|token|api_key|AKIA|BEGIN [A-Z]+ KEY`.
13
+ 6. <!-- include: partials/worktree-seam.md#STRAY_WRITE_CHECK -->
14
+ {{DEPENDENCY_LICENSE_LAYER1_CHECK}}
15
+ {{COAUTHOR_LAYER1_CHECK}}
16
+
17
+ ## Layer 2 — Plan compliance walkthrough
18
+
19
+ Open the phase body alongside the diff and walk:
20
+
21
+ 1. **Every numbered "Changes" item implemented.**
22
+ 2. **Every "Tests" entry materialized**, with assertions actually exercising the called-out behavior.
23
+ 3. **Acceptance line satisfiable** by the diff.
24
+ 4. **Repo conventions** from AGENTS.md.
25
+ 5. **Reusable-skill compliance.**
26
+ {{E2E_LAYER2_CHECK}}
27
+ 6. **Feature-flag wiring** if the plan's **Guiding Decisions** declared a flag — flag-OFF is byte-for-byte pre-feature behavior, ≥1 test asserts it.
28
+ 7. **Cross-phase consistency** with prior tracking summaries.
29
+ 8. **Comment hygiene** — new or changed comments and doc blocks in the diff read as Simple English, one idea per sentence, no AI-slop vocabulary or negative framing, per the `deslop-comments` skill ([ai-tools/skills/deslop-comments/SKILL.md](ai-tools/skills/deslop-comments/SKILL.md)). Flag any that need rewriting; the fix loop dispatches a fixer to run `deslop-comments` on the phase's touched files.
30
+
31
+ ## Layer 3 — Independent reviewer subagent
32
+
33
+ After Layers 1–2 pass, spawn a **separate** subagent (different session, no implementation context) using the project's `reviewer` agent type ([ai-tools/agents/reviewer.md](ai-tools/agents/reviewer.md)). Read-only by design.
34
+
35
+ Reviewer prompt template — see the reviewer agent's body for the standard form. Triage findings:
36
+ - **BLOCKER**: must fix before the phase is pushed (the conductor's integrate step).
37
+ - **SHOULD-FIX**: fix in-phase if cheap; else follow-up issue + tracking note.
38
+ - **NIT**: ignore unless trivially cheap.
39
+
40
+ The reviewer also applies a condensed **structural-simplification lens** — one question: is there an obvious "code-judo" reframe that would make whole branches, helpers, modes, or layers disappear, rather than polishing what's there? Routine phases stop at that one question. When the phase touched core architecture, pushed a file past ~1,000 lines, or the lens surfaces a structural smell too big to resolve inline, escalate to the full [thermo-nuclear-code-quality-review](ai-tools/skills/thermo-nuclear-code-quality-review/SKILL.md) skill against the phase diff — an opt-in deep audit, run deliberately, never on every phase.
41
+
42
+ The reviewer finds nothing on a >300-LoC multi-file phase → suspicious. Read once more.
43
+
44
+ ## Fix loop
45
+
46
+ 1. Spawn a **new** subagent — the project's `fixer` agent type ([ai-tools/agents/fixer.md](ai-tools/agents/fixer.md)). The fix prompt quotes the finding verbatim. For comment-hygiene findings (Layer 2 item 8), the fix prompt tells the fixer to run the `deslop-comments` skill ([ai-tools/skills/deslop-comments/SKILL.md](ai-tools/skills/deslop-comments/SKILL.md)) scoped to the phase's touched files — comment-only edits, no behavior change.
47
+ 2. The `fixer`'s system prompt mandates re-running the inner loop + outer gate (in `<WORKROOT>`).
48
+ 3. After the fixer returns, redo Layer 1 in full + the affected portion of Layer 2.
49
+ 4. Loop until Layers 1, 2, 3 are all clean.
50
+ <!-- block-end: LAYERS -->
@@ -0,0 +1,68 @@
1
+ <!-- Partial: worktree-seam — the WORKROOT abstraction. Collapses the former scattered `if use_worktree` conditionals into one resolution (conductor) + two local, data-driven checks (implement-phase spawn wrap, review-phase stray-write). Blocks: WORKROOT_RESOLUTION (conductors), WORKROOT_TOPOLOGY_RULE (conductors + integrate-phase), SANDBOX_WRAP (implement-phase), STRAY_WRITE_CHECK (review-phase). -->
2
+
3
+ <!-- block-begin: WORKROOT_RESOLUTION -->
4
+ ## Step 0.5 — Resolve `WORKROOT`
5
+
6
+ Resolve three values **once**, before any phase runs, and record them in tracking. Every later step uses them as data — no step re-derives worktree state.
7
+
8
+ | Value | `run_options.use_worktree = false` | `run_options.use_worktree = true` |
9
+ |---|---|---|
10
+ | `WORKROOT` | the main checkout root (the repo the skill was invoked from) | `<worktree_path>` returned by prepare-worktree |
11
+ | `BASE_BRANCH` | `{{DEFAULT_BRANCH}}` | `<worktree_branch>` prepare-worktree created |
12
+ | `SANDBOX_TIER` | `none` | `enforced` or `none` (probed by prepare-worktree) |
13
+
14
+ **When `use_worktree = false`:** set `WORKROOT` = main checkout, `BASE_BRANCH = {{DEFAULT_BRANCH}}`, `SANDBOX_TIER = none`. Make `BASE_BRANCH` current + up to date: `git -C <WORKROOT> checkout {{DEFAULT_BRANCH}} && git -C <WORKROOT> pull --ff-only`. Jump to Step 1.
15
+
16
+ **When `use_worktree = true`:** invoke [prepare-worktree](../prepare-worktree/SKILL.md) **once**:
17
+
18
+ 1. **Inputs.** Plan path (so prepare-worktree can read it for deps / migrations / env / compose churn — see prepare-worktree's **Plan inspection** step), suggested worktree name = `plan-{plan-id-kebab}`, plan-driven mode.
19
+ 2. **Pre-run sanity.** Confirm no existing worktree at the target path (`git worktree list | grep <name>` — refuse if collision). Confirm `git -C <main_checkout> status` of the main checkout (warn if dirty; defer to prepare-worktree's **Sanity checks** step for the call).
20
+ 3. **Run prepare-worktree.** Pass the plan file + worktree name. It returns:
21
+ - `worktree_path` → `WORKROOT`.
22
+ - `worktree_branch` → `BASE_BRANCH` (prepare-worktree based it on `origin/{{DEFAULT_BRANCH}}`, so it is already current).
23
+ - `worktree_summary` — `.vinta-ai-workflows/worktrees/<name>.yaml` (read by teardown).
24
+ - `sandbox_tier` → `SANDBOX_TIER`: `enforced` (the [Filesystem sandbox](../prepare-worktree/SKILL.md#step-55--filesystem-sandbox-os-level-write-guard) step found `sandbox-exec` / `bwrap` and will OS-block main-checkout writes) or `none` (no sandbox tool — prevention degrades to the review-phase stray-write backstop).
25
+ 4. **Persist to tracking.** Write `run_options.worktree_path`, `run_options.worktree_branch`, `run_options.worktree_summary`, `run_options.sandbox_tier` into `{{PLAN_DIR}}/TRACKING_{plan-id}.md`. All later phases read them — never re-provision mid-plan.
26
+ 5. **Report to user.** Quote the prepare-worktree summary back: which dirs symlinked vs copied vs forked; which DB(s) forked + their names; compose project name; teardown command. Hold here until the user confirms (`AskUserQuestion`: `Looks good — start phase 1`, `Stop — let me adjust`).
27
+
28
+ Failure modes:
29
+ - **prepare-worktree returns an error** (disk full, branch exists, DB clone failed) → surface to the user; do NOT fall back to "just run in the main checkout" silently — that defeats the opt-in. Ask: `Retry`, `Run in main checkout instead (flip use_worktree to false)`, `Stop`.
30
+ - **User cancels at the confirmation gate** → tear the worktree down (run the teardown command from prepare-worktree's report) before exiting, so the next run starts clean.
31
+ <!-- block-end: WORKROOT_RESOLUTION -->
32
+
33
+ <!-- block-begin: WORKROOT_TOPOLOGY_RULE -->
34
+ **`WORKROOT` topology rule.** Every phase branches off the previous phase (first executed phase off `<BASE_BRANCH>`), and **every** `git` / lint / test / build / migrate call runs with `git -C <WORKROOT>` (or after `cd <WORKROOT>`). When `use_worktree = false`, `WORKROOT` is the main checkout and this is exactly today's in-place behavior; when `true`, `WORKROOT` is the worktree and branches / commits stack inside it, never touching the main checkout's working tree. One uniform path — no per-step worktree branching.
35
+ <!-- block-end: WORKROOT_TOPOLOGY_RULE -->
36
+
37
+ <!-- block-begin: SANDBOX_WRAP -->
38
+ **Sandbox the spawn — only when `SANDBOX_TIER = enforced`.** The prompt tells the subagent to stay in `WORKROOT`, but that's cooperative — a smaller model can resolve a path back to the main checkout and silently write there (the review-phase stray-write check catches this reactively). When `SANDBOX_TIER = enforced` **and** the runtime spawns subagents as **subprocesses** (it shells out to an agent CLI — e.g. `codex exec …`, a `claude -p …` child, a custom runner), wrap that launch command in the worktree's bundled guard so the OS blocks main-checkout writes regardless of harness:
39
+
40
+ ```bash
41
+ ai-tools/skills/prepare-worktree/scripts/sandbox-run.sh \
42
+ --deny <main_checkout> \
43
+ --allow <WORKROOT> \
44
+ --allow <main_checkout>/.vinta-ai-workflows \
45
+ --allow <main_checkout>/.git \
46
+ -- <the agent spawn command>
47
+ ```
48
+
49
+ `<main_checkout>` is the repo root the skill was invoked from (never `WORKROOT` when a worktree is in use). A stray write then fails with `Operation not permitted` / `EROFS`; the subagent retries against the worktree. `<main_checkout>/.git` must be allowed because git worktrees write commits into the main repo's `.git` (shared objects/refs, `.git/worktrees/<name>/index.lock`); omitting it makes the subagent's own `git commit` fail.
50
+
51
+ - **In-process subagent runtimes** (orchestrator and subagent share one OS process — e.g. claude-code's Task tool) can't wrap a single spawn. Two options: (a) install a runtime pre-write guard hook scoped to `WORKROOT` (prepare-worktree ships `scripts/claude-worktree-write-guard.py` + `scripts/gen-claude-sandbox-settings.sh` for claude-code); or (b) run the **entire** invocation under `sandbox-run.sh` with the same `--deny` / `--allow` set. Pick whichever the runtime supports.
52
+ - **`SANDBOX_TIER = none`** (no sandbox tool, or `use_worktree = false`) → skip wrapping; prevention falls back entirely to the review-phase stray-write check. Surface this once to the user when a worktree run is unsandboxed so the weaker guarantee is explicit.
53
+ <!-- block-end: SANDBOX_WRAP -->
54
+
55
+ <!-- block-begin: STRAY_WRITE_CHECK -->
56
+ **Stray main-checkout writes — only when `WORKROOT != <main_checkout>` (i.e. a worktree run).** A subagent told to work inside the worktree can resolve an absolute path back to the **main checkout** and silently edit files there; because worktrees have independent working trees, those edits never reach the phase commit — they sit as uncommitted thrash in the main checkout and read as a silent implementer/fixer failure. **When `SANDBOX_TIER = enforced`, the OS sandbox already blocks these writes and this becomes a cheap backstop (a clean `git status` is the expected result). When `SANDBOX_TIER = none`, it is the *only* defense — run it religiously.** After **every** implementer **and** fixer subagent returns, run:
57
+
58
+ ```bash
59
+ git -C <main_checkout> status --short | grep -vE '^\?\?' # tracked modifications only
60
+ ```
61
+
62
+ Any output is a BLOCKER for this phase:
63
+ - Diff the stray files (`git -C <main_checkout> diff -- <path>`) to recover intent.
64
+ - If the edit belongs in the worktree, re-dispatch the fixer/implementer with an explicit instruction to write to `WORKROOT` (the change is missing from the phase commit until it does).
65
+ - Once recovered (or confirmed superseded by the correctly-committed worktree version), discard the stray edits with `git -C <main_checkout> restore -- <path>` so the main checkout returns clean. Never leave the main checkout dirty between phases — a later phase can't tell new thrash from old.
66
+
67
+ `<main_checkout>` is the repo root the skill was invoked from (NOT `WORKROOT`). When `WORKROOT == <main_checkout>` (`use_worktree = false`), skip this check entirely — your work legitimately lives in that tree.
68
+ <!-- block-end: STRAY_WRITE_CHECK -->