- Extremely concise. Passive or imperative voice. No softening, hedging, first-person.
- Accurate, robust solutions over agreement. Blunt feedback — don't validate a confidently-stated but flawed premise; say so.
- Comments wrap at 90 columns when practical.
- End plans with a concise list of unresolved questions, if any.
- Performance work favors reducing heap allocations.
- When summarizing, synthesize — explain implications, don't just compress.
- Test Driven Development should be favored where practical.
- Shell scripts and command line recommendations should use Fish, my preferred shell, or explicity call bash.
- Be generious with code comments when generating or updating code so I can understand your reasoning.
-
-
Save mike-ward/8ea756fdc68227ddcc3c5ee6c90a1395 to your computer and use it in GitHub Desktop.
| name | harden |
|---|---|
| description | Harden uncommitted changes against bad data and denial of service attacks. |
| user_invocable | true |
For all uncommitted changes (staged and unstaged), harden inputs against bad data and DoS:
Steps:
- Run
git diffandgit diff --cachedto identify changed files and functions - Read surrounding context in modified files as needed
- For each public function or entry point in the diff, check for and fix:
- NaN/Inf floats — clamp or replace with safe defaults (pixelMin convention)
- Nil/empty slices and maps — early return or no-op, never panic
- Unbounded input sizes — cap slice lengths, iteration counts, string lengths
- Division by zero — guard before dividing
- Integer overflow — check before arithmetic on user-supplied counts
- Excessive allocations — pre-check sizes before allocating large buffers
- Duplicate or degenerate data — handle gracefully, no infinite loops
- Error returns handled correctly - no bare errors
- Apply fixes directly to the source files
- Run
go build ./...andgo vet ./...to verify changes compile - Summarize what was hardened and where
| name | quality |
|---|---|
| description | One-command quality pipeline over uncommitted changes — review, harden, fill test gaps, simplify (changed files only), then verify. Leaves changes uncommitted. |
| user_invocable | true |
Run the full quality pass on the current uncommitted diff, in order. Apply
findings as you go; do not just report them. Stop and surface anything that
can't be safely auto-resolved. Leave the changes uncommitted — do not stage
or commit. The user commits separately (e.g. /ship or /commit).
Before any other work: if a task-tracking tool is available (todowrite,
TaskCreate), create a tracker with all steps below and mark each
in_progress/completed as you go — this populates the IDE's right-panel
progress view. If no such tool is in this session's roster, skip it and say
so once in the final summary; do not stall the pass on it.
Do not delegate pipeline steps to subagents. The pipeline is sequential
over one shared file set, so splitting it buys nothing — and built-in skills
such as simplify and harden are injected into the main agent's skill
roster by the harness rather than existing as files on disk, so a subagent
cannot invoke them at all.
Parallel fan-out within a single step is a separate question and is
sometimes worth it. Step 5 may use simplify's multi-agent fan-out when the
diff is large (roughly 500+ changed lines) — below that, the review agents
cost more than they find. When you do fan out, pass the agents the decisions
already settled in steps 2–4, including anything deliberate that reads as a
defect from the outside. Cold agents re-derive context and will otherwise
re-report handled findings and re-litigate intentional choices, and
adjudicating those false positives can cost more than the parallel sweep
saves.
-
Scope — capture the changed file set: !
git diff --name-only HEADEvery later step operates ONLY on these files. Never edit other packages. -
Review — do a thorough correctness pass over the step-1 files yourself, at high effort, and apply the fixes. There is no
code-reviewskill to call:/code-reviewis a built-in command, user-triggered and billed, so it cannot be launched from here. Cover at minimum:- Correctness: off-by-one, nil/zero-value handling, early returns that skip cleanup, incorrect boundary conditions.
- Error paths: every returned error handled or deliberately ignored with a reason; no swallowed failures.
- Concurrency: lock discipline as the repo defines it — no lock held across a call into another subsystem, cross-goroutine state reached only through the repo's sanctioned path.
- Allocation: no per-item heap traffic in documented hot paths.
- Layering: dependencies flow in the direction the repo's architecture
notes specify; no lower layer reaching up into a higher one.
Defer to the project's CLAUDE.md for the concrete names behind these —
which lock, which hot path, which layers — and apply its rules, not
these generic ones, wherever it is specific.
If the diff warrants the deeper multi-agent pass, say so in the final
summary and let the user run
/code-review ultrathemselves.
-
Harden — run the
hardenskill. Apply defenses against bad data / DoS on the changed code. -
Test — run the
test-gapsskill. Add the missing tests it reports (untested public funcs, edge cases, error paths). -
Simplify — run the
simplifyskill, CONSTRAINED to the step-1 file set only. Reject any change that touches other packages or that broadens scope. Watch for the known failure modes of an over-eager simplify: recursion introduced by collapsing a call chain, regressions in behaviour that has no test to catch it (rendering, layout, focus), and "unused" wiring deleted because its only caller is a framework or callback the analysis could not see. If the skill does not resolve, do not stop — apply its criteria inline under the same file-set constraint: reuse existing helpers instead of new near-duplicates, collapse needless indirection, delete dead abstraction, and pitch each function at one consistent altitude. Quality only — bug hunting belongs to step 2. -
Verify — rebuild and run the suite; do not proceed on red:
go build ./...go test ./...golangci-lint run ./...(Adjust only for a non-Go repo.) Confirm all pass.
Do NOT commit. Leave the changes staged-or-unstaged exactly as the user had them plus the pass's edits, for the user to review and commit.
- Minimal scoped diffs — no cosmetic churn, no drive-by edits.
- If any stage introduces a regression caught at step 6, revert that stage's change and report it rather than leaving the tree broken.
- Report a final summary: what each stage changed and the test outcome.
If $ARGUMENTS is provided, treat it as extra scope/context for the pass.
| name | release |
|---|---|
| description | Update changelog, commit, tag with patch bump, push |
| user_invocable | true |
Release workflow for the current project. Steps:
- Get last tag: !
git describe --tags --abbrev=0 - Get changes since last tag: !
git log $(git describe --tags --abbrev=0)..HEAD --oneline - Determine next version by incrementing the minor number of the last tag. If no new user facing features or no breaking changes, increment the patch number instead.
- Confirm the version tag with the user before proceeding. Show the proposed version and why (e.g. "minor: new feature X" or "patch: bug fixes only"). Do not continue until the user approves the version.
- Update CHANGELOG.md with a new entry for the next version, summarizing changes
- Create a branch for the release, commit CHANGELOG.md and any staged/modified tracked files with message:
changelog: add <version> (<summary>) - Push the branch and create a PR (
gh pr create) - Wait for CI (
gh pr checks --watch), classify failures before acting - Squash-merge the PR (
gh pr merge --squash --delete-branch), then pull main - Create annotated tag for the new version on the merged commit
- Push the tag to origin (
git push origin <tag>) - Clean up: delete the local release branch
If $ARGUMENTS is provided, use it as additional context for the changelog entry.
| name | ship |
|---|---|
| description | Drive a change from branch to merged PR — verify rebased on base, commit, push, open PR, then merge and clean up branches (handles squash merges) |
| user_invocable | true |
| model | sonnet |
End-to-end ship workflow for the current change. Verify each step before proceeding; do not declare success on an unverified step.
Before any other work: use todowrite to create a task tracker with all
steps below. Mark each step in_progress/completed as you go — this
populates the IDE's right-panel progress view.
-
Determine base branch: !
git remote show origin | sed -n 's/.*HEAD branch: //p' -
Never commit directly to the base branch. If the current branch is the base branch, create a feature branch (give it a short, descriptive name) before proceeding. A PR requires two distinct branches.
-
Confirm current branch is rebased on the current base. If behind, fetch and rebase first — do not open a PR from a stale base.
-
Run, in order, stopping and reporting on first failure. Suppress success output — only failures belong in context. This repo has 87 packages; a bare
go test ./...dumps ~87oklines that carry no information.go build ./... 2>&1 | tail -20 go test ./... 2>&1 | grep -vE '^ok |no test files' | tail -40 golangci-lint run ./... 2>&1 | tail -40
Empty output means the step passed — say so and move on; do NOT re-run verbosely to confirm. Only if a step reports a failure, re-run that one package or linter verbosely to get the detail needed to fix it. (These are the go-gui-org conventions; adjust only for a non-Go repo.)
- Commit any uncommitted tracked changes. Only ask before committing if what the changes contain (not the workflow) is unclear — e.g. the diff includes unrelated files. Push the branch to origin.
- Open the PR with
gh pr create— title + body summarizing the change. - Wait for CI:
-
First, check whether CI is configured: use the
Globtool with pattern.github/workflows/*.{yml,yaml}(NOT a shell glob —lsfails silently in zsh when one pattern has no match). If no workflows exist, skip CI waiting — the repo has no checks. -
If workflows exist, wait for CI without streaming.
gh pr checks --watchre-emits the whole check table on every refresh, which is the single most expensive thing this skill does. Use a quiet poll instead:gh pr checks --watch --fail-fast > /dev/null 2>&1; gh pr checks
The redirect discards the stream; the trailing
gh pr checksprints the final table once. If it reports "no checks reported", CI may not have started yet — pollgh pr checkswith a 30s retry loop before accepting the result. Never interpret "no checks reported" as "no CI exists". -
For a red check, classify runner noise (CPU/timing jitter) vs real regression before re-running vs fixing.
-
- Merge once checks pass (
gh pr merge). Note the merge strategy used. - Clean up: switch to base, pull, delete the local branch. For a squash
merge the local branch won't show as merged — verify the PR is merged
via
gh pr view --json statebefore forcing the local delete, then prune the remote ref.
Report a final status: PR URL, merge strategy, CI outcome, branches deleted.
If $ARGUMENTS is provided, use it as the PR title/context.
| name | simplify |
|---|---|
| description | Four-agent cleanup pass over a diff — reuse, simplification, efficiency, and altitude findings, then the fixes are applied directly. Use when the user says "simplify", "clean up the diff", "tighten this code", "reduce duplication", "make this less convoluted", or asks for a quality pass over changed code. Improves quality of changed code — NOT bug hunting (that is review-changes / code review). |
Quality pass over changed code: reuse, simplification, efficiency, altitude. Correctness bugs are the review skill's job — if the pass turns up one, note it and move on; do not fix it here.
Determine the target and capture the file set. Every later step operates ONLY on these files — never edit other packages.
git diff @{upstream}...HEAD; fall back togit diff main...HEAD, thengit diff HEAD~1.- If
git diff HEADreports uncommitted changes — or the range diff came back empty — also capture those: the pass often runs pre-commit. $ARGUMENTSoverrides the target: a PR number, a branch name, or a path argument selects the diff to review instead.
Save the file list (git diff --name-only) — it is what the four agents
receive.
Launch all four subagents in a single message so they run in parallel. Each is report-only: it returns findings, never edits. Give every agent:
- the changed-file list (and how to view the diff themselves)
- its angle (below)
- the output format
| Angle | Looks for |
|---|---|
| Reuse | New code re-implementing existing helpers; greps shared/utility modules and adjacent files, names the helper to call instead |
| Simplification | Redundant/derivable state, copy-paste with variation, deep nesting, dead code |
| Efficiency | Redundant computation, repeated I/O, needless sequencing, blocking work on startup/hot paths; long-lived closures retaining enclosing scope (prefer a struct copying only needed fields) |
| Altitude | Fix depth — special cases layered on shared infrastructure signal the fix should generalize the underlying mechanism |
Output format per finding:
<file>:<line> — <one-line summary> — <concrete cost> — <suggested fix>
Concrete cost means the actual downside in the repo's terms: allocations per frame, a duplicated helper that will drift, N copies of the same special case that all need touching to change the rule. Costless or stylistic nits are not findings.
Per-agent brief template:
You are the {Angle} reviewer in a simplify pass. Report-only: do NOT edit
anything.
Changed files: <list>
Run `git diff <range>` (and `git diff HEAD` if noted) to see the changes, then
read surrounding context as needed. Find findings ONLY in the changed files.
Your angle: <table row>. {Reuse: also grep shared/utility modules and adjacent
files for an existing helper that does what the new code does; name it.}
Return findings as:
<file>:<line> — <one-line summary> — <concrete cost> — <suggested fix>
One per line. Nothing that changes intended behavior. If you find nothing,
say so in one line.
- Wait for all four agents. Deduplicate findings that hit the same line/mechanism (the Altitude and Simplification agents often converge).
- Fix directly. When two suggested fixes conflict, keep the one that removes more special-casing.
- Skip — and note, without arguing — anything that would change intended behavior, reach well outside the diff, or is a false positive.
- Verify: build, run the suite, and lint (adjust per repo, e.g.
go build ./...,go test ./...,golangci-lint run ./...). Do not proceed on red; revert a stage's fix if it introduced a regression. - Close with what was fixed vs skipped. Leave the changes uncommitted — the user commits separately.
- Minimal scoped diffs. No cosmetic churn, no drive-by edits, no widening of scope.
- Bug hunting belongs to the review skill. A real bug found here gets a one-line report in the summary, not a fix.
- Watch the known failure modes of an eager simplify: recursion introduced by collapsing a call chain, regressions in behavior that has no test to catch it (rendering, layout, focus), and "unused" wiring deleted because its only caller is a framework or callback the analysis could not see.
- Reuse the repo's existing helpers instead of adding near-duplicates; delete dead abstraction; pitch each function at one consistent altitude.
- This skill spawns four subagents by design — the sanctioned exception to "don't spawn unless asked".
- Name collision. A different, report-only simplify skill exists as an x-cmd
preset (
x-cmd mod slash/lib/preset/simplify). It never edits files and runs a single agent; this skill is the one that reviews AND applies.
| name | sync-siblings |
|---|---|
| description | Propagate the latest go-glyph/go-gui across all go-gui-org sibling repos in topological order — release upstream tags, bump + ship every consumer, verify CI green and local repos synced. Triggers - bump siblings, update go-glyph/go-gui everywhere, sync sibling deps, propagate dependency versions. |
| user_invocable | true |
Propagate the latest go-glyph and go-gui across every go-gui-org sibling
repo, robustly, leaving all local repos clean and synced with green CI. This
skill exists because ad-hoc bumps keep failing the same ways: deps edited but
not pushed; pushed but CI red on a stale generated file or a hardcoded
workflow; a repo left out; local repos never synced back.
Before anything else: use todowrite to create a tracker — one item per
phase, plus one item per consumer repo in Phase 3. Mark each
in_progress/completed as you go.
- Not done until reconciled. A bump is complete only when: PR merged
and local
mainpulled andgo.modon freshmainshows the target version. Never stop at "edited" or "pushed". GOWORK=offfor all verification. Run everygo build/test/vet/mod tidy/get/listand everymakegate withGOWORK=off. Several repos have a gitignoredgo.work(go-gui, go-edit, go-kite) that resolves siblings from local working trees — that masks failures CI will hit against published modules.GOWORK=offmakes local match CI.- Strict topological order. glyph tag → gui tag → consumers. Never bump a consumer to an upstream version that is not yet a published, proxy-served tag.
- Dynamic discovery, never a hardcoded repo list. Recompute the consumer set each run (below) and print it with a count. If it differs from what you expect, say so — this is the guard against leaving a repo out.
- Mirror CI locally before pushing. After a bump, regenerate the repo's
derived artifacts and run that repo's own gate, not just build/test. If the
repo has a
Makefile, inspect.github/workflows/*.ymlfor themake …the gate runs and run those exact targets. If a workflow regenerates a file then git-diffs it (*-check, orgo generate ./...+ diff), run the generator and commit the regenerated file in the same PR. (This is the fix for the go-guideps-doc-checkfailure —docs/dependencies.mdis generated fromgo.mod.) - Idempotent. A repo already on the target versions is a logged no-op. Safe to rerun after a mid-run failure — re-derive state, don't assume it.
- Reuse the
shipandreleaseskills for PRs and tags; do not reinvent their commit/CI-watch/merge/cleanup logic.
Resolve SIBLINGS_ROOT = parent dir of the invoking repo (fallback
~/Documents/github). Then:
cd "$SIBLINGS_ROOT"
# Consumers: siblings with a DIRECT (non-indirect) require on glyph or gui,
# excluding the two upstream libs themselves.
for d in */; do gm="$d/go.mod"; [ -f "$gm" ] || continue
mod=$(head -1 "$gm" | awk '{print $2}')
case "$mod" in */go-glyph|*/go-gui) continue;; esac
deps=$(grep -E 'go-gui-org/go-(glyph|gui) ' "$gm" | grep -v '// indirect' \
| awk '{print $1"@"$2}' | paste -sd, -)
[ -n "$deps" ] && printf '%-14s %s\n' "$d" "$deps"
donePrint the resolved UPSTREAM = [go-glyph, go-gui] (fixed order) and the
discovered CONSUMERS with a count. For every repo (upstream + consumers):
git -C <r> fetch --all --tags, then require a clean working tree and
main even with origin/main. Abort and list any repo that is dirty,
ahead/behind, or detached — do not mutate a dirty workspace.
GLYPH_VERSION=$(git -C go-glyph ls-remote --tags --refs origin \
| awk -F/ '{print $NF}' | grep -E '^v[0-9]' | sort -V | tail -1)If origin/main is ahead of GLYPH_VERSION (commits since the tag):
PAUSE. Show the commit list and ask whether to cut a glyph release (invoke
the release skill inside go-glyph) or propagate the existing tag. Never tag
go-glyph unattended. Record the final GLYPH_VERSION.
Compare go-gui/go.mod's glyph require to GLYPH_VERSION.
If behind:
- Branch off fresh
main. GOWORK=off go get github.com/go-gui-org/go-glyph@$GLYPH_VERSIONGOWORK=off go mod tidy- Regenerate + mirror the gate (the step skipped in the failure that
motivated this skill):
GOWORK=off make deps-docto refreshdocs/dependencies.md, then run the workflow's gate verbatim —GOWORK=off make vet deps-doc-check large-files generate-check— plusGOWORK=off go build ./... && GOWORK=off go test ./.... Re-read.github/workflows/ci.ymlfor the current gate target list in case it changed; run whatever it runs. Stage every regenerated file (esp.docs/dependencies.md). - Ship the PR via the
shipskill (commit, push, watch CI, squash-merge, pullmain).
Then, whenever go-gui's main is ahead of its latest tag and that delta
must reach consumers (always true after a glyph bump), cut a go-gui release
via the release skill so the change is exposed as a tag.
GUI_VERSION=$(git -C go-gui ls-remote --tags --refs origin \
| awk -F/ '{print $NF}' | grep -E '^v[0-9]' | sort -V | tail -1)
# Wait out module-proxy lag before any consumer bump:
until GOWORK=off go list -m github.com/go-gui-org/go-gui@$GUI_VERSION >/dev/null 2>&1
do sleep 15; doneRecord GLYPH_VERSION and GUI_VERSION — the targets every consumer bumps to.
Process each consumer independently so one failure never hides the others. For
repo R (in $SIBLINGS_ROOT/R):
-
Branch
bump-deps-$(date +%Y%m%d)off freshly pulledmain. -
GOWORK=off go getonly the depsRactually uses (from the Phase 0 discovery):github.com/go-gui-org/go-glyph@$GLYPH_VERSIONand/orgithub.com/go-gui-org/go-gui@$GUI_VERSION. -
GOWORK=off go mod tidy. -
Bump any workflow
ref:that pins the upstream you just bumped —grep -rn -A6 'repository: go-gui-org' .github/workflows/. A pinnedreplaceoverridesgo.mod, so skipping this makes CI go green while testing the old version; the bump ships unexercised. Every workflow that pins it, not justci.yml. Unpinned checkouts (noref:) track main and need no edit — but note their green does not prove the tag either. -
Mirror
R's CI locally. Base verify:GOWORK=off go build ./... && GOWORK=off go test ./... && GOWORK=off go vet ./.... IfRhas aMakefile, also run the gate targets its.github/workflows/*.ymlinvokes, and commit any regenerated file. (Today only go-gui has such a gate, but check every repo — this future-proofs.) -
Ship via the
shipskill → commit, push, PR, watch CI, squash-merge, delete branch, pullmain. Prefership(orgh pr checks <n> --watch) for a single PR. When polling several consumer PRs in one loop, decide pass/fail from thegh pr checksexit code (0= all passed; non-zero = still pending or failing), never by grepping stdout forfail/error— gh prints aFailed: 0summary line whose substring produces false "failure" readings. If distinguishing pending from failed, match the per-row status column (--jsonstate, or an anchored\tpass\t/\tfail\tfield), not a bare substring. -
Red-CI triage — classify before re-running or editing:
module@version not found→ proxy lag from Phase 2; wait and retry the bump/go get.- Generated/derived file out of date (
*-checkdiff, deps-doc, orgo generategate) → run the generator, commit, update the PR. - Hardcoded workflow assumption — a repo's CI checks out an upstream and
go mod edit -replaces onto it, so the workflow's ref, notgo.mod, decides what is compiled. Either polarity breaks (see below) → fix the workflow in the same PR, do not work around it. - Runner/timing flake → re-run once before treating as a regression.
replace-based CI: two opposite failures. Re-derive each repo's refs at run time (grep -rn -A6 'repository: go-gui-org' <r>/.github/workflows/) — do not trust this list, it drifts:repo → upstream ref today failure mode go-gui → go-glyph unpinned ( setup-go-glyph/action.yml, noref:)tracks glyph main TIP. Glyph main advancing reds go-gui PRs before any bump; green does not prove the published tag. go-charts → go-gui pinned ( ci.yml,gallery.yml)stale pin silently validates nothing. go-charts → go-glyph pinned ( ci.yml,gallery.yml)same. The pinned case is the dangerous one and is not caught by a red CI: the
replaceoverridesgo.mod, so ago get-only bump leaves CI compiling against the old pinned tag and going green — the bump is never exercised. When bumping a repo whose CI pins an upstream, bump the workflowref:in the same PR, in every workflow that pins it (go-charts has two:ci.ymlandgallery.yml). If the upstream release is breaking, skipping this instead goes red with a confusing error: migrated source compiled against the pre-migration API.Either way, a
replace-based green proves less than it appears. Trust theGOWORK=offlocal verify and the published-version consumers (go-edit/go-kite/go-map/go-term) for real coverage.
Re-git fetch and re-run the Phase 0 discovery grep against fresh main for
every consumer. Assert glyph == GLYPH_VERSION and gui == GUI_VERSION where
each is used. Assert every repo (upstream + consumers): clean tree, on main,
even with origin/main, no leftover bump-deps-* branch local or remote.
Also assert no workflow pins a superseded version — go.mod matching the
target while CI still pins the old tag is the silent-green case from Phase 3
step 4, and it survives every other check here:
cd "$SIBLINGS_ROOT"
grep -rn -A6 'repository: go-gui-org' */.github/workflows/ */.github/actions/*/ \
2>/dev/null | grep -E 'repository:|ref:'Read it in pairs: each repository: line and the ref: that follows it. A
repository: with no ref: before the next one tracks main (expected for
go-gui → go-glyph). Every ref: that does appear must equal $GUI_VERSION /
$GLYPH_VERSION. A stale one means that repo's green CI never compiled the
version its go.mod claims to require.
Emit a final table — repo | glyph | gui | PR URL | CI | local-synced — and
call out explicitly any row that is not fully reconciled. The run is not "done"
until every consumer matches the targets and every local repo is clean and
pulled.
If $ARGUMENTS is provided, treat it as an override for the target versions
(e.g. a specific glyph/gui tag to propagate instead of newest).
| name | test-gaps |
|---|---|
| description | Find test gaps in uncommitted code changes. Reports untested public functions, missing edge cases, and uncovered error paths. |
| user_invocable | true |
Analyze all uncommitted changes (staged and unstaged) for test coverage gaps:
Steps:
- Run
git diffandgit diff --cachedto identify changed/added files and functions - For each changed file, find the corresponding
_test.gofile (if any) - Read the changed code and existing tests to understand current coverage
- Report gaps grouped by severity:
Missing tests (no test exists):
- New exported functions or methods with no corresponding test
- New unexported functions with non-trivial logic and no test
Missing edge cases (test exists but incomplete):
- Error return paths not exercised
- Boundary values: zero, negative, empty, nil, max-size inputs
- NaN/Inf float inputs (for numeric code)
- Single-element and two-element cases for slice/collection code
Missing integration tests:
- New cross-package interactions without an integration test
- New I/O paths (file, network) without a test that exercises them
For each gap:
- State the file:function and what is untested
- Rate as high (crash/panic risk), medium (silent wrong result), or low (cosmetic)
- Suggest a one-line test name (e.g.,
TestExportSVG_EmptySeriesNoPanic)