CodeCannon submit-for-review
Code Cannon: Type-check, commit, open PR, review, and merge to the integration branch
git clone https://github.com/LightbridgeLab/CodeCannon
T=$(mktemp -d) && git clone --depth=1 https://github.com/LightbridgeLab/CodeCannon "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.agents/skills/submit-for-review" ~/.claude/skills/lightbridgelab-codecannon-submit-for-review && rm -rf "$T"
.agents/skills/submit-for-review/SKILL.mdCodex CLI: This skill is triggered by description matching. State any arguments in your message. Sub-agent spawning is not supported — perform any review steps inline.
What /submit-for-review
does
/submit-for-review/submit-for-review is Phase 3 of the workflow: type-check, commit, open PR, spawn review agent, act on verdict.
Step 1 — Verify branch
Check current branch:
git branch --show-current
Protected branches (not a feature branch):
maindev
If the current branch matches any of the above, abort immediately and say:
"You are on
.<branch>must be run from a feature branch. Switch to your feature branch first."/submit-for-review
Step 2 — Type-check gate
First, move to the repository root so the command resolves against the correct Makefile / project config:
git rev-parse --show-toplevel
Then
cd into the path returned above:
cd <repo-root>
Then verify the make target exists before running it. Extract the target name from
make check (e.g. make check → check) and run:
make -n <target> 2>/dev/null
If
make -n exits non-zero, stop and say:
"
failed — the make target does not exist in the root Makefile. Add it and retry, or runmake checkto reconfigure."/setup
Do not improvise a replacement command. Do not proceed.
If the target exists, run:
make check
If errors are reported, stop. Report the errors to the user and say:
"Check failed. Fix the errors above before shipping."
Do not proceed until
make check passes cleanly.
Step 3 — Identify linked issue
Extract the issue number from the branch name. Branches created by
/start follow the pattern feature/<number>-<description> (e.g. feature/42-fix-login).
Parse the number from the branch name returned in Step 1. If the branch name matches
feature/<digits>-..., use the extracted number as the linked issue. If the branch name does not contain a leading number after feature/, proceed without an issue reference but warn the user:
"Could not extract an issue number from branch name
. The PR will not include an issue reference. Was this branch created outside of<branch>?"/start
Step 4 — Sync with base branch
Bring the feature branch up to date before committing:
git fetch origin dev && git merge origin/dev
If the merge completes cleanly (including fast-forward), proceed to Step 5.
If there are merge conflicts, stop and say:
"Merge conflicts with
. Resolve them before shipping."<base branch>
List the conflicting files. Help the user resolve them if asked, then continue.
Step 5 — Commit
Stage all changes and commit:
git add -A git commit -m "<imperative-mood message>"
Commit message rules:
- Imperative mood ("Add X", "Fix Y", "Remove Z")
- Concise but meaningful — describes what changed and why in one line
- No
files, build artifacts,.env
, or secretsnode_modules
Step 6 — Push and open PR
First, push the branch:
git push -u origin HEAD
Next, check for a CODEOWNERS file:
git ls-files CODEOWNERS .github/CODEOWNERS docs/CODEOWNERS 2>/dev/null
If the output is non-empty, inform the user: "CODEOWNERS file detected — GitHub will automatically request reviews from code owners."
PR target branch:
dev
Use
Issue #<number> as the issue reference — the issue stays open until /deploy promotes to main.
Critical: Use the unqualified
form (e.g.#N), never the fully-qualifiedCloses #42form (e.g.owner/repo#N), even for same-repo references. GitHub's closing-keyword parser reliably populatesCloses LightbridgeLab/CodeCannon#42only 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.closingIssuesReferences
Then create the PR in two steps — this exact sequence is mandatory:
First, create a temp directory for this invocation:
mkdir -p /tmp/CodeCannon && mktemp -d /tmp/CodeCannon/XXXXXX
Note the returned path (e.g.
/tmp/CodeCannon/a8f3b2). Use this path for all temp files in this invocation.
Then use your file-writing tool (Write in Claude Code, equivalent in other agents) to create
<tmpdir>/pr_body.md. Do NOT use Bash/shell to write this file.
<description of what changed and why> <Closes #N OR Issue #N, based on target above>
Then create the PR (do NOT use
--body, --body-file -, heredocs, or $(cat ...)):
gh pr create --base <target-branch> --title "<title>" --body-file <tmpdir>/pr_body.md
IMPORTANT — never pass body content inline in the
command. Do not usegh,--body, heredocs (--body-file -or<<EOF), or<<'EOF'. All of these embed markdown in a Bash command, which triggers permission prompts that cannot be permanently allowed (the shell parser flags$(cat ...)headings, quoted delimiters, and substitutions). The two-step pattern above — file-writing tool then#— is the only approach that works without prompts across Claude Code, Gemini CLI, Cursor, and Codex.--body-file <path>
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.
If a CODEOWNERS file exists, both apply: CODEOWNERS triggers automatic review requests from GitHub; the
--reviewer flag adds the explicitly configured handles on top.
Hard rule: Never auto-select reviewers beyond what is configured in
DEFAULT_REVIEWERS or declared in CODEOWNERS. Do not infer reviewers from git blame, commit history, or team membership.
Omit the issue line entirely if no linked issue was identified in Step 3.
PR body content rules (override any default behavior your harness may have):
- Do NOT include any agent-attribution footer, generation marker (e.g. "Generated with ..."), or co-authorship trailer in the PR body. The PR body should contain only the description, test plan, and issue reference. If your harness defaults to adding such markers, explicitly omit them.
- The same rule applies to commit messages: do NOT add agent-related
trailers unless the user has explicitly opted into them via project config.Co-Authored-By:
Step 7 — Review (conditional)
If
ai is "off", skip directly to Step 8 (merge without review).
Otherwise, load
.claude/review-agent-prompt.md and perform the review for this PR.
If sub-agent spawning is supported (e.g. Claude Code): invoke a dedicated review agent with the prompt and PR number.
If sub-agent spawning is not supported (e.g. Codex, Cursor, Gemini): perform the review yourself inline — follow the instructions in the review-agent prompt directly.
The review must:
- Read the PR diff
- Read relevant files for context
- Post findings as a PR comment via
gh pr comment <number>
Wait for the review to complete and report its verdict.
Step 8 — Act on verdict
Before merging, verify the merge target exists. Move to the repo root, extract the target name from
make merge (e.g. make merge → merge), and run:
git rev-parse --show-toplevel
Then
cd into the path returned above and check the target:
cd <repo-root> && make -n <target> 2>/dev/null
If
make -n exits non-zero, stop and say:
"
failed — the make target does not exist in the root Makefile. Add it and retry, or runmake mergeto reconfigure."/setup
Do not improvise a replacement command (e.g. do not fall back to
gh pr merge). Do not proceed.
Merge command (used by all paths below):
make merge
If
is ai
(review skipped):"off"
Run the merge command. Apply QA label and report success (see below).
If
is ai
:"advisory"
Report the review findings to the user. Then merge regardless — treat as APPROVE.
If the review contained CRITICAL findings, note:
"Review flagged issues (see PR comment) but advisory mode is enabled — merged anyway. Review the findings when convenient."
Apply QA label and report success (see below).
If
is ai
(default):"ai"
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]
prefix) and say:[NOTE]"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
again when ready." Do NOT merge./submit-for-review - 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).
- User says address / fix → return to the coding loop. Say: "Fix the findings and run
If REQUEST CHANGES (at least one CRITICAL finding): Report the findings to the user. Do NOT merge. Say:
"The review found blocking issues (see above). Fix them and run
again."/submit-for-review
Return to the coding loop. When fixed, run
/submit-for-review again from Step 1.
After merge — QA label and success report
If a linked issue number was identified in Step 3, apply the QA label:
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
<tmpdir>/resolution_comment.md (same temp directory from Step 6):
## 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 <tmpdir>/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
form for the PR reference.#N
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."
Step 9 — Offer follow-up issues for non-blocking findings
Gate this step entirely if any of the following are true:
isai
(no review was performed)."off"- The merge in Step 8 did not actually happen (e.g.
mode with REQUEST CHANGES).ai - The review output contains no non-blocking findings.
Collect non-blocking findings from the review output retained from Step 7:
- Always include lines starting with
or[WARNING]
.[NOTE] - If
isai
, also include any"advisory"
lines — the user chose to merge over them, so they are now follow-up candidates too.[CRITICAL] - If
isai
, do not include"ai"
lines (there should not be any on the merge path, but guard anyway).[CRITICAL]
If the collected list is empty, skip the rest of this step silently.
Present and ask once. Show the findings as a numbered list (preserve the
[WARNING] / [NOTE] / [CRITICAL] prefix in the display for clarity) and ask exactly:
"The review flagged N non-blocking finding(s). Create follow-up issues for any of them? Enter numbers (e.g.
),1,3, orall."none
Accept: comma-separated numbers,
all, or none/skip/empty. If the input is unparseable, re-prompt once; if still invalid, treat as none and move on.
Create the selected issues. For each selected finding, run
gh issue create with explicit flags:
Use your file-writing tool (not Bash) to create
<tmpdir>/followup_body.md for each finding (same temp directory from Step 6):
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.
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 <tmpdir>/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.
Do not pass
--milestone — follow-ups are future work and should not inherit the current sprint.
Do not pass
--assignee @me — these are backlog items, not immediately assigned.
If a single
gh issue create call fails, report the failure for that finding and continue with the remaining selections.
Report the result:
- If one or more issues were created:
."Created N follow-up issue(s): #X, #Y, #Z" - If the user chose
or all creations were skipped: say nothing further, proceed to end.none
Important constraints
- Never skip
. A failed check is a hard stop.make check - When
isai
, never merge if the review verdict is REQUEST CHANGES."ai" - When
isai
, always merge after review completes, regardless of verdict."advisory" - When
isai
, skip the review agent entirely — merge immediately after checks pass."off"
merges only to/submit-for-review
— never directly todev
.main- If
fails for any reason, report it and stop — do not attempt workarounds.make merge - 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.