CodeCannon deploy

Code Cannon: Bump the project version, create a GitHub Release, and promote to production — handles both versioning and releasing in one step

install
source · Clone the upstream repo
git clone https://github.com/LightbridgeLab/CodeCannon
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/LightbridgeLab/CodeCannon "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.agents/skills/deploy" ~/.claude/skills/lightbridgelab-codecannon-deploy && rm -rf "$T"
manifest: .agents/skills/deploy/SKILL.md
source content

Codex CLI: This skill is triggered by description matching. State any arguments in your message. Sub-agent spawning is not supported — perform any review steps inline.


What
/deploy
does

/deploy
is the final step in the workflow. It combines version bumping and release creation into a single command: check state, optionally bump the version, then create a GitHub Release (and in multi-branch mode, promote to production).


Step 1 — Verify branch

Run:

git branch --show-current

Required branch:

dev
(two-branch mode).

If not on the required branch, abort and say: "Switch to

<required-branch>
before running
/deploy
."

Pull the latest changes before proceeding:

git pull

Step 2 — Check current state

Find the latest version tag

git describe --tags --abbrev=0 2>/dev/null

If no tag exists, note this is the first release.

Read current version

cat VERSION

Show commits since last tag

If a previous tag exists, show what's on the branch since that tag:

git log main..dev --merges --pretty=format:"%s"

Parse PR numbers from merge commit subjects (format:

Merge pull request #N from branch/name
).

For each PR number found, retrieve the PR body:

gh pr view <N> --json number,title,body

Extract

Issue #N
and
Closes #N
references from PR bodies. Compile:

  • List of PRs included (number + title)
  • List of issues linked to those PRs

Check for open unmerged PRs

gh pr list --state open --json number,title,headRefName --jq '.[] | "#\(.number) \(.title) (\(.headRefName))"'

Present the summary

Tell the user:

Current version: X.Y.Z
Latest tag: vX.Y.Z

Commits/PRs since last tag:
  #17 — Add /docs directory
  #18 — Fix checkout runtime error

Open PRs not yet merged:
  #19 — Add dark mode (feature/dark-mode)

Would you like to bump the version before deploying?
  - **patch** → X.Y.C
  - **minor** → X.B.0
  - **major** → A.0.0
  - **specific** → enter a version number
  - **skip** → proceed to release with the latest existing tag

Wait for their response.


Step 3 — Version bump (if requested)

If the user chose to skip, find the latest version tag in the branch history:

git describe --tags --abbrev=0 2>/dev/null

If no tag is found at all (first release), warn: "No version tag found. You must bump the version before deploying." Return to the version bump prompt. Otherwise, use the tag found as the release version.

If the user chose a bump level, map their response to a command:

User saysRun
"patch" / anything mentioning patch
make bump-patch
"minor"
make bump-minor
"major"
make bump-major
A specific version e.g. "2.4.5"
make set-version V= 2.4.5

These commands update the version manifest, create a git commit, and create a git tag. Do not create commits or tags manually.

Push the version bump:

git push
git push --tags

Both the version bump commit and the tag must be pushed.


Step 4 — Compute release contents

Determine the version tag (either from the bump just performed, or from the existing HEAD tag if the user skipped bumping).

Find the previous tag to determine the range:

git describe --abbrev=0 <version-tag>^ 2>/dev/null

Use the PR/issue list already computed in Step 2. If the version bump added new commits, re-fetch if needed.


Step 5 — HUMAN GATE

Show the user the release summary. Example format:

Ready to release vX.Y.Z to production.

PRs included:
  #17 — Add /docs directory
  #18 — Fix checkout runtime error

Issues that will close:
  #14 — Add /docs directory
  #15 — Fix checkout runtime error

Have you tested all of the above on preview? Type 'release' to confirm.

Wait for the user to type "release" or an explicit confirmation. Any other response → stop and ask what they'd like to change.


Step 6 — Create PR:
dev
main

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 (not Bash) to create

<tmpdir>/release_pr_body.md
:

Release vX.Y.Z

PRs included:
- #17 — Add /docs directory
- #18 — Fix checkout runtime error

Closes #14
Closes #15

Then create the PR (do NOT use

--body
,
--body-file -
, or heredocs):

gh pr create --base main --head dev \
  --title "Release vX.Y.Z" \
  --body-file <tmpdir>/release_pr_body.md

Note the PR number from the output.

The

Closes #N
lines will auto-close the linked issues because this PR merges into
main
(the default branch).

Critical: Use the unqualified

#N
form only. Never write
Closes owner/repo#N
, even for same-repo refs — GitHub's closing-keyword parser only populates
closingIssuesReferences
for the unqualified form, and the qualified form silently breaks auto-close.


Step 7 — Merge

Do NOT use

make merge
— it refuses PRs targeting
main
. Use
gh pr merge
directly:

gh pr merge <pr-number> --merge

Step 8 — Create GitHub Release

The version tag (from Step 3) and the PR/issue list (from Step 4) are already known. Find the previous tag to build the changelog link:

git describe --abbrev=0 <version-tag>^ 2>/dev/null

If no previous tag exists, omit the "Full changelog" line.

Use your file-writing tool (not Bash) to create

<tmpdir>/release_notes.md
(same temp directory from Step 6):

## 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>

Then create the release (do NOT use

--notes
,
--notes-file -
, or heredocs):

gh release create <version-tag> \
  --title "<version-tag>" \
  --notes-file <tmpdir>/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.

After the command runs, note the release URL from the output.


Step 9 — Report

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.py | skill: deploy | adapter: codex | hash: 1a6fd564 | DO NOT EDIT — run CodeCannon/sync.py to regenerate -->