Three runs failed with `! [rejected] HEAD -> main (non-fast-forward)`. The
runner is maxParallel=1 and shared with mathias/infra, so those jobs started
five minutes and three commits after their own push. The tagger checked out
its commit and pushed that stale HEAD to main, which main had long left behind.
My own change made it worse: pairing the manifest bump and the tag in a single
`git push` turned a partial failure into a total one, so no tag was created
either. Except once — v0.10.0 landed through the no-bump-needed branch while
the manifest stayed at 0.9.0, which is precisely the "installed hosts never
see the release" state, and which #34's ordering check then caught on main.
The tag now goes up first and alone: it names the commit this run checked out
and cannot be rejected however far main has moved. The bump is a separate
concern that must land on whatever main is NOW, so it re-fetches, rebuilds the
commit on origin/main and retries up to three times, and steps aside entirely
if a later run has already bumped past it.
plugin.json is set to 0.10.0 in this commit so the gate can pass at all — main
was red on manifest-behind-tag, which would have blocked the tag job that fixes
the tagger.
Refs #22
Bump-Type: patch
Skills move to skills/<name>/SKILL.md and the repo gains both manifests, so
it is now a marketplace hosting exactly one plugin whose root is the repo
root (source: "."). Claude Code installs it from git; no symlinks involved.
Why: install.sh wired the library into every consuming repo as an ABSOLUTE
symlink to $CHECKOUT_DIR. The checkout moved three times, most recently when
local-dev@1966d5a dropped the embedded .skills/ copy, and nothing migrated
the links — 243 dangling links across 12 repos, hidden from git by the
**/.claude/skills/ ignore rule. Worse, ~/dev spans two path roots
(/Users/mathias on the iCloud-shared Macs, /home/mathias on koala), so an
absolute link stored there is broken on one side by construction. Re-running
the installer cannot fix that; only removing the mechanism can.
install.sh keeps the harnesses with no plugin system and drops from 42 links
per harness to one directory link, via the convergent ~/.agents/skills
convention that Pi and OpenCode both read:
~/.agents/skills -> $CHECKOUT_DIR/skills
~/.config/crush/skills -> ~/.agents/skills
~/.config/opencode/skills -> ~/.agents/skills
wire_claude_repo is deleted outright rather than gated behind a flag — on a
mixed-root fleet it cannot be made correct. Antigravity and Vibe targets go
too; both unused. CHECKOUT_DIR keeps its host-local default deliberately:
pointing it into ~/dev would put a git working tree inside iCloud with two
concurrent writers.
Taskfile drops five near-identical wiring loops (they had already drifted)
and delegates to install.sh. `task check` gains frontmatter validation, a
stray-root-entry gate, and manifest/tag version parity — the loose
secret-hygiene.md sat unloadable for months because nothing checked layout.
Verified: claude plugin validate . passes clean; a probe skill loaded as
skills:zzprobe through --plugin-dir; task check green at 42 skills.
Refs: #23
Bump-Type: minor
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BeAp5LTscnz2W7Ubt4eJ6m