skills/scaffold-cli/SKILL.md
Set up a new Go CLI installable via the personal Homebrew tap. Trigger when the user says "new CLI", "scaffold a CLI", "start a Go project for the tap", or asks how to bootstrap a publishable CLI from scratch.
npx skillsauth add jwa91/agentskills scaffold-cliInstall 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.
Goal: end up with a Go CLI whose goreleaser release builds cross-platform binaries, creates a GitHub Release with notes, and writes Casks/<name>.rb directly to https://github.com/jwa91/homebrew-tap. After the first release, brew install jwa91/tap/<name> works from any machine.
gh, git, goreleaser, op (1Password CLI), and jwa-tobrew on PATH (jwa-tobrew doctor will check)homebrew-tap somewhere reachable ($BREWTAP_DIR or one of the standard locations: ~/developer/homebrew-tap, ~/Developer/homebrew-tap, ~/src/homebrew-tap, ~/code/homebrew-tap)origin is SSH (not HTTPS) — see ADR 0002$GITHUB_TOKEN available via 1Password (the tap repo's .env.template shows the canonical reference)Standard gh repo create flow; nothing CLI-specific yet:
mkdir <name> && cd <name>
git init
go mod init github.com/<owner>/<name>
echo 'package main\n\nimport "fmt"\n\nfunc main() { fmt.Println("hello") }' > main.go
git add . && git commit -m "feat: initial commit"
gh repo create <name> --public --source=. --remote=origin --push
name should match the binary you want users to type (so brew install jwa91/tap/<name> works).
jwa-tobrew init
init auto-detects Go (because of go.mod) and writes:
.goreleaser.yaml — the entire release pipeline. Builds darwin/linux × amd64/arm64, creates the GitHub Release, writes Casks/<name>.rb to the tap via the modern homebrew_casks: block (ADR 0008 in homebrew-tap). Same config runs locally and in CI..env.template — op:// references for $GITHUB_TOKEN (resolved at runtime by jwa-harden; see security note in the jwa-tobrew skill)..gitignore entries that block raw .env files (per ADR 0005)..agents/skills/release/SKILL.md plus harness symlinks — installed by agentskills bootstrap --skill release so future agents know how this project ships.Useful flags: --name <name> (defaults to repo name), --desc "..." (used in the Cask's desc line), --force (overwrite existing files).
--versionThe scaffolded .goreleaser.yaml injects build info via ldflags into main.version, main.commit, main.date. Mirror these in your main.go:
var (
version = "dev"
commit = "none"
date = "unknown"
)
func main() {
if len(os.Args) > 1 && (os.Args[1] == "--version" || os.Args[1] == "version") {
fmt.Printf("%s %s (commit %s, built %s)\n", os.Args[0], version, commit, date)
return
}
// ... rest of main
}
The generated release pipeline expects <name> --version to work so local and post-install smoke checks can verify the binary that was built.
git tag -a v0.1.0 -m v0.1.0
git push origin v0.1.0
jwa-harden run -- goreleaser release --clean
GoReleaser will:
v0.1.0v0.1.0 GitHub Release with auto-grouped changelog (Conventional Commits → "Features" / "Bug fixes" / "Other")checksums.txthomebrew-tap/main adding Casks/<name>.rb with platform-specific url+sha256 entriesAfter it lands, cd ~/developer/homebrew-tap && git pull brings the new Cask in. The README items table updates next time anyone runs jwa-tobrew config (or auto-updates on the next add/bump/release).
For tag-driven CI release, add a workflow at .github/workflows/release.yml:
name: release
on:
push:
tags: ['v*.*.*']
permissions:
contents: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- uses: actions/setup-go@v5
with: { go-version: stable }
- uses: goreleaser/goreleaser-action@v6
with: { args: release --clean }
env:
GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
HOMEBREW_TAP_TOKEN is a fine-grained PAT with write access to jwa91/homebrew-tap and contents:write on this repo. Local releases use jwa-harden run --, CI uses repo secrets — same goreleaser release invocation either way.
Same as step 4 with a new tag, or just push a new v*.*.* tag if CI is wired.
git tag -a v0.2.0 -m v0.2.0
git push origin v0.2.0
# (CI handles it from here)
brew install jwa91/tap/<name>git push origin v0.X.Y — no manual tap editjwa-tobrew align considers clean)scripts/release.sh (which wraps jwa-tobrew release). Use jwa-tobrew init --kind=cask (or --kind=formula) and follow the hint it prints.jwa-tobrew add github.com/SOMEONE/some-cli is the one-shot, no source-repo changes needed.~/dotfiles/docs/security-ground-rules.md. The transitional .env.template + op run pattern is documented there too.data-ai
Release the current project to the personal Homebrew tap from repo-local release config. Use when the user says "release", "ship", "cut a version", "publish", "make a new tag", or asks how to make a new version available via jwa91/tap.
tools
Use the `jwa-harden` CLI for secret-safe command execution, env-template discovery, and signing/notarization preflight checks. Trigger when a command needs secrets, when `.env.template` or 1Password references are involved, or before signed release flows.
documentation
Modify or extend the `jwa-tobrew` scaffolding system — the templates that `init` writes into target projects. Trigger when the user says "add a new scaffold kind", "change what init writes", "update the templates", or asks how the embedded templates are wired.
development
Detect and fix drift between a project and the conventions encoded in `jwa-tobrew`, prek, and the tap ADRs. Trigger when the user says "align", "any drift", "verify conventions", or asks why a particular file/symlink/script is required.