Skip to content
Back to skills

Spec Apply

ASecurity

Implement a GitHub Story and all its Task sub-issues using a spec-driven loop: the AC become failing tests written by test-writer, then ponytail code makes them pass: resolve → (per task: explore → propose → failing tests [test-writer] → apply [with ponytail] → verify [+ mutation check] → commit → archive) → PR. Use when the user provides a Story issue number, a Story ID like 'BE-AUTH-1' from a backlog generated by prd-to-github-backlog, a single Task ID like 'BE-AUTH-1-T1', or says 'implemen...

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 21, 2026
ai-agentsrustgoc#bashtestingrefactoringcode-reviewgitapisecurity

Works with

  • api

Security analysis

A100/100

Scanned October 21, 2026

npx -y skills add orrrrli/clawd-harness --skill spec-apply --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Spec Apply?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Spec Apply
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/orrrrli-spec-apply/badge)](https://www.skillsdirectory.com/skills/orrrrli-spec-apply)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: spec-apply
stacks: [all]
description: "Implement a GitHub Story and all its Task sub-issues using a spec-driven loop: the AC become failing tests written by test-writer, then ponytail code makes them pass: resolve → (per task: explore → propose → failing tests [test-writer] → apply [with ponytail] → verify [+ mutation check] → commit → archive) → PR. Use when the user provides a Story issue number, a Story ID like 'BE-AUTH-1' from a backlog generated by prd-to-github-backlog, a single Task ID like 'BE-AUTH-1-T1', or says 'implement story #N', 'work on BE-AUTH-1', 'list my stories', or 'spec-apply N'."
trigger: /spec-apply
---

# /spec-apply [issue#] (with Ponytail Principles)

Implement a **Story** by driving **all of its Task sub-issues** through the phases below, one at a time,
**committing after each task passes verification**. Never skip a phase. If given a single Task ID,
implement just that one task through the same phases. **Applies ponytail principles during the Apply phase** to favor the simplest, most minimal solution that works.

## Execution model

```
Phase 0  Resolve  → Story# + ordered list of its open Task sub-issues; set up the Story worktree;
                    AC missing/untestable → business-analyst drafts them ⏸ STOP for approval
FOR each Task (in dependency order):
    Phase 1  Explore   (no stop gate — report and continue)
    Phase 2  Propose   ⏸ STOP: wait for OK before writing code
    Phase 2.5 Tests    → test-writer turns the AC into failing tests; they become read-only
    Phase 3  Apply     → Apply with ponytail principles (laziest solution that works)
    Phase 4  Verify    → spec-verify (code-reviewer) [+ security-auditor]; on failure STOP the Story
    Phase 4.5 Commit   (one conventional commit per task)
    Phase 5  Archive   (comment + close the Task issue)
Phase 6  Finish   → push the Story branch and open one PR for the Story
```

## Prerequisites

```bash
gh auth status   # must succeed with repo + project scope
```

---

## Naming convention (how the backlog encodes the hierarchy)

`prd-to-github-backlog` creates every issue with the title `"<ID>: <title>"`, and the
**ID itself encodes the parent chain** — so you never have to guess relationships:

| Level | ID convention      | Example title              | Labels                       |
|-------|--------------------|----------------------------|------------------------------|
| Epic  | `EPIC-<SLUG>`      | `EPIC-AUTH: Authentication`| `type:epic`                  |
| Story | `<AREA>-<EPIC>-<n>`| `BE-AUTH-1: Login endpoint`| `type:story`, `area:<area>`  |
| Task  | `<story-id>-T<k>`  | `BE-AUTH-1-T1: Add route`  | `type:task`, `area:<area>`   |

Derivation rules:
- **Task → Story:** strip the trailing `-T<k>`. `BE-AUTH-1-T1` → story `BE-AUTH-1`.
- **Story → Epic:** the story's `<EPIC>` segment maps to epic `EPIC-<EPIC>`. `BE-AUTH-1` → `EPIC-AUTH`.
- Tasks and stories also have **real GitHub sub-issue parent links** — use those as the source of truth.

---

## Phase 0 — Resolve the Story and its tasks

**Goal:** Turn whatever the user gave you (raw `#N`, a Story ID like `BE-AUTH-1`, a Task ID like
`BE-AUTH-1-T1`, or "list my stories") into a concrete **Story issue number**, its **Epic number**,
and the **ordered list of its open Task sub-issues**. Then set up the Story worktree.

Resolve via the **manifest as a cache, verified against the live board** (the chosen strategy):

1. **Read config from the manifest** if present (`manifest.json` at repo root or alongside the
   backlog skill output). Pull `owner`, `repo`, `project_number`, and the `epics[].stories[].tasks[]`
   tree. The manifest IDs let you map a Story ID → Epic ID and enumerate its Tasks offline.
   - If there is **no manifest**, fall back to pure `gh` label/title queries below.

2. **List stories** (use when the user says "list my stories" or gives ambiguous input):
   ```bash
   gh issue list --repo <owner/repo> --label type:story --state open --limit 100
   ```

3. **Resolve the input → a Story issue number** (exact title prefix match):
   ```bash
   # If given a Story ID (BE-AUTH-1):
   gh issue list --repo <owner/repo> --label type:story --state all \
     --search "in:title <STORY_ID>" --json number,title \
     --jq '.[] | select(.title | startswith("<STORY_ID>:")) | .number'
   # If given a Task ID (BE-AUTH-1-T1): strip the trailing -T<k> to get the Story ID, then as above.
   # If given a raw #N: check its type:* label. If type:task, walk up to its parent story.
   ```

4. **Enumerate the Story's Task sub-issues** (source of truth = live sub-issue links):
   ```bash
   gh api repos/<owner/repo>/issues/<story#>/sub_issues \
     --jq '.[] | {number, title, state}'
   ```
   Keep only **open** tasks. **Order them** by: (a) `depends_on` in the manifest/task body, else
   (b) ascending `-T<k>` suffix. Skip tasks already closed and note them.

5. **Verify against the live board** — confirm the story's parent epic matches the manifest:
   ```bash
   gh api repos/<owner/repo>/issues/<story#>/parent --jq '.number'  # epic number
   ```
   If the live links disagree with the manifest, **trust the live board** and note the drift.

6. **Resolve the base branch** — do NOT hardcode it. Take it from the project config in this order:
   manifest `base_branch` → repo default (`gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name'`)
   → `main`. Call it `<BASE>` and reuse it in Phase 6.

7. **Set up the Story worktree** — one worktree and one branch per Story, so parallel sessions
   never share a working tree. Every task commits onto `feat/<STORY_ID>`. Never `git checkout` in
   the current tree and never `cd`.
   ```bash
   git fetch origin <BASE>
   main=$(dirname "$(git rev-parse --path-format=absolute --git-common-dir)")
   git branch --show-current
   git worktree list --porcelain
   ```
   - Current branch is `feat/<STORY_ID>` → you are in the Story worktree. `git pull --ff-only` if it
     has an upstream, then continue.
   - `feat/<STORY_ID>` is checked out in another worktree → **STOP**: "Open a session in `<path>` and
     run `/spec-apply <STORY_ID>` there."
   - Otherwise create it (the post-checkout hook links the local Claude harness into it):
     ```bash
     git worktree add -b feat/<STORY_ID> "$main-<STORY_ID>" origin/<BASE>   # new branch
     git worktree add "$main-<STORY_ID>" feat/<STORY_ID>                     # branch already exists
     ```
     Then **STOP**: "Worktree ready at `<path>`. Open a session there and run `/spec-apply <STORY_ID>`."

8. **Check the Story's acceptance criteria** — once per Story, since every task and `spec-verify`
   are judged against them:
   ```bash
   gh issue view <story#> --repo <owner/repo> --json body --jq '.body'
   ```
   Testable means Given/When/Then with an observable outcome. If they are present and testable,
   continue. If they are missing or untestable (e.g. "works well", "good UX"):
   - Dispatch `business-analyst`. It cannot see this conversation or run `gh`, so the prompt
     carries the Story body and the Epic body verbatim, plus the paths to `CLAUDE.md` and
     `business/rules.md`. Ask for Given/When/Then criteria returned in the report, no files written.
   - Show them to the user. **STOP** and wait for approval or edits.
   - Once approved, append them to the Story under `## Acceptance criteria` so `spec-verify` reads
     the same ones:
     ```bash
     gh issue view <story#> --repo <owner/repo> --json body --jq '.body' > /tmp/story-<story#>.md
     # append the approved criteria to that file, then:
     gh issue edit <story#> --repo <owner/repo> --body-file /tmp/story-<story#>.md
     ```

**Single-task input:** if the user explicitly named one Task ID/number and asked for just that,
set the task list to that one task (still in the Story worktree).

**Exit gate:** State the resolved `Story #<n> (<STORY_ID>)`, `Epic #<n> (<EPIC_ID>)`, the base branch
`<BASE>`, the working branch `feat/<STORY_ID>` and its worktree path, and the **ordered task list** (`Task #<n> (<TASK_ID>)`
each). If the input matched
zero or many stories, list the candidates and ask which one. Then begin the per-task loop at Phase 1
with the first task.

---

> The phases below run **once per task** in the ordered list from Phase 0. `<task#>` is the current
> task; `<story#>` / `<epic#>` stay fixed for the whole run.

## Phase 1 — Explore

**Goal:** Understand the current task before touching a single file. Use the `Task #`, `Story #`, and
`Epic #` resolved in Phase 0.

1. Fetch the Task issue:
   ```bash
   gh issue view <task#> --repo <owner/repo>
   ```

2. Fetch the parent Story (the sub-issue parent resolved in Phase 0):
   ```bash
   gh issue view <story#> --repo <owner/repo>
   ```
   Read the **acceptance criteria** (Given/When/Then). These are the exit criteria for Phase 4.

3. Fetch the grandparent Epic for broader context:
   ```bash
   gh issue view <epic#> --repo <owner/repo>
   ```

4. **Read the project context index** — find it using this fallback order:
   ```
   CLAUDE.md (standard fill-context structure — root of the repo)
   → .agents/CONTEXT.md (alt structure)
   → AGENTS.md (alt structure)
   ```
   
   Once you find the index, read it to locate these files (most will be linked in the index):
   - `business/overview.md`, `business/rules.md` — domain constraints, success metrics
   - `domains/[entity].md` — detailed model for each entity this task touches
   - `architecture/overview.md`, `architecture/integrations.md` — patterns, stack, external services
   - `engineering/standards.md`, `engineering/testing.md` — coding conventions, test approach
   
   **Always read the context files; do not skip because the task "looks simple."**

5. Locate the relevant code — find the files, components, and layers that this task touches. Report exact file paths and line numbers.

**Report (no stop gate):** State in plain language, then continue straight to Phase 2:
- What this task requires
- Which files will change and why
- Any risks or ambiguities

---

## Phase 2 — Propose

**Goal:** Define the approach before writing code.

Produce a short implementation plan:
- What interfaces / signatures change (if any)
- Which layer(s) are touched (domain / application / infrastructure / presentation)
- Whether new files are needed
- Whether any dependency is required — if so, name it explicitly and wait for approval
- Any architectural decision that deviates from existing patterns — flag it and ask
- Responsibilities: list each distinct one (business rule, persistence, security, external
  call, presentation) and where it lives: an existing component, a new one with its reason,
  or a framework capability (e.g. ASP.NET Identity, NextAuth). Security never lives in an
  ad-hoc check when the framework provides it.
- Behaviors to test: one line per AC this task covers. A task with no testable behavior
  (config, scaffolding) says so here and skips Phase 2.5.

**Exit gate:** Present the plan. STOP and wait for explicit user confirmation before writing any code.

---

## Phase 2.5 — Tests

**Goal:** Turn the AC into failing tests before any implementation exists, written by an
agent that does not implement.

1. Dispatch `test-writer`. Its prompt stands alone: the AC verbatim, the approved
   interface and behavior lines from Phase 2, the paths to `CLAUDE.md` and
   `engineering/testing.md`, and the test command. Ask it to:
   - Cover each behavior line, plus the negative and boundary cases the AC imply.
   - Derive every expected value from the AC, never from existing code.
   - If the interface does not exist yet, add only a signature stub from Phase 2 that
     throws not-implemented. No logic.
   - Run the tests and report each one RED with its failure reason.
2. Check the reasons: a test red for the wrong reason (typo, broken fixture) goes back
   to `test-writer` once.
3. Stage the test files (`git add <test files>`). From here they are read-only for Phase 3.

---

## Phase 3 — Apply (with Ponytail Principles)

**Goal:** Implement exactly what was proposed. Nothing more. **Apply ponytail principles: favor the laziest solution that actually works.**

Rules:
- Only modify files identified in Phase 2
- **Make the Phase 2.5 tests pass. Never edit, skip, delete or weaken them**, and never
  touch test or CI config to get green. If a test looks wrong, STOP and report it: a wrong
  test usually means an ambiguous AC, and that is the user's call.
- **Apply ponytail principles during implementation:**
  1. **Does this need to exist at all?** Speculative need = skip it, say so in one line. (YAGNI)
  2. **Already in this codebase?** A helper, util, type, or pattern that already lives here → reuse it. Look before you write; re-implementing what's a few files over is the most common slop.
  3. **Stdlib does it?** Use it.
  4. **Native platform feature covers it?** `<input type="date">` over a picker lib, CSS over JS, DB constraint over app code.
  5. **Already-installed dependency solves it?** Use it. Never add a new one for what a few lines can do.
  6. **Can it be one line?** One line.
  7. **Only then:** the minimum code that works.
- **Follow the coding conventions and patterns** from:
  - `engineering/standards.md` (naming, structure, test strategy)
  - `business/rules.md` (domain constraints that code must enforce)
  - `domains/[entity].md` (entity-specific rules and relationships)
- No new dependencies without asking
- No refactoring outside the task scope — note suggestions after completing
- If you discover something unexpected mid-implementation, STOP and report it
- **Mark deliberate simplifications with a `ponytail:` comment** (e.g., `# ponytail: using existing util instead of new class`)
- **Bug fix = root cause, not symptom.** Before you edit, grep every caller of the function you're about to touch. The lazy fix IS the root-cause fix: one guard in the shared function is a smaller diff than a guard in every caller.

After each file change, state: file path + what changed + why.

**Output pattern:** `[code] → skipped: [X], add when [Y].`

---

## Phase 4 — Verify

**Goal:** Prove the task is done against the Story's acceptance criteria, with a reviewer that did
not write the code.

1. **Self-check first** (cheap, before spending a review):
   - [ ] Existing tests still pass (`npm run test` / `dotnet test` / equivalent)
   - [ ] Phase 2.5 tests are green and untouched (`git diff -- <test files>` is empty)
   - [ ] No files outside Phase 2 + 2.5 scope were modified
2. **Independent review**, uncommitted, in ONE message so they run concurrently:
   - Invoke the `spec-verify` skill with `<TASK_ID>`. It runs in a fresh `code-reviewer` subagent,
     reads the Story's AC from GitHub, reviews the uncommitted diff, runs the tests, and returns
     PASS/FAIL per criterion.
   - **Also** dispatch `security-auditor` when the diff touches auth, sessions/tokens, permissions,
     payments, webhooks, or untrusted input. Its prompt must stand alone: the Story's AC verbatim,
     the diff command (`git diff HEAD`), and the paths to `CLAUDE.md` and `engineering/standards.md`.
3. **Act on the reports:** reviewers never edit. Fix blocking findings yourself; list minor ones in
   the Phase 5 comment instead of fixing them.

**Failure policy:** If `spec-verify` returns FAIL or the security-auditor reports a critical/high
issue, make **one** attempt to fix it in Phase 3 and verify again. If it still fails, **STOP the
entire Story** here — do NOT commit the failing task, leave
already-committed tasks in place, and report: which task failed, why, and what's left. Do not move on
to the next task.

---

## Phase 4.5 — Commit

**Goal:** One commit per task, only after Verify passes.

```bash
git add <files from Phase 2 + 2.5 scope>
git commit -m "<type>(<TASK_ID>): <Imperative summary>"
# e.g. feat(BE-FOUND-1-T1): Scaffold Go module layout
```

Rules:
- **Conventional Commits format** (`feat`, `fix`, `refactor`, `test`, …) — projects set up by
  `init-project.sh` reject any other subject through the git `commit-msg` hook that
  `core.hooksPath` points to in clawd-harness (`global/githooks/`).
  Pick the type that matches the task.
- **Subject line only — no body, no trailers.** The scope is the Task ID. The task is closed in
  Phase 5 with `gh issue close`, and the Story PR body lists `Closes #<task#>`, so the commit needs
  no `Closes` line.
- **Do NOT add any Claude/AI co-author trailer** (no `Co-Authored-By: Claude`). Author is the user only.
- Commit **only** the files this task changed (they should match Phase 2 + 2.5 scope).

---

## Phase 5 — Archive (per task)

**Goal:** Close the loop on GitHub for this task, then advance the loop.

1. Comment on the Task issue with a brief summary of what was implemented:
   ```bash
   gh issue comment <task#> --repo <owner/repo> --body "Implemented: <one-line summary>. Commit: <sha>. Files changed: <list>. Minor review notes: <list or none>."
   ```

2. Close the task issue:
   ```bash
   gh issue close <task#> --repo <owner/repo>
   ```

3. **Advance:** if more tasks remain in the Phase 0 list, return to Phase 1 for the next task.
   Otherwise continue to Phase 6.

---

## Phase 6 — Finish the Story

**Goal:** Ship all completed tasks as one Story PR.

1. Push the Story branch:
   ```bash
   git push -u origin feat/<STORY_ID>
   ```

2. Open **one PR named after the Story** — title = the Story's full issue title
   (`<STORY_ID>: <story title>`):
   ```bash
   gh pr create --repo <owner/repo> --base <BASE> --head feat/<STORY_ID> \
     --title "<STORY_ID>: <story title>" \
     --body-file <scratchpad>/pr.md
   ```
   Write `pr.md` per `~/.claude/workflows.md` "Pull Requests". `## What` names Story #<story#>
   (<STORY_ID>) and ends with one `Closes #<task#>` line per task. A skipped or failed task goes
   under `## Not changed`.
   Do NOT add a Claude/AI co-author or generated-by trailer to the PR.

3. Report done: the PR URL, the list of tasks committed/closed, and anything skipped or left for a
   follow-up. Close with: "After merge, remove the worktree: delete its harness symlinks first,
   then `git worktree remove <path>`."

---

## Hard rules

- **One Story per invocation.** The unit of work is a Story and all its open Tasks. If the user names
  multiple stories, ask which one to start with.
- **Never implement an Epic directly.** If given an Epic number/ID, list its Story sub-issues and ask
  which Story to run.
- **Always read the project context** (Phase 1, step 4). Do not skip because the task "looks simple."
  This ensures code conforms to domain rules, business constraints, and engineering standards.
- **Work task-by-task inside the Story** — full Explore→Verify→Commit→Archive per task before moving
  on. Never batch multiple tasks into one commit.
- **The Propose gate is per task:** stop and wait for approval before writing code for each task.
- **Tests are written before the code, by `test-writer`** (Phase 2.5), and Phase 3 never
  edits them.
- **Stop on first verify failure:** one fix attempt, then halt the whole Story and report. Committed
  tasks stay; the rest wait.
- If the Story `depends_on` another issue (manifest / Story body), check that dependency is closed
  before starting Phase 3 of the first task.
- **No AI co-authorship** on commits or the PR (no `Co-Authored-By: Claude`, no generated-by trailer).
- **Ponytail principles must be applied during Phase 3 (Apply)** — favor simplicity, reuse, and minimalism.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.