docs+ci: document the plugin path, bump plugin.json version on release
release / tag (push) Successful in 1s
release / tag (push) Successful in 1s
CI now writes the computed semver into .claude-plugin/plugin.json before tagging, committed with [skip-release] so it does not re-trigger the tagger. Claude Code gates plugin updates on that field: without the bump, installed hosts never see a new tag no matter how many releases go out. `task check` enforces manifest/tag equality so the two cannot silently diverge. Docs rewritten around the two delivery paths, and the checkout location is now stated as load-bearing rather than incidental: SKILLS_CHECKOUT_DIR defaults to ~/.local/share/skills because that is host-local and outside any synced directory. The previous docs told you to clone into ~/dev, which on this fleet is an iCloud folder shared by two Macs spanning two path roots — a git working tree with concurrent writers, and absolute links that are broken on one side by construction. That advice is what #23 is about; it is now inverted with the reason attached. Antigravity and Vibe removed from the docs along with their targets. Bump-Type: patch Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BeAp5LTscnz2W7Ubt4eJ6m
This commit is contained in:
@@ -62,6 +62,23 @@ jobs:
|
||||
set -euo pipefail
|
||||
git config user.name "${GITEA_ACTOR}"
|
||||
git config user.email "${GITEA_ACTOR}@noreply.gitea.d-ma.be"
|
||||
|
||||
# Claude Code gates plugin updates on plugin.json's version field:
|
||||
# if it does not move, installed hosts never see the new tag. Bump
|
||||
# it in the same commit train so the tag and the manifest agree —
|
||||
# `task check` enforces that equality on every run.
|
||||
manifest=.claude-plugin/plugin.json
|
||||
version="${TAG#v}"
|
||||
current=$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$manifest" | head -1)
|
||||
if [ "$current" != "$version" ]; then
|
||||
sed -i "s/\"version\"[[:space:]]*:[[:space:]]*\"$current\"/\"version\": \"$version\"/" "$manifest"
|
||||
git add "$manifest"
|
||||
# [skip-release] stops this push from re-triggering the tagger.
|
||||
git commit -m "chore(release): plugin.json version $version [skip-release]"
|
||||
git push origin HEAD:main
|
||||
echo "bumped $manifest to $version"
|
||||
fi
|
||||
|
||||
git tag -a "$TAG" -m "release $TAG"
|
||||
# gitea-actions checkout uses an x-access-token URL; reuse it.
|
||||
git push origin "$TAG"
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
# skills
|
||||
|
||||
Engineering skills library — markdown `SKILL.md` files that plug into any
|
||||
project or AI-coding harness. Installed via `task skills:install` in
|
||||
consumer projects, or directly by `install.sh` on hosts without Task.
|
||||
AI-coding harness.
|
||||
|
||||
For **Claude Code** this repo is a plugin, installed from the marketplace it
|
||||
also hosts; that path carries the hooks and MCP servers too. For **Crush, Pi
|
||||
and OpenCode** it is a plain library wired by `install.sh` as one directory
|
||||
symlink per harness. See [`SKILLS_INDEX.md`](./SKILLS_INDEX.md#wiring-into-tools).
|
||||
|
||||
## What is a skill?
|
||||
|
||||
@@ -16,65 +20,73 @@ references.
|
||||
See [`SKILLS_INDEX.md`](./SKILLS_INDEX.md) for the full catalogue with
|
||||
descriptions and "use when" triggers.
|
||||
|
||||
## Install (consumer project)
|
||||
## Install
|
||||
|
||||
The expected pattern: each consumer project's `Taskfile.yml` has a
|
||||
`skills:install` target that delegates here. From a project root:
|
||||
### Claude Code — the plugin
|
||||
|
||||
```bash
|
||||
task skills:install
|
||||
```
|
||||
/plugin marketplace add https://git.d-ma.be/mathias/skills.git
|
||||
/plugin install skills@mathias
|
||||
```
|
||||
|
||||
Bare-shell fallback for hosts without Task installed:
|
||||
The plugin ships skills, the `secret-guard` + `pre-task-ritual` hooks, and the
|
||||
brain/gitea/infra MCP servers as one versioned unit. Skills are namespaced
|
||||
(`skills:tdd`). Updates land when `.claude-plugin/plugin.json`'s `version`
|
||||
moves — CI bumps it on every release.
|
||||
|
||||
### Crush, Pi, OpenCode — `install.sh`
|
||||
|
||||
```bash
|
||||
curl -fsSL https://gitea.d-ma.be/mathias/skills/raw/branch/main/install.sh | bash
|
||||
curl -fsSL https://git.d-ma.be/mathias/skills/raw/branch/main/install.sh | bash
|
||||
```
|
||||
|
||||
Both forms are idempotent and re-runnable. On every run they:
|
||||
Idempotent. It clones or fast-forwards the checkout, then creates **three**
|
||||
symlinks — one directory link per harness, never one per skill:
|
||||
|
||||
1. `git clone` (or `git pull`) this repo into `~/.local/share/skills/` —
|
||||
the **canonical local checkout** on every host.
|
||||
2. Wire per-skill symlinks into the harnesses found on the host (see
|
||||
[Wired harnesses](#wired-harnesses)).
|
||||
| Link | Target |
|
||||
|---|---|
|
||||
| `~/.agents/skills` | `$SKILLS_CHECKOUT_DIR/skills` (Pi reads this path directly) |
|
||||
| `~/.config/crush/skills` | `~/.agents/skills` |
|
||||
| `~/.config/opencode/skills` | `~/.agents/skills` |
|
||||
|
||||
Re-run after `git pull` upstream to pick up new skills or version
|
||||
changes. CI tags every change as a `vX.Y.Z` release (see
|
||||
[Versioning](#versioning)).
|
||||
Adding a skill wires it everywhere with no re-run.
|
||||
|
||||
## Wired harnesses
|
||||
### Where the checkout must live
|
||||
|
||||
| Harness | Target path | Notes |
|
||||
|---|---|---|
|
||||
| **Claude Code (global)** | `~/.claude/skills/<name>` | Visible in every Claude Code session on the host. |
|
||||
| **Claude Code (per-repo)** | `<repo>/.claude/skills/<name>` | Created when `install` is invoked inside a git repo (not the skills repo itself). Gitignored globally via `**/.claude/skills/`. |
|
||||
| **Crush** | `~/.config/crush/skills/<name>` | Charmbracelet Crush — successor to `opencode-ai/opencode` (archived). |
|
||||
| **Antigravity** | `~/.gemini/antigravity/skills/<name>` | Google Antigravity (VS Code extension). Our `SKILL.md` frontmatter (`name` + `description`) is already in the format Antigravity expects, so symlinks suffice — no manifest translation. |
|
||||
`SKILLS_CHECKOUT_DIR` defaults to `~/.local/share/skills`, and that default is
|
||||
load-bearing: it is **host-local, outside any synced or shared directory**.
|
||||
|
||||
### Not wired (and why)
|
||||
|
||||
- **opencode** (`opencode-ai/opencode`): archive notice; succeeded by Crush.
|
||||
Its only "skill"-like surface — Custom Commands at `~/.config/opencode/commands/` —
|
||||
is for user-facing prompt templates, not system-level instructions.
|
||||
Misaligned with how we use skills. Skipped.
|
||||
- **gitea-resident agents** (cobalt-dingo, agentsquad): they consume
|
||||
skills via their containing project's `.claude/skills` directory
|
||||
(populated by the per-repo wirer when run from the host), or via the
|
||||
brain MCP. No special target needed.
|
||||
On this fleet `~/dev` is an iCloud folder shared by flamingo and iguana, and it
|
||||
spans two path roots — `/Users/mathias` on the Macs, `/home/mathias` on koala.
|
||||
A checkout there is a git working tree with two concurrent writers, and any
|
||||
absolute symlink stored there is broken on one side by construction. That is
|
||||
what produced 243 dangling links across 12 repos (#23). Do not "fix" the
|
||||
default to point into `~/dev`.
|
||||
|
||||
### Per-host env-var overrides
|
||||
|
||||
Each target path can be overridden by setting the matching env var before
|
||||
running `install.sh`:
|
||||
|
||||
| Env var | Default |
|
||||
|---|---|
|
||||
| `SKILLS_REPO_URL` | `https://gitea.d-ma.be/mathias/skills.git` |
|
||||
| `SKILLS_REF` | `main` (set to e.g. `v0.1.0` to pin a release) |
|
||||
| `SKILLS_REPO_URL` | `https://git.d-ma.be/mathias/skills.git` |
|
||||
| `SKILLS_REF` | `main` (set to e.g. `v0.4.0` to pin a release) |
|
||||
| `SKILLS_CHECKOUT_DIR` | `$HOME/.local/share/skills` |
|
||||
| `CLAUDE_SKILLS_DIR` | `$HOME/.claude/skills` |
|
||||
| `SKILLS_SKIP_FETCH` | unset (`1` wires an existing checkout without touching HEAD) |
|
||||
| `AGENTS_SKILLS_DIR` | `$HOME/.agents/skills` |
|
||||
| `CRUSH_SKILLS_DIR` | `$HOME/.config/crush/skills` |
|
||||
| `ANTIGRAVITY_SKILLS_DIR` | `$HOME/.gemini/antigravity/skills` |
|
||||
| `OPENCODE_SKILLS_DIR` | `$HOME/.config/opencode/skills` |
|
||||
|
||||
Antigravity and Mistral Vibe targets were removed — unused.
|
||||
|
||||
## Checking a host
|
||||
|
||||
```bash
|
||||
task doctor # or bin/doctor
|
||||
```
|
||||
|
||||
Reports dangling links, links resolving into a foreign checkout, skill-count
|
||||
mismatches, stray entries, and leftover per-skill Claude symlinks. Non-zero
|
||||
exit on drift. It also runs at session start via the plugin, so a drifting
|
||||
host says so rather than waiting to be discovered.
|
||||
|
||||
## Versioning
|
||||
|
||||
|
||||
+47
-15
@@ -47,23 +47,55 @@ This index lists all available engineering skills. Load the full SKILL.md on dem
|
||||
|
||||
## Wiring into tools
|
||||
|
||||
This repo **is** the canonical home. Wire every skill into each harness with the
|
||||
**`install.sh`** script (idempotent, per-skill symlinks) — either the one-shot
|
||||
`curl -fsSL https://git.d-ma.be/mathias/skills/raw/branch/main/install.sh | bash`,
|
||||
or, from a clone, `SKILLS_CHECKOUT_DIR="$PWD" bash install.sh`. (The `task
|
||||
install` targets are currently broken — see issue — use `install.sh`.)
|
||||
This repo is the canonical home, and it is delivered two different ways.
|
||||
|
||||
- **Claude Code (global)** — `~/.claude/skills/<name>` → `<repo>/<name>`.
|
||||
- **Claude Code (per-repo)** — `<repo>/.claude/skills/<name>` when `task install`
|
||||
is run inside another git repo (excluded via `~/.config/git/ignore`).
|
||||
- **Crush** — `~/.config/crush/skills/<name>`.
|
||||
- **Antigravity** — `~/.gemini/antigravity/skills/<name>`.
|
||||
- **Mistral Vibe** — `~/.vibe/skills/<name>.md` → `<repo>/<name>/SKILL.md`
|
||||
(flat `.md` layout).
|
||||
### Claude Code — install the plugin
|
||||
|
||||
Individual targets are also runnable: `task install:claude:global`,
|
||||
`install:crush`, `install:antigravity`, `install:vibe`. `task update` pulls the
|
||||
canonical checkout then re-wires.
|
||||
This repo hosts a marketplace containing exactly one plugin: itself. The plugin
|
||||
carries the skills **plus** the `secret-guard` and `pre-task-ritual` hooks and
|
||||
the brain/gitea/infra MCP servers — none of which a symlink can deliver.
|
||||
|
||||
```
|
||||
/plugin marketplace add https://git.d-ma.be/mathias/skills.git
|
||||
/plugin install skills@mathias
|
||||
```
|
||||
|
||||
Skills are namespaced: `tdd` becomes `skills:tdd`. Updates arrive when
|
||||
`.claude-plugin/plugin.json`'s `version` moves, which CI does on every release.
|
||||
Remove any leftover `~/.claude/skills/<name>` symlinks from the pre-plugin era —
|
||||
plugin skills do **not** override same-named user skills, so leftovers make
|
||||
everything load twice.
|
||||
|
||||
### Crush, Pi, OpenCode — run `install.sh`
|
||||
|
||||
These have no plugin system, so they get symlinks — but **one directory link
|
||||
each**, never one per skill:
|
||||
|
||||
```
|
||||
~/.agents/skills -> $SKILLS_CHECKOUT_DIR/skills (Pi reads this directly)
|
||||
~/.config/crush/skills -> ~/.agents/skills
|
||||
~/.config/opencode/skills -> ~/.agents/skills
|
||||
```
|
||||
|
||||
Adding a skill therefore wires it everywhere with no re-run, and a broken link
|
||||
is one broken link instead of 42.
|
||||
|
||||
```
|
||||
curl -fsSL https://git.d-ma.be/mathias/skills/raw/branch/main/install.sh | bash
|
||||
```
|
||||
|
||||
`SKILLS_CHECKOUT_DIR` defaults to `~/.local/share/skills` and **must stay
|
||||
outside `~/dev`**. On this fleet `~/dev` is an iCloud folder shared by both
|
||||
Macs and spans two path roots (`/Users/mathias` vs `/home/mathias` on koala);
|
||||
a checkout there means a git working tree with two concurrent writers, and any
|
||||
absolute link stored there is broken on one side by construction. See #23.
|
||||
|
||||
### Check a host
|
||||
|
||||
`task doctor` (or `bin/doctor`) reports dangling links, links resolving into a
|
||||
foreign checkout, count mismatches, stray entries, and leftover Claude
|
||||
symlinks. It also runs automatically at session start via the plugin, so drift
|
||||
announces itself instead of waiting to be found.
|
||||
|
||||
## Skill Relationships
|
||||
|
||||
|
||||
Reference in New Issue
Block a user