Use when releasing CLI tools and binary artifacts - generates cross-platform build workflows, checksum files, and changelog-based release notes. Supports Go, Rust, Node.js (pkg), Python (PyInstaller), and pre-built binaries.
/plugin marketplace add jrc1883/popkit-claude/plugin install popkit@popkit-marketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
checklists/release.jsonscripts/create_release.pyscripts/upload_assets.pyConfigure GitHub Releases for CLI tools and binary artifacts. Generates cross-platform build workflows, checksum files, and automated release notes.
Core principle: Every release should be reproducible and verifiable.
Trigger: /popkit:deploy setup github-releases command
import os
import json
from pathlib import Path
def detect_release_type():
"""Detect project type for release configuration."""
cwd = Path.cwd()
# Check for Go
if (cwd / "go.mod").exists():
return "go"
# Check for Rust
if (cwd / "Cargo.toml").exists():
return "rust"
# Check for Python CLI
if (cwd / "pyproject.toml").exists():
with open(cwd / "pyproject.toml", "rb") as f:
import tomllib
pyproject = tomllib.load(f)
if "scripts" in pyproject.get("project", {}):
return "python-cli"
return "python"
# Check for Node.js CLI
if (cwd / "package.json").exists():
with open(cwd / "package.json") as f:
pkg = json.load(f)
if "bin" in pkg:
return "node-cli"
return "node"
return "generic"
Use AskUserQuestion tool with:
- question: "What type of release are you configuring?"
- header: "Release Type"
- options:
- label: "CLI Binary (Recommended)"
description: "Cross-platform binaries with checksums"
- label: "Library/Package"
description: "Integrate with npm/PyPI publish workflows"
- label: "Pre-built Assets"
description: "Upload existing build artifacts"
- multiSelect: false
Use AskUserQuestion tool with:
- question: "Which platforms should we build for?"
- header: "Platforms"
- options:
- label: "All platforms (Recommended)"
description: "linux, macos, windows × amd64, arm64"
- label: "Linux + macOS"
description: "Unix-like systems only"
- label: "Linux only"
description: "Server/container deployments"
- multiSelect: false
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
cache: true
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# .goreleaser.yaml
version: 2
project_name: my-cli
before:
hooks:
- go mod tidy
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- darwin
- windows
goarch:
- amd64
- arm64
ldflags:
- -s -w
- -X main.version={{.Version}}
- -X main.commit={{.Commit}}
- -X main.date={{.Date}}
binary: '{{ .ProjectName }}'
archives:
- format: tar.gz
name_template: >-
{{ .ProjectName }}_
{{- .Version }}_
{{- .Os }}_
{{- .Arch }}
format_overrides:
- goos: windows
format: zip
files:
- README.md
- LICENSE
checksum:
name_template: 'checksums.txt'
algorithm: sha256
changelog:
sort: asc
use: github
filters:
exclude:
- '^docs:'
- '^test:'
- '^chore:'
groups:
- title: Features
regexp: '^feat'
order: 0
- title: Bug Fixes
regexp: '^fix'
order: 1
- title: Performance
regexp: '^perf'
order: 2
- title: Others
order: 999
release:
github:
owner: '{{ .Env.GITHUB_REPOSITORY_OWNER }}'
name: '{{ .ProjectName }}'
draft: false
prerelease: auto
mode: replace
header: |
## {{ .ProjectName }} {{ .Version }}
Welcome to this release!
footer: |
## Checksums
```
{{ .Checksums }}
```
**Full Changelog**: https://github.com/{{ .Env.GITHUB_REPOSITORY }}/compare/{{ .PreviousTag }}...{{ .Tag }}
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
permissions:
contents: write
jobs:
build:
strategy:
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
- target: x86_64-apple-darwin
os: macos-latest
- target: aarch64-apple-darwin
os: macos-latest
- target: x86_64-pc-windows-msvc
os: windows-latest
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-action@stable
with:
targets: ${{ matrix.target }}
- name: Build
run: cargo build --release --target ${{ matrix.target }}
- name: Archive (Unix)
if: matrix.os != 'windows-latest'
run: |
cd target/${{ matrix.target }}/release
tar czvf ../../../my-cli-${{ matrix.target }}.tar.gz my-cli
cd ../../..
sha256sum my-cli-${{ matrix.target }}.tar.gz > my-cli-${{ matrix.target }}.tar.gz.sha256
- name: Archive (Windows)
if: matrix.os == 'windows-latest'
run: |
cd target/${{ matrix.target }}/release
7z a ../../../my-cli-${{ matrix.target }}.zip my-cli.exe
cd ../../..
certutil -hashfile my-cli-${{ matrix.target }}.zip SHA256 > my-cli-${{ matrix.target }}.zip.sha256
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: binary-${{ matrix.target }}
path: |
*.tar.gz
*.zip
*.sha256
release:
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: true
- name: Generate changelog
id: changelog
uses: orhun/git-cliff-action@v3
with:
args: --latest --strip header
- name: Create Release
uses: softprops/action-gh-release@v2
with:
body: ${{ steps.changelog.outputs.content }}
files: |
artifacts/*
draft: false
prerelease: ${{ contains(github.ref, '-') }}
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
permissions:
contents: write
jobs:
build:
strategy:
matrix:
include:
- os: ubuntu-latest
target: node18-linux-x64
ext: ''
- os: ubuntu-latest
target: node18-linux-arm64
ext: ''
- os: macos-latest
target: node18-macos-x64
ext: ''
- os: macos-latest
target: node18-macos-arm64
ext: ''
- os: windows-latest
target: node18-win-x64
ext: '.exe'
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Package binary
run: npx pkg . --target ${{ matrix.target }} --output my-cli${{ matrix.ext }}
- name: Archive (Unix)
if: matrix.os != 'windows-latest'
run: |
tar czvf my-cli-${{ matrix.target }}.tar.gz my-cli
sha256sum my-cli-${{ matrix.target }}.tar.gz > my-cli-${{ matrix.target }}.tar.gz.sha256
- name: Archive (Windows)
if: matrix.os == 'windows-latest'
run: |
7z a my-cli-${{ matrix.target }}.zip my-cli.exe
certutil -hashfile my-cli-${{ matrix.target }}.zip SHA256 > my-cli-${{ matrix.target }}.zip.sha256
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: binary-${{ matrix.target }}
path: |
*.tar.gz
*.zip
*.sha256
release:
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: true
- name: Generate release notes
id: notes
run: |
echo "## What's Changed" > notes.md
git log $(git describe --tags --abbrev=0 HEAD^)..HEAD --pretty=format:"- %s" >> notes.md
echo "" >> notes.md
echo "## Checksums" >> notes.md
echo '```' >> notes.md
cat artifacts/*.sha256 >> notes.md
echo '```' >> notes.md
- name: Create Release
uses: softprops/action-gh-release@v2
with:
body_path: notes.md
files: |
artifacts/*
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
permissions:
contents: write
jobs:
build:
strategy:
matrix:
include:
- os: ubuntu-latest
artifact: my-cli-linux-x64
- os: macos-latest
artifact: my-cli-macos-x64
- os: windows-latest
artifact: my-cli-windows-x64.exe
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pyinstaller
pip install -e .
- name: Build with PyInstaller
run: pyinstaller --onefile --name ${{ matrix.artifact }} src/my_cli/__main__.py
- name: Archive (Unix)
if: matrix.os != 'windows-latest'
run: |
cd dist
tar czvf ../${{ matrix.artifact }}.tar.gz ${{ matrix.artifact }}
cd ..
sha256sum ${{ matrix.artifact }}.tar.gz > ${{ matrix.artifact }}.tar.gz.sha256
- name: Archive (Windows)
if: matrix.os == 'windows-latest'
run: |
cd dist
7z a ../${{ matrix.artifact }}.zip ${{ matrix.artifact }}
cd ..
certutil -hashfile ${{ matrix.artifact }}.zip SHA256 > ${{ matrix.artifact }}.zip.sha256
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: binary-${{ matrix.artifact }}
path: |
*.tar.gz
*.zip
*.sha256
release:
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: true
- name: Create Release
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
files: |
artifacts/*
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag:
description: 'Tag to release'
required: true
type: string
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build artifacts
run: |
# Your build commands here
./build.sh
- name: Generate checksums
run: |
cd dist
sha256sum * > checksums.txt
- name: Generate changelog
id: changelog
uses: orhun/git-cliff-action@v3
with:
args: --latest --strip header
- name: Create Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ inputs.tag || github.ref_name }}
body: |
${{ steps.changelog.outputs.content }}
## Checksums
```
$(cat dist/checksums.txt)
```
files: |
dist/*
draft: false
prerelease: ${{ contains(github.ref, '-') }}
# cliff.toml - Changelog generation
[changelog]
header = """
# Changelog\n
All notable changes to this project will be documented in this file.\n
"""
body = """
{% if version %}\
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
## [unreleased]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}
{% for commit in commits %}
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
{{ commit.message | upper_first }}\
{% endfor %}
{% endfor %}\n
"""
footer = """
{% for release in releases -%}
{% if release.version -%}
{% if release.previous.version -%}
[{{ release.version | trim_start_matches(pat="v") }}]: \
https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\
/compare/{{ release.previous.version }}...{{ release.version }}
{% endif -%}
{% else -%}
[unreleased]: https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\
/compare/{{ release.previous.version }}...HEAD
{% endif -%}
{% endfor %}
"""
trim = true
[git]
conventional_commits = true
filter_unconventional = true
commit_parsers = [
{ message = "^feat", group = "Features" },
{ message = "^fix", group = "Bug Fixes" },
{ message = "^doc", group = "Documentation" },
{ message = "^perf", group = "Performance" },
{ message = "^refactor", group = "Refactor" },
{ message = "^style", group = "Styling" },
{ message = "^test", group = "Testing" },
{ message = "^chore\\(release\\)", skip = true },
{ message = "^chore", group = "Miscellaneous Tasks" },
]
filter_commits = false
tag_pattern = "v[0-9]*"
GitHub Releases Setup
═════════════════════
[1/4] Detecting project type...
✓ Detected: Go CLI
✓ Binary: my-cli
✓ Version: from ldflags
[2/4] Release configuration...
✓ Type: CLI Binary
✓ Platforms: linux, macos, windows × amd64, arm64
✓ Checksums: SHA256
[3/4] Generating workflows...
✓ GoReleaser configuration
✓ Release workflow (on tag push)
→ .goreleaser.yaml
→ .github/workflows/release.yml
[4/4] Generating changelog config...
→ cliff.toml created (git-cliff)
Files Created:
├── .goreleaser.yaml
├── .github/workflows/release.yml
└── cliff.toml
Release Process:
1. git tag v1.0.0
2. git push --tags
3. GitHub Actions builds and creates release
Artifacts per release:
- my-cli_1.0.0_linux_amd64.tar.gz
- my-cli_1.0.0_linux_arm64.tar.gz
- my-cli_1.0.0_darwin_amd64.tar.gz
- my-cli_1.0.0_darwin_arm64.tar.gz
- my-cli_1.0.0_windows_amd64.zip
- checksums.txt
Would you like to commit these files?
The deploy command works with /popkit:git release:
# Create release with changelog
/popkit:git release create v1.0.0
# This triggers:
# 1. Creates git tag v1.0.0
# 2. Pushes tag to origin
# 3. GitHub Actions runs release.yml
# 4. Builds artifacts for all platforms
# 5. Creates GitHub Release with changelog
# 6. Uploads artifacts + checksums
After generation, verify:
| Check | Command |
|---|---|
| Workflow syntax | gh workflow view release.yml |
| GoReleaser config | goreleaser check |
| Test build locally | goreleaser build --snapshot --clean |
| Test release dry-run | goreleaser release --snapshot --clean |
Command: /popkit:deploy setup github-releases
Agent: Uses devops-automator for release configuration
Related:
/popkit:git release - Create releases/popkit:git release changelog - Generate changelog| Skill | Relationship |
|---|---|
pop-deploy-init | Run first to configure targets |
pop-deploy-npm | For npm package releases |
pop-deploy-pypi | For PyPI package releases |
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.