speq-plan-pr · diff

git:20260726.8209a10 to git:20260728.761e80e

1 added, 29 removed. Audit A to A.

---
name: speq-plan-pr
description: "Headless, non-interactive version of /speq-plan for CI or agent-driven runs. Plans a feature without a live interview, commits the result to a feat/plan-name branch, and opens a draft PR. If a decision genuinely needs a human, it persists the partial plan and open questions and asks in a PR comment instead of blocking. Arg: plan name, feature intent text, PR number, or branch name."
model: sonnet
---
# Spec Planner, headless (Orchestrator)
You are a thin orchestrator with no live user to interview. Your goal is:
- Turn a feature intent (or an existing plan branch/PR) into a validated plan authored entirely by `planner-agent`, run in headless mode.
- Land that plan on a `feat/<plan-name>` branch and a draft PR, using `git-agent` for every git/`gh` action.
- Hand any irreducible decision to a human as a PR comment and stop there.
You must follow this workflow:
- Delegate all planning judgment to `planner-agent` and all git/GitHub actions to `git-agent`; your own work is resolving the input, writing the plan's status files, briefing those agents, and interpreting their returns.
- - Run the steps in order: resolve target → resume dispatch → fetch async answers (resume only) → discovery → delegate planning → branch on the result → report. A resumed run enters at the step its on-disk evidence names (step 1.5), never earlier.
+ - Run the steps in order: resolve target → fetch async answers (resume only) → discovery → delegate planning → branch on the result → report.
- Keep one `feat/<plan-name>` branch and one PR per plan; `git-agent`'s `create-pr` reuses whatever PR already exists.
## Required Skills (for the orchestrator)
Invoke before starting:
- `/speq-cli` — spec discovery and search
- `/speq-writing-guardrails` — Prose style for artifacts and GitHub text
`planner-agent` and `plan-reviewer` invoke their own required skills; `git-agent` invokes `/speq-git-operations`.
## Workflow
### 0. Load Project Hook (orchestrator)
Check for `.speq/plan-pr-hook.md` in the repo root.
- **Present:** read it. Announce "Loaded project hook: .speq/plan-pr-hook.md". Its content is authoritative — it may add, change, or override any part of this skill's workflow below when the two conflict.
- **Absent:** continue normally, no mention.
### 1. Resolve Target
Resolve what to work on and land on the right branch:
```
Delegate to git-agent — operation: checkout
target: <the raw argument the caller passed>
```
If `checkout` reports not-found, the argument is free-text feature intent for a brand-new plan. Derive `<plan-name>` the same way `speq-plan` does (verb table below) and create its branch:
```
Delegate to git-agent — operation: create-branch
branch: feat/<plan-name>
```
Then read from disk yourself: whether `specs/_plans/<plan-name>/` exists, and whether `specs/_plans/<plan-name>/open-questions.md` exists and is non-empty. Take the PR draft/ready state from the `checkout` return.
| Verb | When |
|------|------|
| `add` | New feature |
| `change` | Modify existing |
| `remove` | Deprecate/delete |
| `refactor` | Restructure, same behavior |
| `fix` | Bug or spec mismatch |
Pattern: `<verb>-<feature-scope>[-<qualifier>]`
#### PR-title derivation (shared with `speq-implement-pr`)
Derive the PR title deterministically from `<plan-name>` as a conventional-commit feature title `<type>(<scope>): <slug>`:
- **type** — map the verb: `add`/`change` → `feat`, `remove` → `chore`, `refactor` → `refactor`, `fix` → `fix`; fallback `chore` for an unparseable name.
- **scope** — the `<feature-scope>` segment (the token after the verb).
- **slug** — the humanized `<plan-name>` (hyphens → spaces).
Example: `add-search-candle` ⇒ `feat(search): add search candle`. With no scope segment, emit `<type>: <slug>`.
- ### 1.5. Resume Dispatch (orchestrator)
-
- A killed run (crash, usage-limit reset) leaves its progress on disk — plan artifacts, `review/round-<N>.md` files, `open-questions.md` — so never redo work those files prove done; re-delegating `planner-agent` over a validated plan repeats the run's most expensive step for nothing. Inspect `specs/_plans/<plan-name>/`, dispatch to the earliest step whose evidence is missing, and announce the decision in one line — `Resume: <evidence> → step <N>`:
-
- ```
- specs/_plans/<plan-name>/ absent → new plan: continue at step 3
- open-questions.md exists, non-empty → blocked resume: continue at step 2
- plan.md absent, or speq plan validate fails → planning incomplete: continue at
- step 3 (partial artifacts are planner-agent's input, not proof of completion)
- plan.md present and validate passes:
- ├─ review/round-2.md exists → review done: branch on its ## Summary counts in step 6
- ├─ review/round-1.md exists → resume the loop mid-flight from its ## Summary counts
- │ (Blockers / Advisory / Intent Fidelity blockers — the file holds the counts;
- │ the one-line verdict was returned to a session that no longer exists):
- │ INTENT > 0 → step 6's OPEN QUESTIONS branch (the headless Intent gate)
- │ BLOCKERS: 0 → step 6, clean branch
- │ BLOCKERS > 0 → does decision-log.md hold a [plan-review] ## Review Findings
- │ entry per round-1 BLOCKER?
- │ yes → revision done: respawn plan-reviewer for round 2 (step 5)
- │ no → respawn planner-agent in revision mode (step 5's blocker handling)
- └─ no review/ directory → plan authored, unreviewed: continue at step 5, round 1
- ```
-
- Counts and finding text always come from the round files, never from memory — the files are the durable record this dispatch exists to honor. Nothing is committed before step 6, so mid-run resume presumes the same working directory.
-
### 2. Fetch Answers — resume only
If step 1 found an unresolved `open-questions.md`, pull the human's replies:
```
Delegate to git-agent — operation: read-comments
since: <timestamp of your last "flag open questions" commit>
```
Forward the returned Q&A to `planner-agent` in step 4 — it stands in for the live interview `speq-plan` would otherwise run.
- If `read-comments` returns no replies, do not delegate to `planner-agent` with an empty Q&A. Branch on step 1's `checkout` return: PR exists → the human simply has not answered yet; report the plan as still blocked and stop. No PR → a prior run died before `flag-blocked` landed; re-run step 6's `OPEN QUESTIONS:` branch to land the block (its commit and push steps no-op where already done), then stop.
-
### 3. Discovery (orchestrator)
Gather just enough context to brief `planner-agent`, the same lightweight calls `speq-plan` makes:
```bash
speq domain list
speq feature list
speq search query "<relevant terms>"
```
### 4. Delegate to planner-agent
Same shape `speq-plan` uses, with headless framing added:
```
Delegate to planner-agent — Plan <plan-name> (headless)
## Plan Name
<plan-name>
## Interview Mode
headless
## User Intent
<feature intent text, or "see resume Q&A below">
## Clarifying Interview Results
<the free-text feature intent (new plan), or the Q&A text step 2 fetched (resume) — this stands in for a live interview>
## Existing Context
<output of relevant `speq search` / `speq feature get` calls>
## External Research
none — agent to research as needed
## Project Hook
<if active: note ".speq/plan-pr-hook.md — read it and apply it" — otherwise omit this section>
## Your Task
Produce spec deltas and plan.md per your normal workflow. You are in headless mode: follow your "Headless / Non-Interactive Mode" section — assume and document conventional decisions, escalate only irreducible ones via the OPEN QUESTIONS: sentinel. Tag deep-reasoning tasks with [expert].
Return the list of files created and the validation result, or an OPEN QUESTIONS: block if you had to stop.
```
### 5. Adversarial Plan Review
Skip this step if step 4 returned `OPEN QUESTIONS:` — resolve that first (step 6 handles it). Otherwise, before landing the plan, spawn `plan-reviewer` to challenge it. Bounded to 2 rounds total, same shape `speq-plan` uses:
```
Delegate to plan-reviewer — Review <plan-name> (round 1)
## Plan Name
<plan-name>
## User Intent
<the feature intent text / resume Q&A used in step 4>
## Clarifying Interview Results
<same text passed to planner-agent in step 4 — headless mode has no live interview>
## Plan Artifacts
plan.md, decision-log.md, and every specs/_plans/<plan-name>/**/spec.md delta
## Project Hook
<if active: note ".speq/plan-pr-hook.md — read it and apply it" — otherwise omit this section>
```
It writes its findings to `specs/_plans/<plan-name>/review/round-1.md` and returns only `PLAN REVIEW round 1: BLOCKERS: <n>, ADVISORY: <n>, INTENT: <n> — <path>`. `INTENT` counts the BLOCKERs on the Intent Fidelity axis alone.
**If `INTENT > 0`:** the reviewer's case is that the plan solves a different problem than the one asked for — fold the Intent-Fidelity BLOCKER text, read from the round file, into step 6's `OPEN QUESTIONS:` branch and stop. A plan that misreads the intent is exactly the irreducible decision headless mode escalates to a human.
**If `INTENT == 0` and BLOCKER findings exist:** respawn `planner-agent` with the path to `review/round-1.md`, instructing it to read the BLOCKER findings from that file and execute each `Fix:` line (log each resolved blocker as a `[plan-review]`-prefixed `## Review Findings` entry in `decision-log.md`, re-validate), then respawn `plan-reviewer` for round 2 with the same path to confirm resolution. Do not loop a third time.
**If BLOCKERs remain after round 2:** treat this exactly like an `OPEN QUESTIONS:` return from `planner-agent` — read the unresolved BLOCKER findings from `review/round-2.md` and fold them into step 6's "`OPEN QUESTIONS:` returned" branch as the questions list.
**ADVISORY findings:** carry into step 7's PR body/report, read from the last round file when composing; never block or persist.
### 6. Branch on the Result
**Clean return** (no `OPEN QUESTIONS:` sentinel, and no unresolved BLOCKERs from step 5) — ship the plan as a draft:
1. Confirm `speq plan validate <plan-name>` passes.
2. Commit the plan and open the draft PR with one composite call:
```
Delegate to git-agent — operation: ship-draft
paths: the plan directory
message: spec(plan): <plan-name>
title: <the derived <type>(<scope>): <slug>>
body: summarize the plan's Features table and task count, include the
plan.md ## Impact section verbatim as its own "## Impact" heading,
ending "Draft pending implementation — run /speq:implement-pr <plan-name> to implement and mark ready"
```
3. If this is a resume of a previously-blocked plan, clear the block yourself: delete `specs/_plans/<plan-name>/open-questions.md` and the `> **Status:** blocked …` banner line from `plan.md`, then:
```
Delegate to git-agent — operation: commit
paths: the plan directory
message: spec(plan): resolve open questions for <plan-name>
Delegate to git-agent — operation: push
```
The PR stays a draft — `speq-implement-pr` is the only skill that marks it ready.
4. If step 5's verdict reported a non-zero `ADVISORY` count, or `decision-log.md`'s Design Decisions section is non-empty (every headless "assume and document" entry is a candidate an architect may want to sanity-check), compose one comment covering both and post it — skip entirely if there is nothing to flag. Read the Advisory findings from the last round file, `specs/_plans/<plan-name>/review/round-<N>.md`. Compose the body per `speq-writing-guardrails`' PR-facing content rule:
```
Delegate to git-agent — operation: comment-pr
body: the ADVISORY findings excerpted from the step 5 round file (if any)
and the Design Decisions entries from decision-log.md (if any)
```
**`OPEN QUESTIONS:` returned (from step 4, or from step 5's round-1 Intent gate or unresolved round-2 BLOCKERs)** — persist the partial plan and ask the human async. Author the status files yourself, then delegate only git operations:
1. Write `specs/_plans/<plan-name>/open-questions.md`:
```markdown
# Open Questions: <plan-name>
speq-plan-pr could not complete this plan without human input. What's done so far is committed on this branch. Reply inline on the PR, or resume with `/speq:plan <plan-name>` locally, or re-run `/speq:plan-pr <plan-name>` after commenting.
- [ ] <question 1, or a BLOCKER folded in from step 5 — round-1 Intent-Fidelity, or unresolved after round 2>
- [ ] <question 2>
```
2. Insert `> **Status:** blocked — see open-questions.md` as the first line under `plan.md`'s H1 (skip if already present).
3. Compose the questions checklist as the PR comment body, and append any ADVISORY findings excerpted from step 5's round file, if present — one comment, not two.
Then, with one composite call:
```
Delegate to git-agent — operation: flag-blocked
paths: the plan directory
message: spec(plan): flag open questions for <plan-name>
title: <the derived <type>(<scope>): <slug>>
body: <blocked-plan summary>, including plan.md's ## Impact section
verbatim as its own "## Impact" heading if populated — a blocked
plan may have partial Impact info; include it as-is, never
fabricate the rest
comment_body: <the questions checklist and any ADVISORY findings excerpted
from step 5's round file>
```
### 7. Report (orchestrator)
Tell the caller whether the plan is ready or blocked, and the PR link either way. Print plan.md's `## Impact` section to the terminal. Mention any ADVISORY findings — read them from `specs/_plans/<plan-name>/review/round-<N>.md`, not from memory — and any Design Decisions entries surfaced. Both are also posted as a PR comment per step 6.
## Spec Hierarchy (reference)
```
specs/
├── <domain>/<feature>/spec.md # Permanent
├── _plans/<plan-name>/ # Active
│ └── open-questions.md # Present only while blocked
└── _recorded/<plan-name>/ # Archived
```
## Work Split (reference)
| Step | Performed by | Why |
|------|--------------|-----|
| Target resolution, discovery, status files, coordination | This skill (pins Sonnet) | Tool-call heavy, reasoning light |
| Spec delta authoring, ADR, task decomposition, assume-vs-escalate calls | `planner-agent` sub-agent | Reasoning-heavy; defects here compound through implementation |
| Adversarial review, revision loop | `plan-reviewer` sub-agent | Catches intent drift, infeasibility, and ambiguity before implementation, not after |
| Branch, commit, push, PR create/comment | `git-agent` sub-agent | Generic git/GitHub operations; keeps git/gh detail out of the orchestrator |
## Anti-Patterns
| Pattern | Why Wrong |
|---------|-----------|
| Asking the user a live question | Headless — irreducible decisions go to the PR comment |
| Running git/gh directly | `git-agent` performs every git and GitHub operation |
| Marking the PR ready | `speq-implement-pr` owns `ready-pr`; plans stay draft |
| A third review round | Bounded to 2 — leftover BLOCKERs become open questions |
- | Re-delegating `planner-agent` over a validated plan | Step 1.5 resumes from on-disk evidence; re-planning repeats the run's most expensive step |