diff --git a/.agents/skills/deploy/SKILL.md b/.agents/skills/deploy/SKILL.md index 037b39a..7d00d24 100644 --- a/.agents/skills/deploy/SKILL.md +++ b/.agents/skills/deploy/SKILL.md @@ -166,10 +166,9 @@ Wait for the user to type "release" or an explicit confirmation. Any other respo ## Step 6 — Create PR: `dev` → `main` -```bash -gh pr create --base main --head dev \ - --title "Release vX.Y.Z" \ - --body-file - <<'EOF' +Use your file-writing tool (not Bash) to create `/tmp/cc_release_pr_body.md`: + +```markdown Release vX.Y.Z PRs included: @@ -178,7 +177,14 @@ PRs included: Closes #14 Closes #15 -EOF +``` + +Then create the PR (do NOT use `--body`, `--body-file -`, or heredocs): + +```bash +gh pr create --base main --head dev \ + --title "Release vX.Y.Z" \ + --body-file /tmp/cc_release_pr_body.md ``` Note the PR number from the output. @@ -209,19 +215,23 @@ git describe --abbrev=0 ^ 2>/dev/null If no previous tag exists, omit the "Full changelog" line. -Create the release: +Use your file-writing tool (not Bash) to create `/tmp/cc_release_notes.md`: -```bash -gh release create \ - --title "" \ - --notes-file - <<'EOF' +```markdown ## Changes - # (PR #) [... one line per PR included in this release ...] **Full changelog:** https://github.com///compare/... -EOF +``` + +Then create the release (do NOT use `--notes`, `--notes-file -`, or heredocs): + +```bash +gh release create \ + --title "" \ + --notes-file /tmp/cc_release_notes.md ``` Format each PR line as `- # (PR #)`. If a PR had no linked issue, omit the `#` prefix and use just the PR title. @@ -235,4 +245,4 @@ After the command runs, note the release URL from the output. Tell the user: > "Released vX.Y.Z. Issues #N, #M closed automatically. GitHub Release vX.Y.Z created at ``. Run `make deploy-prod` to ship to production." - + diff --git a/.agents/skills/start/SKILL.md b/.agents/skills/start/SKILL.md index 740cfa5..837fb80 100644 --- a/.agents/skills/start/SKILL.md +++ b/.agents/skills/start/SKILL.md @@ -76,29 +76,40 @@ Read the relevant code. Propose a concrete implementation approach. Be specific ### Step 2 — HUMAN GATE -Say exactly: **"Does this approach sound right? I'll create a GitHub issue and branch before writing any code."** +Say exactly: -Stop. Wait for the user to confirm. +> **"Does this approach sound right? Type `go` to create a GitHub issue and branch, or share any questions/adjustments first."** + +Stop. Wait for the user to respond. The friendly text question is required regardless of harness mode. If your harness is currently in a preview / plan / dry-run mode where you cannot passively stop and wait (and must instead invoke the harness's own approval mechanism), still include the text question in your response. The harness's approval UI mediates the wait, but it is not a substitute for the question itself. Users expect to see the consistent text language across all modes; do not silently swap it for the harness's UI. -- User says yes → continue to Step 3. -- User redirects → revise approach, ask again. -- User abandons → stop. Nothing to clean up. +**Intent classification (not keyword matching):** + +- **Affirmative with no conditions** ("go", "yes", "looks good", "let's do it") → continue to Step 3. +- **Affirmative with conditions** ("go, but first change X", "yes but can we also...") → treat as discussion. Address the conditions, revise the approach if needed, then re-ask. +- **Questions or pushback** ("what about...", "I'm not sure about...", any adjustment) → discuss, revise approach, re-ask. +- **Abandonment** ("never mind", "not now", "stop") → stop. Nothing to clean up. ### Step 3 — Create GitHub Issue -Run `gh issue create` with explicit flags (do NOT open an interactive editor): +Create the issue in two steps — **this exact sequence is mandatory**: + +**Step 3a — Write the body to a temp file.** Use your file-writing tool (Write in Claude Code, equivalent in other agents) to create `/tmp/cc_issue_body.md` with the structured markdown body (see sections below). Do NOT use Bash/shell to write this file. Do NOT use heredocs, `cat`, or `echo`. The file-writing tool bypasses shell parsing entirely. + +**Step 3b — Run `gh issue create`** with `--body-file` pointing to the temp file: ```bash gh issue create \ --title "" \ - --body "" \ --assignee @me \ [--label ""] \ - [--milestone ""] + [--milestone ""] \ + --body-file /tmp/cc_issue_body.md ``` +> **IMPORTANT — never pass body content inline in the `gh` command.** Do not use `--body`, `--body-file -`, heredocs (`<` — is the only approach that works without prompts across Claude Code, Gemini CLI, Cursor, and Codex. + Resolve labels and milestone using the resolution steps in the Parsing section above: - **Labels**: use the value from three-tier label resolution. If non-empty, add `--label ""` to the command. If empty (no flag, empty pool, creation not allowed), omit `--label` entirely. - **Milestone**: use the value from three-tier milestone resolution. If non-empty, add `--milestone ""` to the command. If empty (no flag, no config default, no open milestones), omit `--milestone` entirely. @@ -115,12 +126,22 @@ Resolve labels and milestone using the resolution steps in the Parsing section a ## General Approach +## Complexity +**Verification / QA effort:** + + ## Acceptance Criteria - - ``` -All four sections are required. Write for a non-developer audience — no code, no file paths. Acceptance Criteria must be concrete and verifiable (not vague goals). +All five sections are required. Write for a non-developer audience — no code, no file paths. Acceptance Criteria must be concrete and verifiable (not vague goals). + +**Complexity scale guidance (for agent use only — do not include the scale definition in the issue body):** +- **trivial** — single obvious check (e.g. color change, label text, toggle visibility) +- **moderate** — a few scenarios to verify, minor setup needed (e.g. form validation, a new UI component with a couple of states) +- **significant** — many scenarios, data setup, or cross-feature impact (e.g. multi-step workflow, permission changes across roles) +- **extensive** — complex data flows, integration testing, or edge cases spanning multiple areas (e.g. data import/export mapping, API contract changes consumed by multiple clients) **Title rules:** - ✅ `Fix 'Contact Us' footer link pointing to 404 instead of /contact-us` @@ -130,12 +151,18 @@ After the command runs, note the issue number from the output URL (e.g. `https:/ Show the user: `Created issue #: ` -Then immediately post agent implementation notes as a comment: +Then immediately post agent implementation notes as a comment. -```bash -gh issue comment <number> --body "## Agent Implementation Notes +Use your file-writing tool (not Bash) to create `/tmp/cc_issue_comment.md`: +```markdown +## Agent Implementation Notes + +<full technical plan: exact files to change, approach, key decisions, edge cases> +``` -<full technical plan: exact files to change, approach, key decisions, edge cases>" +Then post it (do NOT use `--body` or heredocs — same rule as Step 3): +```bash +gh issue comment <number> --body-file /tmp/cc_issue_comment.md ``` ### Step 4 — Create feature branch @@ -193,10 +220,15 @@ Tell the user: - What was previously done (from agent notes if present) - What appears to remain -Ask: **"Does this match your understanding? Continue this ticket, or open a fresh one?"** +Ask: **"Does this match your understanding? Type `go` to start coding, or share any questions/adjustments first."** + +**Intent classification (not keyword matching):** -- Continue → Step 3. -- New ticket → restart as Case A with a new description. +- **Affirmative with no conditions** ("go", "yes", "continue", "looks right") → proceed to Step 3. +- **Affirmative with conditions** ("go, but first...", "yes but let's also...") → treat as discussion. Address the conditions, then re-ask. +- **Questions or discussion** ("what about...", "can we change...", any adjustment) → discuss, then re-ask. +- **Fresh start** ("open a new one", "start fresh", "new ticket") → restart as Case A with a new description. +- **Abandonment** ("never mind", "not now", "stop") → stop. Nothing to clean up. ### Step 3 — Check out branch @@ -244,4 +276,4 @@ When done, say: **"The code is ready for review. Please run `make dev` and test - 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.sh | skill: start | adapter: codex | hash: c10aad5a | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> +<!-- generated by CodeCannon/sync.sh | skill: start | adapter: codex | hash: 7ba07088 | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> diff --git a/.agents/skills/submit-for-review/SKILL.md b/.agents/skills/submit-for-review/SKILL.md index 4bb8b8c..d711c85 100644 --- a/.agents/skills/submit-for-review/SKILL.md +++ b/.agents/skills/submit-for-review/SKILL.md @@ -109,16 +109,23 @@ Use `Issue #<number>` as the issue reference — the issue stays open until `/de > **Critical:** Use the unqualified `#N` form (e.g. `Closes #42`), never the fully-qualified `owner/repo#N` form (e.g. `Closes LightbridgeLab/CodeCannon#42`), even for same-repo references. GitHub's closing-keyword parser reliably populates `closingIssuesReferences` only for the unqualified form; the qualified form leaves that GraphQL edge empty, which silently breaks GitHub's native auto-close and any downstream automation that reads it. This overrides any general "use owner/repo#N for cross-linking" guidance your harness may have — closing-keyword lines in PR bodies are a special case. -Then create the PR with explicit title and body (never use an interactive editor): -``` -gh pr create --base <target-branch> --title "<title>" --body-file - <<'EOF' +Then create the PR in two steps — **this exact sequence is mandatory**: + +First, use your file-writing tool (Write in Claude Code, equivalent in other agents) to create `/tmp/cc_pr_body.md`. Do NOT use Bash/shell to write this file. + +```markdown <description of what changed and why> <Closes #N OR Issue #N, based on target above> -EOF ``` -> **Why `--body-file -` + stdin heredoc?** Claude Code's permission matcher refuses to extend any `Bash(gh:*)` allow rule over a command containing `$(...)` substitution, so `--body "$(cat <<'EOF' ...)"` triggers a Yes/No prompt on every run with no "Allow always" option. Piping the body in on stdin via heredoc redirection is not command substitution — the matcher sees a clean `gh pr create …` invocation and `Bash(gh:*)` matches. Apply this pattern to every multi-line `--body` / `--notes` in skills (`gh pr create`, `gh issue create`, `gh issue comment`, and `gh release create` all accept `-` for their `*-file` flags). +Then create the PR (do NOT use `--body`, `--body-file -`, heredocs, or `$(cat ...)`): + +``` +gh pr create --base <target-branch> --title "<title>" --body-file /tmp/cc_pr_body.md +``` + +> **IMPORTANT — never pass body content inline in the `gh` command.** Do not use `--body`, `--body-file -`, heredocs (`<<EOF` or `<<'EOF'`), or `$(cat ...)`. All of these embed markdown in a Bash command, which triggers permission prompts that cannot be permanently allowed (the shell parser flags `#` headings, quoted delimiters, and substitutions). The two-step pattern above — file-writing tool then `--body-file <path>` — is the only approach that works without prompts across Claude Code, Gemini CLI, Cursor, and Codex. Add `--reviewer` to the `gh pr create` command above using the handles from `@sebastientaggart`. Before passing them, strip any leading `@` from each comma-separated handle (e.g. `@alice,@org/team` becomes `alice,org/team`) — the `gh` CLI requires bare usernames. @@ -180,7 +187,24 @@ Apply QA label and report success (see below). **If `ai` is `"ai"` (default):** -**If APPROVE (no CRITICAL findings):** Run the merge command. Apply QA label and report success (see below). +**If APPROVE (no CRITICAL findings):** + +Collect any non-blocking findings (`[WARNING]` or `[NOTE]` lines) from the review output. + +- **If there are no non-blocking findings** (clean review): Run the merge command immediately. Apply QA label and report success (see below). + +- **If there are non-blocking findings**: Present the findings as a numbered list (preserve the `[WARNING]` / `[NOTE]` prefix) and say: + + > "The review approved with N non-blocking finding(s): + > + > <numbered list of findings> + > + > Would you like to **address these first** before merging, or **merge now**?" + + Wait for the user to respond. + + - User says **address / fix** → return to the coding loop. Say: "Fix the findings and run `/submit-for-review` again when ready." Do NOT merge. + - User says **merge now** → run the merge command. Apply QA label and report success (see below). Proceed to Step 9 as normal (which will offer to create follow-up issues for any remaining findings). **If REQUEST CHANGES (at least one CRITICAL finding):** Report the findings to the user. Do NOT merge. Say: @@ -198,6 +222,32 @@ gh issue edit <number> --add-label "ready-for-qa" ``` If no linked issue was found, skip silently. +**Post a resolution comment** on the linked issue (skip silently if no linked issue): + +Read the issue body (from Step 3 or via `gh issue view <number>`) to recall the original problem description. Then post a comment summarizing what was done: + +Use your file-writing tool (not Bash) to create `/tmp/cc_resolution_comment.md`: + +```markdown +## Resolution + +<1-3 sentences explaining what was done to fix the problem, written in plain language for a non-technical audience — no code, no file paths, no jargon. Focus on what changed from the user's perspective and why it solves the problem described in the issue.> + +See #<PR-number> for full technical details. +``` + +Then post it (do NOT use `--body` or heredocs): + +``` +gh issue comment <number> --body-file /tmp/cc_resolution_comment.md +``` + +**Resolution writing rules:** +- Write for PMs and BAs, not developers. Describe the *outcome*, not the implementation. +- Reference the original problem from the issue body so the resolution reads as a direct answer to it. +- Keep it to 1-3 sentences. If one sentence covers it, don't pad. +- Use the unqualified `#N` form for the PR reference. + Report success based on mode: "PR merged. Issues stay open until testing confirms the fix. Run `make deploy-preview` when ready to deploy to preview." @@ -225,17 +275,23 @@ Accept: comma-separated numbers, `all`, or `none`/`skip`/empty. If the input is **Create the selected issues.** For each selected finding, run `gh issue create` with explicit flags: -``` -gh issue create \ - --title "<finding text with [WARNING]/[NOTE]/[CRITICAL] prefix stripped, trimmed to a standalone sentence>" \ - [--label "<pool-selected labels>"] \ - --body-file - <<'EOF' +Use your file-writing tool (not Bash) to create `/tmp/cc_followup_body.md` for each finding: + +```markdown Follow-up from PR #<merged-pr-number> — auto-proposed from the code review. **Finding:** <full finding text, prefix included> See the review comment on the PR for context. -EOF +``` + +Then create the issue (do NOT use `--body` or heredocs): + +``` +gh issue create \ + --title "<finding text with [WARNING]/[NOTE]/[CRITICAL] prefix stripped, trimmed to a standalone sentence>" \ + [--label "<pool-selected labels>"] \ + --body-file /tmp/cc_followup_body.md ``` Label resolution for each follow-up issue: use the pool-based selection tier from `/start` — pick 1–3 labels from `bug, documentation, enhancement, chore` that genuinely fit the finding. If `bug, documentation, enhancement, chore` is empty or no pool label fits, omit `--label`. Do not attempt per-invocation flag resolution (there is no flag here) and never create new labels from follow-ups, even if label creation is enabled for the project. @@ -261,4 +317,4 @@ If a single `gh issue create` call fails, report the failure for that finding an - `/submit-for-review` merges only to `dev` — never directly to `main`. - If `make merge` fails for any reason, report it and stop — do not attempt workarounds. - The follow-up issue offer in Step 9 runs only after a successful merge and only when the review produced non-blocking findings. Never prompt the user for follow-ups when the review blocked the merge — those findings should be fixed, not ticketed. -<!-- generated by CodeCannon/sync.sh | skill: submit-for-review | adapter: codex | hash: 7f9a2844 | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> +<!-- generated by CodeCannon/sync.sh | skill: submit-for-review | adapter: codex | hash: d09ab40d | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> diff --git a/.claude/commands/deploy.md b/.claude/commands/deploy.md index 4c919ad..962a484 100644 --- a/.claude/commands/deploy.md +++ b/.claude/commands/deploy.md @@ -161,10 +161,9 @@ Wait for the user to type "release" or an explicit confirmation. Any other respo ## Step 6 — Create PR: `dev` → `main` -```bash -gh pr create --base main --head dev \ - --title "Release vX.Y.Z" \ - --body-file - <<'EOF' +Use your file-writing tool (not Bash) to create `/tmp/cc_release_pr_body.md`: + +```markdown Release vX.Y.Z PRs included: @@ -173,7 +172,14 @@ PRs included: Closes #14 Closes #15 -EOF +``` + +Then create the PR (do NOT use `--body`, `--body-file -`, or heredocs): + +```bash +gh pr create --base main --head dev \ + --title "Release vX.Y.Z" \ + --body-file /tmp/cc_release_pr_body.md ``` Note the PR number from the output. @@ -204,19 +210,23 @@ git describe --abbrev=0 <version-tag>^ 2>/dev/null If no previous tag exists, omit the "Full changelog" line. -Create the release: +Use your file-writing tool (not Bash) to create `/tmp/cc_release_notes.md`: -```bash -gh release create <version-tag> \ - --title "<version-tag>" \ - --notes-file - <<'EOF' +```markdown ## Changes - #<issue> — <PR title> (PR #<pr-number>) [... one line per PR included in this release ...] **Full changelog:** https://github.com/<owner>/<repo>/compare/<previous-tag>...<version-tag> -EOF +``` + +Then create the release (do NOT use `--notes`, `--notes-file -`, or heredocs): + +```bash +gh release create <version-tag> \ + --title "<version-tag>" \ + --notes-file /tmp/cc_release_notes.md ``` Format each PR line as `- #<linked-issue> — <PR title> (PR #<N>)`. If a PR had no linked issue, omit the `#<issue>` prefix and use just the PR title. @@ -230,4 +240,4 @@ After the command runs, note the release URL from the output. Tell the user: > "Released vX.Y.Z. Issues #N, #M closed automatically. GitHub Release vX.Y.Z created at `<url>`. Run `make deploy-prod` to ship to production." -<!-- generated by CodeCannon/sync.sh | skill: deploy | adapter: claude | hash: b1efee29 | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> +<!-- generated by CodeCannon/sync.sh | skill: deploy | adapter: claude | hash: 88439028 | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> diff --git a/.claude/commands/start.md b/.claude/commands/start.md index dc9d2b3..2458d44 100644 --- a/.claude/commands/start.md +++ b/.claude/commands/start.md @@ -71,29 +71,40 @@ Read the relevant code. Propose a concrete implementation approach. Be specific ### Step 2 — HUMAN GATE -Say exactly: **"Does this approach sound right? I'll create a GitHub issue and branch before writing any code."** +Say exactly: -Stop. Wait for the user to confirm. +> **"Does this approach sound right? Type `go` to create a GitHub issue and branch, or share any questions/adjustments first."** + +Stop. Wait for the user to respond. The friendly text question is required regardless of harness mode. If your harness is currently in a preview / plan / dry-run mode where you cannot passively stop and wait (and must instead invoke the harness's own approval mechanism), still include the text question in your response. The harness's approval UI mediates the wait, but it is not a substitute for the question itself. Users expect to see the consistent text language across all modes; do not silently swap it for the harness's UI. -- User says yes → continue to Step 3. -- User redirects → revise approach, ask again. -- User abandons → stop. Nothing to clean up. +**Intent classification (not keyword matching):** + +- **Affirmative with no conditions** ("go", "yes", "looks good", "let's do it") → continue to Step 3. +- **Affirmative with conditions** ("go, but first change X", "yes but can we also...") → treat as discussion. Address the conditions, revise the approach if needed, then re-ask. +- **Questions or pushback** ("what about...", "I'm not sure about...", any adjustment) → discuss, revise approach, re-ask. +- **Abandonment** ("never mind", "not now", "stop") → stop. Nothing to clean up. ### Step 3 — Create GitHub Issue -Run `gh issue create` with explicit flags (do NOT open an interactive editor): +Create the issue in two steps — **this exact sequence is mandatory**: + +**Step 3a — Write the body to a temp file.** Use your file-writing tool (Write in Claude Code, equivalent in other agents) to create `/tmp/cc_issue_body.md` with the structured markdown body (see sections below). Do NOT use Bash/shell to write this file. Do NOT use heredocs, `cat`, or `echo`. The file-writing tool bypasses shell parsing entirely. + +**Step 3b — Run `gh issue create`** with `--body-file` pointing to the temp file: ```bash gh issue create \ --title "<standalone full sentence — must make sense with no context>" \ - --body "<structured markdown body — see sections below>" \ --assignee @me \ [--label "<resolved labels>"] \ - [--milestone "<resolved milestone>"] + [--milestone "<resolved milestone>"] \ + --body-file /tmp/cc_issue_body.md ``` +> **IMPORTANT — never pass body content inline in the `gh` command.** Do not use `--body`, `--body-file -`, heredocs (`<<EOF` or `<<'EOF'`), or `$(cat ...)`. All of these embed markdown in a Bash command, which triggers permission prompts that cannot be permanently allowed (the shell parser flags `#` headings, quoted delimiters, and substitutions). The two-step pattern above — file-writing tool then `--body-file <path>` — is the only approach that works without prompts across Claude Code, Gemini CLI, Cursor, and Codex. + Resolve labels and milestone using the resolution steps in the Parsing section above: - **Labels**: use the value from three-tier label resolution. If non-empty, add `--label "<value>"` to the command. If empty (no flag, empty pool, creation not allowed), omit `--label` entirely. - **Milestone**: use the value from three-tier milestone resolution. If non-empty, add `--milestone "<value>"` to the command. If empty (no flag, no config default, no open milestones), omit `--milestone` entirely. @@ -110,12 +121,22 @@ Resolve labels and milestone using the resolution steps in the Parsing section a ## General Approach <high-level direction for the fix, in plain language> +## Complexity +**Verification / QA effort:** <trivial | moderate | significant | extensive> +<one-line justification — what makes verification easy or hard for this specific change> + ## Acceptance Criteria - <specific, verifiable outcome> - <another outcome> ``` -All four sections are required. Write for a non-developer audience — no code, no file paths. Acceptance Criteria must be concrete and verifiable (not vague goals). +All five sections are required. Write for a non-developer audience — no code, no file paths. Acceptance Criteria must be concrete and verifiable (not vague goals). + +**Complexity scale guidance (for agent use only — do not include the scale definition in the issue body):** +- **trivial** — single obvious check (e.g. color change, label text, toggle visibility) +- **moderate** — a few scenarios to verify, minor setup needed (e.g. form validation, a new UI component with a couple of states) +- **significant** — many scenarios, data setup, or cross-feature impact (e.g. multi-step workflow, permission changes across roles) +- **extensive** — complex data flows, integration testing, or edge cases spanning multiple areas (e.g. data import/export mapping, API contract changes consumed by multiple clients) **Title rules:** - ✅ `Fix 'Contact Us' footer link pointing to 404 instead of /contact-us` @@ -125,12 +146,18 @@ After the command runs, note the issue number from the output URL (e.g. `https:/ Show the user: `Created issue #<number>: <title>` -Then immediately post agent implementation notes as a comment: +Then immediately post agent implementation notes as a comment. -```bash -gh issue comment <number> --body "## Agent Implementation Notes +Use your file-writing tool (not Bash) to create `/tmp/cc_issue_comment.md`: +```markdown +## Agent Implementation Notes + +<full technical plan: exact files to change, approach, key decisions, edge cases> +``` -<full technical plan: exact files to change, approach, key decisions, edge cases>" +Then post it (do NOT use `--body` or heredocs — same rule as Step 3): +```bash +gh issue comment <number> --body-file /tmp/cc_issue_comment.md ``` ### Step 4 — Create feature branch @@ -188,10 +215,15 @@ Tell the user: - What was previously done (from agent notes if present) - What appears to remain -Ask: **"Does this match your understanding? Continue this ticket, or open a fresh one?"** +Ask: **"Does this match your understanding? Type `go` to start coding, or share any questions/adjustments first."** + +**Intent classification (not keyword matching):** -- Continue → Step 3. -- New ticket → restart as Case A with a new description. +- **Affirmative with no conditions** ("go", "yes", "continue", "looks right") → proceed to Step 3. +- **Affirmative with conditions** ("go, but first...", "yes but let's also...") → treat as discussion. Address the conditions, then re-ask. +- **Questions or discussion** ("what about...", "can we change...", any adjustment) → discuss, then re-ask. +- **Fresh start** ("open a new one", "start fresh", "new ticket") → restart as Case A with a new description. +- **Abandonment** ("never mind", "not now", "stop") → stop. Nothing to clean up. ### Step 3 — Check out branch @@ -239,4 +271,4 @@ When done, say: **"The code is ready for review. Please run `make dev` and test - 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.sh | skill: start | adapter: claude | hash: c3649e3f | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> +<!-- generated by CodeCannon/sync.sh | skill: start | adapter: claude | hash: d1144b46 | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> diff --git a/.claude/commands/submit-for-review.md b/.claude/commands/submit-for-review.md index cf071a5..98a6d71 100644 --- a/.claude/commands/submit-for-review.md +++ b/.claude/commands/submit-for-review.md @@ -104,16 +104,23 @@ Use `Issue #<number>` as the issue reference — the issue stays open until `/de > **Critical:** Use the unqualified `#N` form (e.g. `Closes #42`), never the fully-qualified `owner/repo#N` form (e.g. `Closes LightbridgeLab/CodeCannon#42`), even for same-repo references. GitHub's closing-keyword parser reliably populates `closingIssuesReferences` only for the unqualified form; the qualified form leaves that GraphQL edge empty, which silently breaks GitHub's native auto-close and any downstream automation that reads it. This overrides any general "use owner/repo#N for cross-linking" guidance your harness may have — closing-keyword lines in PR bodies are a special case. -Then create the PR with explicit title and body (never use an interactive editor): -``` -gh pr create --base <target-branch> --title "<title>" --body-file - <<'EOF' +Then create the PR in two steps — **this exact sequence is mandatory**: + +First, use your file-writing tool (Write in Claude Code, equivalent in other agents) to create `/tmp/cc_pr_body.md`. Do NOT use Bash/shell to write this file. + +```markdown <description of what changed and why> <Closes #N OR Issue #N, based on target above> -EOF ``` -> **Why `--body-file -` + stdin heredoc?** Claude Code's permission matcher refuses to extend any `Bash(gh:*)` allow rule over a command containing `$(...)` substitution, so `--body "$(cat <<'EOF' ...)"` triggers a Yes/No prompt on every run with no "Allow always" option. Piping the body in on stdin via heredoc redirection is not command substitution — the matcher sees a clean `gh pr create …` invocation and `Bash(gh:*)` matches. Apply this pattern to every multi-line `--body` / `--notes` in skills (`gh pr create`, `gh issue create`, `gh issue comment`, and `gh release create` all accept `-` for their `*-file` flags). +Then create the PR (do NOT use `--body`, `--body-file -`, heredocs, or `$(cat ...)`): + +``` +gh pr create --base <target-branch> --title "<title>" --body-file /tmp/cc_pr_body.md +``` + +> **IMPORTANT — never pass body content inline in the `gh` command.** Do not use `--body`, `--body-file -`, heredocs (`<<EOF` or `<<'EOF'`), or `$(cat ...)`. All of these embed markdown in a Bash command, which triggers permission prompts that cannot be permanently allowed (the shell parser flags `#` headings, quoted delimiters, and substitutions). The two-step pattern above — file-writing tool then `--body-file <path>` — is the only approach that works without prompts across Claude Code, Gemini CLI, Cursor, and Codex. Add `--reviewer` to the `gh pr create` command above using the handles from `@sebastientaggart`. Before passing them, strip any leading `@` from each comma-separated handle (e.g. `@alice,@org/team` becomes `alice,org/team`) — the `gh` CLI requires bare usernames. @@ -175,7 +182,24 @@ Apply QA label and report success (see below). **If `ai` is `"ai"` (default):** -**If APPROVE (no CRITICAL findings):** Run the merge command. Apply QA label and report success (see below). +**If APPROVE (no CRITICAL findings):** + +Collect any non-blocking findings (`[WARNING]` or `[NOTE]` lines) from the review output. + +- **If there are no non-blocking findings** (clean review): Run the merge command immediately. Apply QA label and report success (see below). + +- **If there are non-blocking findings**: Present the findings as a numbered list (preserve the `[WARNING]` / `[NOTE]` prefix) and say: + + > "The review approved with N non-blocking finding(s): + > + > <numbered list of findings> + > + > Would you like to **address these first** before merging, or **merge now**?" + + Wait for the user to respond. + + - User says **address / fix** → return to the coding loop. Say: "Fix the findings and run `/submit-for-review` again when ready." Do NOT merge. + - User says **merge now** → run the merge command. Apply QA label and report success (see below). Proceed to Step 9 as normal (which will offer to create follow-up issues for any remaining findings). **If REQUEST CHANGES (at least one CRITICAL finding):** Report the findings to the user. Do NOT merge. Say: @@ -193,6 +217,32 @@ gh issue edit <number> --add-label "ready-for-qa" ``` If no linked issue was found, skip silently. +**Post a resolution comment** on the linked issue (skip silently if no linked issue): + +Read the issue body (from Step 3 or via `gh issue view <number>`) to recall the original problem description. Then post a comment summarizing what was done: + +Use your file-writing tool (not Bash) to create `/tmp/cc_resolution_comment.md`: + +```markdown +## Resolution + +<1-3 sentences explaining what was done to fix the problem, written in plain language for a non-technical audience — no code, no file paths, no jargon. Focus on what changed from the user's perspective and why it solves the problem described in the issue.> + +See #<PR-number> for full technical details. +``` + +Then post it (do NOT use `--body` or heredocs): + +``` +gh issue comment <number> --body-file /tmp/cc_resolution_comment.md +``` + +**Resolution writing rules:** +- Write for PMs and BAs, not developers. Describe the *outcome*, not the implementation. +- Reference the original problem from the issue body so the resolution reads as a direct answer to it. +- Keep it to 1-3 sentences. If one sentence covers it, don't pad. +- Use the unqualified `#N` form for the PR reference. + Report success based on mode: "PR merged. Issues stay open until testing confirms the fix. Run `make deploy-preview` when ready to deploy to preview." @@ -220,17 +270,23 @@ Accept: comma-separated numbers, `all`, or `none`/`skip`/empty. If the input is **Create the selected issues.** For each selected finding, run `gh issue create` with explicit flags: -``` -gh issue create \ - --title "<finding text with [WARNING]/[NOTE]/[CRITICAL] prefix stripped, trimmed to a standalone sentence>" \ - [--label "<pool-selected labels>"] \ - --body-file - <<'EOF' +Use your file-writing tool (not Bash) to create `/tmp/cc_followup_body.md` for each finding: + +```markdown Follow-up from PR #<merged-pr-number> — auto-proposed from the code review. **Finding:** <full finding text, prefix included> See the review comment on the PR for context. -EOF +``` + +Then create the issue (do NOT use `--body` or heredocs): + +``` +gh issue create \ + --title "<finding text with [WARNING]/[NOTE]/[CRITICAL] prefix stripped, trimmed to a standalone sentence>" \ + [--label "<pool-selected labels>"] \ + --body-file /tmp/cc_followup_body.md ``` Label resolution for each follow-up issue: use the pool-based selection tier from `/start` — pick 1–3 labels from `bug, documentation, enhancement, chore` that genuinely fit the finding. If `bug, documentation, enhancement, chore` is empty or no pool label fits, omit `--label`. Do not attempt per-invocation flag resolution (there is no flag here) and never create new labels from follow-ups, even if label creation is enabled for the project. @@ -256,4 +312,4 @@ If a single `gh issue create` call fails, report the failure for that finding an - `/submit-for-review` merges only to `dev` — never directly to `main`. - If `make merge` fails for any reason, report it and stop — do not attempt workarounds. - The follow-up issue offer in Step 9 runs only after a successful merge and only when the review produced non-blocking findings. Never prompt the user for follow-ups when the review blocked the merge — those findings should be fixed, not ticketed. -<!-- generated by CodeCannon/sync.sh | skill: submit-for-review | adapter: claude | hash: 4845c4c2 | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> +<!-- generated by CodeCannon/sync.sh | skill: submit-for-review | adapter: claude | hash: 7cc1a5b2 | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> diff --git a/.cursor/rules/deploy.mdc b/.cursor/rules/deploy.mdc index a34de2c..d4e7d70 100644 --- a/.cursor/rules/deploy.mdc +++ b/.cursor/rules/deploy.mdc @@ -167,10 +167,9 @@ Wait for the user to type "release" or an explicit confirmation. Any other respo ## Step 6 — Create PR: `dev` → `main` -```bash -gh pr create --base main --head dev \ - --title "Release vX.Y.Z" \ - --body-file - <<'EOF' +Use your file-writing tool (not Bash) to create `/tmp/cc_release_pr_body.md`: + +```markdown Release vX.Y.Z PRs included: @@ -179,7 +178,14 @@ PRs included: Closes #14 Closes #15 -EOF +``` + +Then create the PR (do NOT use `--body`, `--body-file -`, or heredocs): + +```bash +gh pr create --base main --head dev \ + --title "Release vX.Y.Z" \ + --body-file /tmp/cc_release_pr_body.md ``` Note the PR number from the output. @@ -210,19 +216,23 @@ git describe --abbrev=0 <version-tag>^ 2>/dev/null If no previous tag exists, omit the "Full changelog" line. -Create the release: +Use your file-writing tool (not Bash) to create `/tmp/cc_release_notes.md`: -```bash -gh release create <version-tag> \ - --title "<version-tag>" \ - --notes-file - <<'EOF' +```markdown ## Changes - #<issue> — <PR title> (PR #<pr-number>) [... one line per PR included in this release ...] **Full changelog:** https://github.com/<owner>/<repo>/compare/<previous-tag>...<version-tag> -EOF +``` + +Then create the release (do NOT use `--notes`, `--notes-file -`, or heredocs): + +```bash +gh release create <version-tag> \ + --title "<version-tag>" \ + --notes-file /tmp/cc_release_notes.md ``` Format each PR line as `- #<linked-issue> — <PR title> (PR #<N>)`. If a PR had no linked issue, omit the `#<issue>` prefix and use just the PR title. @@ -236,4 +246,4 @@ After the command runs, note the release URL from the output. Tell the user: > "Released vX.Y.Z. Issues #N, #M closed automatically. GitHub Release vX.Y.Z created at `<url>`. Run `make deploy-prod` to ship to production." -<!-- generated by CodeCannon/sync.sh | skill: deploy | adapter: cursor | hash: 96c1037f | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> +<!-- generated by CodeCannon/sync.sh | skill: deploy | adapter: cursor | hash: a7a8fe00 | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> diff --git a/.cursor/rules/start.mdc b/.cursor/rules/start.mdc index 56b6728..3adac90 100644 --- a/.cursor/rules/start.mdc +++ b/.cursor/rules/start.mdc @@ -77,29 +77,40 @@ Read the relevant code. Propose a concrete implementation approach. Be specific ### Step 2 — HUMAN GATE -Say exactly: **"Does this approach sound right? I'll create a GitHub issue and branch before writing any code."** +Say exactly: -Stop. Wait for the user to confirm. +> **"Does this approach sound right? Type `go` to create a GitHub issue and branch, or share any questions/adjustments first."** + +Stop. Wait for the user to respond. The friendly text question is required regardless of harness mode. If your harness is currently in a preview / plan / dry-run mode where you cannot passively stop and wait (and must instead invoke the harness's own approval mechanism), still include the text question in your response. The harness's approval UI mediates the wait, but it is not a substitute for the question itself. Users expect to see the consistent text language across all modes; do not silently swap it for the harness's UI. -- User says yes → continue to Step 3. -- User redirects → revise approach, ask again. -- User abandons → stop. Nothing to clean up. +**Intent classification (not keyword matching):** + +- **Affirmative with no conditions** ("go", "yes", "looks good", "let's do it") → continue to Step 3. +- **Affirmative with conditions** ("go, but first change X", "yes but can we also...") → treat as discussion. Address the conditions, revise the approach if needed, then re-ask. +- **Questions or pushback** ("what about...", "I'm not sure about...", any adjustment) → discuss, revise approach, re-ask. +- **Abandonment** ("never mind", "not now", "stop") → stop. Nothing to clean up. ### Step 3 — Create GitHub Issue -Run `gh issue create` with explicit flags (do NOT open an interactive editor): +Create the issue in two steps — **this exact sequence is mandatory**: + +**Step 3a — Write the body to a temp file.** Use your file-writing tool (Write in Claude Code, equivalent in other agents) to create `/tmp/cc_issue_body.md` with the structured markdown body (see sections below). Do NOT use Bash/shell to write this file. Do NOT use heredocs, `cat`, or `echo`. The file-writing tool bypasses shell parsing entirely. + +**Step 3b — Run `gh issue create`** with `--body-file` pointing to the temp file: ```bash gh issue create \ --title "<standalone full sentence — must make sense with no context>" \ - --body "<structured markdown body — see sections below>" \ --assignee @me \ [--label "<resolved labels>"] \ - [--milestone "<resolved milestone>"] + [--milestone "<resolved milestone>"] \ + --body-file /tmp/cc_issue_body.md ``` +> **IMPORTANT — never pass body content inline in the `gh` command.** Do not use `--body`, `--body-file -`, heredocs (`<<EOF` or `<<'EOF'`), or `$(cat ...)`. All of these embed markdown in a Bash command, which triggers permission prompts that cannot be permanently allowed (the shell parser flags `#` headings, quoted delimiters, and substitutions). The two-step pattern above — file-writing tool then `--body-file <path>` — is the only approach that works without prompts across Claude Code, Gemini CLI, Cursor, and Codex. + Resolve labels and milestone using the resolution steps in the Parsing section above: - **Labels**: use the value from three-tier label resolution. If non-empty, add `--label "<value>"` to the command. If empty (no flag, empty pool, creation not allowed), omit `--label` entirely. - **Milestone**: use the value from three-tier milestone resolution. If non-empty, add `--milestone "<value>"` to the command. If empty (no flag, no config default, no open milestones), omit `--milestone` entirely. @@ -116,12 +127,22 @@ Resolve labels and milestone using the resolution steps in the Parsing section a ## General Approach <high-level direction for the fix, in plain language> +## Complexity +**Verification / QA effort:** <trivial | moderate | significant | extensive> +<one-line justification — what makes verification easy or hard for this specific change> + ## Acceptance Criteria - <specific, verifiable outcome> - <another outcome> ``` -All four sections are required. Write for a non-developer audience — no code, no file paths. Acceptance Criteria must be concrete and verifiable (not vague goals). +All five sections are required. Write for a non-developer audience — no code, no file paths. Acceptance Criteria must be concrete and verifiable (not vague goals). + +**Complexity scale guidance (for agent use only — do not include the scale definition in the issue body):** +- **trivial** — single obvious check (e.g. color change, label text, toggle visibility) +- **moderate** — a few scenarios to verify, minor setup needed (e.g. form validation, a new UI component with a couple of states) +- **significant** — many scenarios, data setup, or cross-feature impact (e.g. multi-step workflow, permission changes across roles) +- **extensive** — complex data flows, integration testing, or edge cases spanning multiple areas (e.g. data import/export mapping, API contract changes consumed by multiple clients) **Title rules:** - ✅ `Fix 'Contact Us' footer link pointing to 404 instead of /contact-us` @@ -131,12 +152,18 @@ After the command runs, note the issue number from the output URL (e.g. `https:/ Show the user: `Created issue #<number>: <title>` -Then immediately post agent implementation notes as a comment: +Then immediately post agent implementation notes as a comment. -```bash -gh issue comment <number> --body "## Agent Implementation Notes +Use your file-writing tool (not Bash) to create `/tmp/cc_issue_comment.md`: +```markdown +## Agent Implementation Notes + +<full technical plan: exact files to change, approach, key decisions, edge cases> +``` -<full technical plan: exact files to change, approach, key decisions, edge cases>" +Then post it (do NOT use `--body` or heredocs — same rule as Step 3): +```bash +gh issue comment <number> --body-file /tmp/cc_issue_comment.md ``` ### Step 4 — Create feature branch @@ -194,10 +221,15 @@ Tell the user: - What was previously done (from agent notes if present) - What appears to remain -Ask: **"Does this match your understanding? Continue this ticket, or open a fresh one?"** +Ask: **"Does this match your understanding? Type `go` to start coding, or share any questions/adjustments first."** + +**Intent classification (not keyword matching):** -- Continue → Step 3. -- New ticket → restart as Case A with a new description. +- **Affirmative with no conditions** ("go", "yes", "continue", "looks right") → proceed to Step 3. +- **Affirmative with conditions** ("go, but first...", "yes but let's also...") → treat as discussion. Address the conditions, then re-ask. +- **Questions or discussion** ("what about...", "can we change...", any adjustment) → discuss, then re-ask. +- **Fresh start** ("open a new one", "start fresh", "new ticket") → restart as Case A with a new description. +- **Abandonment** ("never mind", "not now", "stop") → stop. Nothing to clean up. ### Step 3 — Check out branch @@ -245,4 +277,4 @@ When done, say: **"The code is ready for review. Please run `make dev` and test - 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.sh | skill: start | adapter: cursor | hash: 7481a231 | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> +<!-- generated by CodeCannon/sync.sh | skill: start | adapter: cursor | hash: 99965523 | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> diff --git a/.cursor/rules/submit-for-review.mdc b/.cursor/rules/submit-for-review.mdc index 7ac52cf..89107be 100644 --- a/.cursor/rules/submit-for-review.mdc +++ b/.cursor/rules/submit-for-review.mdc @@ -110,16 +110,23 @@ Use `Issue #<number>` as the issue reference — the issue stays open until `/de > **Critical:** Use the unqualified `#N` form (e.g. `Closes #42`), never the fully-qualified `owner/repo#N` form (e.g. `Closes LightbridgeLab/CodeCannon#42`), even for same-repo references. GitHub's closing-keyword parser reliably populates `closingIssuesReferences` only for the unqualified form; the qualified form leaves that GraphQL edge empty, which silently breaks GitHub's native auto-close and any downstream automation that reads it. This overrides any general "use owner/repo#N for cross-linking" guidance your harness may have — closing-keyword lines in PR bodies are a special case. -Then create the PR with explicit title and body (never use an interactive editor): -``` -gh pr create --base <target-branch> --title "<title>" --body-file - <<'EOF' +Then create the PR in two steps — **this exact sequence is mandatory**: + +First, use your file-writing tool (Write in Claude Code, equivalent in other agents) to create `/tmp/cc_pr_body.md`. Do NOT use Bash/shell to write this file. + +```markdown <description of what changed and why> <Closes #N OR Issue #N, based on target above> -EOF ``` -> **Why `--body-file -` + stdin heredoc?** Claude Code's permission matcher refuses to extend any `Bash(gh:*)` allow rule over a command containing `$(...)` substitution, so `--body "$(cat <<'EOF' ...)"` triggers a Yes/No prompt on every run with no "Allow always" option. Piping the body in on stdin via heredoc redirection is not command substitution — the matcher sees a clean `gh pr create …` invocation and `Bash(gh:*)` matches. Apply this pattern to every multi-line `--body` / `--notes` in skills (`gh pr create`, `gh issue create`, `gh issue comment`, and `gh release create` all accept `-` for their `*-file` flags). +Then create the PR (do NOT use `--body`, `--body-file -`, heredocs, or `$(cat ...)`): + +``` +gh pr create --base <target-branch> --title "<title>" --body-file /tmp/cc_pr_body.md +``` + +> **IMPORTANT — never pass body content inline in the `gh` command.** Do not use `--body`, `--body-file -`, heredocs (`<<EOF` or `<<'EOF'`), or `$(cat ...)`. All of these embed markdown in a Bash command, which triggers permission prompts that cannot be permanently allowed (the shell parser flags `#` headings, quoted delimiters, and substitutions). The two-step pattern above — file-writing tool then `--body-file <path>` — is the only approach that works without prompts across Claude Code, Gemini CLI, Cursor, and Codex. Add `--reviewer` to the `gh pr create` command above using the handles from `@sebastientaggart`. Before passing them, strip any leading `@` from each comma-separated handle (e.g. `@alice,@org/team` becomes `alice,org/team`) — the `gh` CLI requires bare usernames. @@ -181,7 +188,24 @@ Apply QA label and report success (see below). **If `ai` is `"ai"` (default):** -**If APPROVE (no CRITICAL findings):** Run the merge command. Apply QA label and report success (see below). +**If APPROVE (no CRITICAL findings):** + +Collect any non-blocking findings (`[WARNING]` or `[NOTE]` lines) from the review output. + +- **If there are no non-blocking findings** (clean review): Run the merge command immediately. Apply QA label and report success (see below). + +- **If there are non-blocking findings**: Present the findings as a numbered list (preserve the `[WARNING]` / `[NOTE]` prefix) and say: + + > "The review approved with N non-blocking finding(s): + > + > <numbered list of findings> + > + > Would you like to **address these first** before merging, or **merge now**?" + + Wait for the user to respond. + + - User says **address / fix** → return to the coding loop. Say: "Fix the findings and run `/submit-for-review` again when ready." Do NOT merge. + - User says **merge now** → run the merge command. Apply QA label and report success (see below). Proceed to Step 9 as normal (which will offer to create follow-up issues for any remaining findings). **If REQUEST CHANGES (at least one CRITICAL finding):** Report the findings to the user. Do NOT merge. Say: @@ -199,6 +223,32 @@ gh issue edit <number> --add-label "ready-for-qa" ``` If no linked issue was found, skip silently. +**Post a resolution comment** on the linked issue (skip silently if no linked issue): + +Read the issue body (from Step 3 or via `gh issue view <number>`) to recall the original problem description. Then post a comment summarizing what was done: + +Use your file-writing tool (not Bash) to create `/tmp/cc_resolution_comment.md`: + +```markdown +## Resolution + +<1-3 sentences explaining what was done to fix the problem, written in plain language for a non-technical audience — no code, no file paths, no jargon. Focus on what changed from the user's perspective and why it solves the problem described in the issue.> + +See #<PR-number> for full technical details. +``` + +Then post it (do NOT use `--body` or heredocs): + +``` +gh issue comment <number> --body-file /tmp/cc_resolution_comment.md +``` + +**Resolution writing rules:** +- Write for PMs and BAs, not developers. Describe the *outcome*, not the implementation. +- Reference the original problem from the issue body so the resolution reads as a direct answer to it. +- Keep it to 1-3 sentences. If one sentence covers it, don't pad. +- Use the unqualified `#N` form for the PR reference. + Report success based on mode: "PR merged. Issues stay open until testing confirms the fix. Run `make deploy-preview` when ready to deploy to preview." @@ -226,17 +276,23 @@ Accept: comma-separated numbers, `all`, or `none`/`skip`/empty. If the input is **Create the selected issues.** For each selected finding, run `gh issue create` with explicit flags: -``` -gh issue create \ - --title "<finding text with [WARNING]/[NOTE]/[CRITICAL] prefix stripped, trimmed to a standalone sentence>" \ - [--label "<pool-selected labels>"] \ - --body-file - <<'EOF' +Use your file-writing tool (not Bash) to create `/tmp/cc_followup_body.md` for each finding: + +```markdown Follow-up from PR #<merged-pr-number> — auto-proposed from the code review. **Finding:** <full finding text, prefix included> See the review comment on the PR for context. -EOF +``` + +Then create the issue (do NOT use `--body` or heredocs): + +``` +gh issue create \ + --title "<finding text with [WARNING]/[NOTE]/[CRITICAL] prefix stripped, trimmed to a standalone sentence>" \ + [--label "<pool-selected labels>"] \ + --body-file /tmp/cc_followup_body.md ``` Label resolution for each follow-up issue: use the pool-based selection tier from `/start` — pick 1–3 labels from `bug, documentation, enhancement, chore` that genuinely fit the finding. If `bug, documentation, enhancement, chore` is empty or no pool label fits, omit `--label`. Do not attempt per-invocation flag resolution (there is no flag here) and never create new labels from follow-ups, even if label creation is enabled for the project. @@ -262,4 +318,4 @@ If a single `gh issue create` call fails, report the failure for that finding an - `/submit-for-review` merges only to `dev` — never directly to `main`. - If `make merge` fails for any reason, report it and stop — do not attempt workarounds. - The follow-up issue offer in Step 9 runs only after a successful merge and only when the review produced non-blocking findings. Never prompt the user for follow-ups when the review blocked the merge — those findings should be fixed, not ticketed. -<!-- generated by CodeCannon/sync.sh | skill: submit-for-review | adapter: cursor | hash: 3499993e | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> +<!-- generated by CodeCannon/sync.sh | skill: submit-for-review | adapter: cursor | hash: 141fa52f | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> diff --git a/.gemini/skills/deploy/SKILL.md b/.gemini/skills/deploy/SKILL.md index 9146f22..aaf65c2 100644 --- a/.gemini/skills/deploy/SKILL.md +++ b/.gemini/skills/deploy/SKILL.md @@ -166,10 +166,9 @@ Wait for the user to type "release" or an explicit confirmation. Any other respo ## Step 6 — Create PR: `dev` → `main` -```bash -gh pr create --base main --head dev \ - --title "Release vX.Y.Z" \ - --body-file - <<'EOF' +Use your file-writing tool (not Bash) to create `/tmp/cc_release_pr_body.md`: + +```markdown Release vX.Y.Z PRs included: @@ -178,7 +177,14 @@ PRs included: Closes #14 Closes #15 -EOF +``` + +Then create the PR (do NOT use `--body`, `--body-file -`, or heredocs): + +```bash +gh pr create --base main --head dev \ + --title "Release vX.Y.Z" \ + --body-file /tmp/cc_release_pr_body.md ``` Note the PR number from the output. @@ -209,19 +215,23 @@ git describe --abbrev=0 <version-tag>^ 2>/dev/null If no previous tag exists, omit the "Full changelog" line. -Create the release: +Use your file-writing tool (not Bash) to create `/tmp/cc_release_notes.md`: -```bash -gh release create <version-tag> \ - --title "<version-tag>" \ - --notes-file - <<'EOF' +```markdown ## Changes - #<issue> — <PR title> (PR #<pr-number>) [... one line per PR included in this release ...] **Full changelog:** https://github.com/<owner>/<repo>/compare/<previous-tag>...<version-tag> -EOF +``` + +Then create the release (do NOT use `--notes`, `--notes-file -`, or heredocs): + +```bash +gh release create <version-tag> \ + --title "<version-tag>" \ + --notes-file /tmp/cc_release_notes.md ``` Format each PR line as `- #<linked-issue> — <PR title> (PR #<N>)`. If a PR had no linked issue, omit the `#<issue>` prefix and use just the PR title. @@ -235,4 +245,4 @@ After the command runs, note the release URL from the output. Tell the user: > "Released vX.Y.Z. Issues #N, #M closed automatically. GitHub Release vX.Y.Z created at `<url>`. Run `make deploy-prod` to ship to production." -<!-- generated by CodeCannon/sync.sh | skill: deploy | adapter: gemini | hash: cde00382 | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> +<!-- generated by CodeCannon/sync.sh | skill: deploy | adapter: gemini | hash: 1b252e14 | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> diff --git a/.gemini/skills/start/SKILL.md b/.gemini/skills/start/SKILL.md index 5ad7329..bd2678f 100644 --- a/.gemini/skills/start/SKILL.md +++ b/.gemini/skills/start/SKILL.md @@ -76,29 +76,40 @@ Read the relevant code. Propose a concrete implementation approach. Be specific ### Step 2 — HUMAN GATE -Say exactly: **"Does this approach sound right? I'll create a GitHub issue and branch before writing any code."** +Say exactly: -Stop. Wait for the user to confirm. +> **"Does this approach sound right? Type `go` to create a GitHub issue and branch, or share any questions/adjustments first."** + +Stop. Wait for the user to respond. The friendly text question is required regardless of harness mode. If your harness is currently in a preview / plan / dry-run mode where you cannot passively stop and wait (and must instead invoke the harness's own approval mechanism), still include the text question in your response. The harness's approval UI mediates the wait, but it is not a substitute for the question itself. Users expect to see the consistent text language across all modes; do not silently swap it for the harness's UI. -- User says yes → continue to Step 3. -- User redirects → revise approach, ask again. -- User abandons → stop. Nothing to clean up. +**Intent classification (not keyword matching):** + +- **Affirmative with no conditions** ("go", "yes", "looks good", "let's do it") → continue to Step 3. +- **Affirmative with conditions** ("go, but first change X", "yes but can we also...") → treat as discussion. Address the conditions, revise the approach if needed, then re-ask. +- **Questions or pushback** ("what about...", "I'm not sure about...", any adjustment) → discuss, revise approach, re-ask. +- **Abandonment** ("never mind", "not now", "stop") → stop. Nothing to clean up. ### Step 3 — Create GitHub Issue -Run `gh issue create` with explicit flags (do NOT open an interactive editor): +Create the issue in two steps — **this exact sequence is mandatory**: + +**Step 3a — Write the body to a temp file.** Use your file-writing tool (Write in Claude Code, equivalent in other agents) to create `/tmp/cc_issue_body.md` with the structured markdown body (see sections below). Do NOT use Bash/shell to write this file. Do NOT use heredocs, `cat`, or `echo`. The file-writing tool bypasses shell parsing entirely. + +**Step 3b — Run `gh issue create`** with `--body-file` pointing to the temp file: ```bash gh issue create \ --title "<standalone full sentence — must make sense with no context>" \ - --body "<structured markdown body — see sections below>" \ --assignee @me \ [--label "<resolved labels>"] \ - [--milestone "<resolved milestone>"] + [--milestone "<resolved milestone>"] \ + --body-file /tmp/cc_issue_body.md ``` +> **IMPORTANT — never pass body content inline in the `gh` command.** Do not use `--body`, `--body-file -`, heredocs (`<<EOF` or `<<'EOF'`), or `$(cat ...)`. All of these embed markdown in a Bash command, which triggers permission prompts that cannot be permanently allowed (the shell parser flags `#` headings, quoted delimiters, and substitutions). The two-step pattern above — file-writing tool then `--body-file <path>` — is the only approach that works without prompts across Claude Code, Gemini CLI, Cursor, and Codex. + Resolve labels and milestone using the resolution steps in the Parsing section above: - **Labels**: use the value from three-tier label resolution. If non-empty, add `--label "<value>"` to the command. If empty (no flag, empty pool, creation not allowed), omit `--label` entirely. - **Milestone**: use the value from three-tier milestone resolution. If non-empty, add `--milestone "<value>"` to the command. If empty (no flag, no config default, no open milestones), omit `--milestone` entirely. @@ -115,12 +126,22 @@ Resolve labels and milestone using the resolution steps in the Parsing section a ## General Approach <high-level direction for the fix, in plain language> +## Complexity +**Verification / QA effort:** <trivial | moderate | significant | extensive> +<one-line justification — what makes verification easy or hard for this specific change> + ## Acceptance Criteria - <specific, verifiable outcome> - <another outcome> ``` -All four sections are required. Write for a non-developer audience — no code, no file paths. Acceptance Criteria must be concrete and verifiable (not vague goals). +All five sections are required. Write for a non-developer audience — no code, no file paths. Acceptance Criteria must be concrete and verifiable (not vague goals). + +**Complexity scale guidance (for agent use only — do not include the scale definition in the issue body):** +- **trivial** — single obvious check (e.g. color change, label text, toggle visibility) +- **moderate** — a few scenarios to verify, minor setup needed (e.g. form validation, a new UI component with a couple of states) +- **significant** — many scenarios, data setup, or cross-feature impact (e.g. multi-step workflow, permission changes across roles) +- **extensive** — complex data flows, integration testing, or edge cases spanning multiple areas (e.g. data import/export mapping, API contract changes consumed by multiple clients) **Title rules:** - ✅ `Fix 'Contact Us' footer link pointing to 404 instead of /contact-us` @@ -130,12 +151,18 @@ After the command runs, note the issue number from the output URL (e.g. `https:/ Show the user: `Created issue #<number>: <title>` -Then immediately post agent implementation notes as a comment: +Then immediately post agent implementation notes as a comment. -```bash -gh issue comment <number> --body "## Agent Implementation Notes +Use your file-writing tool (not Bash) to create `/tmp/cc_issue_comment.md`: +```markdown +## Agent Implementation Notes + +<full technical plan: exact files to change, approach, key decisions, edge cases> +``` -<full technical plan: exact files to change, approach, key decisions, edge cases>" +Then post it (do NOT use `--body` or heredocs — same rule as Step 3): +```bash +gh issue comment <number> --body-file /tmp/cc_issue_comment.md ``` ### Step 4 — Create feature branch @@ -193,10 +220,15 @@ Tell the user: - What was previously done (from agent notes if present) - What appears to remain -Ask: **"Does this match your understanding? Continue this ticket, or open a fresh one?"** +Ask: **"Does this match your understanding? Type `go` to start coding, or share any questions/adjustments first."** + +**Intent classification (not keyword matching):** -- Continue → Step 3. -- New ticket → restart as Case A with a new description. +- **Affirmative with no conditions** ("go", "yes", "continue", "looks right") → proceed to Step 3. +- **Affirmative with conditions** ("go, but first...", "yes but let's also...") → treat as discussion. Address the conditions, then re-ask. +- **Questions or discussion** ("what about...", "can we change...", any adjustment) → discuss, then re-ask. +- **Fresh start** ("open a new one", "start fresh", "new ticket") → restart as Case A with a new description. +- **Abandonment** ("never mind", "not now", "stop") → stop. Nothing to clean up. ### Step 3 — Check out branch @@ -244,4 +276,4 @@ When done, say: **"The code is ready for review. Please run `make dev` and test - 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.sh | skill: start | adapter: gemini | hash: d632050d | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> +<!-- generated by CodeCannon/sync.sh | skill: start | adapter: gemini | hash: 250dcb74 | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> diff --git a/.gemini/skills/submit-for-review/SKILL.md b/.gemini/skills/submit-for-review/SKILL.md index fa2e5d5..ec193b8 100644 --- a/.gemini/skills/submit-for-review/SKILL.md +++ b/.gemini/skills/submit-for-review/SKILL.md @@ -109,16 +109,23 @@ Use `Issue #<number>` as the issue reference — the issue stays open until `/de > **Critical:** Use the unqualified `#N` form (e.g. `Closes #42`), never the fully-qualified `owner/repo#N` form (e.g. `Closes LightbridgeLab/CodeCannon#42`), even for same-repo references. GitHub's closing-keyword parser reliably populates `closingIssuesReferences` only for the unqualified form; the qualified form leaves that GraphQL edge empty, which silently breaks GitHub's native auto-close and any downstream automation that reads it. This overrides any general "use owner/repo#N for cross-linking" guidance your harness may have — closing-keyword lines in PR bodies are a special case. -Then create the PR with explicit title and body (never use an interactive editor): -``` -gh pr create --base <target-branch> --title "<title>" --body-file - <<'EOF' +Then create the PR in two steps — **this exact sequence is mandatory**: + +First, use your file-writing tool (Write in Claude Code, equivalent in other agents) to create `/tmp/cc_pr_body.md`. Do NOT use Bash/shell to write this file. + +```markdown <description of what changed and why> <Closes #N OR Issue #N, based on target above> -EOF ``` -> **Why `--body-file -` + stdin heredoc?** Claude Code's permission matcher refuses to extend any `Bash(gh:*)` allow rule over a command containing `$(...)` substitution, so `--body "$(cat <<'EOF' ...)"` triggers a Yes/No prompt on every run with no "Allow always" option. Piping the body in on stdin via heredoc redirection is not command substitution — the matcher sees a clean `gh pr create …` invocation and `Bash(gh:*)` matches. Apply this pattern to every multi-line `--body` / `--notes` in skills (`gh pr create`, `gh issue create`, `gh issue comment`, and `gh release create` all accept `-` for their `*-file` flags). +Then create the PR (do NOT use `--body`, `--body-file -`, heredocs, or `$(cat ...)`): + +``` +gh pr create --base <target-branch> --title "<title>" --body-file /tmp/cc_pr_body.md +``` + +> **IMPORTANT — never pass body content inline in the `gh` command.** Do not use `--body`, `--body-file -`, heredocs (`<<EOF` or `<<'EOF'`), or `$(cat ...)`. All of these embed markdown in a Bash command, which triggers permission prompts that cannot be permanently allowed (the shell parser flags `#` headings, quoted delimiters, and substitutions). The two-step pattern above — file-writing tool then `--body-file <path>` — is the only approach that works without prompts across Claude Code, Gemini CLI, Cursor, and Codex. Add `--reviewer` to the `gh pr create` command above using the handles from `@sebastientaggart`. Before passing them, strip any leading `@` from each comma-separated handle (e.g. `@alice,@org/team` becomes `alice,org/team`) — the `gh` CLI requires bare usernames. @@ -180,7 +187,24 @@ Apply QA label and report success (see below). **If `ai` is `"ai"` (default):** -**If APPROVE (no CRITICAL findings):** Run the merge command. Apply QA label and report success (see below). +**If APPROVE (no CRITICAL findings):** + +Collect any non-blocking findings (`[WARNING]` or `[NOTE]` lines) from the review output. + +- **If there are no non-blocking findings** (clean review): Run the merge command immediately. Apply QA label and report success (see below). + +- **If there are non-blocking findings**: Present the findings as a numbered list (preserve the `[WARNING]` / `[NOTE]` prefix) and say: + + > "The review approved with N non-blocking finding(s): + > + > <numbered list of findings> + > + > Would you like to **address these first** before merging, or **merge now**?" + + Wait for the user to respond. + + - User says **address / fix** → return to the coding loop. Say: "Fix the findings and run `/submit-for-review` again when ready." Do NOT merge. + - User says **merge now** → run the merge command. Apply QA label and report success (see below). Proceed to Step 9 as normal (which will offer to create follow-up issues for any remaining findings). **If REQUEST CHANGES (at least one CRITICAL finding):** Report the findings to the user. Do NOT merge. Say: @@ -198,6 +222,32 @@ gh issue edit <number> --add-label "ready-for-qa" ``` If no linked issue was found, skip silently. +**Post a resolution comment** on the linked issue (skip silently if no linked issue): + +Read the issue body (from Step 3 or via `gh issue view <number>`) to recall the original problem description. Then post a comment summarizing what was done: + +Use your file-writing tool (not Bash) to create `/tmp/cc_resolution_comment.md`: + +```markdown +## Resolution + +<1-3 sentences explaining what was done to fix the problem, written in plain language for a non-technical audience — no code, no file paths, no jargon. Focus on what changed from the user's perspective and why it solves the problem described in the issue.> + +See #<PR-number> for full technical details. +``` + +Then post it (do NOT use `--body` or heredocs): + +``` +gh issue comment <number> --body-file /tmp/cc_resolution_comment.md +``` + +**Resolution writing rules:** +- Write for PMs and BAs, not developers. Describe the *outcome*, not the implementation. +- Reference the original problem from the issue body so the resolution reads as a direct answer to it. +- Keep it to 1-3 sentences. If one sentence covers it, don't pad. +- Use the unqualified `#N` form for the PR reference. + Report success based on mode: "PR merged. Issues stay open until testing confirms the fix. Run `make deploy-preview` when ready to deploy to preview." @@ -225,17 +275,23 @@ Accept: comma-separated numbers, `all`, or `none`/`skip`/empty. If the input is **Create the selected issues.** For each selected finding, run `gh issue create` with explicit flags: -``` -gh issue create \ - --title "<finding text with [WARNING]/[NOTE]/[CRITICAL] prefix stripped, trimmed to a standalone sentence>" \ - [--label "<pool-selected labels>"] \ - --body-file - <<'EOF' +Use your file-writing tool (not Bash) to create `/tmp/cc_followup_body.md` for each finding: + +```markdown Follow-up from PR #<merged-pr-number> — auto-proposed from the code review. **Finding:** <full finding text, prefix included> See the review comment on the PR for context. -EOF +``` + +Then create the issue (do NOT use `--body` or heredocs): + +``` +gh issue create \ + --title "<finding text with [WARNING]/[NOTE]/[CRITICAL] prefix stripped, trimmed to a standalone sentence>" \ + [--label "<pool-selected labels>"] \ + --body-file /tmp/cc_followup_body.md ``` Label resolution for each follow-up issue: use the pool-based selection tier from `/start` — pick 1–3 labels from `bug, documentation, enhancement, chore` that genuinely fit the finding. If `bug, documentation, enhancement, chore` is empty or no pool label fits, omit `--label`. Do not attempt per-invocation flag resolution (there is no flag here) and never create new labels from follow-ups, even if label creation is enabled for the project. @@ -261,4 +317,4 @@ If a single `gh issue create` call fails, report the failure for that finding an - `/submit-for-review` merges only to `dev` — never directly to `main`. - If `make merge` fails for any reason, report it and stop — do not attempt workarounds. - The follow-up issue offer in Step 9 runs only after a successful merge and only when the review produced non-blocking findings. Never prompt the user for follow-ups when the review blocked the merge — those findings should be fixed, not ticketed. -<!-- generated by CodeCannon/sync.sh | skill: submit-for-review | adapter: gemini | hash: 56d02482 | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> +<!-- generated by CodeCannon/sync.sh | skill: submit-for-review | adapter: gemini | hash: ba3271f2 | DO NOT EDIT — run CodeCannon/sync.sh to regenerate --> diff --git a/Makefile b/Makefile index f2f11d9..75c1bff 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,7 @@ check: # Preview what sync would generate without writing any files. dev: + ./sync.sh --validate ./sync.sh --dry-run # Regenerate .claude/commands/ and other adapter output from skills/. @@ -97,5 +98,6 @@ deploy-preview: # Publish a tagged release to production. deploy-prod: git checkout $(PRODUCTION_BRANCH) - git pull --rebase origin $(PRODUCTION_BRANCH) --tags + git pull --rebase origin $(PRODUCTION_BRANCH) + git fetch origin --tags --force git push origin $(PRODUCTION_BRANCH) --tags diff --git a/README.md b/README.md index 0177c8c..7535f6f 100644 --- a/README.md +++ b/README.md @@ -2,123 +2,75 @@ # Code Cannon -A portable agent workflow skill library. Write your team's development workflow once — start, submit-for-review, review, deploy — and sync it to Claude Code, Cursor, and other AI coding agents across all your projects. - -Repository: [github.com/LightbridgeLab/CodeCannon](https://github.com/LightbridgeLab/CodeCannon) +Write your team's AI agent workflow once — start, submit-for-review, review, deploy — and sync it to Claude Code, Cursor, Gemini, and Codex across all your projects. ## The problem -AI coding agents are powerful, but every project reinvents the same workflows: how to create issues, open PRs, run reviews, bump versions, deploy releases. These instructions live in scattered prompt files, maintained per-project, per-agent, with no consistency and no reuse. +AI coding agents are powerful, but every project reinvents the same workflows: how to create issues, open PRs, run reviews, deploy releases. These instructions live in scattered prompt files, maintained per-project, per-agent, with no consistency and no reuse. ## The solution -Code Cannon is a shared skill library that lives as a git submodule. Skills are written once as portable markdown with placeholder tokens. A sync script reads your project config, substitutes values, and generates agent-specific command files for each AI tool your team uses. +Code Cannon is a shared skill library that lives as a git submodule. Skills are written once as portable markdown. A sync script reads your project config and generates agent-specific command files: ``` skills/*.md → sync.sh + .codecannon.yaml → .claude/commands/*.md → .cursor/rules/*.mdc ``` -One source of truth. Every project. Every agent. +One source of truth for every project and every agent. ## What you get -**A complete development workflow in five commands:** +A complete development workflow in five commands: ``` /start → [code + test] → /submit-for-review → [QA] → /deploy ``` -- `/start` — creates a GitHub issue, feature branch, and writes code (with human approval before any work begins) -- `/submit-for-review` — checks, commits, opens PR, runs AI review, merges -- `/review` — standalone code review on any PR -- `/deploy` — bumps version, creates a GitHub Release, promotes to production -- `/status` — standup-ready snapshot of PRs, issues, and progress +| Command | What it does | +|---|---| +| `/start` | Create a GitHub issue, feature branch, and write code | +| `/submit-for-review` | Check, commit, open PR, run AI review, merge | +| `/review` | Standalone code review on any PR | +| `/deploy` | Bump version, create a GitHub Release, promote to production | +| `/status` | Standup-ready snapshot of PRs, issues, and progress | Plus `/qa` for structured QA workflows and `/setup` for guided onboarding. +![Code Cannon Agents Working With Humans](.github/assets/readme-inline-agents-working-with-humans.png) + ## Philosophy -**Humans stay in the loop.** The agent proposes; you approve. `/start` waits for your sign-off before creating anything. `/deploy` requires explicit confirmation. The agent commits; you test. +**Humans stay in the loop.** The agent proposes; you approve. `/start` waits for your sign-off before creating anything. `/deploy` requires explicit confirmation. **Every change has a ticket.** There is no path for code without an issue. The issue is the unit of work — branch, PR, and release all link back to it. -## GitHub baseline for PM/BA setup - -If your repo is new and you want predictable behavior from `/start` and `/qa`, configure a minimal GitHub baseline before day-to-day usage: - -- **Starter labels for issue intake:** `bug`, `enhancement`, `chore`, `documentation` -- **QA lifecycle labels:** `ready-for-qa`, `qa-passed`, `qa-failed` -- **Optional planning labels:** a single priority scheme (for example `priority:high`, `priority:medium`, `priority:low`) - -How this maps to Code Cannon behavior: - -- `/start` uses `TICKET_LABELS` as its allowed label pool when creating issues. -- `/qa` depends on `QA_READY_LABEL` to build the QA queue and applies `QA_PASSED_LABEL` or `QA_FAILED_LABEL` as verdicts. -- Milestones can stay dynamic (auto-detected from GitHub open milestones) or be pinned using `DEFAULT_MILESTONE` when your team runs fixed iterations (for example `Sprint 12` or `Release 2026.04`). - -For first-time setup, run `/setup`; it can populate labels and walk through these options interactively. - -**Reviewer selection is never automatic.** `/submit-for-review` adds reviewers only from two sources: a detected `CODEOWNERS` file (checked in `CODEOWNERS`, `.github/CODEOWNERS`, and `docs/CODEOWNERS`) and the `DEFAULT_REVIEWERS` config key. The agent never infers reviewers from git history, blame, or team membership. - -**Configure, don't fork.** Skills use `{{PLACEHOLDER}}` tokens for project-specific values. Your `.codecannon.yaml` fills them in. When upstream skills improve, pull the submodule and re-sync. - -**Agent-agnostic.** Skills are written once. Adapters handle the translation to Claude Code, Cursor, or any future agent. - -![Code Cannon Agents Working With Humans](.github/assets/readme-inline-agents-working-with-humans.png) +**Configure, don't fork.** Skills use `{{PLACEHOLDER}}` tokens. Your `.codecannon.yaml` fills them in. When upstream improves, pull the submodule and re-sync. ## Quick start ```bash -# Add Code Cannon to your project git submodule add https://github.com/LightbridgeLab/CodeCannon.git CodeCannon -git submodule update --init - -# Create and edit your config cp CodeCannon/templates/codecannon.yaml .codecannon.yaml - -# Generate skill files CodeCannon/sync.sh ``` -To update Code Cannon to the latest version, run from your project root: - -```bash -CodeCannon/sync.sh --update -``` - -This pulls the latest `main` in the CodeCannon checkout and regenerates your project's skill files in one step. If the CodeCannon checkout is on a branch other than `main`, `--update` stops with a message — update it manually and re-run `sync.sh` without `--update`. +Then optionally run `/setup` for a guided walkthrough. -If you installed Code Cannon as a git submodule, you can instead pin to the new commit: +To update to the latest version: ```bash -git submodule update --remote CodeCannon -git add CodeCannon -git commit -m "Update CodeCannon submodule to latest" -CodeCannon/sync.sh +CodeCannon/sync.sh --update ``` -Or run `/setup` for a guided walkthrough that detects your project state and configures everything interactively. - ## Documentation -- **[Getting started](docs/index.md)** — detailed overview, full quickstart, migration guide +- **[Getting started](docs/index.md)** — full quickstart, migration guide, and workflow details - **[Branching models](docs/branching.md)** — trunk, two-branch, and three-branch workflows -- **[Customization](docs/customization.md)** — tailoring skills to your project, sync.sh reference +- **[Customization](docs/customization.md)** — tailoring skills, sync.sh reference - **[Config reference](docs/config-reference.md)** — every `.codecannon.yaml` setting documented - **[Adapters](docs/adapters.md)** — supported agents and how to add new ones - -### Skill reference - -| Skill | Docs | Description | -|---|---|---| -| `/start` | [docs](docs/skills/start.md) | Create a GitHub issue, branch, and write code | -| `/submit-for-review` | [docs](docs/skills/submit-for-review.md) | Check, commit, open PR, review, merge | -| `/review` | [docs](docs/skills/review.md) | Standalone code review on a PR | -| `/deploy` | [docs](docs/skills/deploy.md) | Bump version, create GitHub Release, promote to production | -| `/qa` | [docs](docs/skills/qa.md) | QA queue and structured review workflow | -| `/status` | [docs](docs/skills/status.md) | Snapshot of PRs, issues, and progress | -| `/setup` | [docs](docs/skills/setup.md) | Guided onboarding and configuration | +- **Skill reference:** [/start](docs/skills/start.md) · [/submit-for-review](docs/skills/submit-for-review.md) · [/review](docs/skills/review.md) · [/deploy](docs/skills/deploy.md) · [/qa](docs/skills/qa.md) · [/status](docs/skills/status.md) · [/setup](docs/skills/setup.md) ## License diff --git a/VERSION b/VERSION index 1d0ba9e..267577d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.0 +0.4.1 diff --git a/docs/index.md b/docs/index.md index 9d92188..6202157 100644 --- a/docs/index.md +++ b/docs/index.md @@ -29,9 +29,9 @@ The intended sequence for a complete change: Code Cannon is opinionated about where humans stay in the loop: - `/start` pauses before creating the issue to confirm the implementation approach. +- `/submit-for-review` pauses after review if there are non-blocking findings, letting you choose to address them or merge now. - `/deploy` requires an explicit "release" confirmation before promoting to production. - `/qa` shows the review comment and waits for approval before posting. -- Everything else runs unattended. The agent commits; you test. `/start` writes code but does not commit — it hands off to you with "run your dev command and test locally." Committing happens in `/submit-for-review`. The human approval loop before shipping is where you catch things the agent missed. diff --git a/docs/skills/start.md b/docs/skills/start.md index db2c2db..2fbab94 100644 --- a/docs/skills/start.md +++ b/docs/skills/start.md @@ -40,9 +40,20 @@ Flags replace auto-selection entirely; they do not append. 1. **Investigate** — the agent reads relevant code and proposes a concrete implementation approach, specifying which files change and how. -2. **Human gate** — the agent asks: *"Does this approach sound right? I'll create a GitHub issue and branch before writing any code."* Nothing happens until you confirm. +2. **Human gate** — the agent asks: *"Does this approach sound right? Type `go` to create a GitHub issue and branch, or share any questions/adjustments first."* The agent uses intent classification (not keyword matching) to interpret your response: + - **Affirmative with no conditions** ("go", "yes", "looks good") → proceeds + - **Affirmative with conditions** ("go, but first change X") → treats as discussion, addresses conditions, re-asks + - **Questions or pushback** ("what about...", "I'm not sure") → discusses, revises, re-asks + - **Abandonment** ("never mind", "stop") → stops with nothing to clean up -3. **Create GitHub issue** — runs `gh issue create` with a descriptive title, human-readable body, and resolved labels/milestone. Posts a technical implementation plan as an issue comment. +3. **Create GitHub issue** — runs `gh issue create` with a descriptive title, structured body, and resolved labels/milestone. The issue body contains five required sections: + - **Problem to Fix** — what is broken or missing, in plain language + - **Why it Matters** — the impact or motivation + - **General Approach** — high-level direction for the fix + - **Complexity** — verification/QA effort rating (trivial, moderate, significant, or extensive) with a one-line justification + - **Acceptance Criteria** — specific, verifiable outcomes + + After the issue is created, a technical implementation plan is posted as an issue comment. 4. **Create feature branch** — runs `gh issue develop` to create a `feature/*` branch linked to the issue in GitHub. Verifies the branch before proceeding. @@ -52,7 +63,7 @@ Flags replace auto-selection entirely; they do not append. 1. **Load context** — reads the issue body, all comments, and any prior agent implementation notes. -2. **Summarize and gate** — tells you what the issue is about, what was done, and what remains. Asks if this matches your understanding. +2. **Summarize and gate** — tells you what the issue is about, what was done, and what remains. Uses the same intent classification as new work to interpret your response. 3. **Check out branch** — finds or creates the linked feature branch. diff --git a/docs/skills/submit-for-review.md b/docs/skills/submit-for-review.md index 1d2c1f7..73dc060 100644 --- a/docs/skills/submit-for-review.md +++ b/docs/skills/submit-for-review.md @@ -37,9 +37,9 @@ No arguments. `/submit-for-review` operates on the current branch. - `advisory`: spawns a review agent, posts findings, merges regardless - `off`: skips review entirely -7. **Act on verdict** — if `REVIEW_GATE` is `ai` and the review finds CRITICAL issues, `/submit-for-review` stops and asks you to fix them. Otherwise, it merges the PR. +7. **Act on verdict** — if `REVIEW_GATE` is `ai` and the review finds CRITICAL issues, `/submit-for-review` stops and asks you to fix them. If the review approves but includes non-blocking findings (warnings or notes), a human gate asks whether you want to address them first or merge now. -8. **Post-merge** — in two-branch mode, applies `QA_READY_LABEL` to the linked issue if configured. Reports next steps based on your branching model. +8. **Post-merge** — in two-branch mode, applies `QA_READY_LABEL` to the linked issue if configured. Posts a resolution comment to the linked issue summarizing what was done in plain language (written for non-technical audiences like PMs or QA). Reports next steps based on your branching model. ## Reviewer selection diff --git a/skills/deploy.md b/skills/deploy.md index a0c21c4..cbf7cdc 100644 --- a/skills/deploy.md +++ b/skills/deploy.md @@ -239,17 +239,23 @@ Wait for the user to type "release" or an explicit confirmation. Any other respo The version tag and PR/issue list are already known. If no previous tag exists, omit the "Full changelog" line. -```bash -gh release create <version-tag> \ - --title "<version-tag>" \ - --notes-file - <<'EOF' +Use your file-writing tool (not Bash) to create `/tmp/cc_release_notes.md`: + +```markdown ## Changes - #<issue> — <PR title> (PR #<pr-number>) [... one line per PR included in this release ...] **Full changelog:** https://github.com/<owner>/<repo>/compare/<previous-tag>...<version-tag> -EOF +``` + +Then create the release (do NOT use `--notes`, `--notes-file -`, or heredocs): + +```bash +gh release create <version-tag> \ + --title "<version-tag>" \ + --notes-file /tmp/cc_release_notes.md ``` Format each PR line as `- #<linked-issue> — <PR title> (PR #<N>)`. If a PR had no linked issue, use just the PR title. @@ -268,10 +274,9 @@ Tell the user: {{#if !BRANCH_TEST}} ## Step 6 — Create PR: `{{BRANCH_DEV}}` → `{{BRANCH_PROD}}` -```bash -gh pr create --base {{BRANCH_PROD}} --head {{BRANCH_DEV}} \ - --title "Release vX.Y.Z" \ - --body-file - <<'EOF' +Use your file-writing tool (not Bash) to create `/tmp/cc_release_pr_body.md`: + +```markdown Release vX.Y.Z PRs included: @@ -280,7 +285,14 @@ PRs included: Closes #14 Closes #15 -EOF +``` + +Then create the PR (do NOT use `--body`, `--body-file -`, or heredocs): + +```bash +gh pr create --base {{BRANCH_PROD}} --head {{BRANCH_DEV}} \ + --title "Release vX.Y.Z" \ + --body-file /tmp/cc_release_pr_body.md ``` Note the PR number from the output. @@ -311,19 +323,23 @@ git describe --abbrev=0 <version-tag>^ 2>/dev/null If no previous tag exists, omit the "Full changelog" line. -Create the release: +Use your file-writing tool (not Bash) to create `/tmp/cc_release_notes.md`: -```bash -gh release create <version-tag> \ - --title "<version-tag>" \ - --notes-file - <<'EOF' +```markdown ## Changes - #<issue> — <PR title> (PR #<pr-number>) [... one line per PR included in this release ...] **Full changelog:** https://github.com/<owner>/<repo>/compare/<previous-tag>...<version-tag> -EOF +``` + +Then create the release (do NOT use `--notes`, `--notes-file -`, or heredocs): + +```bash +gh release create <version-tag> \ + --title "<version-tag>" \ + --notes-file /tmp/cc_release_notes.md ``` Format each PR line as `- #<linked-issue> — <PR title> (PR #<N>)`. If a PR had no linked issue, omit the `#<issue>` prefix and use just the PR title. @@ -341,10 +357,9 @@ Tell the user: {{#if BRANCH_TEST}} ## Step 6 — Create PR: `{{BRANCH_TEST}}` → `{{BRANCH_PROD}}` -```bash -gh pr create --base {{BRANCH_PROD}} --head {{BRANCH_TEST}} \ - --title "Release vX.Y.Z" \ - --body-file - <<'EOF' +Use your file-writing tool (not Bash) to create `/tmp/cc_release_pr_body.md`: + +```markdown Release vX.Y.Z PRs included: @@ -353,7 +368,14 @@ PRs included: Closes #14 Closes #15 -EOF +``` + +Then create the PR (do NOT use `--body`, `--body-file -`, or heredocs): + +```bash +gh pr create --base {{BRANCH_PROD}} --head {{BRANCH_TEST}} \ + --title "Release vX.Y.Z" \ + --body-file /tmp/cc_release_pr_body.md ``` Note the PR number from the output. @@ -384,19 +406,23 @@ git describe --abbrev=0 <version-tag>^ 2>/dev/null If no previous tag exists, omit the "Full changelog" line. -Create the release: +Use your file-writing tool (not Bash) to create `/tmp/cc_release_notes.md`: -```bash -gh release create <version-tag> \ - --title "<version-tag>" \ - --notes-file - <<'EOF' +```markdown ## Changes - #<issue> — <PR title> (PR #<pr-number>) [... one line per PR included in this release ...] **Full changelog:** https://github.com/<owner>/<repo>/compare/<previous-tag>...<version-tag> -EOF +``` + +Then create the release (do NOT use `--notes`, `--notes-file -`, or heredocs): + +```bash +gh release create <version-tag> \ + --title "<version-tag>" \ + --notes-file /tmp/cc_release_notes.md ``` Format each PR line as `- #<linked-issue> — <PR title> (PR #<N>)`. If a PR had no linked issue, omit the `#<issue>` prefix and use just the PR title. diff --git a/skills/start.md b/skills/start.md index 0f72dc6..3d43eed 100644 --- a/skills/start.md +++ b/skills/start.md @@ -119,29 +119,40 @@ Read the relevant code. Propose a concrete implementation approach. Be specific ### Step 2 — HUMAN GATE -Say exactly: **"Does this approach sound right? I'll create a GitHub issue and branch before writing any code."** +Say exactly: -Stop. Wait for the user to confirm. +> **"Does this approach sound right? Type `go` to create a GitHub issue and branch, or share any questions/adjustments first."** + +Stop. Wait for the user to respond. The friendly text question is required regardless of harness mode. If your harness is currently in a preview / plan / dry-run mode where you cannot passively stop and wait (and must instead invoke the harness's own approval mechanism), still include the text question in your response. The harness's approval UI mediates the wait, but it is not a substitute for the question itself. Users expect to see the consistent text language across all modes; do not silently swap it for the harness's UI. -- User says yes → continue to Step 3. -- User redirects → revise approach, ask again. -- User abandons → stop. Nothing to clean up. +**Intent classification (not keyword matching):** + +- **Affirmative with no conditions** ("go", "yes", "looks good", "let's do it") → continue to Step 3. +- **Affirmative with conditions** ("go, but first change X", "yes but can we also...") → treat as discussion. Address the conditions, revise the approach if needed, then re-ask. +- **Questions or pushback** ("what about...", "I'm not sure about...", any adjustment) → discuss, revise approach, re-ask. +- **Abandonment** ("never mind", "not now", "stop") → stop. Nothing to clean up. ### Step 3 — Create GitHub Issue -Run `gh issue create` with explicit flags (do NOT open an interactive editor): +Create the issue in two steps — **this exact sequence is mandatory**: + +**Step 3a — Write the body to a temp file.** Use your file-writing tool (Write in Claude Code, equivalent in other agents) to create `/tmp/cc_issue_body.md` with the structured markdown body (see sections below). Do NOT use Bash/shell to write this file. Do NOT use heredocs, `cat`, or `echo`. The file-writing tool bypasses shell parsing entirely. + +**Step 3b — Run `gh issue create`** with `--body-file` pointing to the temp file: ```bash gh issue create \ --title "<standalone full sentence — must make sense with no context>" \ - --body "<structured markdown body — see sections below>" \ --assignee @me \ [--label "<resolved labels>"] \ - [--milestone "<resolved milestone>"] + [--milestone "<resolved milestone>"] \ + --body-file /tmp/cc_issue_body.md ``` +> **IMPORTANT — never pass body content inline in the `gh` command.** Do not use `--body`, `--body-file -`, heredocs (`<<EOF` or `<<'EOF'`), or `$(cat ...)`. All of these embed markdown in a Bash command, which triggers permission prompts that cannot be permanently allowed (the shell parser flags `#` headings, quoted delimiters, and substitutions). The two-step pattern above — file-writing tool then `--body-file <path>` — is the only approach that works without prompts across Claude Code, Gemini CLI, Cursor, and Codex. + Resolve labels and milestone using the resolution steps in the Parsing section above: - **Labels**: use the value from three-tier label resolution. If non-empty, add `--label "<value>"` to the command. If empty (no flag, empty pool, creation not allowed), omit `--label` entirely. - **Milestone**: use the value from three-tier milestone resolution. If non-empty, add `--milestone "<value>"` to the command. If empty (no flag, no config default, no open milestones), omit `--milestone` entirely. @@ -158,12 +169,22 @@ Resolve labels and milestone using the resolution steps in the Parsing section a ## General Approach <high-level direction for the fix, in plain language> +## Complexity +**Verification / QA effort:** <trivial | moderate | significant | extensive> +<one-line justification — what makes verification easy or hard for this specific change> + ## Acceptance Criteria - <specific, verifiable outcome> - <another outcome> ``` -All four sections are required. Write for a non-developer audience — no code, no file paths. Acceptance Criteria must be concrete and verifiable (not vague goals). +All five sections are required. Write for a non-developer audience — no code, no file paths. Acceptance Criteria must be concrete and verifiable (not vague goals). + +**Complexity scale guidance (for agent use only — do not include the scale definition in the issue body):** +- **trivial** — single obvious check (e.g. color change, label text, toggle visibility) +- **moderate** — a few scenarios to verify, minor setup needed (e.g. form validation, a new UI component with a couple of states) +- **significant** — many scenarios, data setup, or cross-feature impact (e.g. multi-step workflow, permission changes across roles) +- **extensive** — complex data flows, integration testing, or edge cases spanning multiple areas (e.g. data import/export mapping, API contract changes consumed by multiple clients) **Title rules:** - ✅ `Fix 'Contact Us' footer link pointing to 404 instead of /contact-us` @@ -173,12 +194,18 @@ After the command runs, note the issue number from the output URL (e.g. `https:/ Show the user: `Created issue #<number>: <title>` -Then immediately post agent implementation notes as a comment: +Then immediately post agent implementation notes as a comment. -```bash -gh issue comment <number> --body "## Agent Implementation Notes +Use your file-writing tool (not Bash) to create `/tmp/cc_issue_comment.md`: +```markdown +## Agent Implementation Notes + +<full technical plan: exact files to change, approach, key decisions, edge cases> +``` -<full technical plan: exact files to change, approach, key decisions, edge cases>" +Then post it (do NOT use `--body` or heredocs — same rule as Step 3): +```bash +gh issue comment <number> --body-file /tmp/cc_issue_comment.md ``` ### Step 4 — Create feature branch @@ -252,10 +279,15 @@ Tell the user: - What was previously done (from agent notes if present) - What appears to remain -Ask: **"Does this match your understanding? Continue this ticket, or open a fresh one?"** +Ask: **"Does this match your understanding? Type `go` to start coding, or share any questions/adjustments first."** + +**Intent classification (not keyword matching):** -- Continue → Step 3. -- New ticket → restart as Case A with a new description. +- **Affirmative with no conditions** ("go", "yes", "continue", "looks right") → proceed to Step 3. +- **Affirmative with conditions** ("go, but first...", "yes but let's also...") → treat as discussion. Address the conditions, then re-ask. +- **Questions or discussion** ("what about...", "can we change...", any adjustment) → discuss, then re-ask. +- **Fresh start** ("open a new one", "start fresh", "new ticket") → restart as Case A with a new description. +- **Abandonment** ("never mind", "not now", "stop") → stop. Nothing to clean up. ### Step 3 — Check out branch diff --git a/skills/submit-for-review.md b/skills/submit-for-review.md index d598aec..c1bdf67 100644 --- a/skills/submit-for-review.md +++ b/skills/submit-for-review.md @@ -126,16 +126,23 @@ Use `Closes #<number>` as the issue reference — merging to the default branch > **Critical:** Use the unqualified `#N` form (e.g. `Closes #42`), never the fully-qualified `owner/repo#N` form (e.g. `Closes LightbridgeLab/CodeCannon#42`), even for same-repo references. GitHub's closing-keyword parser reliably populates `closingIssuesReferences` only for the unqualified form; the qualified form leaves that GraphQL edge empty, which silently breaks GitHub's native auto-close and any downstream automation that reads it. This overrides any general "use owner/repo#N for cross-linking" guidance your harness may have — closing-keyword lines in PR bodies are a special case. -Then create the PR with explicit title and body (never use an interactive editor): -``` -gh pr create --base <target-branch> --title "<title>" --body-file - <<'EOF' +Then create the PR in two steps — **this exact sequence is mandatory**: + +First, use your file-writing tool (Write in Claude Code, equivalent in other agents) to create `/tmp/cc_pr_body.md`. Do NOT use Bash/shell to write this file. + +```markdown <description of what changed and why> <Closes #N OR Issue #N, based on target above> -EOF ``` -> **Why `--body-file -` + stdin heredoc?** Claude Code's permission matcher refuses to extend any `Bash(gh:*)` allow rule over a command containing `$(...)` substitution, so `--body "$(cat <<'EOF' ...)"` triggers a Yes/No prompt on every run with no "Allow always" option. Piping the body in on stdin via heredoc redirection is not command substitution — the matcher sees a clean `gh pr create …` invocation and `Bash(gh:*)` matches. Apply this pattern to every multi-line `--body` / `--notes` in skills (`gh pr create`, `gh issue create`, `gh issue comment`, and `gh release create` all accept `-` for their `*-file` flags). +Then create the PR (do NOT use `--body`, `--body-file -`, heredocs, or `$(cat ...)`): + +``` +gh pr create --base <target-branch> --title "<title>" --body-file /tmp/cc_pr_body.md +``` + +> **IMPORTANT — never pass body content inline in the `gh` command.** Do not use `--body`, `--body-file -`, heredocs (`<<EOF` or `<<'EOF'`), or `$(cat ...)`. All of these embed markdown in a Bash command, which triggers permission prompts that cannot be permanently allowed (the shell parser flags `#` headings, quoted delimiters, and substitutions). The two-step pattern above — file-writing tool then `--body-file <path>` — is the only approach that works without prompts across Claude Code, Gemini CLI, Cursor, and Codex. {{#if DEFAULT_REVIEWERS}} Add `--reviewer` to the `gh pr create` command above using the handles from `{{DEFAULT_REVIEWERS}}`. Before passing them, strip any leading `@` from each comma-separated handle (e.g. `@alice,@org/team` becomes `alice,org/team`) — the `gh` CLI requires bare usernames. @@ -204,7 +211,24 @@ Apply QA label and report success (see below). **If `{{REVIEW_GATE}}` is `"ai"` (default):** -**If APPROVE (no CRITICAL findings):** Run the merge command. Apply QA label and report success (see below). +**If APPROVE (no CRITICAL findings):** + +Collect any non-blocking findings (`[WARNING]` or `[NOTE]` lines) from the review output. + +- **If there are no non-blocking findings** (clean review): Run the merge command immediately. Apply QA label and report success (see below). + +- **If there are non-blocking findings**: Present the findings as a numbered list (preserve the `[WARNING]` / `[NOTE]` prefix) and say: + + > "The review approved with N non-blocking finding(s): + > + > <numbered list of findings> + > + > Would you like to **address these first** before merging, or **merge now**?" + + Wait for the user to respond. + + - User says **address / fix** → return to the coding loop. Say: "Fix the findings and run `/submit-for-review` again when ready." Do NOT merge. + - User says **merge now** → run the merge command. Apply QA label and report success (see below). Proceed to Step 9 as normal (which will offer to create follow-up issues for any remaining findings). **If REQUEST CHANGES (at least one CRITICAL finding):** Report the findings to the user. Do NOT merge. Say: @@ -228,6 +252,32 @@ If no linked issue was found, skip silently. {{/if}} {{/if}} +**Post a resolution comment** on the linked issue (skip silently if no linked issue): + +Read the issue body (from Step 3 or via `gh issue view <number>`) to recall the original problem description. Then post a comment summarizing what was done: + +Use your file-writing tool (not Bash) to create `/tmp/cc_resolution_comment.md`: + +```markdown +## Resolution + +<1-3 sentences explaining what was done to fix the problem, written in plain language for a non-technical audience — no code, no file paths, no jargon. Focus on what changed from the user's perspective and why it solves the problem described in the issue.> + +See #<PR-number> for full technical details. +``` + +Then post it (do NOT use `--body` or heredocs): + +``` +gh issue comment <number> --body-file /tmp/cc_resolution_comment.md +``` + +**Resolution writing rules:** +- Write for PMs and BAs, not developers. Describe the *outcome*, not the implementation. +- Reference the original problem from the issue body so the resolution reads as a direct answer to it. +- Keep it to 1-3 sentences. If one sentence covers it, don't pad. +- Use the unqualified `#N` form for the PR reference. + Report success based on mode: {{#if !BRANCH_DEV}} "PR merged. Issue #N closed automatically. Run `{{DEPLOY_PROD_CMD}}` when ready to deploy to production." @@ -265,17 +315,23 @@ Accept: comma-separated numbers, `all`, or `none`/`skip`/empty. If the input is **Create the selected issues.** For each selected finding, run `gh issue create` with explicit flags: -``` -gh issue create \ - --title "<finding text with [WARNING]/[NOTE]/[CRITICAL] prefix stripped, trimmed to a standalone sentence>" \ - [--label "<pool-selected labels>"] \ - --body-file - <<'EOF' +Use your file-writing tool (not Bash) to create `/tmp/cc_followup_body.md` for each finding: + +```markdown Follow-up from PR #<merged-pr-number> — auto-proposed from the code review. **Finding:** <full finding text, prefix included> See the review comment on the PR for context. -EOF +``` + +Then create the issue (do NOT use `--body` or heredocs): + +``` +gh issue create \ + --title "<finding text with [WARNING]/[NOTE]/[CRITICAL] prefix stripped, trimmed to a standalone sentence>" \ + [--label "<pool-selected labels>"] \ + --body-file /tmp/cc_followup_body.md ``` Label resolution for each follow-up issue: use the pool-based selection tier from `/start` — pick 1–3 labels from `{{TICKET_LABELS}}` that genuinely fit the finding. If `{{TICKET_LABELS}}` is empty or no pool label fits, omit `--label`. Do not attempt per-invocation flag resolution (there is no flag here) and never create new labels from follow-ups, even if label creation is enabled for the project.