Skip to content
Back to skills

Cut Release

ASecurity

Cut a new Fabrik release — gathers changes since last tag, writes release notes, delegates publication to scripts/cut-release.sh

  • 22 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 19, 2026
ai-agentsrustgobashgitapi

Works with

  • api

Security analysis

A100/100

Scanned September 19, 2026

npx -y skills add handarbeit/fabrik --skill cut-release --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Cut Release?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Cut Release
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/handarbeit-cut-release/badge)](https://www.skillsdirectory.com/skills/handarbeit-cut-release)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: cut-release
description: Cut a new Fabrik release — gathers changes since last tag, writes release notes, delegates publication to scripts/cut-release.sh
user_invocable: true
---

# Cut Release

Cut a new Fabrik release. Your job is to **author the release notes**; `scripts/cut-release.sh` does everything else (commit, tag, push as @arbeithand, watch workflow, verify identity, file doc-update issue).

## Usage

Invoked as `/cut-release` or `/cut-release v0.0.67`. If no version is provided, suggest the next patch bump from the current latest tag.

## Steps

### 1. Determine version

- Find the latest tag: `git describe --tags --abbrev=0`
- If a version arg was provided, validate semver with `v` prefix and that it's greater than the latest tag.
- If no version arg, suggest the next patch bump and proceed.

### 2. Author release notes

This is the part requiring judgment — do not delegate it.

- `git log <last-tag>..HEAD --oneline` to enumerate commits since the last release.
- Group user-facing changes by category: **Features**, **Fixes**, **Improvements**, **Internal**. Omit empty sections.
- Ignore merge commits and `Co-Authored-By` lines.
- Collapse internal churn into a single line under **Internal**. Don't enumerate refactors / test additions.
- Write the notes to `release-notes/<version>.md` (one file per release, archived in-tree). The release workflow reads this path directly via `${{ github.ref_name }}` — there is no repo-root `release-notes.md` and you should not create one (it is `.gitignore`d).

Use this schema:

```markdown
# Fabrik <version>

## Summary

<1-3 sentences. Punchy headline themes only. This block is what the Discussions
announcement post will contain — everything else lives on the GitHub Release page.>

## Features
- Description (#issue)

## Fixes
- Description (#issue)

## Improvements
- Description (#issue)

## Internal
- One-line summary of internal churn

## Upgrading

\```bash
# Auto-upgrade from a running Fabrik instance
# Fabrik checks for new releases each poll cycle and upgrades automatically with --auto-upgrade

# Or download directly (auto-detects OS and architecture)
gh release download --repo handarbeit/fabrik \
  --pattern "fabrik_*_$(uname -s | tr A-Z a-z)_$(uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/').tar.gz" \
  -O - | tar xz
\```
```

**Both the `# Fabrik <version>` heading and the `## Summary` section are required.** The script validates both and refuses to proceed on either failure.

**Sizing the Summary.** This block IS the Discussions announcement body. Aim for somewhere between a short paragraph (50–80 words for a patch release) and a few themed bullets (~150–250 words for a release with multiple headline features). It should read as a standalone announcement — someone scanning the Discussions feed should immediately understand what shipped and roughly what it does.

What to include:
- The headline theme(s) — what this release is *about*. For a multi-feature release, list 2–4 themed bullets.
- Enough context that each theme is meaningful on its own (one sentence of "what" + one of "why it matters" is usually right per theme).

What NOT to include:
- The full Features/Fixes/Improvements bullets that already live below — the announcement links to the full release page for that.
- Internal/test/refactor details.
- Implementation specifics (issue numbers belong in the body sections, not the Summary).

A one-line tagline is too terse. A duplicate of the body sections is too long. Aim for "the elevator pitch."

### 3. Run the publish script

```bash
scripts/cut-release.sh v0.0.67
```

The script handles, in order:
1. **Pre-flight** — on main; ff'd to origin/main; tag `<version>` not already taken locally or on origin; `release-notes/<version>.md` exists, heading is exactly `# Fabrik <version>`, and contains a `## Summary` section. Working tree must be clean except for `release-notes/<version>.md` (either untracked or modified) — any other dirty file aborts.
2. **PAT identity check** — reads `FABRIK_TOKEN` from `.env`; aborts unless `gh api user` resolves to `@arbeithand`.
3. `go build ./...` and `go test -race ./...`. Skippable only via `--skip-tests` (last resort).
4. Stages `release-notes/<version>.md` and commits it with `GIT_AUTHOR_*` + `GIT_COMMITTER_*` env vars so the commit is `arbeithand <handarbeit@handarbeit.io>`. Verifies the resulting `%an <%ae>` matches; aborts otherwise.
5. Pushes the release-notes commit, then tags and pushes the tag — both with `credential.helper=` and `credential.https://github.com.helper=` nuked, plus PAT-in-URL. This is the exact incantation needed on this machine to push as the bot rather than the default `gh auth` identity.
6. Polls for the release workflow run, watches it, and **explicitly re-checks** `conclusion == "success"` via `gh run view` (the `--exit-status` flag alone is not trusted).
7. **Hard identity verification** — fetches `release.author.login` and the latest Discussion's `author.login`. **Aborts loudly** if either is not `arbeithand`, with a pointer to rotate the `PUBLIC_REPO_RELEASE_TOKEN` repo secret (root cause of every wrong-identity recurrence so far).
8. Files the doc-update issue and adds it to project #1 at Status=Specify with `fabrik:yolo` — all authored by `arbeithand` via the PAT.

Flags:
- `--skip-tests` — skip the race-tested suite (use only if it's already known-green from a recent run).
- `--no-doc-issue` — skip the doc-update issue creation.

### 4. Report back

If the script exits 0, the release is live and verified. Report:
- "✅ Release v0.0.67 published to handarbeit/fabrik — release + announcement authored by @arbeithand. Doc-update issue #<n> filed at Specify."

If the script exits non-zero, surface the script's last error message verbatim. Do NOT attempt to repair the half-published state automatically — the script intentionally avoids destructive cleanup. The cleanup commands are commented at the bottom of the script for reference; relay them to the user and ask how they want to proceed.

## Important

- **Never edit `scripts/cut-release.sh` to bypass a check** — every guard exists because something failed once. The bot-identity guards in particular took three deletion-and-republish cycles to diagnose (the workflow secret `PUBLIC_REPO_RELEASE_TOKEN` is the root cause when the wrong-identity attribution bug recurs).
- **The script is bot-only** — only someone with the `arbeithand` PAT (i.e., the handarbeit/fabrik publisher) can use it. Fork maintainers cutting their own fork releases would need to parameterize the constants at the top.
- **Authoring release notes is the AI's job; everything else is the script's.** Don't reinvent the publication mechanics inline — past attempts at that produced wrong-identity releases that had to be cleaned up.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.