Install
$ agentstack add skill-cboone-agent-harness-plugins-add-cobra-version ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Add Cobra Version
Add a version subcommand with version, commit hash, build date, and Go runtime version to an existing Cobra-based Go CLI, and coordinate the matching ldflags wiring across main.go, cmd/root.go, .goreleaser.yml, and the Makefile.
Workflow
1. Verify the Project
Confirm the current directory is a Go CLI project with Cobra using the main.go plus cmd package layout this skill updates:
go.modexists. If not, abort with a message that this skill requires an existing Go module.- A Cobra root command exists in
package cmd. Checkcmd/root.gofirst (the canonical location used byscaffold-go-cli); if absent, inspectcmd/*.gofor a package-level variable assigned to&cobra.Command{. - Record the root command variable identifier from that declaration, for example
rootCmd,cliCmd, orcommand. Use this identifier everywhere the templates refer to the root command. - If Cobra commands exist only outside
package cmd, abort with a message that this skill expects acmdpackage root command thatmain.goruns viacmd.Execute(). - Read
go.modto extract the module path; needed when reasoning about ldflags-Xtargets.
2. Detect Current Version State
Determine which of three states the project is in. The state controls how aggressive the changes need to be.
- No version wiring: no package-level
versiondeclaration exists, either asvar version ...or as aversionentry in a top-levelvar ( ... )block. - Basic version only: a package-level
version = "dev"(or similar) declaration exists, typically inmain.goorcmd/root.go, but package-levelcommitordatedeclarations are missing. - Full version info already present:
version,commit, anddatepackage-level variables all exist, whether as single-linevardeclarations or entries in a top-levelvar ( ... )block.
Detection commands:
# Find direct single-line declarations across the project.
grep -rnE '^[[:space:]]*var[[:space:]]+version([[:space:]=]|$)' --include='*.go' .
grep -rnE '^[[:space:]]*var[[:space:]]+commit([[:space:]=]|$)' --include='*.go' .
grep -rnE '^[[:space:]]*var[[:space:]]+date([[:space:]=]|$)' --include='*.go' .
# Also find identifiers inside top-level var (...) blocks.
grep -rnE '^[[:space:]]*version[[:space:]]*=' --include='*.go' .
grep -rnE '^[[:space:]]*commit[[:space:]]*=' --include='*.go' .
grep -rnE '^[[:space:]]*date[[:space:]]*=' --include='*.go' .
Read the surrounding context for every match and count only package-level declarations. Do not treat function-local variables as version wiring.
Also check for an existing version subcommand:
# Existing cmd/version.go file.
test -f cmd/version.go && echo "cmd/version.go exists"
# Existing version subcommand registration via &cobra.Command{ Use: "version", ... }.
grep -rnE 'Use:[[:space:]]*"version"' --include='*.go' .
If a cmd/version.go already exists, read it. Decide:
- If it already prints version, commit, date, and Go runtime version with a
--jsonflag, treat it as up to date and skip step 5 (only continue with the wiring steps for any state still missing). - Otherwise, ask the user whether to overwrite. If they decline, skip step 5 and continue with the remaining wiring steps so the existing file is preserved while partial version state is repaired.
3. Detect ldflags Target Package
The version variables can live in package main (-X main.version=...) or in the cmd package (-X MODULE-PATH/cmd.version=...). Pick a target convention:
- If
var versionalready exists inmain.goor any file inpackage main, targetmain. Thecmdpackage will receive the values via aSetVersionInfocall frommain. - If
var versionexists only in thecmdpackage andmain.godoes not declare it, still targetmain: this skill standardizes on themain-declared,cmd.SetVersionInfo-injected pattern (it is the pattern produced byscaffold-go-cliand used bybopca). Plan to move the declaration intomain.goand add thecommit/datesiblings there. - If no
versiondeclaration exists anywhere, targetmain: the skill will add the variables tomain.go.
Record the chosen ldflags prefix (main.) and the resolved module path; both are used in steps 7 and 8.
4. Determine Project Name for Output Headers
The version subcommand prints a human-readable header that begins with the binary name (for example bopca 1.2.3). Determine the binary name in this precedence order:
- The
Usefield on the Cobra root command variable detected in step 1. Strip any trailing argument hints, for exampleUse: "bopca [flags]"becomesbopca. - A
BINARYor similar Makefile variable. - The last segment of the module path in
go.mod.
Use the result wherever templates reference PROJECT-NAME.
5. Generate cmd/version.go
Read ./references/version-go.md for the cmd/version.go template and create the file from it.
- Replace
PROJECT-NAMEwith the binary name from step 4. - Replace
ROOT-COMMAND-VARwith the root command variable identifier detected in step 1. - Do not modify the file if step 2 found an up-to-date
cmd/version.goor the user chose to keep the existing file.
The generated subcommand:
- Prints version, commit, date, and
runtime.Version()tocmd.OutOrStdout(). - Accepts a
--jsonflag for machine-readable output. - Registers itself on the detected root command variable from its
init()function, so no edits tocmd/root.goare required solely to wire up the subcommand.
6. Update cmd/root.go
Read ./references/root-go-update.md for the modifications to apply.
If the file already declares the package-level variables (version, commit, date) and exposes a SetVersionInfo(v, c, d string) function, leave it alone.
Otherwise:
- Add (or extend) the package-level
var ( ... )block to declareversion = "dev",commit = "none", anddate = "unknown". - Add a
SetVersionInfo(v, c, d string)function that assigns the three variables and sets the detected root command variable'sVersionfield so Cobra's built-in--versionflag still works. If aSetVersion(v string)function already exists, replace it withSetVersionInfo. If callers inmain.goreference the old name, they will be updated in step 7. - If the file currently sets
Version: versiondirectly on the detected root command variable and nothing else, leave that field in place;SetVersionInfowill overwrite it at startup.
7. Update main.go
Read ./references/main-go-update.md for the modifications to apply.
If main.go already declares all three version, commit, date package-level variables and calls cmd.SetVersionInfo(version, commit, date) before cmd.Execute(), leave the file alone.
Otherwise:
- Ensure the package-level declarations include
version = "dev",commit = "none", anddate = "unknown". Add missing siblings; do not remove unrelated variables. - Replace any existing
cmd.SetVersion(version)call withcmd.SetVersionInfo(version, commit, date). - If no
SetVersion-style call exists yet, addcmd.SetVersionInfo(version, commit, date)immediately beforecmd.Execute().
8. Update .goreleaser.yml
Read ./references/goreleaser-update.md for the modifications to apply.
GoReleaser may use .goreleaser.yml or .goreleaser.yaml. Check both. If neither exists, skip this step and note in the summary that GoReleaser is not configured (the user can run /add-goreleaser-homebrew to add it).
In the existing config, find the builds[].ldflags list. Ensure all three -X entries are present:
- -X main.version={{.Version}}
- -X main.commit={{.ShortCommit}}
- -X main.date={{.Date}}
If -X main.version=... is already present, keep it. Add only the -X entries that are missing. Preserve any existing -s -w or other ldflags.
9. Update the Makefile
Read ./references/makefile-update.md for the modifications to apply.
If no Makefile exists in the project root, skip this step and note in the summary.
Otherwise, ensure the Makefile defines:
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo "none")DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
Then ensure LDFLAGS (or the equivalent variable already in use) contains the matching -X entries:
LDFLAGS := -s -w \
-X main.version=$(VERSION) \
-X main.commit=$(COMMIT) \
-X main.date=$(DATE)
Preserve any other flags already in LDFLAGS. Ensure the build target uses $(LDFLAGS) in its go build invocation; if it already uses a sub-variable, leave it alone.
10. Verify the Build
Run a quick build to confirm everything compiles and the new subcommand wires up cleanly:
go build ./...
If a Makefile build target now exists with the expanded ldflags, prefer:
make build
Then exercise the new command, ignoring exit code (the subcommand always exits 0 on success):
go run . version
go run . version --json
go run . --version
If any of those fail, inspect the error and fix the offending file before continuing.
11. Summary
Print a summary covering:
- Files created (
cmd/version.go). - Files modified (
main.go,cmd/root.go,.goreleaser.yml,Makefile), one bullet each, noting whether the change was a clean add or a replacement of an existingSetVersion/-X main.versionsite. - Skipped steps and why (for example "no GoReleaser config detected; run
/add-goreleaser-homebrewto set one up"). - The three commands the user can now run:
version,version --json, and--version. - A reminder that local builds without ldflags will display
dev/none/unknown, and that a tagged GoReleaser release is what fills in real values.
Error Handling
- If
go.modis missing, abort: this skill requires an existing Go module. - If no Cobra root command can be located, abort: this skill is Cobra-specific.
- If no package-level Cobra root command variable can be located in
package cmd, abort: this skill updates themain.gopluscmdpackage layout used byscaffold-go-cliand does not safely patch arbitrary Cobra layouts. - If
cmd/version.goalready exists and the user declines to overwrite it, skip step 5 but continue with the remaining wiring steps so partial state is repaired. - If the version variables are split between
main.goandcmd/root.goin a way that conflicts (for example, both declarevar versionwith different defaults), surface the conflict to the user and ask which file should own the canonical declarations before proceeding. - If
go build ./...fails after the edits, show the error and attempt to fix it; do not leave the project in a broken state.
Reference Templates
./references/version-go.md-- thecmd/version.gotemplate../references/root-go-update.md-- modifications tocmd/root.go../references/main-go-update.md-- modifications tomain.go../references/goreleaser-update.md-- ldflags additions for.goreleaser.yml/.goreleaser.yaml../references/makefile-update.md--VERSION/COMMIT/DATEandLDFLAGSadditions for the Makefile.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: cboone
- Source: cboone/agent-harness-plugins
- License: MIT
- Homepage: https://github.com/cboone/agent-harness-plugins
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.