AGENT SKILL

openspec-apply-parallel

Implement an OpenSpec change in parallel using multiple subagents (one per disjoint task group inside the same slice). Use when the slice's tasks.md has ≥2 task groups with disjoint write-paths AND >30 min of parallelisable work. For sequential implementation use openspec-apply-change instead.

License 许可
MIT
最近更新
2026-11-09
Stars
★ 6
Forks
1

01 前言 Front Matter

name
openspec-apply-parallel
license
MIT
metadata
{ "spec": "docs/concepts/release-management.md §6.6", "author": "ai-playbook", "version": "1.0" }
description
Implement an OpenSpec change in parallel using multiple subagents (one per disjoint task group inside the same slice). Use when the slice's tasks.md has ≥2 task groups with disjoint write-paths AND >30 min of parallelisable work. For sequential implementation use openspec-apply-change instead.

03 SKILL.md 正文

Implement a multi-group OpenSpec change with parallel subagents.

Input: Required: a change name. Optional: --dry-run to print the planned spawn matrix without actually spawning.

When to use this skill (gating questions)

You MUST answer YES to all four before invoking this skill. If any is NO, fall back to /opsx:apply (sequential):

  1. Multi-group: does tasks.md declare ≥2 task groups with explicit **Owns:** write-paths in their headers?
  2. Disjoint: are those write-paths non-overlapping? (no two groups touch the same directory subtree)
  3. >30 min: is the parallelisable work substantial? Rule of thumb: each group has ≥10 tasks, OR cumulative parallel work is ≥30 min wall-clock. Below that, recombination overhead (~10-15 min) wipes the saving.
  4. Pre-allocated migration numbers: if the slice creates DB migrations, are sequence numbers reserved per group in tasks.md (NOT chosen by subagents)?

If you can't answer YES to all four, the slice is mis-sliced for parallel execution. Either re-slice, OR run sequentially via /opsx:apply.

Steps

1. Select the change

If a name is provided, use it. Otherwise:

  • Infer from conversation context if the user mentioned a change.
  • Auto-select if only one active change exists.
  • If ambiguous, run openspec list --json and ask the user to pick.

Announce: "Parallel-applying change: <name>. Spawn matrix below."

2. Read the contract artifacts (no edits)

Read in this order:

  • openspec/changes/<change-id>/proposal.md — scope.
  • openspec/changes/<change-id>/design.md — design decisions.
  • openspec/changes/<change-id>/tasks.md — REQUIRED. Identify task groups + their write-path ownership headers.
  • .ai-playbook/docs/concepts/release-management.md §6.6 — the contract you'll follow.

3. Cross-check ownership (BEFORE spawning anything)

Build a table from the per-group **Owns:** declarations in tasks.md:

Group ID Branch (slice/<id>--<group>) Owns paths Reads (no edit) Migration #s reserved
§2 IAM slice/module-1-ingredients-impl--iam apps/api/src/iam/**, migrations/0001-0004_*.ts data-source.ts, app.module.ts 0001-0004
§3 Ingredients slice/module-1-ingredients-impl--ingredients apps/api/src/ingredients/**, migrations/0005-0009_*.ts (same) 0005-0009
... ... ... ... ...

Verify:

  • No two groups own the same path (any subtree overlap → abort, fall back to sequential).
  • Migration numbers are non-overlapping (gaps OK; overlaps NOT OK).
  • Shared files (app.module.ts, package.json, data-source.ts, top-level tsconfig, Makefile, pyproject.toml runtime deps) are NOT owned by any group — flag them as "main agent recombination work".

If the cross-check fails, STOP and tell the user: "tasks.md ownership is inconsistent (concrete reason). Re-slice via /opsx:propose, or sequentialize via /opsx:apply." Do NOT proceed.

4. Pre-flight (per §6.5 + §6.6 pre-conditions)

git fetch origin
git checkout slice/<change-id>
git rebase origin/main   # abort on conflict; tell user to re-slice

For each group, create the ephemeral branch (NOT pushed to origin) from origin/main. Name the ref, never a shell variable from an earlier block: each Bash tool call is a fresh shell, so the variable would be empty and git branch would silently start from HEAD.

git branch slice/<change-id>--<group-id> origin/main

5. Print the spawn matrix (and if --dry-run, stop here)

Show the user the table from step 3 + the planned subagent count. Confirm: "Spawning N subagents. Continue?" If they say no, stop. If --dry-run, stop after printing.

6. Spawn subagents in parallel (single message, multiple Agent tool calls)

For each group, invoke the Agent tool with isolation: "worktree" and a scoped prompt. CRITICAL: all calls go in one message so they run concurrently. Each prompt MUST include:

  • The branch to commit on: slice/<change-id>--<group-id> (DO NOT push to origin).
  • The owned paths (write-allowed).
  • The read-only paths (consult, don't edit).
  • The reserved migration numbers (if any).
  • The relevant subset of tasks.md (their group only).
  • Return contract: "When done, return your branch name + the SHA range you committed (<base-sha>..<head-sha>)."

Template prompt for each subagent:

You are implementing task group <group-id> of OpenSpec change <change-id>.

## Owned paths (write here only)
<paths from tasks.md>

## Read-only paths (consult, don't edit)
<paths from tasks.md>

## Reserved migration numbers
<migration #s>

## Tasks
<the task group's tasks from tasks.md>

## Contract
1. Implement every task in the list. Mark each `- [ ]` → `- [x]` in tasks.md as you complete it.
2. Commit ONLY to branch `slice/<change-id>--<group-id>`. Do NOT push to origin.
3. Do NOT edit ANY file outside the owned paths.
4. Run the slice's local tests scoped to your group (e.g. `pytest apps/api/tests/<group-dir>/`) before each commit.
5. When all tasks are done, return: branch name + SHA range (`<base>..<head>`).

If you discover a task requires editing a shared file, STOP and return: "blocked: needs <file> edit (out of scope for this group)". The main agent will handle shared files in recombination.

7. Await completion + collect results

Each subagent returns its branch name + commit SHA range. Build the recombination plan:

Recombination order (apply in dependency order — leaf groups first, shared-state last):
  1. <group-A> commits: <sha>..<sha>
  2. <group-B> commits: <sha>..<sha>
  ...
  N. Main agent: shared file updates (app.module.ts, package.json, data-source.ts)

If ANY subagent returned blocked: ..., stop. Show the user which group blocked + on what file. They decide: split the slice, or sequentialize.

8. Recombine onto slice/<change-id> (sequential, main agent only)

git checkout slice/<change-id>
# Abort point for step 9, recorded before any cherry-pick. A ref, not a shell
# variable: step 9 runs in a later Bash call (a fresh shell), and a ref also
# survives context compaction. Run this block once: a second run would move
# the abort point onto the half-recombined HEAD.
git branch -f slice/<change-id>--pre-recombine HEAD
for group in <ordered groups>; do
  git cherry-pick <group's-sha-range>
done
# Now update shared files (the parts no subagent owned).
# Examples: register modules in app.module.ts, aggregate deps in package.json,
#           wire migrations into data-source.ts.

9. Run the FULL test suite (NOT scoped to a group)

# Slice-wide. Fails here = recombination conflict or untracked shared file.
pytest apps/api/tests/   # (or the equivalent for your stack)

If the test fails:

  • Conflict in shared files → fix the shared-file edit (commit it on slice/<change-id>) and re-run the suite above. Do NOT re-run step 8's block: its cherry-picks are already applied, and its git branch -f would move the abort point onto this half-recombined HEAD.
  • Two groups had implicit cross-dependency not caught in step 3 → ABORT recombination + fall back to sequential /opsx:apply. File a slicing-too-coarse retro for next time. Aborting discards the recombined commits, so confirm with the user first, then return slice/<id> to the slice/<id>--pre-recombine ref recorded in step 8 — never to origin/main, which would also drop every slice commit made before this parallel run:
    git cherry-pick --abort 2>/dev/null || true
    git reset --hard slice/<change-id>--pre-recombine
    
    The per-group branches slice/<id>--<group> still hold the subagents' work. If the ref is missing, git reflog slice/<change-id> lists the branch's earlier tips; ask the user which one to return to.

10. Push the slice branch + open PR

git push -u origin slice/<change-id>

Then follow the standard /opsx:apply post-implementation flow: open PR, populate §4.5 AI-reviewer signoff, await reviews, gate F, archive.

11. Clean up ephemeral branches

for group in <groups>; do
  git branch -D slice/<change-id>--<group-id>   # local only; never were on origin
done
git branch -D slice/<change-id>--pre-recombine   # the step 8 abort point

Anti-patterns (each is a goal_drift per agentic-failures.md §X)

  • Subagent edits a file outside owned paths → caught by main agent during cross-check at recombination time. If it slipped through, ABORT + fall back to sequential.
  • Subagent pushes to a public branch (origin/slice/... or origin/feat/...) → reject the work. Branches MUST stay local until the main agent pushes the bundled slice/<change-id>.
  • Main agent skips the cross-check step 3 and spawns with overlapping ownership → race conditions in cherry-pick. Cross-check is non-negotiable.
  • Migration numbers chosen by subagents instead of pre-allocated in step 3 → migration sequence collisions on recombination. Numbers come from the spec, not from subagent inference.

Hard limit

This pattern caps at the number of disjoint bounded contexts the slice covers. Most slices have 1–2 (use /opsx:apply); modules-as-foundation slices have 3–5; nothing in the playbook spawns >6 subagents inside one slice (above that, the slice is mis-sliced — see runbook-bmad-openspec.md §2.2).

When this skill is the wrong tool

Fall back to /opsx:apply (sequential) when:

  • The slice has 1 task group, OR
  • Task groups are TDD-tight (interface → impl → consumer cannot be parallelised), OR
  • Each group is <10 tasks (overhead exceeds saving), OR
  • Cross-checks in step 3 reveal overlapping ownership.

References

  • docs/concepts/release-management.md §6.6 — the contract this skill implements.
  • docs/concepts/runbook-bmad-openspec.md §3.8 — pointer to §6.6.
  • skills/openspec-apply-change/SKILL.md — the sequential cousin.

04 同仓库更多 Skills

Wizarck
Wizarck/ai-playbook

sweep

Use when the user wants to find code that has quietly stopped being used — types /sweep, asks for a "dead code sweep", "repo entropy", "what can we delete", "orphan files", "unused code", or asks to review a sweep ledger. Adjudicates candidates a deterministic scanner already produced; it never deletes anything and never re-derives findings from raw source. Pairs with ponytail, which gates what gets written rather than what rots.

★ 6
Wizarck
Wizarck/ai-playbook

ponytail

Use when the user wants the laziest solution that actually works — types /ponytail, says "be lazy", "lazy mode", "simplest solution", "minimal solution", "yagni", "do less", or "shortest path", or complains about over-engineering, bloat, boilerplate, or unnecessary dependencies. Supports intensity levels lite, full, ultra (default). Pairs with caveman, which compresses prose, not code.

★ 6
Wizarck
Wizarck/ai-playbook

ponytail-review

Use when the user wants a code review focused exclusively on over-engineering — says "review for over-engineering", "what can we delete", "is this over-engineered", "simplify review", or invokes /ponytail-review. Complements correctness/security review; this one only hunts complexity in the current diff. Gated by the ponytail review_ponytail component.

代码审查
★ 6
Wizarck
Wizarck/ai-playbook

ponytail-debt

Use when the user wants to harvest every `ponytail:` comment in the codebase into a tracked debt ledger — says "ponytail debt", "/ponytail-debt", "what did ponytail defer", "list the shortcuts", "ponytail ledger", or "what did we mark to do later". One-shot report, changes nothing. Gated by the ponytail debt_ponytail component.

★ 6
Wizarck
Wizarck/ai-playbook

ponytail-audit

Use when the user wants a whole-repo audit for over-engineering — says "audit this codebase", "audit for over-engineering", "what can I delete from this repo", "find bloat", or invokes /ponytail-audit. Like ponytail-review but scans the entire tree, not a diff. One-shot report, applies no fixes. Gated by the ponytail audit_ponytail component.

★ 6
Wizarck
Wizarck/ai-playbook

openspec-propose

Propose a new change with all artifacts generated in one step. Use when the user wants to quickly describe what they want to build and get a complete proposal with design, specs, and tasks ready for implementation.

★ 6