Go CLI Ship
Use this skill to turn a Go CLI into a reproducible product: stable command contract, testable implementation, npm installer, GitHub Release artifacts, concise README, optional Agent Skill package, and release gates that prevent drift.
First Principles
- Treat the CLI as an automation API, not only a terminal UI.
- Keep stdout for results, stderr for diagnostics, and exit codes stable.
- Make JSON output additive and backward compatible.
- Make release repeatable: one version, one tag, verified artifacts, tested installer.
- Keep
skills/ as content only. Put Go code in internal/, not under Agent Skill folders.
- Keep README and SKILL.md operational. Remove internal paths, release process noise, and maintenance notes unless the target user needs them.
Reject These Anti-Patterns
- Do not use labels like "Unix-friendly" or "Agent Native" as decoration. Convert them into concrete contracts: stable stdout/stderr, exit codes, JSON, noninteractive commands, and repeatable install flows.
- Do not put source code, generated files, changelog notes, or repository maintenance instructions inside
skills/.
- Do not copy
skills/<name>/SKILL.md into internal/ or any other second source of truth. Runtime code should read the packaged or repository skills/ directory.
- Do not publish a release after changing install behavior unless npm install, GitHub Release artifacts, checksum verification, and optional
skills list/read all pass from a fresh environment.
- Do not make README or SKILL.md explain the whole architecture when the user only needs to install, configure, run, and verify the CLI.
- Do not rely on local success alone. CI must run the same gates, and release workflows must verify the packaged artifact.
Start Here
Before changing a project:
git status --short
go version
npm --version
Identify:
- CLI binary name.
- Go module and main package.
- npm package name.
- GitHub repo.
- target OS/ARCH matrix.
- whether the CLI ships an Agent Skill.
- whether the CLI should expose
skills list/read.
Template Replacement Protocol
When copying files from templates/, replace every placeholder before running tests:
| Placeholder |
Replace with |
__CLI_NAME__ |
final binary name, for example acme |
__NPM_PACKAGE_NAME__ |
npm package, for example @org/acme |
__GITHUB_REPO__ |
owner/repo |
__RELEASE_ENV_PREFIX__ |
uppercase env prefix without trailing underscore, for example ACME |
__GO_VERSION_FILE__ |
Go version file, usually go.mod |
__GO_MAIN_PACKAGE__ |
build package, for example ./cmd/acme |
__SKILL_NAME__ |
bundled skill directory name under skills/ |
After replacing placeholders, run:
rg "__[A-Z0-9_]+__" .
node -c scripts/install.js
node -c scripts/run.js
bash -n scripts/release-check.sh
If rg "__[A-Z0-9_]+__" . returns any template placeholder, stop and replace it before continuing.
Required Project Shape
Use this baseline unless the existing repository has stronger conventions:
cmd/<cli>/ CLI entrypoint
internal/ private implementation
e2e/ end-to-end tests
scripts/ install, smoke, release checks
.github/workflows/ CI and release automation
skills/<name>/ Agent Skill content only
Rules:
- Do not put
.go files under skills/.
- Do not duplicate
skills/<name>/SKILL.md under internal/.
- If the CLI reads skills, keep reader and locator code under
internal/skillcontent.
- Let npm
scripts/run.js set <PREFIX>_SKILLS_DIR to the package skills/ directory when present.
- Let local development read the repository
skills/ directory.
CLI Contract
Define these before implementation:
- commands and subcommands.
- human output versus
--json output.
- stable error and exit codes.
- config precedence: flags, environment, config file, defaults.
- compatibility policy for new fields and flags.
Prefer explicit commands and flags over hidden global state, background daemons, caches, or browser scraping.
Required Agent Skill Commands
When a CLI ships an Agent Skill under skills/, add these commands:
<cli> skills list --json
<cli> skills read <name>
<cli> skills read <name> --json
<cli> skills read <name>/<path> --json
Contract:
skills list returns JSON with version, skills, and count.
skills read returns raw Markdown by default.
skills read --json returns version, skill, path, content, and optional guidance.
- reject absolute paths,
.., backslashes, directories, and unknown skills.
- tests cover list, read, JSON read, unknown skill, and path traversal.
Use templates/go/internal/skillcontent/ as the starting point, then wire it into the CLI parser.
If the CLI intentionally ships skills/ without skills list/read, remove the corresponding release-check assertions and document why. Do not leave the default checks failing.
Quality Gates
Every production CLI should expose:
make release-check
The gate should cover:
- version consistency.
- required files.
- README install command.
- npm package metadata and
npm run pack:check.
gofmt -l ..
go vet ./....
go test -count=1 ./....
- locked
golangci-lint.
- no Go files under
skills/.
- if
skills/ exists: README documents npx skills add, package.json includes skills/**, and the release smoke test exercises skills list/read when available.
If local sandboxing blocks Go cache or httptest, rerun with a writable GOCACHE or with the same permissions CI has. Do not mark the gate green without a real command result.
Failure Handling
Use this table instead of guessing through release failures:
| Trigger |
First action |
If still failing |
Placeholder scan finds __...__ |
Replace all placeholders in copied templates |
Remove unused template files or document intentionally literal placeholders |
npm run pack:check omits skills/** |
Add skills/** to package.json.files |
Inspect npm pack --json --dry-run output and fix path roots |
skills list/read fails from npm wrapper |
Check <PREFIX>_SKILLS_DIR in scripts/run.js and package contents |
Run the installed wrapper from a fresh prefix and inspect its environment |
| Checksum mismatch |
Regenerate SHA256SUMS from flattened release artifacts |
Stop release; rebuild artifacts from the exact tag |
NPM_TOKEN missing |
Add repository secret before tagging |
Publish GitHub Release only after deciding whether npm publish is in scope |
| npm publish permission denied |
Confirm package name, scope ownership, and publishConfig.access |
Rename package or request scope access before retrying |
| Git tag and package version differ |
Move the tag or update version sources before release |
Delete the bad tag only after user confirmation |
| CI passes locally but fails in workflow |
Reproduce the exact workflow command locally |
Align Go, Node, CGO, cache, and lint versions |
Version Checks
Before tagging a release, align all version sources:
package.json version.
Makefile version when present.
- CLI
version variable or ldflags value.
- top
CHANGELOG.md entry.
- Git tag
vX.Y.Z.
- GitHub Actions
GITHUB_REF_NAME when running in CI.
Release checks should fail fast on drift. A patch release is required after changing published install behavior, package contents, or release workflow outputs.
npm Distribution
Recommend npm for developer installation:
npm install -g <package-name>
<cli-name> version
The npm package is a thin wrapper:
package.json declares bin, files, postinstall, pack:check, and publishConfig.access.
scripts/install.js downloads the matching GitHub Release archive and verifies SHA256SUMS.
scripts/run.js forwards args, stdio, and exit code to the real binary.
- no binary is committed to git or packed from the working tree.
- first publish does not require manually creating the npm package;
npm publish --access public creates it when the account or scope has permission.
If the project ships an Agent Skill, include skills/** in the npm package and let scripts/run.js set <PREFIX>_SKILLS_DIR.
Agent Skill Packaging
Use Agent Skills for agent instructions, not project maintenance documentation.
Recommended README command:
npx skills add <owner>/<repo>
Skill rules:
SKILL.md frontmatter contains only name and description.
- Body is concise, procedural, and English unless the project explicitly requires another language.
- Body describes how to use the CLI, not how to maintain the repository.
- Do not include changelogs, internal source paths, release process, or test commands unless the skill is specifically for development work.
- Keep
skills/<name>/ free of Go code and generated binaries.
Release Automation
Use tag-triggered release workflow:
CHECKPOINT - STOP before pushing a release tag. Confirm with the user:
final version and tag.
npm package name and access.
GitHub repository target.
NPM_TOKEN is configured when npm publish is in scope.
make release-check passed from the current commit.
fresh npm install smoke test passed when install behavior changed.
trigger: push.tags: v*.
build linux, darwin, and windows for amd64 and arm64 when supported.
inject version from the tag.
archive README.md, LICENSE, CHANGELOG.md, and skills/ when present.
generate SHA256SUMS from flattened artifacts.
smoke-test npm install on Linux and Windows before publishing.
if the CLI supports skills list/read, smoke-test those commands from the npm-installed wrapper.
publish GitHub Release before npm.
publish npm with NPM_TOKEN after version-tag validation.
README Standard
First screen should answer:
- what is this CLI?
- who is it for?
- how do I install it?
- what is the fastest useful command?
Keep README practical. Avoid internal architecture unless users need it to operate the CLI.
Delivery Report
When finishing work, report:
- scope changed.
- important files changed.
- commands run and results.
- known risks or skipped checks.
- whether the work was committed, tagged, or only left in the worktree.
1---2name: go-cli-ship-23description: Use this skill to build, upgrade, or stabilize Go CLI projects for production release. It covers CLI contracts, Go engineering gates, npm-based binary distribution, GitHub Release automation, README quality, Agent Skill packaging, skills list/read support, version checks, release checks, and CI smoke-test closure. Use when a user asks to create a Go CLI from scratch, harden an existing CLI, fix CI/release drift, publish a version, or standardize a reusable CLI scaffold.4---56# Go CLI Ship78Use this skill to turn a Go CLI into a reproducible product: stable command contract, testable implementation, npm installer, GitHub Release artifacts, concise README, optional Agent Skill package, and release gates that prevent drift.910## First Principles1112- Treat the CLI as an automation API, not only a terminal UI.13- Keep stdout for results, stderr for diagnostics, and exit codes stable.14- Make JSON output additive and backward compatible.15- Make release repeatable: one version, one tag, verified artifacts, tested installer.16- Keep `skills/` as content only. Put Go code in `internal/`, not under Agent Skill folders.17- Keep README and SKILL.md operational. Remove internal paths, release process noise, and maintenance notes unless the target user needs them.1819## Reject These Anti-Patterns2021- Do not use labels like "Unix-friendly" or "Agent Native" as decoration. Convert them into concrete contracts: stable stdout/stderr, exit codes, JSON, noninteractive commands, and repeatable install flows.22- Do not put source code, generated files, changelog notes, or repository maintenance instructions inside `skills/`.23- Do not copy `skills/<name>/SKILL.md` into `internal/` or any other second source of truth. Runtime code should read the packaged or repository `skills/` directory.24- Do not publish a release after changing install behavior unless npm install, GitHub Release artifacts, checksum verification, and optional `skills list/read` all pass from a fresh environment.25- Do not make README or SKILL.md explain the whole architecture when the user only needs to install, configure, run, and verify the CLI.26- Do not rely on local success alone. CI must run the same gates, and release workflows must verify the packaged artifact.2728## Start Here2930Before changing a project:3132```bash33git status --short34go version35npm --version36```3738Identify:3940- CLI binary name.41- Go module and main package.42- npm package name.43- GitHub repo.44- target OS/ARCH matrix.45- whether the CLI ships an Agent Skill.46- whether the CLI should expose `skills list/read`.4748## Template Replacement Protocol4950When copying files from `templates/`, replace every placeholder before running tests:5152| Placeholder | Replace with |53|---|---|54| `__CLI_NAME__` | final binary name, for example `acme` |55| `__NPM_PACKAGE_NAME__` | npm package, for example `@org/acme` |56| `__GITHUB_REPO__` | `owner/repo` |57| `__RELEASE_ENV_PREFIX__` | uppercase env prefix without trailing underscore, for example `ACME` |58| `__GO_VERSION_FILE__` | Go version file, usually `go.mod` |59| `__GO_MAIN_PACKAGE__` | build package, for example `./cmd/acme` |60| `__SKILL_NAME__` | bundled skill directory name under `skills/` |6162After replacing placeholders, run:6364```bash65rg "__[A-Z0-9_]+__" .66node -c scripts/install.js67node -c scripts/run.js68bash -n scripts/release-check.sh69```7071If `rg "__[A-Z0-9_]+__" .` returns any template placeholder, stop and replace it before continuing.7273## Required Project Shape7475Use this baseline unless the existing repository has stronger conventions:7677```text78cmd/<cli>/ CLI entrypoint79internal/ private implementation80e2e/ end-to-end tests81scripts/ install, smoke, release checks82.github/workflows/ CI and release automation83skills/<name>/ Agent Skill content only84```8586Rules:8788- Do not put `.go` files under `skills/`.89- Do not duplicate `skills/<name>/SKILL.md` under `internal/`.90- If the CLI reads skills, keep reader and locator code under `internal/skillcontent`.91- Let npm `scripts/run.js` set `<PREFIX>_SKILLS_DIR` to the package `skills/` directory when present.92- Let local development read the repository `skills/` directory.9394## CLI Contract9596Define these before implementation:9798- commands and subcommands.99- human output versus `--json` output.100- stable error and exit codes.101- config precedence: flags, environment, config file, defaults.102- compatibility policy for new fields and flags.103104Prefer explicit commands and flags over hidden global state, background daemons, caches, or browser scraping.105106## Required Agent Skill Commands107108When a CLI ships an Agent Skill under `skills/`, add these commands:109110```bash111<cli> skills list --json112<cli> skills read <name>113<cli> skills read <name> --json114<cli> skills read <name>/<path> --json115```116117Contract:118119- `skills list` returns JSON with `version`, `skills`, and `count`.120- `skills read` returns raw Markdown by default.121- `skills read --json` returns `version`, `skill`, `path`, `content`, and optional `guidance`.122- reject absolute paths, `..`, backslashes, directories, and unknown skills.123- tests cover list, read, JSON read, unknown skill, and path traversal.124125Use `templates/go/internal/skillcontent/` as the starting point, then wire it into the CLI parser.126127If the CLI intentionally ships `skills/` without `skills list/read`, remove the corresponding release-check assertions and document why. Do not leave the default checks failing.128129## Quality Gates130131Every production CLI should expose:132133```bash134make release-check135```136137The gate should cover:138139- version consistency.140- required files.141- README install command.142- npm package metadata and `npm run pack:check`.143- `gofmt -l .`.144- `go vet ./...`.145- `go test -count=1 ./...`.146- locked `golangci-lint`.147- no Go files under `skills/`.148- if `skills/` exists: README documents `npx skills add`, `package.json` includes `skills/**`, and the release smoke test exercises `skills list/read` when available.149150If local sandboxing blocks Go cache or `httptest`, rerun with a writable `GOCACHE` or with the same permissions CI has. Do not mark the gate green without a real command result.151152## Failure Handling153154Use this table instead of guessing through release failures:155156| Trigger | First action | If still failing |157|---|---|---|158| Placeholder scan finds `__...__` | Replace all placeholders in copied templates | Remove unused template files or document intentionally literal placeholders |159| `npm run pack:check` omits `skills/**` | Add `skills/**` to `package.json.files` | Inspect `npm pack --json --dry-run` output and fix path roots |160| `skills list/read` fails from npm wrapper | Check `<PREFIX>_SKILLS_DIR` in `scripts/run.js` and package contents | Run the installed wrapper from a fresh prefix and inspect its environment |161| Checksum mismatch | Regenerate `SHA256SUMS` from flattened release artifacts | Stop release; rebuild artifacts from the exact tag |162| `NPM_TOKEN` missing | Add repository secret before tagging | Publish GitHub Release only after deciding whether npm publish is in scope |163| npm publish permission denied | Confirm package name, scope ownership, and `publishConfig.access` | Rename package or request scope access before retrying |164| Git tag and package version differ | Move the tag or update version sources before release | Delete the bad tag only after user confirmation |165| CI passes locally but fails in workflow | Reproduce the exact workflow command locally | Align Go, Node, CGO, cache, and lint versions |166167## Version Checks168169Before tagging a release, align all version sources:170171- `package.json` version.172- `Makefile` version when present.173- CLI `version` variable or ldflags value.174- top `CHANGELOG.md` entry.175- Git tag `vX.Y.Z`.176- GitHub Actions `GITHUB_REF_NAME` when running in CI.177178Release checks should fail fast on drift. A patch release is required after changing published install behavior, package contents, or release workflow outputs.179180## npm Distribution181182Recommend npm for developer installation:183184```bash185npm install -g <package-name>186<cli-name> version187```188189The npm package is a thin wrapper:190191- `package.json` declares `bin`, `files`, `postinstall`, `pack:check`, and `publishConfig.access`.192- `scripts/install.js` downloads the matching GitHub Release archive and verifies `SHA256SUMS`.193- `scripts/run.js` forwards args, stdio, and exit code to the real binary.194- no binary is committed to git or packed from the working tree.195- first publish does not require manually creating the npm package; `npm publish --access public` creates it when the account or scope has permission.196197If the project ships an Agent Skill, include `skills/**` in the npm package and let `scripts/run.js` set `<PREFIX>_SKILLS_DIR`.198199## Agent Skill Packaging200201Use Agent Skills for agent instructions, not project maintenance documentation.202203Recommended README command:204205```bash206npx skills add <owner>/<repo>207```208209Skill rules:210211- `SKILL.md` frontmatter contains only `name` and `description`.212- Body is concise, procedural, and English unless the project explicitly requires another language.213- Body describes how to use the CLI, not how to maintain the repository.214- Do not include changelogs, internal source paths, release process, or test commands unless the skill is specifically for development work.215- Keep `skills/<name>/` free of Go code and generated binaries.216217## Release Automation218219Use tag-triggered release workflow:220221CHECKPOINT - STOP before pushing a release tag. Confirm with the user:222223- final version and tag.224- npm package name and access.225- GitHub repository target.226- `NPM_TOKEN` is configured when npm publish is in scope.227- `make release-check` passed from the current commit.228- fresh npm install smoke test passed when install behavior changed.229230- trigger: `push.tags: v*`.231- build linux, darwin, and windows for amd64 and arm64 when supported.232- inject version from the tag.233- archive `README.md`, `LICENSE`, `CHANGELOG.md`, and `skills/` when present.234- generate `SHA256SUMS` from flattened artifacts.235- smoke-test npm install on Linux and Windows before publishing.236- if the CLI supports `skills list/read`, smoke-test those commands from the npm-installed wrapper.237- publish GitHub Release before npm.238- publish npm with `NPM_TOKEN` after version-tag validation.239240## README Standard241242First screen should answer:243244- what is this CLI?245- who is it for?246- how do I install it?247- what is the fastest useful command?248249Keep README practical. Avoid internal architecture unless users need it to operate the CLI.250251## Delivery Report252253When finishing work, report:254255- scope changed.256- important files changed.257- commands run and results.258- known risks or skipped checks.259- whether the work was committed, tagged, or only left in the worktree.