harness-release
Skill42 starsChanged 6 days agoMITView on GitHub
Generic release automation for projects using Keep a Changelog + GitHub. Single confirmation gate then end-to-end automation: bump detection, CHANGELOG promotion, PR/main merge, tag, GitHub Release. Trigger: release, version bump, publish. Do NOT load for: implementation, review, planning, setup.
- Commits and pushes
1 other project uses a version of this, 1 of them edited.
Adopted by
Most recently taken up by
- Chachamaru127/claude-code-harnessedited, first seen Oct 13, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 1
- Chachamaru127/claude-code-harness★ 3.2k15% same
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository32 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- agent-browserSkill
- authSkill
- ciSkill
- crudSkill
- deploySkill
- harness-acceptSkill
- harness-loopSkill
- harness-plan-briefSkill
- harness-planSkill
- harness-progressSkill
- harness-reviewSkill
- harness-setupSkill
- harness-syncSkill
- harness-workSkill
- maintenanceSkill
- memorySkill
- principlesSkill
- research-harness-auditSkill
- research-harness-cleanSkill
- research-harness-planSkill
- research-harness-releaseSkill
- research-harness-reviewSkill
- research-harness-setupSkill
- research-harness-workSkill
- session-controlSkill
- session-initSkill
- session-memorySkill
- sessionSkill
- session-stateSkill
- uiSkill
- workflow-guideSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
32 rules. About 0 are common, 15 are distinctive, and 17 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈15
Distinctive · estimate
This author's own choices. Worth a look.
17
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 38
Always output the following literal marker in the first response on bare invocation:
- Distinctive: line 56
Do not stop with "No tasks" or "Waiting for instructions."
- Very specific: line 60
Check git status --porcelain and git log @{upstream}..HEAD / main..HEAD to identify the target "work done so far"
- Very specific: line 61
Check .claude/state/review-result.json and .claude/state/review-approved.json to verify whether the target work has an APPROVEd review
- Very specific: line 62
When no APPROVEd review exists, confirm with AskUserQuestion
- Very specific: line 63
When user selects "Start from review," launch harness-review and do not proceed to release until APPROVE is returned
- Very specific: line 64
When harness-review returns REQUEST_CHANGES, hold the release, fix with harness-work, then re-run harness-review.
- Very specific: line 65
After harness-review returns APPROVE, create a work commit for the working tree
- Distinctive: line 66
After the working tree is clean, proceed to normal release preflight / confirmation gate / PR merge / tag / GitHub Release
- Very specific: line 70
When running harness-release and review approval cannot be confirmed, do not release by guessing.
- Very specific: line 84
When user selects "Start from review," start harness-review in the same session.
- Very specific: line 86
If review is APPROVE, return to the harness-release Work Commit Gate.
- Very specific: line 87
If review is REQUEST_CHANGES, hold release, fix with harness-work, then re-run harness-review.
- Distinctive: line 90
Only return to the user in these cases:
- Very specific: line 96
Do not use REQUEST_CHANGES alone as a final stop reason.
- Very specific: line 110
When unclear, present 2-3 commit message candidates with AskUserQuestion.
- Very specific: line 111
After creating the work commit, verify or update commit_hash in .claude/state/review-result.json, then proceed to release preflight.
- Distinctive: line 113
After entering normal release preflight, treat dirty working tree as failure as before.
- Distinctive: line 114
Do not proceed to version bump / tag / GitHub Release with a dirty tree.
- Distinctive: line 141
When these are not met, Preflight detects and aborts.
- Distinctive: line 219
When wanting to commit "work done so far" on bare release, complete the Review Gate and Work Commit Gate before this check.
- Distinctive: line 220
Do not abort and finish just because of an unreviewed dirty tree at this check.
- Distinctive: line 226
Search in this priority order.
- Very specific: line 285
Use --json for machine processing or CI:
- Very specific: line 310
When user explicitly specifies /release patch|minor|major, that takes priority.
- Very specific: line 318
Create the form with ## [<new>] - YYYY-MM-DD inserted between ## [Unreleased] and ## [<previous>]
- Distinctive: line 348
When all drafts are ready, present to user once:
- Distinctive: line 398
After the release commit in Post-Gate, merge the GitHub PR to the default branch before creating the tag.
- Distinctive: line 414
When an existing PR exists, update its body and merge without creating a new one.
- Distinctive: line 416
Create the tag after this Gate is complete, against HEAD of the default branch or a commit reachable from the release commit.
- Distinctive: line 434
Run all Pre-Gate steps and display content through Confirmation Gate, but stop at the gate without proceeding to Post-Gate.
- Very specific: line 480
Project-independent: No assumptions about VERSION file format, mirrors, residue checks etc.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Harness Release (Generic)
Generic release automation skill for any project using Keep a Changelog + GitHub.
Design principle: Single confirmation gate. The user sees and approves the full plan once. After approval, execution continues uninterrupted: file rewrite → commit → branch push → PR create/update → merge to default branch → tag on default branch → GitHub Release.
Definition of release complete: A release is not complete just by "creating a tag and GitHub Release." Complete means: the target work and release bump are merged into the default branch (usually main), the release tag points to a commit reachable from the default branch, and the GitHub Release is published against that tag.
Literal invocation note: The entry point for this skill uses literal commands as-is:
harness-release,/release,/release patch,/release --dry-run.
Bare invocation contract
if $ARGUMENTS == "": → Interpret as "commit work done so far and complete through PR/main merge before releasing," and run Review Gate detection → Auto-proceed to Step 0 (Review Gate) only when exactly one target work can be determined → When target is unclear or no review state exists, present options with AskUserQuestion before proceeding
Always output the following literal marker in the first response on bare invocation:
RELEASE_AUTOSTART: target=<work-summary>, base_ref=<ref>, mode=<patch|minor|major|auto>
Prohibited responses: "Task is unclear," "Waiting for instructions," "No tasks," "Waiting for additional instructions."
<!-- Above block is AUTO-START CONTRACT. Compliant with skill-editing.md "within first 3 lines" rule. patterns.md P27 solution triple (machine-readable condition + prohibited action literal + AUTOSTART marker) -->Output Contract (P35: "appears stuck" UX countermeasure)
The last line of skill output must always include this literal:
↑Claude will summarize this result. Press Enter to continue, or enter a new prompt for a different instruction.
This is an explicit instruction for the UX problem where text displayed via <local-command-stdout> makes users feel it has "stopped" (patterns.md P35).
harness-release / /release alone means "commit work done so far and release through PR/main merge."
The older phrasing "commit work done so far and release" has the same intent, but the completion condition must always include PR/main merge.
Do not stop with "No tasks" or "Waiting for instructions."
On bare release, run the Review Gate and Work Commit Gate before the normal release preflight.
- Check
git status --porcelainandgit log @{upstream}..HEAD/main..HEADto identify the target "work done so far" - Check
.claude/state/review-result.jsonand.claude/state/review-approved.jsonto verify whether the target work has anAPPROVEd review - When no APPROVEd review exists, confirm with
AskUserQuestion - When user selects "Start from review," launch
harness-reviewand do not proceed to release untilAPPROVEis returned - When
harness-reviewreturnsREQUEST_CHANGES, hold the release, fix withharness-work, then re-runharness-review. Loop untilAPPROVE. - After
harness-reviewreturnsAPPROVE, create a work commit for the working tree - After the working tree is clean, proceed to normal release preflight / confirmation gate / PR merge / tag / GitHub Release
Review Gate AskUserQuestion
When running harness-release and review approval cannot be confirmed, do not release by guessing.
Present the following Ask:
question: "harness-release will commit work done so far and release, but no APPROVE review was found for this work. How would you like to proceed?"
options:
- label: "Start from review (Recommended)"
description: "Run harness-review and proceed to commit/release only if APPROVE is returned."
- label: "release dry-run"
description: "No file changes; check only the release plan and missing gates."
- label: "Cancel"
description: "Stop without review or release."When user selects "Start from review," start harness-review in the same session.
Target determination in harness-review follows harness-review's own bare review contract.
If review is APPROVE, return to the harness-release Work Commit Gate.
If review is REQUEST_CHANGES, hold release, fix with harness-work, then re-run harness-review.
This post-fix re-review loop continues until APPROVE.
Only return to the user in these cases:
- Fix requires decisions about spec source of truth / Plans.md / API / permission / migration / billing etc., and
AskUserQuestionis needed - Multiple fix approaches exist where choice affects user value or compatibility
- User selected
release dry-runorCancelin Ask
Do not use REQUEST_CHANGES alone as a final stop reason.
Work Commit Gate
On bare release, when there are uncommitted changes in the working tree, create a reviewed work commit separately from the release version bump commit first.
git status --short
git diff --stat
git add <reviewed files>
git commit -m "<type>: <summary>"Generate commit message briefly from review summary / Plans.md task / branch name.
When unclear, present 2-3 commit message candidates with AskUserQuestion.
After creating the work commit, verify or update commit_hash in .claude/state/review-result.json, then proceed to release preflight.
After entering normal release preflight, treat dirty working tree as failure as before. Do not proceed to version bump / tag / GitHub Release with a dirty tree.
Quick Reference
/release # Review gate → commit → PR/main merge → release work done so far
/release patch # Explicitly specify bump as patch
/release minor # Explicitly specify bump as minor
/release major # Explicitly specify bump as major
/release --dry-run # Display plan only, do not executePrerequisites
Projects where this skill operates must satisfy:
CHANGELOG.mdin Keep a Changelog format[Unreleased]section exists- Has one of the following version files:
VERSION(standalone file)package.json(npm)pyproject.toml(Python,[project]or[tool.poetry])Cargo.toml(Rust,[package])
ghCLI installed and authenticated- Git remote
originpoints to GitHub - For Claude Code plugin projects:
claudeCLI supportsplugin tag
When these are not met, Preflight detects and aborts.
prUrlTemplate multi-host review URL is recognized as a future candidate, but this skill's release automation still uses gh CLI and GitHub remote as the primary path. Auto-retrieval of owner / branch / release asset / CI metadata has large host-by-host differences, so Phase 56.2.3 remains docs-only.
Single gate flow
[Bare release only: work review/commit pre-step]
↓
0. Review Gate (AskUserQuestion → harness-review if no review)
0.5 Work Commit Gate (commit review-APPROVEd work separately from release bump)
↓
[Pre-Gate: information collection only, no file changes]
↓
1. Preflight (working tree clean / CHANGELOG / gh etc. checks)
2. Version file auto-detection
3. Read current version
4. Claude plugin tag preflight (plugin projects only)
5. Parse [Unreleased] content → estimate bump level
6. Calculate new version
7. Create CHANGELOG diff draft (in memory)
8. Create GitHub Release notes draft (in memory)
★━━━━━━ Single Confirmation Gate ━━━━━━★
Present full plan to user once:
- Detected version file
- Current version → new version
- Bump determination reason (e.g., "minor because ### Added is in [Unreleased]")
- CHANGELOG change preview
- GitHub Release notes draft
- Files to commit
- Final actions (branch push + PR merge + tag + release publish)
User response:
"yes" → Proceed to Post-Gate
"<fix instruction>" → Regenerate draft per instruction, re-confirm
"cancel/no" → Do nothing and exit
★━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━★
↓
[Post-Gate: after approval, no interruption]
9. Rewrite version file
10. Rewrite CHANGELOG.md ([Unreleased] → [X.Y.Z] promotion + compare link)
11. git add + commit
12. Release branch push
13. PR create/update
14. Merge to default branch
15. Fetch/checkout default branch; verify release commit is reachable
16. Claude plugin tag validation + tag (plugin projects only)
17. GitHub Release semver tag (only for projects that need it)
18. git push origin <default-branch> --tags
19. gh release create vX.Y.Z
20. Completion reportPre-Gate details
1. Preflight
# Required tools
command -v gh >/dev/null || { echo "gh CLI not found"; exit 1; }
command -v python3 >/dev/null || { echo "python3 required"; exit 1; }
# Working tree
if [ -n "$(git status --porcelain)" ]; then
echo "Uncommitted changes in working tree"; exit 1;
fi
# CHANGELOG
[ -f CHANGELOG.md ] || { echo "CHANGELOG.md not found"; exit 1; }
grep -q "^## \[Unreleased\]" CHANGELOG.md || { echo "[Unreleased] section not found"; exit 1; }
# plugin/mirror projects
scripts/release-preflight.shThis working tree clean check is the gate for normal release preflight. When wanting to commit "work done so far" on bare release, complete the Review Gate and Work Commit Gate before this check. Do not abort and finish just because of an unreviewed dirty tree at this check.
scripts/release-preflight.sh also detects mirror drift in opencode/, skills-codex/, codex/.codex/skills/ before tag creation. When node scripts/build-opencode.js generates a diff, stop the release, commit that diff, then proceed to tag.
2. Version file auto-detection
Search in this priority order; use the first found as authoritative:
import os, json, re
import tomllib # Python 3.11+
def detect_version_file():
if os.path.exists("VERSION"):
with open("VERSION") as f:
return ("VERSION", f.read().strip(), None)
if os.path.exists("package.json"):
with open("package.json") as f:
data = json.load(f)
return ("package.json", data["version"], None)
if os.path.exists("pyproject.toml"):
with open("pyproject.toml", "rb") as f:
data = tomllib.load(f)
if "project" in data:
return ("pyproject.toml", data["project"]["version"], "[project]")
if "tool" in data and "poetry" in data["tool"]:
return ("pyproject.toml", data["tool"]["poetry"]["version"], "[tool.poetry]")
if os.path.exists("Cargo.toml"):
with open("Cargo.toml", "rb") as f:
data = tomllib.load(f)
return ("Cargo.toml", data["package"]["version"], "[package]")
raise RuntimeError("No supported version file found")Details: version-files.md
3. Claude Plugin Tag Preflight
For projects with .claude-plugin/plugin.json, create a Claude plugin release tag separately from the normal GitHub Release tag.
In short: before assembling git tag -a manually, pass Claude Code's own plugin validation and then create the {plugin-name}--v{version} tag.
Pre-Gate does not rewrite files; verify the following. Read version sync with structured parser, not grep/sed:
command -v claude >/dev/null || { echo "claude CLI not found"; exit 1; }
claude plugin validate .claude-plugin/plugin.json
HARNESS_PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-.}"
python3 "${HARNESS_PLUGIN_ROOT}/scripts/check-release-version-sync.py" --root .
claude plugin tag .claude-plugin --dry-run${HARNESS_PLUGIN_ROOT}/scripts/check-release-version-sync.py reads all existing release surfaces and determines canonical in the order VERSION > package.json > .claude-plugin/plugin.json > .codex-plugin/plugin.json.
Then it does not proceed to tag/release if any of the following have mismatches or are missing:
VERSIONpackage.json.version.claude-plugin/plugin.json.version.codex-plugin/plugin.json.version.claude-plugin/marketplace.json.metadata.version.claude-plugin/marketplace.json.plugins[].version(each plugin entry in the array)
On mismatch, show which surface differs from canonical or which field is missing/invalid.
Use --json for machine processing or CI:
python3 "${HARNESS_PLUGIN_ROOT}/scripts/check-release-version-sync.py" --root . --jsonThis check prevents 3 accidents:
- Cutting a tag with
VERSIONand.claude-plugin/plugin.jsonversion out of sync - Proceeding to release workflow with stale
package.json/ marketplace entry version - Getting stuck on plugin install/update side after skipping plugin manifest/marketplace entry validation
--dry-run shows the tag name claude plugin tag would create and the internal git tag -a / push equivalent command. Include the command shown here in the Confirmation Gate plan.
4. Bump auto-estimation
Parse headings directly under [Unreleased] to determine bump level:
| Headings in [Unreleased] | Estimated bump |
Contains ### Breaking Changes or ### Removed | major |
Contains ### Added (no Removed/Breaking) | minor |
Only ### Fixed / ### Changed / ### Security | patch |
| Empty section | error: no release target |
When user explicitly specifies /release patch|minor|major, that takes priority.
Details: bump-detection.md
5. CHANGELOG draft creation (in memory)
Calculate the following; do not write yet:
- Cut out body of
## [Unreleased] - Create the form with
## [<new>] - YYYY-MM-DDinserted between## [Unreleased]and## [<previous>] - Trailing compare link:
[Unreleased]: .../compare/v<prev>...HEAD→v<new>...HEAD- Add
[<new>]: .../compare/v<prev>...v<new>
- Dynamically extract repo URL from existing
[Unreleased]:line
6. Release notes draft creation (in memory)
Generate GitHub Release markdown from the ## [<new>] section content:
## What's Changed
**<release theme (1 line)>**
### Before / After
<table>
### Added / Changed / Fixed / Removed
<copy applicable sections>
---
🤖 Generated with [Claude Code](https://claude.com/claude-code)Details: release-notes.md
Confirmation Gate
When all drafts are ready, present to user once:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Release Plan: v<old> → v<new> (<bump>)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Version file: <detected file>
Bump reason: <why this level was chosen>
CHANGELOG changes:
<N> changes detected in [Unreleased]
Confirmed as [<new>] - YYYY-MM-DD
Compare link added
GitHub Release notes preview:
<first 10 lines>
...
Files to modify:
- <version file>
- CHANGELOG.md
Final actions:
- git commit -m "chore: release v<new>"
- git push origin <release-branch>
- gh pr create/update + gh pr merge into <default-branch>
- git fetch origin <default-branch> && git checkout <default-branch>
- claude plugin tag .claude-plugin --push --remote origin # plugin projects only; run on default branch
- git tag -a v<new> # GitHub Release semver tag if needed; create on default branch
- git push origin <default-branch> --tags
- gh release create v<new>
Proceed? [yes / cancel / <fix instruction>]Post-Gate details
Execute without interruption after approval. On failure, follow this policy:
| Failure point | Recovery |
| File rewrite failure | Abort there; local is left dirty for human judgment |
| Commit failure | Hook rejection etc. Present cause to user and prompt for fix |
| PR create/merge failure | Stop as incomplete release; do not proceed to tag/GitHub Release |
| Plugin tag validation failure | Fix VERSION / .claude-plugin/plugin.json / marketplace entry mismatch; do not proceed to tag creation |
| Push failure | Remote-side issue. Local commit/tag remains. |
gh release create failure | Tag is already pushed; existing release.yml safety net may fire, or run gh release create manually |
PR / Main Merge Gate
After the release commit in Post-Gate, merge the GitHub PR to the default branch before creating the tag.
release_branch="$(git branch --show-current)"
default_branch="${HARNESS_RELEASE_DEFAULT_BRANCH:-main}"
git push -u origin "$release_branch"
gh pr create --base "$default_branch" --head "$release_branch" --title "chore: release v<new>" --body "<release summary>"
gh pr merge --merge --delete-branch=false
git fetch origin "$default_branch" --tags
git checkout "$default_branch"
git pull --ff-only origin "$default_branch"
git merge-base --is-ancestor "<release-commit>" "origin/$default_branch"When an existing PR exists, update its body and merge without creating a new one. When repository policy requires squash merge, verify that release bump content (version files + CHANGELOG + source commits) is included in the default branch — not just the release commit hash.
Create the tag after this Gate is complete, against HEAD of the default branch or a commit reachable from the release commit. Do not create a GitHub Release with a tag pointing to a commit that exists only on the release branch.
Claude plugin project tag creation
For projects with .claude-plugin/plugin.json, verify version sync on the default branch once more after PR/main merge, then create the plugin tag:
HARNESS_PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-.}"
python3 "${HARNESS_PLUGIN_ROOT}/scripts/check-release-version-sync.py" --root .
claude plugin tag .claude-plugin --dry-run
claude plugin tag .claude-plugin --push --remote originThe tag claude plugin tag creates is in {plugin-name}--v{version} format. For projects where existing GitHub Release workflows assume a vX.Y.Z tag, also create git tag -a v<new> separately from the plugin tag. Let claude plugin tag handle distribution tags; treat the GitHub Release semver tag as a compatible release automation surface.
--dry-run mode
Run all Pre-Gate steps and display content through Confirmation Gate, but stop at the gate without proceeding to Post-Gate.
For Claude plugin projects, even in dry-run, execute python3 "${HARNESS_PLUGIN_ROOT}/scripts/check-release-version-sync.py" --root . and claude plugin tag .claude-plugin --dry-run to show the actual plugin tag name to be created and push targets. If any version surfaces in VERSION / package.json / .claude-plugin/plugin.json / .codex-plugin/plugin.json / .claude-plugin/marketplace.json are mismatched or missing, stop at dry-run time.
Environment variables
For per-project adjustments:
| Variable | Description |
HARNESS_RELEASE_PROJECT_ROOT | Repository root (default: $(pwd)) |
HARNESS_RELEASE_BRANCH | Branch to push (default: current branch) |
HARNESS_RELEASE_DEFAULT_BRANCH | Default branch for PR merge target (default: main) |
HARNESS_RELEASE_HEALTHCHECK_CMD | Additional command to run in Preflight |
HARNESS_RELEASE_SKIP_GH | 1 skips GitHub Release creation |
CHANGELOG writing rules
The [Unreleased] section must always have one of these subsections:
## [Unreleased]
### Added ← minor
### Changed ← patch
### Deprecated ← minor
### Removed ← major
### Fixed ← patch
### Security ← patch
### Breaking Changes ← major (non-standard in KaCL but common)This skill parses these headings mechanically, so heading variations (### Fix / ### Bug Fixes etc.) cannot be recognized. Use standard KaCL headings.
Related skills
harness-release-internal- Harness-specific preflight/finalization run additionally for claude-code-harness itself (not distributed)harness-plan- Plans.md managementharness-review- Code review before release
Design philosophy
- Single gate: User makes one judgment per release. Multiple mini-confirmations become rubber-stamps and lose meaning.
- Draft everything upfront: No "reconsideration" after entering Post-Gate. Assemble all drafts before the gate.
- Main merge is the completion condition: Release tag / GitHub Release only created after default branch merge. Branch-only releases are treated as incomplete.
- Failures are transparent: On mid-execution failure, do not attempt auto-rollback; present the current state to the user for judgment.
- Project-independent: No assumptions about VERSION file format, mirrors, residue checks etc. specific to certain environments. Harness-specific processing for the main harness is separated into
harness-release-internal.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

