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 47881d4..837fb80 100644 --- a/.agents/skills/start/SKILL.md +++ b/.agents/skills/start/SKILL.md @@ -93,7 +93,11 @@ The friendly text question is required regardless of harness mode. If your harne ### 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 \ @@ -101,12 +105,10 @@ gh issue create \ --assignee @me \ [--label ""] \ [--milestone ""] \ - --body-file - <<'EOF' - -EOF + --body-file /tmp/cc_issue_body.md ``` -> **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 avoids this — the matcher sees a clean `gh …` invocation and `Bash(gh:*)` matches. +> **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. @@ -149,14 +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-file - <<'EOF' +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> -EOF +``` + +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 @@ -270,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: 5603cf1a | 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 dd35ec9..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. @@ -219,14 +226,20 @@ If no linked issue was found, skip silently. 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: -``` -gh issue comment <number> --body-file - <<'EOF' +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. -EOF +``` + +Then post it (do NOT use `--body` or heredocs): + +``` +gh issue comment <number> --body-file /tmp/cc_resolution_comment.md ``` **Resolution writing rules:** @@ -262,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. @@ -298,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: ba60d5aa | 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 edbe3e6..2458d44 100644 --- a/.claude/commands/start.md +++ b/.claude/commands/start.md @@ -88,7 +88,11 @@ The friendly text question is required regardless of harness mode. If your harne ### 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 \ @@ -96,12 +100,10 @@ gh issue create \ --assignee @me \ [--label "<resolved labels>"] \ [--milestone "<resolved milestone>"] \ - --body-file - <<'EOF' -<structured markdown body — see sections below> -EOF + --body-file /tmp/cc_issue_body.md ``` -> **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 avoids this — the matcher sees a clean `gh …` invocation and `Bash(gh:*)` matches. +> **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. @@ -144,14 +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-file - <<'EOF' +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> -EOF +``` + +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 @@ -265,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: 3c1bac69 | 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 95d9218..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. @@ -214,14 +221,20 @@ If no linked issue was found, skip silently. 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: -``` -gh issue comment <number> --body-file - <<'EOF' +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. -EOF +``` + +Then post it (do NOT use `--body` or heredocs): + +``` +gh issue comment <number> --body-file /tmp/cc_resolution_comment.md ``` **Resolution writing rules:** @@ -257,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. @@ -293,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: 28da1f65 | 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 58a770b..3adac90 100644 --- a/.cursor/rules/start.mdc +++ b/.cursor/rules/start.mdc @@ -94,7 +94,11 @@ The friendly text question is required regardless of harness mode. If your harne ### 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 \ @@ -102,12 +106,10 @@ gh issue create \ --assignee @me \ [--label "<resolved labels>"] \ [--milestone "<resolved milestone>"] \ - --body-file - <<'EOF' -<structured markdown body — see sections below> -EOF + --body-file /tmp/cc_issue_body.md ``` -> **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 avoids this — the matcher sees a clean `gh …` invocation and `Bash(gh:*)` matches. +> **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. @@ -150,14 +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-file - <<'EOF' +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> -EOF +``` + +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 @@ -271,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: fad7e3ef | 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 ef6b002..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. @@ -220,14 +227,20 @@ If no linked issue was found, skip silently. 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: -``` -gh issue comment <number> --body-file - <<'EOF' +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. -EOF +``` + +Then post it (do NOT use `--body` or heredocs): + +``` +gh issue comment <number> --body-file /tmp/cc_resolution_comment.md ``` **Resolution writing rules:** @@ -263,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. @@ -299,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: d2df6354 | 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 6695df4..bd2678f 100644 --- a/.gemini/skills/start/SKILL.md +++ b/.gemini/skills/start/SKILL.md @@ -93,7 +93,11 @@ The friendly text question is required regardless of harness mode. If your harne ### 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 \ @@ -101,12 +105,10 @@ gh issue create \ --assignee @me \ [--label "<resolved labels>"] \ [--milestone "<resolved milestone>"] \ - --body-file - <<'EOF' -<structured markdown body — see sections below> -EOF + --body-file /tmp/cc_issue_body.md ``` -> **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 avoids this — the matcher sees a clean `gh …` invocation and `Bash(gh:*)` matches. +> **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. @@ -149,14 +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-file - <<'EOF' +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> -EOF +``` + +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 @@ -270,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: 064b9454 | 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 c494469..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. @@ -219,14 +226,20 @@ If no linked issue was found, skip silently. 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: -``` -gh issue comment <number> --body-file - <<'EOF' +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. -EOF +``` + +Then post it (do NOT use `--body` or heredocs): + +``` +gh issue comment <number> --body-file /tmp/cc_resolution_comment.md ``` **Resolution writing rules:** @@ -262,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. @@ -298,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: 156f1ee6 | 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/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 aefb3b8..3d43eed 100644 --- a/skills/start.md +++ b/skills/start.md @@ -136,7 +136,11 @@ The friendly text question is required regardless of harness mode. If your harne ### 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 \ @@ -144,12 +148,10 @@ gh issue create \ --assignee @me \ [--label "<resolved labels>"] \ [--milestone "<resolved milestone>"] \ - --body-file - <<'EOF' -<structured markdown body — see sections below> -EOF + --body-file /tmp/cc_issue_body.md ``` -> **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 avoids this — the matcher sees a clean `gh …` invocation and `Bash(gh:*)` matches. +> **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. @@ -192,14 +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-file - <<'EOF' +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> -EOF +``` + +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 diff --git a/skills/submit-for-review.md b/skills/submit-for-review.md index 9def763..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. @@ -249,14 +256,20 @@ If no linked issue was found, skip silently. 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: -``` -gh issue comment <number> --body-file - <<'EOF' +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. -EOF +``` + +Then post it (do NOT use `--body` or heredocs): + +``` +gh issue comment <number> --body-file /tmp/cc_resolution_comment.md ``` **Resolution writing rules:** @@ -302,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.