On this page
Release Manager
Create and manage release PRs against master branch. Handles the full release workflow including merging release into master, version bumping in pyproject.toml, running uv lock, and creating GitHub releases.
Overview
Create and manage release PRs against master branch. Handles the full release workflow including merging release into master, version bumping in pyproject.toml, running uv lock, and creating GitHub releases.
This skill ships inside the Backend Release Manager plugin and can be installed through the Claude Code marketplace or directly in Codex from its skill path.
Parent Surface
Parent docs: Backend Release Manager
Related wrapper commands from the parent plugin:
/backend-release:check/backend-release:create/backend-release:publish When to Use This Skill
- Creating promotion PRs from dev → release to deploy staging
- Creating release PRs from release → master to deploy production
- Preparing hotfix releases
- Bumping versions in pyproject.toml
- Resolving merge conflicts between branches
- Publishing GitHub releases after PRs are merged
- Checking what commits are pending promotion or release
Branch Model
feature PRs
│ merge to dev (validation only, no deploy)
▼
dev ── integration branch
│ promotion PR (dev → release) → staging deploy
▼
release ── staging promotion branch
│ release PR (release → master) → production deploy
▼
master ── production branch Core Workflow
Before a production release, promote changes from the integration branch to the staging branch. This is the ONLY path that triggers staging deploy.
First principles — why two phases?
The old model deployed staging on every merge to release:
This was noisy and expensive. The new model separates concerns:
Routine feature PRs merge into dev where CI validates but never deploys. Only a human opening a dev → release promotion PR triggers staging deploy. This means:
and believe they're ready for staging"
not full run_staging_deploy
After merge: Validate staging. If issues are found, fix them on dev and create a new promotion PR. Do not fix directly on release — release should only receive changes through promotion PRs.
git diff --stat compares the actual tree state (file contents), not commit history. It is the only reliable way to determine whether there is something to release. If the output is empty, there is nothing to release — stop here.
If there ARE differences, identify which PRs they belong to. Use GitHub's PR metadata (merge timestamps), not git commit ancestry:
Why the release PR's mergedAt instead of publishedAt? GitHub release publishedAt is when a human clicks "Publish" — which can be minutes or hours after the release PR actually merges. PRs merged to release in that gap would be missed on the next check. The release PR's mergedAt is the definitive cutoff because git merge origin/release captures the exact state of the release branch at that moment.
Why GitHub metadata instead of git log? All git log-based approaches (master..release, --cherry-pick, --first-parent with tags) can return stale results due to historical cherry-pick artifacts and because release tags live on master's ancestry, not release's first-parent chain. PR merge timestamps from GitHub are immune to git ancestry issues.
Merge the release branch into a branch from master. This preserves commit ancestry so that git log master..release works correctly after the PR merges.
Why merge instead of cherry-pick? Cherry-picking creates new commits with different SHAs. Even with merge-back, git log master..release permanently shows the original commits as "pending" because git compares SHAs, not patches. Merging preserves the original commit objects so master and release share the same ancestry. After the release PR merges to master, git log master..release correctly shows only genuinely new commits.
See detailed-procedures.md for:
This step is mandatory after every release PR merge. It keeps all three branches in sync so future work starts from a consistent baseline.
First principles — why sync all three?
After a production release, the branches look like this:
The sync cascade fixes this:
Without syncing to release: the next release PR sees a stale diff (git diff --stat origin/master origin/release shows the version bump as "pending") and the release merge conflicts on pyproject.toml/uv.lock.
Without syncing to dev: the integration branch drifts from production, and subsequent feature branches are developed against code that doesn't match what's actually running in production.
- Fewer staging deploys — only when someone intentionally promotes
- Clearer intent — the promotion PR says "I've reviewed these changes and believe they're ready for staging"
- Lower CI cost — dev merges run run_tests (classifier-derived flags), not full run_staging_deploy
- Version numbering conventions (YYYY.MM.DD[-N])
- PR title patterns (Promotion, Release, Hotfix)
- Resolving merge conflicts
- Publishing GitHub releases (merge strategy, verification, creation)
git fetch origin dev release
git diff --stat origin/release origin/dev
git checkout -b promote/YYYY.MM.DD[-N] origin/release
git merge origin/dev --no-edit
git push -u origin promote/YYYY.MM.DD[-N]
gh pr create --base release --title "Promotion: DDth Month YYYY" --body "..." old: feature PR → release → staging deploy (every merge!) Pre-Release Checks
Before creating a release PR, verify:
If it fails, fix with:
before final release readiness.
- Detect in this order unless repo docs/CI differ:
- ty (mandatory if configured)
- pyright
- mypy
- Run on touched paths at minimum, and run any repo-required broad gate before final release readiness.
./.security/ruff_pr_diff.sh .bin/ruff format <file> Resources
Declared allowed tools:
BashReadEditGrepGlob References
detailed-procedures.md
Installation
Switch between Claude Code and Codex, then copy the install command for the runtime you use.
claude plugin marketplace add DiversioTeam/agent-skills-marketplace
claude plugin install backend-release@diversiotech CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
python3 "$CODEX_HOME/skills/.system/skill-installer/scripts/install-skill-from-github.py" \
--repo DiversioTeam/agent-skills-marketplace \
--path plugins/backend-release/skills/release-manager Invocation:
/backend-release:check
/backend-release:create
/backend-release:publish name: release-manager