BS

brickswhale/skills

Developer tools
0 stars Quality 47 Trend 20

One place for every custom skill, agent, and hook. Reused across every project, read by Claude Code and Codex.

Overview

One place for every custom skill, agent, and hook. Reused across every project, read by Claude Code and Codex. One method, symlinks, for both hosts: Claude Code reads ~/.claude/skills/, Codex reads ~/.agents/skills/. - re-run the loop when a skill is added. git pull updates every linked skill. - when a skill is removed, delete its link from both ~/.claude/skills/ and ~/.agents/skills/. The loop never deletes. - MACHINE.md holds the rules every session on the machine loads, in both hosts. The last two lines of the block link it once per machine. Claude Code reads the @ line as an import and keeps what ~/.claude/CLAUDE.md already holds. Codex reads no import line, so the link replaces ~/.codex/AGENTS.md; when that file holds lines of its own, the block leaves it alone: move the lines elsewhere and run the block again. A fresh session in each host then has the rules loaded.

README

brickswhale plugin

One place for every custom skill, agent, and hook. Reused across every project, read by Claude Code and Codex.

.claude-plugin/plugin.json   the plugin manifest
MACHINE.md                   the machine briefing: rules every session loads, both hosts
skills//SKILL.md       skills; one the owner normally starts by typing is a command
agents/.md             subagent definitions, when earned
hooks/hooks.json             shared hooks, when earned
reviews/.md           what a review left unsettled, when one was run

Install, once per machine

git clone https://github.com/brickswhale/skills.git ~/skills
mkdir -p ~/.claude/skills ~/.agents/skills ~/.codex
for d in ~/skills/skills/*/; do n=$(basename "$d"); ln -sfn "$d" ~/.claude/skills/$n; ln -sfn "$d" ~/.agents/skills/$n; done
grep -sqxF '@~/skills/MACHINE.md' ~/.claude/CLAUDE.md || printf '\n@~/skills/MACHINE.md\n' >> ~/.claude/CLAUDE.md
[ -s ~/.codex/AGENTS.md ] && [ ! -L ~/.codex/AGENTS.md ] || ln -sfn ~/skills/MACHINE.md ~/.codex/AGENTS.md

One method, symlinks, for both hosts: Claude Code reads ~/.claude/skills/, Codex reads ~/.agents/skills/.

  • Add: re-run the loop when a skill is added. git pull updates every linked skill.
  • Remove: when a skill is removed, delete its link from both ~/.claude/skills/ and ~/.agents/skills/. The loop never deletes.
  • The machine briefing: MACHINE.md holds the rules every session on the machine loads, in both hosts. The last two lines of the block link it once per machine. Claude Code reads the @ line as an import and keeps what ~/.claude/CLAUDE.md already holds. Codex reads no import line, so the link replaces ~/.codex/AGENTS.md; when that file holds lines of its own, the block leaves it alone: move the lines elsewhere and run the block again. A fresh session in each host then has the rules loaded.
  • Plugin install is not an install method here. A plugin install would load every skill a second time in Claude Code under a prefixed name (brickswhale:) beside the linked ``, while the links already serve both hosts. The eval runners load the repo per run with --plugin-dir; that is test wiring, not an install. The links carry skills only: agents/ and hooks/hooks.json reach a session only through that plugin load, so an agent or hook that earns its place also earns its own install line, as the hook below does.

Off by default, Claude Code only: hooks/fresh-call-guard.py refuses a SendMessage to a finished subagent’s raw id, a backstop for route’s fresh-call floor (#28). The cause it met was a session that read the rules once, so the pointer line now has a session re-read them before every round; enable the guard only if a session that has read the rules still sends a round to an earlier agent. Symlinks load no hooks, so it would go in the user settings as a PreToolUse command hook with the matcher SendMessage, running f=/hooks/fresh-call-guard.py; [ ! -f "$f" ] || python3 "$f": a bare python3 exits 2 when the file is missing, and exit 2 blocks the call, so a moved clone would block every message. Its test: bash hooks/fresh-call-guard.test.sh.

Off by default, Claude Code only: hooks/ask-link-check.py stops the desktop app’s next-step box (mcp__ccd_turn__wrap_up) once per turn when a ticket named in the box or in that turn’s text is not a link in that text (#61: a rule line alone left 9 of 12 asks without links). Switch it on per project, in that project’s settings, as a PreToolUse command hook with the matcher mcp__ccd_turn__wrap_up, running f=/hooks/ask-link-check.py; [ ! -f "$f" ] || python3 "$f" --id '', so a moved clone passes instead of blocking every box. Its test: bash hooks/ask-link-check.test.sh.

Who owns what

Owner What Where
This repo skills, the machine briefing’s text, hooks, eval cases skills/, MACHINE.md, hooks/, evals/
The machine the links into this repo; each skill’s data between runs (rule 9); the two host files that load the machine briefing ~/.claude/skills/, ~/.agents/skills/, ~/.config//, ~/.claude/CLAUDE.md, ~/.codex/AGENTS.md
A project its own briefing (project facts and any rule that overrides the machine briefing), its tickets, at most one pointer line per shared skill it uses the project’s AGENTS.md / CLAUDE.md
The Claude app its own synced skills and the copies it moves aside; nothing here writes to them ~/.claude/skills/synced/, ~/.claude/skills/.trash/

Where two owners say different things, the project wins in that project: the machine briefing is the default, a project’s briefing the override.

How work flows

From an idea to the main branch. The discussion, the coordinator and each ticket’s worker run in sessions of their own, so the owner knows which session holds what:

  1. Idea → discussion session. A fresh session takes the idea: consult pressure-tests it, pair adds a second model’s view, intent writes the ticket, plan writes its steps. It ends with a decided ticket, or the reason there is none.
  2. Ticket → queue. The ticket joins a queue ticket, the coordinator’s list.
  3. Queue → coordinator. /supervise makes the session the owner talks to the coordinator: it finds the queue, the open ticket whose title begins [supervise] (or the one /supervise # names), keeps the list, hands out each ticket and checks each report on disk. A new idea or an undecided ticket that reaches it goes back to stage 1.
  4. Ticket → worker. One fresh worker session per ticket, running flow: re-check, plan, build, review, commit.
  5. Merge and push on the owner’s word.

What a project gets

The contract onboard applies to a consumer project.

  1. Overrides kept. A project rule that differs from the machine briefing or a shared skill stays in the project’s briefing, with its effect intact.
  2. Every old-kit rule gets a home. Each rule in the project’s old-kit briefing maps to exactly one of: covered by a named shared skill; covered by the machine briefing; kept as a project rule; retired on the owner’s word. A rule with no home is listed for the owner; none is dropped silently.
  3. Pointers, not copies. The project gets at most one pointer line per shared skill (rule 9 in AGENTS.md); no skill text is pasted into the project.
  4. A second run adds nothing. Running the setup again on a set-up project changes no file.

Structure

Flat. One folder per skill under skills/, holding SKILL.md and, where a skill needs reference data too long to inline, a references/ beside it — the hook word-caps and genericity-checks SKILL.md alone, so anything else there is scrubbed by hand or not committed. No category folders: the plugin manifest can list several skill directories, and the install loop reads one level, so a category, when there are enough skills to need one, becomes a second directory listed in plugin.json and read by its own install loop, never a nested path. Until then the table below groups skills by SDLC stage. A command is a skill the owner normally starts by typing its name (rule 2); there is no commands/ folder.

Frontmatter keys: only those in Claude Code’s frontmatter reference, which is the list, not a copy here. model and effort are among them and switch the model and effort while the skill runs, so neither ever labels the model a skill was written for.

Evals

Real use is the proof (owner’s ruling 2026-10-11, #40): a skill that fails in real use gets a ticket. Eval runs proved that some skills change behaviour (consult 5/5 against 0/5 bare) and that some should not be built (route’s bare setup passed 5/5), but no eval caught a broken skill before real use did, and their batches burned the usage window four times (#37).

Every skill has a fire case under evals/-/, in the layout claude plugin eval reads: prompt.md with frontmatter, graders/*.md — skill-fired.md proving the skill fired, plus an llm grader with a PASS/FAIL rubric for the outcome — optional case.yaml with a scaffold_script that builds a self-contained fixture, an optional followup.md as a second user turn, and a writes file (rule 9). A case that starts its skill by a bare slash name makes no Skill call, so its skill-fired grader is an llm one matching a line only its body produces; plan’s cases call /brickswhale:plan, since a bare /plan reaches Claude Code’s built-in command.

  • Every commit: evals/check-static.sh, from the pre-commit hook — frontmatter, scrub, case files, script syntax. Free.
  • A new skill, or a changed description: line: one fire check, about 2 calls, on the owner’s OK: evals/run-eval.sh --model --budget --tracer . The commit message names it in a fire-check: line; .githooks/commit-msg asks for that line, and for a fire case, only in these two situations.
  • A body edit: no live run.

The eval tools stay as they are: nothing new is added, and a piece is deleted only when it breaks. evals/run-eval.sh is the runner (a named model, a budget printed before the first call, one run at a time, a stop at the first usage-limit line); evals/run-valid.sh is its gate; evals/replay.sh re-checks saved route runs without a new session; route’s two-stage cases run through evals/run-route-case.sh, with the account in reviews/route-design.md. Judges stay on the default model: in the route record haiku misgraded, then sonnet at low effort misgraded five of twenty-five verdicts. CI skips the 17 pinned replay checks that require saved runs on the owner’s machine; changes to evals/replay.sh or evals/route-checks/ also require running evals/replay.test.sh there.

Working on this repo

Two repo-local skills in .claude/skills/, not installed globally: /new-skill scaffolds a skill and its eval case, /eval-skill runs it fenced and says whether the result counts. Both are model-invocable, so an agent can run them, which is what rule 7 asks for. Their job is to make sure every skill here is well made. They never leave this repo.

Rules

  • This repo is public. No client names, no home paths, no credentials in any skill, ever.
  • A skill is a checklist, never a script. Target under 300 words — a target, not a blocker. Exceed it when the extra lines change what the agent does.
  • A skill that a tool can replace is deleted the day the tool exists.
  • A skill is self-contained: its rules stay in its own folder, its machine data under ~/.config//, and a consumer repository gets only what the owner asked for plus at most one pointer line. Rule 9 in AGENTS.md.
  • Nothing copied from agent-kit verbatim. A kit-* skill is rewritten here only when a real ticket shows its judgment step done badly twice, or on the owner’s word. Its kit-* symlink stays until the last project using it moves to the new name.

Skills

Skill Use
consult an idea gets pressure-tested before anyone builds it — its real terms, the assumptions, the strongest objection, a verdict that may be “don’t”. Writes nothing, produces no plan. /consult, or any “what if we”
flow one task runs from ask to closed ticket — the ticket in the project’s own place first, findings written to it as they appear, a re-check before building, test then review then commit, a commit that lands an item of the plan list ticks it with that commit, and a six-line wrap-up block; a typo, comment or format fix takes the fast lane. A project connects with one briefing line naming its ticket place: “Tickets: . Work beyond a typo, comment or format fix follows the flow skill: call it before the first edit.” /flow
gate a phase boundary gets a go or no-go — every criterion labelled against an artifact that was actually run, never a note asserting it, and “not yet” is a real verdict carrying what would flip it. /gate, or “are we ready for the next phase”
intent a raw ask becomes an issue — problem, outcome, affected, constraints, open questions, interrogated until each is concrete. /intent , or a session calls it by name
learn a mistake becomes one rule on the highest rung that can catch it — test, hook, skill line, briefing — replacing a line, never adding one. /learn, or when a lesson needs to stick
onboard one project is set up on the shared skills, or checked — an inventory of its agent setup and the machine side, a status table per layer, a duty table giving every old rule one home with its source line (a named skill, the machine briefing, a project rule, or retired on the owner’s word) and a “what you lose” list; then one diff applied on the owner’s yes, the flow pointer line, the owner’s own /route connect, and a wiring check that ends in pass or fail. “Check only” writes nothing; a re-run on a set-up project changes nothing. A command: /onboard, /onboard check
pair a second opinion from another model on one question — your own position written first, the ask put blind, both views attributed and the dissent kept rather than averaged. /pair, or “second model opinion”
plan an ask becomes ordered steps — files, the test per step, blast radius, riskiest step, numbered alternatives; nothing is written until the asker picks, and then the picked steps go into the ticket as a - [ ] list, each with its proof. /plan , or a session calls it by name
progress the list re-checked against its proofs before any report — found in the ticket, or drafted from evidence as a DRAFT with a source per item; state changes need proof, scope changes are proposed; then what changed, what waits on the owner, the list, the next step. /progress, or “what’s the progress”
review four lenses over a diff — bugs, security, does it match the plan, scope creep — every finding verified against the code and given a counted class, verdict as JSON. /review
route the machine’s model dictionary and its jobs with ranked models get written or brought up to date, under ~/.config/route/ and shared by every project — which models this machine has and what each is good for, from its own tools and the owner’s answers, and which one builds and which reviews each job. Drafts, checks, then writes on the owner’s yes; a project gets one pointer line to the skill’s rules, which sessions read in place with the two files. A command: /route
supervise the session the owner talks to supervises an effort while other sessions do the work — the list re-checked through progress at the start, on each progress ask and after each worker report; before a hand-off, a check that no other worktree or branch changes the same files; a brief that ends in a six-line callback; each report checked on disk, where a change counts as done only once its commit is on the main branch; decisions relayed in the owner’s words. /supervise, which finds the open ticket whose title begins [supervise]; /supervise ; or “supervise this”

Photography

Skill Use
photo-taste photographic direction, reference interpretation, critique and reversible editing; judges composition, light and colour against visual intent. “Make this photo professional”, “critique this edit”. LightCraft guidance included.

agent-kit skills, where each one goes

kit skill goes to
kit-lens-review, kit-eng-pass review — judgment only; kit-eng-pass ran the tests and mapped coverage, review runs nothing
kit-adr, kit-consult’s ranking plan — done
kit-consult’s advisory mode consult — done
kit-idea, kit-setup’s interview intent — judgment only; kit-idea appended one dated line and left, intent interrogates until each field is concrete
kit-setup’s setup and update onboard — judgment only: a project is moved onto the shared skills with every old rule given a home; the template scaffold and the version sync did not come across
kit-doc-sync learn — judgment only; the per-commit sweep over every doc surface did not come across
kit-milestone-gate gate — done
kit-recenter attempted, rejected — see below
kit-report progress — judgment only: what waits on the owner comes first, and every state is re-checked on disk before it is shown; the CLI did not come across
kit-problem-log, kit-pause wrappers round a CLI that does not exist here
kit-log, kit-phase-map git and the issue tracker already hold this
kit-batch, kit-prompt-cycle, kit-inline the framework’s own orchestration; it retires with it
kit-pair pair — done, on the owner’s word; the catalog came too, the machine-local record did not
skills-extra (agent-kit’s folder) a category for skills outside the main flow, with its own README heading as Photography has — no folder here; its three skills each have a row below
design-flow flow’s design-change rule and route’s Design job — judgment only: the transports catalog, the live specialist pick and the route receipt did not come across; a project’s own preview gate, psychology lens and decision fields stay in the project
deepen mattpocock-skills improve-codebase-architecture (installed plugin) — judgment only: the two-signal scope, the reading ceiling, the adversarial verification and the lasting docs/reviews/ report with dispositions did not come across
naming-review not coming — no replacement; one run (2026-07), no live reference; rewritten here only on the step-1 trigger or the owner’s word

“Done” means the judgment came across, not the job. Seven rows above say so explicitly, because a reader migrating a project off these names will otherwise swap kit-doc-sync for learn and silently lose a commit gate. Checked against the skills as written: learn carries nothing about reconciling a doc surface, review never runs a test, and intent has no one-line capture. kit-adr’s decision record did come across, as plan step 6. A cross-model review found this and it was verified before being believed; the table had read “done” for all six since the migration closed.

A project cannot be migrated by renaming. Each reference has to be read for what it obliges, and an obligation with no new home is either restated in the project or deliberately retired.

How a kit-* skill migrates here

Trigger-based, never scheduled. One skill at a time.

  1. Trigger. A real ticket shows that judgment step done badly twice. Note the ticket in the commit message.
  2. Rewrite. To the word target under Rules, generic, no kit vocabulary, no project names. The old skill is source material, not text to copy.
  3. Test. One fire check, as for any new skill (rule 6); real use decides whether it earned its place.
  4. Retire. Remove that kit-* symlink when the last project using it migrates to the driver. Projects still on the old name keep working until then; the new name differs, so the two coexist without colliding. One copy of each thing, once nothing reads the old one.

Nine, after three reopenings. review, plan, intent, learn, consult and gate came across, and the migration was declared closed at six. pair reopened it on the owner’s word, against the line this file used to carry — that its value was a machine-local transport record and a catalog of sharp edges, with no home here. Half of that objection held. The record is genuinely machine-local and stays there, at ~/.config/pair/ (rule 9); the skill names that path and the lines the file must carry. The catalog was the half that did not hold: it is generic knowledge about public CLIs, it costs nothing against the word cap because the hook reads only SKILL.md, and a skill pointing at a catalog it cannot name is worse than either keeping it out or bringing it in. It was rewritten, scrubbed and now sits at skills/pair/references/transports.md. progress reopened it a second time (#21): kit-report was filed as a wrapper, but only its CLI was; its judgment — what waits on the owner first, every state re-checked on disk before it is shown — is what the owner kept asking sessions for. onboard reopened it a third time (#46): kit-setup’s interview had gone to intent, but moving a project onto the skills was done by hand, and duties were lost on the way. Of the twenty-one kit skills, ten were absorbed into these nine, two are covered by other skills (design-flow by flow and route, deepen by an installed plugin), and the other nine are not coming: two are wrappers round a CLI this repo does not have, two are document layouts git and the issue tracker already hold, three are the old framework’s own orchestration and retire with it, one was attempted and rejected, and naming-review has nothing that needs it yet.

kit-recenter is the one that was attempted and rejected, and the reason is worth keeping. It audits a session’s own recent turns against its standing rules. Built here and evaluated, it twice raised a drift finding against a rule that appeared nowhere in its context, and when the rubric was tightened to demand a source, it invented the source too. A session cannot reliably tell a rule it was given from one it believes it was given, and the eval regime makes it worse: a fresh subprocess has no prior turns, so the fixture must hand it a transcript, which is a different skill from the one intended. Do not rebuild it without a way to verify a cited rule against a file the run actually read.

Reopening needs the trigger in step 1, not a tidy-up impulse. The kit-* symlinks stay until the last project using each one moves across.

View this README on GitHub

Recommended Tools

Try a different keyword or remove a filter.

Install

npx skillfish add brickswhale/skills