Both services are now proxied from koala and reachable: tailscale serve 8445 -> 127.0.0.1:31877 (cad) and 8446 -> 127.0.0.1:30340 (gitea-mcp). Both answer 401 unauthenticated, so the path is right and auth is enforced. They stay out of mcpServers because neither token resolves on this host. The static tokens live in the 1Password AgentSecrets vault; koala's op identity sees HomeLab only: op vault list -> HomeLab, and nothing else op://HomeLab/CAD_STATIC_TOKEN -> could not find item op://HomeLab/gitea-mcp-shared-token -> could not find item That is infra#224, not the OAuth-discovery bug #32 and #33 both flagged as the likely blocker. A live entry that cannot authenticate would fail on every session start, so the wiring is recorded rather than enabled. The item names come from the ExternalSecrets, read by reference only — no secret value was retrieved, printed, or transformed at any point. Refs #32, #33 Bump-Type: patch
skills
Engineering skills library — markdown SKILL.md files that plug into any
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.
What is a skill?
A skill is a single directory containing one or more markdown files. The
canonical entrypoint is <name>/SKILL.md. Additional reference material
lives alongside in the same directory (e.g.
clean-code/references/code-smells.md). Harnesses load skills on
demand — keep SKILL.md short and triggerable; push depth into
references.
See SKILLS_INDEX.md for the full catalogue with
descriptions and "use when" triggers.
Install
Claude Code — the plugin
/plugin marketplace add https://git.d-ma.be/mathias/skills.git
/plugin install skills@mathias
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
curl -fsSL https://git.d-ma.be/mathias/skills/raw/branch/main/install.sh | bash
Idempotent. It clones or fast-forwards the checkout, then populates one managed directory and gives each harness a single link to it:
| Path | Target |
|---|---|
~/.agents/skills/ |
a real directory, one symlink per skill (Pi reads this path directly) |
~/.agents/skills/<skill> |
$SKILLS_CHECKOUT_DIR/skills/<skill>, or another configured source |
~/.config/crush/skills |
~/.agents/skills |
~/.config/opencode/skills |
~/.agents/skills |
Total links are N + one per harness — not N x harnesses, which is what #23 was actually about.
More than one source of skills
~/.agents/skills used to be a single link straight at this checkout. That
encoded an assumption nobody had stated — that this checkout is the only source
of skills on the host — and on flamingo the only way to install this library
was to displace Anthropic's official set, which lived in Crush's directory.
Real capability loss dressed up as a tidy-up (#27).
Point SKILLS_EXTRA_SOURCES at any number of extra directories, colon
separated, each holding <skill>/SKILL.md:
SKILLS_EXTRA_SOURCES=~/.config/crush/skills.anthropic bash install.sh
- The checkout is always first and always wins a name collision — but the collision is logged, never resolved in silence. Quietly picking one is how stale content wins.
- Removing a skill from a source removes its link on the next run.
- Anything in the managed directory that is not a symlink is reported and left alone. install.sh does not delete content it did not create.
- The source list is recorded at
~/.agents/skills-sourcessobin/doctorcan tell a link into a known source from a link into a forgotten one.
Where the checkout must live
SKILLS_CHECKOUT_DIR defaults to ~/.local/share/skills, and that default is
load-bearing: it is host-local, outside any synced or shared directory.
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
| Env var | Default |
|---|---|
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 |
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 |
OPENCODE_SKILLS_DIR |
$HOME/.config/opencode/skills |
SKILLS_EXTRA_SOURCES |
unset (colon-separated extra source directories) |
Antigravity and Mistral Vibe targets were removed — unused.
Checking a host
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
Every commit to main is auto-tagged as a semver release by the
.gitea/workflows/release.yml action. Bump direction follows the commit
footer:
Bump-Type: major→X.0.0Bump-Type: minor→0.Y.0- anything else →
0.0.Z(patch, the default)
Consumer projects can pin a version by setting SKILLS_REF=v0.1.0
before task skills:install; default is main for always-current.
Contributing a skill
- Add a directory
<short-kebab-name>/. - Create
<short-kebab-name>/SKILL.md— start with one-paragraph purpose, then triggers ("use when …"), then mechanics. - Add a row to
SKILLS_INDEX.md(description + use-when). - Commit directly to
main. Conventional-commit prefix (feat:/fix:/docs:). AddBump-Type: minorfooter when adding a new skill or expanding scope; default patch covers edits.
This repo is markdown-only and public — never include secrets, client names, or anything under NDA in a skill.