skills/local/cali-github-releases/SKILL.md
Create GitHub releases following project conventions. Triggers when: user says 'release', 'create release', 'push release', 'deploy to main', 'merge to main', user merges a PR to main, or when git push to main is detected. Also triggers on mentions of: gh release, semver, version bump, changelog, release-please. Covers: automated (release-please) and manual (gh CLI) release flows, versioning rules, tag management, and the mandatory release-on-merge convention.
npx skillsauth add renatocaliari/agent-sync-public-skills cali-github-releasesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Rule: Any merge/push to main MUST include a GitHub release.
Do not wait to be asked — generate release automatically.
Read first: {project}/.pi/instructions.md (if exists)
Use this skill when:
mainmain| Section | What | When to consult | |---------|------|------------------| | Release Strategies | Automated vs Manual | Before any release | | Versioning Rules | Alpha/beta convention, version increments | Before creating any release | | Automated Flow (release-please) | PR-based automation | When project uses release-please | | Manual Flow (gh CLI) | Direct release creation | When project uses manual releases | | Refactor Commit Handling | Releases for non-conventional commits | When refactor commits need releases | | CI/CD Integration | Build triggers, deploy patterns | When project uses CI/CD | | Edge Cases | Common problems and solutions | When issues arise |
Choose based on project setup:
| Strategy | When to use | Pros | Cons | |----------|-------------|------|------| | release-please | Teams, conventional commits | Auto versioning, changelogs, PRs | Setup complexity | | Manual (gh CLI) | Solo projects, simple needs | Full control, simple | Manual versioning |
Detection: Check for .release-please-manifest.json or release.yml workflow.
| Rule | Example |
|------|---------|
| Use alpha/beta only | 0.2.0-alpha, 0.3.1-beta |
| NEVER 1.0.0 without owner confirmation | ❌ 1.0.0 → ✅ 0.9.0 |
| Increment patch for fixes | 0.2.0 → 0.2.1 |
| Increment minor for features | 0.2.0 → 0.3.0 |
| Increment major for breaking | 0.2.0 → 1.0.0 (with approval) |
When project uses googleapis/release-please-action:
name: Release
on:
push:
branches: [master]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: googleapis/release-please-action@v4
id: release
with:
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
target-branch: master
token: ${{ secrets.GITHUB_TOKEN }}
- name: Auto-merge Release PR
if: ${{ steps.release.outputs.release_created != 'true' }}
env:
GH_TOKEN: ${{ secrets.GH_PAT || secrets.GITHUB_TOKEN }}
RELEASE_PR: ${{ steps.release.outputs.pr }}
run: |
if [ -z "$RELEASE_PR" ] || [ "$RELEASE_PR" = "null" ]; then
echo "No release PR created, skipping merge"
exit 0
fi
PR_NUMBER=$(echo "$RELEASE_PR" | jq -r '.number // empty')
if [ -n "$PR_NUMBER" ]; then
echo "Merging release PR #$PR_NUMBER"
gh pr merge --merge "$PR_NUMBER"
else
echo "No release PR to merge"
fi
Problem: GitHub Actions context outputs contain JSON with special characters (parentheses, quotes) that break bash syntax when expanded inline.
Wrong:
# ❌ BREAKS when JSON contains parentheses or special chars
PR_NUMBER="${{ fromJSON(steps.release.outputs.pr).number }}"
Correct:
# ✅ Pass JSON via env var, parse with jq
env:
RELEASE_PR: ${{ steps.release.outputs.pr }}
run: |
if [ -z "$RELEASE_PR" ] || [ "$RELEASE_PR" = "null" ]; then
echo "No release PR"
exit 0
fi
PR_NUMBER=$(echo "$RELEASE_PR" | jq -r '.number // empty')
Why:
${{ }} expansion happens before bash parsing(), ", $ causes syntax errorsjq safely extracts valuesRule: One workflow per trigger type. Avoid duplicate workflows for same event.
Check: If you have both release.yml and auto-merge-release.yml:
release.yml on push → handles release-please + auto-mergeauto-merge-release.yml on pull_request_target → redundant if release.yml already mergesFix: Remove redundant workflow. Keep the one that handles the full flow.
# Run tests
npm run test # or: go test ./... / make test
# Run linter
npm run lint # or: golangci-lint run
# Check for uncommitted changes
git status
# Check current version
git tag --sort=-v:refname | head -5
# Or check package.json / go module version
# Create release (interactive — pick or type version)
gh release create
# Or explicit:
gh release create v0.X.Y-alpha \
--title "v0.X.Y-alpha: <summary>" \
--notes "## Changes
- Feature: description
- Fix: description
## Breaking Changes
- None (or list)
## Testing
- [ ] All tests pass
- [ ] Manual verification done"
git push origin v0.X.Y-alpha
# Check release appears
gh release list
# Check tag exists
git tag -l "v0.X.Y*"
When commits use refactor: prefix (not conventional commit types), release-please won't create a release. Handle manually:
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
COMMITS_SINCE=$(git log "${LATEST_TAG}"..HEAD --format="%s" 2>/dev/null || echo "")
if echo "$COMMITS_SINCE" | grep -qE "^refactor:"; then
echo "Refactor commits detected — manual release needed"
fi
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
CURRENT=${LATEST_TAG#v}
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT"
NEW_PATCH=$((PATCH + 1))
NEW_TAG="v${MAJOR}.${MINOR}.${NEW_PATCH}"
gh release create "$NEW_TAG" \
--title "$NEW_TAG" \
--notes "Code refactoring changes" \
--target master
Add to release workflow after release-please step:
- name: Create release for refactor commits
if: ${{ steps.release.outputs.release_created != 'true' }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
COMMITS_SINCE=$(git log "${LATEST_TAG}"..HEAD --format="%s" 2>/dev/null || echo "")
if echo "$COMMITS_SINCE" | grep -qE "^refactor:"; then
CURRENT=${LATEST_TAG#v}
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT"
NEW_PATCH=$((PATCH + 1))
NEW_TAG="v${MAJOR}.${MINOR}.${NEW_PATCH}"
gh release create "$NEW_TAG" \
--title "$NEW_TAG" \
--notes "Code refactoring changes" \
--target master
fi
If project uses ko for builds, the release can trigger image builds:
# .github/workflows/deploy.yml (triggered on release)
on:
release:
types: [published]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ko-build/[email protected]
- run: ko build --platform=linux/amd64,linux/arm64 --bare ./cmd/web/
on:
push:
branches: [master]
jobs:
build-and-deploy:
steps:
- uses: actions/checkout@v4
- name: Build and push
run: ko build --platform=linux/amd64,linux/arm64 --bare ./cmd/web/
- name: Deploy via SSH
env:
SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
run: |
echo "$SSH_KEY" > /tmp/deploy_key && chmod 600 /tmp/deploy_key
ssh -i /tmp/deploy_key deploy@server 'cd /opt/app && docker compose up -d'
Never put secrets in workflow files. Use GitHub Secrets:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
Use dotenvx for encrypted .env files (see cali-package-audit):
# Run with env vars injected
dotenvx run -- go run ./cmd/web/
# Encrypt .env for safe commit
dotenvx encrypt
# Decrypt when needed
dotenvx decrypt
| Pattern | Use case |
|---------|----------|
| ${{ secrets.X }} | GitHub Actions secrets |
| env: VAR: ${{ ... }} | Pass context to bash safely |
| jq parsing | Extract values from JSON |
| dotenvx | Local dev encrypted envs |
# 1. Create hotfix branch
git checkout -b hotfix/fix-critical main
# 2. Make fix, commit
git commit -m "fix: critical issue description"
# 3. Merge to main
git checkout main
git merge hotfix/fix-critical
# 4. Create release immediately
gh release create v0.X.Y-alpha \
--title "v0.X.Y-alpha: Hotfix - description" \
--notes "Critical fix for..."
# 5. Clean up
git branch -d hotfix/fix-critical
Input: "Pushed fix to main"
Steps:
Output: "Release v0.24.8 created via release-please"
Input: "Just merged the auth feature to main"
Steps:
git tag --sort=-v:refname | head -3 → last tag was v0.2.0-alphagh release create v0.3.0-alpha --title "v0.3.0-alpha: Auth feature" --notes "..."git push origin v0.3.0-alphaOutput: "Released v0.3.0-alpha with auth feature. Tag pushed."
Input: "Merged refactor commits, need release"
Steps:
git log v0.24.7..HEAD --oneline → shows refactor: ... commitsgh release create v0.24.8 --title "v0.24.8" --notes "Code refactoring changes"Output: "Released v0.24.8 for refactor commits"
Input: "Production is down, critical bug in auth"
Steps:
git checkout -b hotfix/fix-auth-crash maingh release create v0.2.1-alpha --title "v0.2.1-alpha: Hotfix auth crash" --notes "..."Output: "Hotfix released v0.2.1-alpha. Production should recover."
go test ./... or npm testgit diff v0.X.Y-alpha..HEAD --statgh auth statusgh auth login (interactive)git tag -l "v0.X.Y*"feat:, fix:, etc.)refactor: commits don't trigger releases — use manual flow.release-please-manifest.json existsError reading JToken from JsonReader or syntax errorsjqreferences/ko-build.md — ko build pipeline referencecali-package-audit — dotenvx for env managementcali-deploy-github-tailscale — deploy pipeline patternsdevelopment
PocketBase v0.39+ development - API rules, auth, collections, SDK, realtime, files, Go/JS extending, deployment, production tuning.
tools
Auto-initialize structured documentation for any project using lat.md (knowledge graph of markdown files with [[wiki links]], // @lat: code refs, and semantic search). Detects cali-product-workflow artifacts (spec-product.md, spec-tech.md, critiques) and uses them as seed material. Falls back to extracting business rules, architecture, and design decisions directly from the codebase. Use when a project lacks structured documentation or when lat.md/ is missing. After seeding, lat.md extension hooks keep documentation alive automatically.
testing
[Cali] Server security audit and hardening for private servers behind Tailscale. Use when: auditing server security, hardening SSH/firewall/Docker, checking for vulnerabilities, setting up fail2ban, reviewing port exposure, or responding to security alerts. Covers 6 layers: CloudFlare, UFW, Tailscale, SSH, Docker, Application. Triggers: "server security", "security audit", "harden server", "SSH hardening", "firewall rules", "UFW config", "fail2ban", "port security", "Docker security", "vulnerability check", "security review".
tools
Run supply chain security scans before installing packages or before releases. Triggers when: user installs a package (npm, pip, go get, brew), user asks to 'scan dependencies', 'check vulnerabilities', 'supply chain', 'security audit', 'run trivy', 'run socket', or before any release/deployment. Also triggers on mentions of: socket.dev, trivy, OSV-scanner, dotenvx, CVE, dependency audit. Covers all four tools with concrete commands.