diff --git a/.agents/skills/start/SKILL.md b/.agents/skills/start/SKILL.md index 8a9a8e1..a645b21 100644 --- a/.agents/skills/start/SKILL.md +++ b/.agents/skills/start/SKILL.md @@ -234,6 +234,13 @@ When done, say: **"When you've verified locally, reply `yes` to submit, or say w ## Case B: Resume existing issue (numeric argument) +> **Story-driver recognition:** If the immediately preceding context shows a preamble line of the form `[story-driver: parent= ticket= of ]`, the `/start` invocation is being orchestrated by the `/story` driver. Under that signal: +> - Step 2's "Does this match your understanding?" gate is implicitly satisfied (the operator approved the entire story plan at story start). Skip the gate, do not ask, proceed directly toward Step 4. +> - Step 3's investigation findings prompt is suppressed (default to skip silently). Genuine root-cause corrections or project-wide gotchas should still be raised, but routine "this looks like the ticket says" observations stay quiet. +> - Step 5's closing "verified locally" prompt is implicitly approved — automatically proceed to `/submit-for-review` without waiting for `yes`. The `make check` gate inside `/submit-for-review` is the verification safety net under the driver. +> +> Everything else in Case B (loading context, checking out the branch, writing the code, all real escalation triggers) behaves identically. The driver only suppresses the three routine prompts above. + ### Step 1 — Load context ```bash @@ -330,4 +337,4 @@ When done, say: **"When you've verified locally, reply `yes` to submit, or say w - The issue is assigned to `@me` at creation. If you are creating a ticket on someone else's behalf, remove the assignee after creation with `gh issue edit --remove-assignee @me`. - Apply resolved labels and milestone to every new issue. Label resolution order: per-invocation flag → pool selection from `bug, documentation, enhancement, chore` → omit `--label` entirely. Never apply a label outside `bug, documentation, enhancement, chore`. - Milestone resolution order: per-invocation flag → auto-detected from GitHub open milestones. Never prompt for a milestone more than once per invocation. - + diff --git a/.agents/skills/story/SKILL.md b/.agents/skills/story/SKILL.md new file mode 100644 index 0000000..fed5530 --- /dev/null +++ b/.agents/skills/story/SKILL.md @@ -0,0 +1,178 @@ +--- +name: story +description: Code Cannon: Walk the open sub-issues of a story ticket within one session +--- + +> **Codex CLI:** This skill is triggered by description matching. State any arguments in your message. Sub-agent spawning is not supported — perform any review steps inline. + +--- + +## What `/story` does + +`/story ` walks the open sub-issues of a parent ("story") ticket in their GitHub-defined order, threading `/start` and `/submit-for-review` for each one into a single interactive session. It removes a few routine per-ticket prompts (`/start`'s plan-confirm gate and verified-locally prompt) — the operator already approved the whole story plan at story start. + +What `/story` deliberately does **not** do: it does not auto-decide on `/submit-for-review`'s `needs-attention` warnings or `must-address` blockers. Those remain human-judgment moments. When the review stops, the driver pauses and waits — when the operator finishes, the driver resumes with the next sub-issue. + +`/story` is intentionally a thin coordinator. See #167 for the design discussion and #177 for the deferred path that would automate judgment moments based on observed usage. + +--- + +## Step 1 — Argument check + +Required: a single integer (the parent issue number). If missing or non-numeric, abort: + +> "/story requires a parent issue number. Usage: /story " + +--- + +## Step 2 — Fetch and echo the story plan + +Find owner/repo if not already known: + +``` +gh repo view --json owner,name +``` + +Verify the parent and fetch its sub-issues: + +``` +gh issue view --json number,title,state +gh api repos///issues//sub_issues --jq '.[] | {number, title, state}' +``` + +Stop immediately if any of these hold: + +- Parent issue is closed → "Issue # is closed. /story requires an open parent." +- Sub-issue list is empty → "Issue # has no sub-issues. /story requires a parent with linked sub-issues." +- All sub-issues are closed → "All sub-issues of # are closed. Story is complete." + +Otherwise, echo the plan (filter to `state == "open"` for the work list; show closed ones for context): + +> Story #: +> +> Open sub-issues (worked in this order): +> 1. #<Na> <title> +> 2. #<Nb> <title> +> ... +> +> Closed sub-issues (already complete): <"none" or list> +> +> Routine per-ticket prompts (plan-confirm at `/start` and verified-locally at end of `/start`) are auto-passed under the driver. Review-stage prompts (`needs-attention` warnings, `must-address` blockers) still stop and ask — they are the human-judgment moments. +> +> Type `go` to start, or share concerns first. + +Wait for the operator. Proceed only on unconditional `go`. Treat any other response as discussion — address concerns and re-ask. If the operator abandons, stop with nothing to clean up. + +--- + +## Step 3 — Ticket loop + +For each open sub-issue, in the order returned by the API: + +### 3a — Pre-flight escalation check + +Read the sub-issue body (already fetched, or re-fetch via `gh issue view <sub#>` if needed). Stop and ask **before** invoking `/start` if any of these triggers fire: + +- The acceptance criteria contain phrases like "TBD", "decide later", "?", or otherwise indicate unresolved scope. +- The body mentions a sensitive surface: authentication, authorization, payments, billing, secrets, credentials, production configuration, destructive operations (`DROP TABLE`, `rm -rf`, `git push --force`, mass deletes, schema drops). +- The body or any project-level guidance (e.g. `CLAUDE.md`) names a domain the operator has flagged for explicit review. + +If any trigger fires: + +> "Sub-issue #<sub#> triggered escalation: <reason>. +> +> - `proceed` — invoke `/start` for this sub-issue anyway (operator confirms they want it under the driver). +> - `defer` — skip this sub-issue for now and move on to the next. +> - `stop` — exit the driver with a partial summary." + +Wait for the operator. Honor the choice exactly. + +### 3b — Invoke `/start <sub#>` under the driver + +Print this preamble line immediately before invoking the skill (this is the signal `/start` recognizes): + +``` +[story-driver: parent=<parent#> ticket=<index> of <open-count>] +``` + +Then invoke `/start <sub#>`. `/start` recognizes the preamble (see Case B in `/start`) and auto-passes its plan-confirm gate and verified-locally prompt. All other `/start` behavior is unchanged — including writing the code. + +### 3c — `/submit-for-review` runs from `/start`'s auto-proceed + +`/start` under the driver auto-fires `/submit-for-review` itself (because its verified-locally prompt is auto-approved). The driver does not invoke `/submit-for-review` separately — it observes the outcome and routes accordingly. The tier routing applies as today: + +- `clean` or `informational` → auto-merge. The driver continues to the next sub-issue. +- `needs-attention` → `/submit-for-review` itself stops and asks the operator (address now / follow up later / accept as-is). The driver waits for the operator to respond through `/submit-for-review`. When `/submit-for-review` completes (either by merging or by routing back to coding), the driver resumes — either with the next sub-issue (on merge) or by re-running `/submit-for-review` after the operator fixes things. +- `must-address` → `/submit-for-review` itself stops; the operator fixes the blocker; the driver resumes on the next `/submit-for-review` invocation. + +### 3d — Per-ticket safety + +Track an attempt counter per sub-issue (start at 1; increment on each `/start → /submit-for-review` pass for the same sub-issue): + +- **Attempt cap of 2**: if a sub-issue would require a third pass, stop and ask: + > "Sub-issue #<sub#> has hit the attempt cap (2). Continue manually or stop the story?" +- **No-progress guard**: before each attempt past the first, capture `git diff origin/dev` on the feature branch. After the attempt, if the new diff is byte-identical to the previous attempt's diff, the iteration made no code change. Stop and ask: + > "Sub-issue #<sub#> made no code progress on this attempt. Stop the story or take over manually?" + +Both guards exist to prevent unbounded retry loops; neither tries to be clever. + +--- + +## Step 4 — Track follow-up tickets created during the story + +During each `/submit-for-review` run, follow-up tickets may be created (the `needs-attention` "follow up later" branch and the Step 9 selective branch both do this). Keep a running list of those follow-up issue numbers and their titles for the story summary in Step 5. The list is purely informational — sub-issue closure status is still the source of truth for "what got done." + +--- + +## Step 5 — Story session end + +When the loop exits (all open sub-issues processed, or operator chose `stop`), post a session summary as a comment on the parent issue. Skip the comment silently if nothing actually merged in this session. + +Create a temp directory if not already created: + +``` +mkdir -p /tmp/CodeCannon && mktemp -d /tmp/CodeCannon/XXXXXX +``` + +Use the file-writing tool to create `<tmpdir>/story_summary.md`: + +```markdown +## /story session summary + +Worked by the /story driver in one interactive session. + +**Merged:** +- #<sub#> <title> → PR #<pr#> +- ... + +**Deferred or not addressed:** +- #<sub#> <title> (reason: <escalation / cap / no-progress / operator-stop>) +- ... (or "none") + +**Follow-up tickets created during the story:** +- #<f#> <title> +- ... (or "none") +``` + +Post via the comment-posting script: + +``` +python3 CodeCannon/skills/github-agile/scripts/post-issue-comment.py <parent#> <tmpdir>/story_summary.md +``` + +Then close out to the operator: + +> Story #<parent#> session done. Merged: N. Deferred: M. Open sub-issues remaining: K. +> If K > 0, run `/story <parent#>` again to resume from the next open sub-issue. + +--- + +## Hard rules + +- `/story` runs entirely inside the current interactive session. No `claude -p`, no headless subprocesses, no daemons. +- `/story` does not write or edit code itself — it sequences `/start` and `/submit-for-review`. The code is written inside `/start` as it normally would be. +- `/story` does not auto-decide on `/submit-for-review`'s `needs-attention` or `must-address` tiers. Those remain human-judgment moments. +- Sub-issue state is the source of truth. The Step 5 session summary is informational — deleting or editing it must not affect resumption. A fresh `/story <parent#>` invocation always re-derives state from open sub-issues. +- Attempt cap and no-progress guards stop the story rather than retry past the limit. +- If the driver itself is interrupted (operator switches tasks, session ends), no state needs to be saved. The next `/story <parent#>` resumes by picking up the next open sub-issue. +<!-- generated by CodeCannon/sync.py | skill: story | adapter: codex | hash: 18fd74d5 | DO NOT EDIT — run CodeCannon/sync.py to regenerate --> diff --git a/.claude/commands/start.md b/.claude/commands/start.md index abc45ad..c036fbc 100644 --- a/.claude/commands/start.md +++ b/.claude/commands/start.md @@ -229,6 +229,13 @@ When done, say: **"When you've verified locally, reply `yes` to submit, or say w ## Case B: Resume existing issue (numeric argument) +> **Story-driver recognition:** If the immediately preceding context shows a preamble line of the form `[story-driver: parent=<N> ticket=<K> of <M>]`, the `/start` invocation is being orchestrated by the `/story` driver. Under that signal: +> - Step 2's "Does this match your understanding?" gate is implicitly satisfied (the operator approved the entire story plan at story start). Skip the gate, do not ask, proceed directly toward Step 4. +> - Step 3's investigation findings prompt is suppressed (default to skip silently). Genuine root-cause corrections or project-wide gotchas should still be raised, but routine "this looks like the ticket says" observations stay quiet. +> - Step 5's closing "verified locally" prompt is implicitly approved — automatically proceed to `/submit-for-review` without waiting for `yes`. The `make check` gate inside `/submit-for-review` is the verification safety net under the driver. +> +> Everything else in Case B (loading context, checking out the branch, writing the code, all real escalation triggers) behaves identically. The driver only suppresses the three routine prompts above. + ### Step 1 — Load context ```bash @@ -325,4 +332,4 @@ When done, say: **"When you've verified locally, reply `yes` to submit, or say w - The issue is assigned to `@me` at creation. If you are creating a ticket on someone else's behalf, remove the assignee after creation with `gh issue edit <number> --remove-assignee @me`. - Apply resolved labels and milestone to every new issue. Label resolution order: per-invocation flag → pool selection from `bug, documentation, enhancement, chore` → omit `--label` entirely. Never apply a label outside `bug, documentation, enhancement, chore`. - Milestone resolution order: per-invocation flag → auto-detected from GitHub open milestones. Never prompt for a milestone more than once per invocation. -<!-- generated by CodeCannon/sync.py | skill: start | adapter: claude | hash: 56496fd3 | DO NOT EDIT — run CodeCannon/sync.py to regenerate --> +<!-- generated by CodeCannon/sync.py | skill: start | adapter: claude | hash: 14c418d5 | DO NOT EDIT — run CodeCannon/sync.py to regenerate --> diff --git a/.claude/commands/story.md b/.claude/commands/story.md new file mode 100644 index 0000000..c62d56f --- /dev/null +++ b/.claude/commands/story.md @@ -0,0 +1,173 @@ +Code Cannon: Walk the open sub-issues of a story ticket within one session + +--- + +## What `/story` does + +`/story <parent#>` walks the open sub-issues of a parent ("story") ticket in their GitHub-defined order, threading `/start` and `/submit-for-review` for each one into a single interactive session. It removes a few routine per-ticket prompts (`/start`'s plan-confirm gate and verified-locally prompt) — the operator already approved the whole story plan at story start. + +What `/story` deliberately does **not** do: it does not auto-decide on `/submit-for-review`'s `needs-attention` warnings or `must-address` blockers. Those remain human-judgment moments. When the review stops, the driver pauses and waits — when the operator finishes, the driver resumes with the next sub-issue. + +`/story` is intentionally a thin coordinator. See #167 for the design discussion and #177 for the deferred path that would automate judgment moments based on observed usage. + +--- + +## Step 1 — Argument check + +Required: a single integer (the parent issue number). If missing or non-numeric, abort: + +> "/story requires a parent issue number. Usage: /story <parent#>" + +--- + +## Step 2 — Fetch and echo the story plan + +Find owner/repo if not already known: + +``` +gh repo view --json owner,name +``` + +Verify the parent and fetch its sub-issues: + +``` +gh issue view <parent#> --json number,title,state +gh api repos/<owner>/<repo>/issues/<parent#>/sub_issues --jq '.[] | {number, title, state}' +``` + +Stop immediately if any of these hold: + +- Parent issue is closed → "Issue #<parent#> is closed. /story requires an open parent." +- Sub-issue list is empty → "Issue #<parent#> has no sub-issues. /story requires a parent with linked sub-issues." +- All sub-issues are closed → "All sub-issues of #<parent#> are closed. Story is complete." + +Otherwise, echo the plan (filter to `state == "open"` for the work list; show closed ones for context): + +> Story #<parent#>: <title> +> +> Open sub-issues (worked in this order): +> 1. #<Na> <title> +> 2. #<Nb> <title> +> ... +> +> Closed sub-issues (already complete): <"none" or list> +> +> Routine per-ticket prompts (plan-confirm at `/start` and verified-locally at end of `/start`) are auto-passed under the driver. Review-stage prompts (`needs-attention` warnings, `must-address` blockers) still stop and ask — they are the human-judgment moments. +> +> Type `go` to start, or share concerns first. + +Wait for the operator. Proceed only on unconditional `go`. Treat any other response as discussion — address concerns and re-ask. If the operator abandons, stop with nothing to clean up. + +--- + +## Step 3 — Ticket loop + +For each open sub-issue, in the order returned by the API: + +### 3a — Pre-flight escalation check + +Read the sub-issue body (already fetched, or re-fetch via `gh issue view <sub#>` if needed). Stop and ask **before** invoking `/start` if any of these triggers fire: + +- The acceptance criteria contain phrases like "TBD", "decide later", "?", or otherwise indicate unresolved scope. +- The body mentions a sensitive surface: authentication, authorization, payments, billing, secrets, credentials, production configuration, destructive operations (`DROP TABLE`, `rm -rf`, `git push --force`, mass deletes, schema drops). +- The body or any project-level guidance (e.g. `CLAUDE.md`) names a domain the operator has flagged for explicit review. + +If any trigger fires: + +> "Sub-issue #<sub#> triggered escalation: <reason>. +> +> - `proceed` — invoke `/start` for this sub-issue anyway (operator confirms they want it under the driver). +> - `defer` — skip this sub-issue for now and move on to the next. +> - `stop` — exit the driver with a partial summary." + +Wait for the operator. Honor the choice exactly. + +### 3b — Invoke `/start <sub#>` under the driver + +Print this preamble line immediately before invoking the skill (this is the signal `/start` recognizes): + +``` +[story-driver: parent=<parent#> ticket=<index> of <open-count>] +``` + +Then invoke `/start <sub#>`. `/start` recognizes the preamble (see Case B in `/start`) and auto-passes its plan-confirm gate and verified-locally prompt. All other `/start` behavior is unchanged — including writing the code. + +### 3c — `/submit-for-review` runs from `/start`'s auto-proceed + +`/start` under the driver auto-fires `/submit-for-review` itself (because its verified-locally prompt is auto-approved). The driver does not invoke `/submit-for-review` separately — it observes the outcome and routes accordingly. The tier routing applies as today: + +- `clean` or `informational` → auto-merge. The driver continues to the next sub-issue. +- `needs-attention` → `/submit-for-review` itself stops and asks the operator (address now / follow up later / accept as-is). The driver waits for the operator to respond through `/submit-for-review`. When `/submit-for-review` completes (either by merging or by routing back to coding), the driver resumes — either with the next sub-issue (on merge) or by re-running `/submit-for-review` after the operator fixes things. +- `must-address` → `/submit-for-review` itself stops; the operator fixes the blocker; the driver resumes on the next `/submit-for-review` invocation. + +### 3d — Per-ticket safety + +Track an attempt counter per sub-issue (start at 1; increment on each `/start → /submit-for-review` pass for the same sub-issue): + +- **Attempt cap of 2**: if a sub-issue would require a third pass, stop and ask: + > "Sub-issue #<sub#> has hit the attempt cap (2). Continue manually or stop the story?" +- **No-progress guard**: before each attempt past the first, capture `git diff origin/dev` on the feature branch. After the attempt, if the new diff is byte-identical to the previous attempt's diff, the iteration made no code change. Stop and ask: + > "Sub-issue #<sub#> made no code progress on this attempt. Stop the story or take over manually?" + +Both guards exist to prevent unbounded retry loops; neither tries to be clever. + +--- + +## Step 4 — Track follow-up tickets created during the story + +During each `/submit-for-review` run, follow-up tickets may be created (the `needs-attention` "follow up later" branch and the Step 9 selective branch both do this). Keep a running list of those follow-up issue numbers and their titles for the story summary in Step 5. The list is purely informational — sub-issue closure status is still the source of truth for "what got done." + +--- + +## Step 5 — Story session end + +When the loop exits (all open sub-issues processed, or operator chose `stop`), post a session summary as a comment on the parent issue. Skip the comment silently if nothing actually merged in this session. + +Create a temp directory if not already created: + +``` +mkdir -p /tmp/CodeCannon && mktemp -d /tmp/CodeCannon/XXXXXX +``` + +Use the file-writing tool to create `<tmpdir>/story_summary.md`: + +```markdown +## /story session summary + +Worked by the /story driver in one interactive session. + +**Merged:** +- #<sub#> <title> → PR #<pr#> +- ... + +**Deferred or not addressed:** +- #<sub#> <title> (reason: <escalation / cap / no-progress / operator-stop>) +- ... (or "none") + +**Follow-up tickets created during the story:** +- #<f#> <title> +- ... (or "none") +``` + +Post via the comment-posting script: + +``` +python3 CodeCannon/skills/github-agile/scripts/post-issue-comment.py <parent#> <tmpdir>/story_summary.md +``` + +Then close out to the operator: + +> Story #<parent#> session done. Merged: N. Deferred: M. Open sub-issues remaining: K. +> If K > 0, run `/story <parent#>` again to resume from the next open sub-issue. + +--- + +## Hard rules + +- `/story` runs entirely inside the current interactive session. No `claude -p`, no headless subprocesses, no daemons. +- `/story` does not write or edit code itself — it sequences `/start` and `/submit-for-review`. The code is written inside `/start` as it normally would be. +- `/story` does not auto-decide on `/submit-for-review`'s `needs-attention` or `must-address` tiers. Those remain human-judgment moments. +- Sub-issue state is the source of truth. The Step 5 session summary is informational — deleting or editing it must not affect resumption. A fresh `/story <parent#>` invocation always re-derives state from open sub-issues. +- Attempt cap and no-progress guards stop the story rather than retry past the limit. +- If the driver itself is interrupted (operator switches tasks, session ends), no state needs to be saved. The next `/story <parent#>` resumes by picking up the next open sub-issue. +<!-- generated by CodeCannon/sync.py | skill: story | adapter: claude | hash: 67207d66 | DO NOT EDIT — run CodeCannon/sync.py to regenerate --> diff --git a/.cursor/rules/start.mdc b/.cursor/rules/start.mdc index 5375d49..f2601e1 100644 --- a/.cursor/rules/start.mdc +++ b/.cursor/rules/start.mdc @@ -235,6 +235,13 @@ When done, say: **"When you've verified locally, reply `yes` to submit, or say w ## Case B: Resume existing issue (numeric argument) +> **Story-driver recognition:** If the immediately preceding context shows a preamble line of the form `[story-driver: parent=<N> ticket=<K> of <M>]`, the `/start` invocation is being orchestrated by the `/story` driver. Under that signal: +> - Step 2's "Does this match your understanding?" gate is implicitly satisfied (the operator approved the entire story plan at story start). Skip the gate, do not ask, proceed directly toward Step 4. +> - Step 3's investigation findings prompt is suppressed (default to skip silently). Genuine root-cause corrections or project-wide gotchas should still be raised, but routine "this looks like the ticket says" observations stay quiet. +> - Step 5's closing "verified locally" prompt is implicitly approved — automatically proceed to `/submit-for-review` without waiting for `yes`. The `make check` gate inside `/submit-for-review` is the verification safety net under the driver. +> +> Everything else in Case B (loading context, checking out the branch, writing the code, all real escalation triggers) behaves identically. The driver only suppresses the three routine prompts above. + ### Step 1 — Load context ```bash @@ -331,4 +338,4 @@ When done, say: **"When you've verified locally, reply `yes` to submit, or say w - The issue is assigned to `@me` at creation. If you are creating a ticket on someone else's behalf, remove the assignee after creation with `gh issue edit <number> --remove-assignee @me`. - Apply resolved labels and milestone to every new issue. Label resolution order: per-invocation flag → pool selection from `bug, documentation, enhancement, chore` → omit `--label` entirely. Never apply a label outside `bug, documentation, enhancement, chore`. - Milestone resolution order: per-invocation flag → auto-detected from GitHub open milestones. Never prompt for a milestone more than once per invocation. -<!-- generated by CodeCannon/sync.py | skill: start | adapter: cursor | hash: f4c0717b | DO NOT EDIT — run CodeCannon/sync.py to regenerate --> +<!-- generated by CodeCannon/sync.py | skill: start | adapter: cursor | hash: 8bdcf6f5 | DO NOT EDIT — run CodeCannon/sync.py to regenerate --> diff --git a/.cursor/rules/story.mdc b/.cursor/rules/story.mdc new file mode 100644 index 0000000..510c907 --- /dev/null +++ b/.cursor/rules/story.mdc @@ -0,0 +1,179 @@ +--- +description: Code Cannon: Walk the open sub-issues of a story ticket within one session +globs: +alwaysApply: false +--- + +> **Cursor:** Trigger this skill via `@story` in Agent mode. State any arguments in your message. Sub-agent spawning is not supported — the automated review step in `/submit-for-review` must be done manually using the review-agent prompt. + +--- + +## What `/story` does + +`/story <parent#>` walks the open sub-issues of a parent ("story") ticket in their GitHub-defined order, threading `/start` and `/submit-for-review` for each one into a single interactive session. It removes a few routine per-ticket prompts (`/start`'s plan-confirm gate and verified-locally prompt) — the operator already approved the whole story plan at story start. + +What `/story` deliberately does **not** do: it does not auto-decide on `/submit-for-review`'s `needs-attention` warnings or `must-address` blockers. Those remain human-judgment moments. When the review stops, the driver pauses and waits — when the operator finishes, the driver resumes with the next sub-issue. + +`/story` is intentionally a thin coordinator. See #167 for the design discussion and #177 for the deferred path that would automate judgment moments based on observed usage. + +--- + +## Step 1 — Argument check + +Required: a single integer (the parent issue number). If missing or non-numeric, abort: + +> "/story requires a parent issue number. Usage: /story <parent#>" + +--- + +## Step 2 — Fetch and echo the story plan + +Find owner/repo if not already known: + +``` +gh repo view --json owner,name +``` + +Verify the parent and fetch its sub-issues: + +``` +gh issue view <parent#> --json number,title,state +gh api repos/<owner>/<repo>/issues/<parent#>/sub_issues --jq '.[] | {number, title, state}' +``` + +Stop immediately if any of these hold: + +- Parent issue is closed → "Issue #<parent#> is closed. /story requires an open parent." +- Sub-issue list is empty → "Issue #<parent#> has no sub-issues. /story requires a parent with linked sub-issues." +- All sub-issues are closed → "All sub-issues of #<parent#> are closed. Story is complete." + +Otherwise, echo the plan (filter to `state == "open"` for the work list; show closed ones for context): + +> Story #<parent#>: <title> +> +> Open sub-issues (worked in this order): +> 1. #<Na> <title> +> 2. #<Nb> <title> +> ... +> +> Closed sub-issues (already complete): <"none" or list> +> +> Routine per-ticket prompts (plan-confirm at `/start` and verified-locally at end of `/start`) are auto-passed under the driver. Review-stage prompts (`needs-attention` warnings, `must-address` blockers) still stop and ask — they are the human-judgment moments. +> +> Type `go` to start, or share concerns first. + +Wait for the operator. Proceed only on unconditional `go`. Treat any other response as discussion — address concerns and re-ask. If the operator abandons, stop with nothing to clean up. + +--- + +## Step 3 — Ticket loop + +For each open sub-issue, in the order returned by the API: + +### 3a — Pre-flight escalation check + +Read the sub-issue body (already fetched, or re-fetch via `gh issue view <sub#>` if needed). Stop and ask **before** invoking `/start` if any of these triggers fire: + +- The acceptance criteria contain phrases like "TBD", "decide later", "?", or otherwise indicate unresolved scope. +- The body mentions a sensitive surface: authentication, authorization, payments, billing, secrets, credentials, production configuration, destructive operations (`DROP TABLE`, `rm -rf`, `git push --force`, mass deletes, schema drops). +- The body or any project-level guidance (e.g. `CLAUDE.md`) names a domain the operator has flagged for explicit review. + +If any trigger fires: + +> "Sub-issue #<sub#> triggered escalation: <reason>. +> +> - `proceed` — invoke `/start` for this sub-issue anyway (operator confirms they want it under the driver). +> - `defer` — skip this sub-issue for now and move on to the next. +> - `stop` — exit the driver with a partial summary." + +Wait for the operator. Honor the choice exactly. + +### 3b — Invoke `/start <sub#>` under the driver + +Print this preamble line immediately before invoking the skill (this is the signal `/start` recognizes): + +``` +[story-driver: parent=<parent#> ticket=<index> of <open-count>] +``` + +Then invoke `/start <sub#>`. `/start` recognizes the preamble (see Case B in `/start`) and auto-passes its plan-confirm gate and verified-locally prompt. All other `/start` behavior is unchanged — including writing the code. + +### 3c — `/submit-for-review` runs from `/start`'s auto-proceed + +`/start` under the driver auto-fires `/submit-for-review` itself (because its verified-locally prompt is auto-approved). The driver does not invoke `/submit-for-review` separately — it observes the outcome and routes accordingly. The tier routing applies as today: + +- `clean` or `informational` → auto-merge. The driver continues to the next sub-issue. +- `needs-attention` → `/submit-for-review` itself stops and asks the operator (address now / follow up later / accept as-is). The driver waits for the operator to respond through `/submit-for-review`. When `/submit-for-review` completes (either by merging or by routing back to coding), the driver resumes — either with the next sub-issue (on merge) or by re-running `/submit-for-review` after the operator fixes things. +- `must-address` → `/submit-for-review` itself stops; the operator fixes the blocker; the driver resumes on the next `/submit-for-review` invocation. + +### 3d — Per-ticket safety + +Track an attempt counter per sub-issue (start at 1; increment on each `/start → /submit-for-review` pass for the same sub-issue): + +- **Attempt cap of 2**: if a sub-issue would require a third pass, stop and ask: + > "Sub-issue #<sub#> has hit the attempt cap (2). Continue manually or stop the story?" +- **No-progress guard**: before each attempt past the first, capture `git diff origin/dev` on the feature branch. After the attempt, if the new diff is byte-identical to the previous attempt's diff, the iteration made no code change. Stop and ask: + > "Sub-issue #<sub#> made no code progress on this attempt. Stop the story or take over manually?" + +Both guards exist to prevent unbounded retry loops; neither tries to be clever. + +--- + +## Step 4 — Track follow-up tickets created during the story + +During each `/submit-for-review` run, follow-up tickets may be created (the `needs-attention` "follow up later" branch and the Step 9 selective branch both do this). Keep a running list of those follow-up issue numbers and their titles for the story summary in Step 5. The list is purely informational — sub-issue closure status is still the source of truth for "what got done." + +--- + +## Step 5 — Story session end + +When the loop exits (all open sub-issues processed, or operator chose `stop`), post a session summary as a comment on the parent issue. Skip the comment silently if nothing actually merged in this session. + +Create a temp directory if not already created: + +``` +mkdir -p /tmp/CodeCannon && mktemp -d /tmp/CodeCannon/XXXXXX +``` + +Use the file-writing tool to create `<tmpdir>/story_summary.md`: + +```markdown +## /story session summary + +Worked by the /story driver in one interactive session. + +**Merged:** +- #<sub#> <title> → PR #<pr#> +- ... + +**Deferred or not addressed:** +- #<sub#> <title> (reason: <escalation / cap / no-progress / operator-stop>) +- ... (or "none") + +**Follow-up tickets created during the story:** +- #<f#> <title> +- ... (or "none") +``` + +Post via the comment-posting script: + +``` +python3 CodeCannon/skills/github-agile/scripts/post-issue-comment.py <parent#> <tmpdir>/story_summary.md +``` + +Then close out to the operator: + +> Story #<parent#> session done. Merged: N. Deferred: M. Open sub-issues remaining: K. +> If K > 0, run `/story <parent#>` again to resume from the next open sub-issue. + +--- + +## Hard rules + +- `/story` runs entirely inside the current interactive session. No `claude -p`, no headless subprocesses, no daemons. +- `/story` does not write or edit code itself — it sequences `/start` and `/submit-for-review`. The code is written inside `/start` as it normally would be. +- `/story` does not auto-decide on `/submit-for-review`'s `needs-attention` or `must-address` tiers. Those remain human-judgment moments. +- Sub-issue state is the source of truth. The Step 5 session summary is informational — deleting or editing it must not affect resumption. A fresh `/story <parent#>` invocation always re-derives state from open sub-issues. +- Attempt cap and no-progress guards stop the story rather than retry past the limit. +- If the driver itself is interrupted (operator switches tasks, session ends), no state needs to be saved. The next `/story <parent#>` resumes by picking up the next open sub-issue. +<!-- generated by CodeCannon/sync.py | skill: story | adapter: cursor | hash: 0d5e8af1 | DO NOT EDIT — run CodeCannon/sync.py to regenerate --> diff --git a/.gemini/skills/start/SKILL.md b/.gemini/skills/start/SKILL.md index 3b20315..b7bd195 100644 --- a/.gemini/skills/start/SKILL.md +++ b/.gemini/skills/start/SKILL.md @@ -234,6 +234,13 @@ When done, say: **"When you've verified locally, reply `yes` to submit, or say w ## Case B: Resume existing issue (numeric argument) +> **Story-driver recognition:** If the immediately preceding context shows a preamble line of the form `[story-driver: parent=<N> ticket=<K> of <M>]`, the `/start` invocation is being orchestrated by the `/story` driver. Under that signal: +> - Step 2's "Does this match your understanding?" gate is implicitly satisfied (the operator approved the entire story plan at story start). Skip the gate, do not ask, proceed directly toward Step 4. +> - Step 3's investigation findings prompt is suppressed (default to skip silently). Genuine root-cause corrections or project-wide gotchas should still be raised, but routine "this looks like the ticket says" observations stay quiet. +> - Step 5's closing "verified locally" prompt is implicitly approved — automatically proceed to `/submit-for-review` without waiting for `yes`. The `make check` gate inside `/submit-for-review` is the verification safety net under the driver. +> +> Everything else in Case B (loading context, checking out the branch, writing the code, all real escalation triggers) behaves identically. The driver only suppresses the three routine prompts above. + ### Step 1 — Load context ```bash @@ -330,4 +337,4 @@ When done, say: **"When you've verified locally, reply `yes` to submit, or say w - The issue is assigned to `@me` at creation. If you are creating a ticket on someone else's behalf, remove the assignee after creation with `gh issue edit <number> --remove-assignee @me`. - Apply resolved labels and milestone to every new issue. Label resolution order: per-invocation flag → pool selection from `bug, documentation, enhancement, chore` → omit `--label` entirely. Never apply a label outside `bug, documentation, enhancement, chore`. - Milestone resolution order: per-invocation flag → auto-detected from GitHub open milestones. Never prompt for a milestone more than once per invocation. -<!-- generated by CodeCannon/sync.py | skill: start | adapter: gemini | hash: 25457446 | DO NOT EDIT — run CodeCannon/sync.py to regenerate --> +<!-- generated by CodeCannon/sync.py | skill: start | adapter: gemini | hash: 7bbbcc71 | DO NOT EDIT — run CodeCannon/sync.py to regenerate --> diff --git a/.gemini/skills/story/SKILL.md b/.gemini/skills/story/SKILL.md new file mode 100644 index 0000000..208c649 --- /dev/null +++ b/.gemini/skills/story/SKILL.md @@ -0,0 +1,178 @@ +--- +name: story +description: Code Cannon: Walk the open sub-issues of a story ticket within one session +--- + +> **Gemini CLI:** This skill is triggered by description matching. State any arguments in your message. Sub-agent spawning is not supported — the automated review step in `/submit-for-review` must be done manually using the review-agent prompt in a separate session. + +--- + +## What `/story` does + +`/story <parent#>` walks the open sub-issues of a parent ("story") ticket in their GitHub-defined order, threading `/start` and `/submit-for-review` for each one into a single interactive session. It removes a few routine per-ticket prompts (`/start`'s plan-confirm gate and verified-locally prompt) — the operator already approved the whole story plan at story start. + +What `/story` deliberately does **not** do: it does not auto-decide on `/submit-for-review`'s `needs-attention` warnings or `must-address` blockers. Those remain human-judgment moments. When the review stops, the driver pauses and waits — when the operator finishes, the driver resumes with the next sub-issue. + +`/story` is intentionally a thin coordinator. See #167 for the design discussion and #177 for the deferred path that would automate judgment moments based on observed usage. + +--- + +## Step 1 — Argument check + +Required: a single integer (the parent issue number). If missing or non-numeric, abort: + +> "/story requires a parent issue number. Usage: /story <parent#>" + +--- + +## Step 2 — Fetch and echo the story plan + +Find owner/repo if not already known: + +``` +gh repo view --json owner,name +``` + +Verify the parent and fetch its sub-issues: + +``` +gh issue view <parent#> --json number,title,state +gh api repos/<owner>/<repo>/issues/<parent#>/sub_issues --jq '.[] | {number, title, state}' +``` + +Stop immediately if any of these hold: + +- Parent issue is closed → "Issue #<parent#> is closed. /story requires an open parent." +- Sub-issue list is empty → "Issue #<parent#> has no sub-issues. /story requires a parent with linked sub-issues." +- All sub-issues are closed → "All sub-issues of #<parent#> are closed. Story is complete." + +Otherwise, echo the plan (filter to `state == "open"` for the work list; show closed ones for context): + +> Story #<parent#>: <title> +> +> Open sub-issues (worked in this order): +> 1. #<Na> <title> +> 2. #<Nb> <title> +> ... +> +> Closed sub-issues (already complete): <"none" or list> +> +> Routine per-ticket prompts (plan-confirm at `/start` and verified-locally at end of `/start`) are auto-passed under the driver. Review-stage prompts (`needs-attention` warnings, `must-address` blockers) still stop and ask — they are the human-judgment moments. +> +> Type `go` to start, or share concerns first. + +Wait for the operator. Proceed only on unconditional `go`. Treat any other response as discussion — address concerns and re-ask. If the operator abandons, stop with nothing to clean up. + +--- + +## Step 3 — Ticket loop + +For each open sub-issue, in the order returned by the API: + +### 3a — Pre-flight escalation check + +Read the sub-issue body (already fetched, or re-fetch via `gh issue view <sub#>` if needed). Stop and ask **before** invoking `/start` if any of these triggers fire: + +- The acceptance criteria contain phrases like "TBD", "decide later", "?", or otherwise indicate unresolved scope. +- The body mentions a sensitive surface: authentication, authorization, payments, billing, secrets, credentials, production configuration, destructive operations (`DROP TABLE`, `rm -rf`, `git push --force`, mass deletes, schema drops). +- The body or any project-level guidance (e.g. `CLAUDE.md`) names a domain the operator has flagged for explicit review. + +If any trigger fires: + +> "Sub-issue #<sub#> triggered escalation: <reason>. +> +> - `proceed` — invoke `/start` for this sub-issue anyway (operator confirms they want it under the driver). +> - `defer` — skip this sub-issue for now and move on to the next. +> - `stop` — exit the driver with a partial summary." + +Wait for the operator. Honor the choice exactly. + +### 3b — Invoke `/start <sub#>` under the driver + +Print this preamble line immediately before invoking the skill (this is the signal `/start` recognizes): + +``` +[story-driver: parent=<parent#> ticket=<index> of <open-count>] +``` + +Then invoke `/start <sub#>`. `/start` recognizes the preamble (see Case B in `/start`) and auto-passes its plan-confirm gate and verified-locally prompt. All other `/start` behavior is unchanged — including writing the code. + +### 3c — `/submit-for-review` runs from `/start`'s auto-proceed + +`/start` under the driver auto-fires `/submit-for-review` itself (because its verified-locally prompt is auto-approved). The driver does not invoke `/submit-for-review` separately — it observes the outcome and routes accordingly. The tier routing applies as today: + +- `clean` or `informational` → auto-merge. The driver continues to the next sub-issue. +- `needs-attention` → `/submit-for-review` itself stops and asks the operator (address now / follow up later / accept as-is). The driver waits for the operator to respond through `/submit-for-review`. When `/submit-for-review` completes (either by merging or by routing back to coding), the driver resumes — either with the next sub-issue (on merge) or by re-running `/submit-for-review` after the operator fixes things. +- `must-address` → `/submit-for-review` itself stops; the operator fixes the blocker; the driver resumes on the next `/submit-for-review` invocation. + +### 3d — Per-ticket safety + +Track an attempt counter per sub-issue (start at 1; increment on each `/start → /submit-for-review` pass for the same sub-issue): + +- **Attempt cap of 2**: if a sub-issue would require a third pass, stop and ask: + > "Sub-issue #<sub#> has hit the attempt cap (2). Continue manually or stop the story?" +- **No-progress guard**: before each attempt past the first, capture `git diff origin/dev` on the feature branch. After the attempt, if the new diff is byte-identical to the previous attempt's diff, the iteration made no code change. Stop and ask: + > "Sub-issue #<sub#> made no code progress on this attempt. Stop the story or take over manually?" + +Both guards exist to prevent unbounded retry loops; neither tries to be clever. + +--- + +## Step 4 — Track follow-up tickets created during the story + +During each `/submit-for-review` run, follow-up tickets may be created (the `needs-attention` "follow up later" branch and the Step 9 selective branch both do this). Keep a running list of those follow-up issue numbers and their titles for the story summary in Step 5. The list is purely informational — sub-issue closure status is still the source of truth for "what got done." + +--- + +## Step 5 — Story session end + +When the loop exits (all open sub-issues processed, or operator chose `stop`), post a session summary as a comment on the parent issue. Skip the comment silently if nothing actually merged in this session. + +Create a temp directory if not already created: + +``` +mkdir -p /tmp/CodeCannon && mktemp -d /tmp/CodeCannon/XXXXXX +``` + +Use the file-writing tool to create `<tmpdir>/story_summary.md`: + +```markdown +## /story session summary + +Worked by the /story driver in one interactive session. + +**Merged:** +- #<sub#> <title> → PR #<pr#> +- ... + +**Deferred or not addressed:** +- #<sub#> <title> (reason: <escalation / cap / no-progress / operator-stop>) +- ... (or "none") + +**Follow-up tickets created during the story:** +- #<f#> <title> +- ... (or "none") +``` + +Post via the comment-posting script: + +``` +python3 CodeCannon/skills/github-agile/scripts/post-issue-comment.py <parent#> <tmpdir>/story_summary.md +``` + +Then close out to the operator: + +> Story #<parent#> session done. Merged: N. Deferred: M. Open sub-issues remaining: K. +> If K > 0, run `/story <parent#>` again to resume from the next open sub-issue. + +--- + +## Hard rules + +- `/story` runs entirely inside the current interactive session. No `claude -p`, no headless subprocesses, no daemons. +- `/story` does not write or edit code itself — it sequences `/start` and `/submit-for-review`. The code is written inside `/start` as it normally would be. +- `/story` does not auto-decide on `/submit-for-review`'s `needs-attention` or `must-address` tiers. Those remain human-judgment moments. +- Sub-issue state is the source of truth. The Step 5 session summary is informational — deleting or editing it must not affect resumption. A fresh `/story <parent#>` invocation always re-derives state from open sub-issues. +- Attempt cap and no-progress guards stop the story rather than retry past the limit. +- If the driver itself is interrupted (operator switches tasks, session ends), no state needs to be saved. The next `/story <parent#>` resumes by picking up the next open sub-issue. +<!-- generated by CodeCannon/sync.py | skill: story | adapter: gemini | hash: 8b38dcd0 | DO NOT EDIT — run CodeCannon/sync.py to regenerate --> diff --git a/skills/github-agile/start.md b/skills/github-agile/start.md index 758f9ae..565fff4 100644 --- a/skills/github-agile/start.md +++ b/skills/github-agile/start.md @@ -293,6 +293,13 @@ When done, say: **"When you've verified locally, reply `yes` to submit, or say w ## Case B: Resume existing issue (numeric argument) +> **Story-driver recognition:** If the immediately preceding context shows a preamble line of the form `[story-driver: parent=<N> ticket=<K> of <M>]`, the `/start` invocation is being orchestrated by the `/story` driver. Under that signal: +> - Step 2's "Does this match your understanding?" gate is implicitly satisfied (the operator approved the entire story plan at story start). Skip the gate, do not ask, proceed directly toward Step 4. +> - Step 3's investigation findings prompt is suppressed (default to skip silently). Genuine root-cause corrections or project-wide gotchas should still be raised, but routine "this looks like the ticket says" observations stay quiet. +> - Step 5's closing "verified locally" prompt is implicitly approved — automatically proceed to `/submit-for-review` without waiting for `yes`. The `make check` gate inside `/submit-for-review` is the verification safety net under the driver. +> +> Everything else in Case B (loading context, checking out the branch, writing the code, all real escalation triggers) behaves identically. The driver only suppresses the three routine prompts above. + ### Step 1 — Load context ```bash diff --git a/skills/github-agile/story.md b/skills/github-agile/story.md new file mode 100644 index 0000000..6b04bb1 --- /dev/null +++ b/skills/github-agile/story.md @@ -0,0 +1,175 @@ +--- +skill: story +type: skill +description: "Code Cannon: Walk the open sub-issues of a story ticket within one session" +args: "parent issue number" +--- + +## What `/story` does + +`/story <parent#>` walks the open sub-issues of a parent ("story") ticket in their GitHub-defined order, threading `/start` and `/submit-for-review` for each one into a single interactive session. It removes a few routine per-ticket prompts (`/start`'s plan-confirm gate and verified-locally prompt) — the operator already approved the whole story plan at story start. + +What `/story` deliberately does **not** do: it does not auto-decide on `/submit-for-review`'s `needs-attention` warnings or `must-address` blockers. Those remain human-judgment moments. When the review stops, the driver pauses and waits — when the operator finishes, the driver resumes with the next sub-issue. + +`/story` is intentionally a thin coordinator. See #167 for the design discussion and #177 for the deferred path that would automate judgment moments based on observed usage. + +--- + +## Step 1 — Argument check + +Required: a single integer (the parent issue number). If missing or non-numeric, abort: + +> "/story requires a parent issue number. Usage: /story <parent#>" + +--- + +## Step 2 — Fetch and echo the story plan + +Find owner/repo if not already known: + +``` +gh repo view --json owner,name +``` + +Verify the parent and fetch its sub-issues: + +``` +gh issue view <parent#> --json number,title,state +gh api repos/<owner>/<repo>/issues/<parent#>/sub_issues --jq '.[] | {number, title, state}' +``` + +Stop immediately if any of these hold: + +- Parent issue is closed → "Issue #<parent#> is closed. /story requires an open parent." +- Sub-issue list is empty → "Issue #<parent#> has no sub-issues. /story requires a parent with linked sub-issues." +- All sub-issues are closed → "All sub-issues of #<parent#> are closed. Story is complete." + +Otherwise, echo the plan (filter to `state == "open"` for the work list; show closed ones for context): + +> Story #<parent#>: <title> +> +> Open sub-issues (worked in this order): +> 1. #<Na> <title> +> 2. #<Nb> <title> +> ... +> +> Closed sub-issues (already complete): <"none" or list> +> +> Routine per-ticket prompts (plan-confirm at `/start` and verified-locally at end of `/start`) are auto-passed under the driver. Review-stage prompts (`needs-attention` warnings, `must-address` blockers) still stop and ask — they are the human-judgment moments. +> +> Type `go` to start, or share concerns first. + +Wait for the operator. Proceed only on unconditional `go`. Treat any other response as discussion — address concerns and re-ask. If the operator abandons, stop with nothing to clean up. + +--- + +## Step 3 — Ticket loop + +For each open sub-issue, in the order returned by the API: + +### 3a — Pre-flight escalation check + +Read the sub-issue body (already fetched, or re-fetch via `gh issue view <sub#>` if needed). Stop and ask **before** invoking `/start` if any of these triggers fire: + +- The acceptance criteria contain phrases like "TBD", "decide later", "?", or otherwise indicate unresolved scope. +- The body mentions a sensitive surface: authentication, authorization, payments, billing, secrets, credentials, production configuration, destructive operations (`DROP TABLE`, `rm -rf`, `git push --force`, mass deletes, schema drops). +- The body or any project-level guidance (e.g. `CLAUDE.md`) names a domain the operator has flagged for explicit review. + +If any trigger fires: + +> "Sub-issue #<sub#> triggered escalation: <reason>. +> +> - `proceed` — invoke `/start` for this sub-issue anyway (operator confirms they want it under the driver). +> - `defer` — skip this sub-issue for now and move on to the next. +> - `stop` — exit the driver with a partial summary." + +Wait for the operator. Honor the choice exactly. + +### 3b — Invoke `/start <sub#>` under the driver + +Print this preamble line immediately before invoking the skill (this is the signal `/start` recognizes): + +``` +[story-driver: parent=<parent#> ticket=<index> of <open-count>] +``` + +Then invoke `/start <sub#>`. `/start` recognizes the preamble (see Case B in `/start`) and auto-passes its plan-confirm gate and verified-locally prompt. All other `/start` behavior is unchanged — including writing the code. + +### 3c — `/submit-for-review` runs from `/start`'s auto-proceed + +`/start` under the driver auto-fires `/submit-for-review` itself (because its verified-locally prompt is auto-approved). The driver does not invoke `/submit-for-review` separately — it observes the outcome and routes accordingly. The tier routing applies as today: + +- `clean` or `informational` → auto-merge. The driver continues to the next sub-issue. +- `needs-attention` → `/submit-for-review` itself stops and asks the operator (address now / follow up later / accept as-is). The driver waits for the operator to respond through `/submit-for-review`. When `/submit-for-review` completes (either by merging or by routing back to coding), the driver resumes — either with the next sub-issue (on merge) or by re-running `/submit-for-review` after the operator fixes things. +- `must-address` → `/submit-for-review` itself stops; the operator fixes the blocker; the driver resumes on the next `/submit-for-review` invocation. + +### 3d — Per-ticket safety + +Track an attempt counter per sub-issue (start at 1; increment on each `/start → /submit-for-review` pass for the same sub-issue): + +- **Attempt cap of 2**: if a sub-issue would require a third pass, stop and ask: + > "Sub-issue #<sub#> has hit the attempt cap (2). Continue manually or stop the story?" +- **No-progress guard**: before each attempt past the first, capture `git diff origin/dev` on the feature branch. After the attempt, if the new diff is byte-identical to the previous attempt's diff, the iteration made no code change. Stop and ask: + > "Sub-issue #<sub#> made no code progress on this attempt. Stop the story or take over manually?" + +Both guards exist to prevent unbounded retry loops; neither tries to be clever. + +--- + +## Step 4 — Track follow-up tickets created during the story + +During each `/submit-for-review` run, follow-up tickets may be created (the `needs-attention` "follow up later" branch and the Step 9 selective branch both do this). Keep a running list of those follow-up issue numbers and their titles for the story summary in Step 5. The list is purely informational — sub-issue closure status is still the source of truth for "what got done." + +--- + +## Step 5 — Story session end + +When the loop exits (all open sub-issues processed, or operator chose `stop`), post a session summary as a comment on the parent issue. Skip the comment silently if nothing actually merged in this session. + +Create a temp directory if not already created: + +``` +mkdir -p /tmp/CodeCannon && mktemp -d /tmp/CodeCannon/XXXXXX +``` + +Use the file-writing tool to create `<tmpdir>/story_summary.md`: + +```markdown +## /story session summary + +Worked by the /story driver in one interactive session. + +**Merged:** +- #<sub#> <title> → PR #<pr#> +- ... + +**Deferred or not addressed:** +- #<sub#> <title> (reason: <escalation / cap / no-progress / operator-stop>) +- ... (or "none") + +**Follow-up tickets created during the story:** +- #<f#> <title> +- ... (or "none") +``` + +Post via the comment-posting script: + +``` +python3 CodeCannon/skills/github-agile/scripts/post-issue-comment.py <parent#> <tmpdir>/story_summary.md +``` + +Then close out to the operator: + +> Story #<parent#> session done. Merged: N. Deferred: M. Open sub-issues remaining: K. +> If K > 0, run `/story <parent#>` again to resume from the next open sub-issue. + +--- + +## Hard rules + +- `/story` runs entirely inside the current interactive session. No `claude -p`, no headless subprocesses, no daemons. +- `/story` does not write or edit code itself — it sequences `/start` and `/submit-for-review`. The code is written inside `/start` as it normally would be. +- `/story` does not auto-decide on `/submit-for-review`'s `needs-attention` or `must-address` tiers. Those remain human-judgment moments. +- Sub-issue state is the source of truth. The Step 5 session summary is informational — deleting or editing it must not affect resumption. A fresh `/story <parent#>` invocation always re-derives state from open sub-issues. +- Attempt cap and no-progress guards stop the story rather than retry past the limit. +- If the driver itself is interrupted (operator switches tasks, session ends), no state needs to be saved. The next `/story <parent#>` resumes by picking up the next open sub-issue.