AGENTS.md · diff

git:20261025.95d4754 to git:20261025.098919d

4 added, 3 removed. Audit B to B.

# Agents
This repository is a catalogue of skills and small utilities for AI coding
agents. It targets any agent that can read Markdown instructions — Claude
Code, Codex CLI, opencode, Continue, Aider, Cursor, and others.
## Start here
- Documentation map: [`docs/README.md`](docs/README.md).
- Add or change a skill: [`docs/contributing.md`](docs/contributing.md); the
conventions below are the reference.
- Install and use the catalogue: [`README.md`](README.md) and
[`docs/install.md`](docs/install.md).
- Vocabulary: [`GLOSSARY.md`](GLOSSARY.md). Decisions:
[`docs/adr/README.md`](docs/adr/README.md).
## How to use this repo
- Each directory under `skills/` that contains a `SKILL.md` file is a
self-contained skill.
- `skills.json` (repo root) is the machine-readable manifest of all
skills. Read it once to discover what is available without crawling the
tree.
- `install.sh` (repo root) symlinks the skills into the conventional
install paths for Codex CLI and opencode. It also renders the plugins'
subagents through `scripts/plugin_agents.py` — Codex custom agents in
`~/.codex/agents/`, opencode subagents in `~/.config/opencode/agents/` —
and for Codex CLI disables routed members via a marker-delimited block in
`~/.codex/config.toml` (all removed by `--uninstall`).
`--merge-guard` adds the model-free hook `scripts/pr_merge_guard.py` that
stops agents from merging PRs (only the human merges); this repo's
`.claude/settings.json` carries it via `scripts/build_project_claude.py`.
`--secret-guard` adds the same kind of hook, `scripts/secret_read_guard.py`,
which stops agents from reading credential files or dumping the environment.
Claude Code gets skills, subagents, the merge guard and the secret read guard
from the plugin marketplace only; `--target=claude` syncs just
`--instructions` and removes the links and settings entry older versions
created.
See `./install.sh --help` and `docs/install.md`.
- `instructions/` holds single-topic rule fragments, ordered by numeric
- filename prefix, in three tiers: 20, 25, 50, 55 and 60 are always on;
+ filename prefix, in three tiers: 20, 25, 45, 50, 55 and 60 are always on;
Python and R rules are path-scoped in Claude, while Codex and opencode get
the Python baseline by pointer and keep the R rules in their block; 70, 80
and 85 are on demand; 85 is also repeated in this repository's `AGENTS.md`.
`install.sh --instructions` composes the always-on
rules and pointers into marker-delimited blocks in each agent's global
instruction file (`~/.claude/CLAUDE.md`, `~/.codex/AGENTS.md`,
`~/.config/opencode/AGENTS.md`) and installs on-demand files under
`~/.agents/instructions/`. Claude loads `paths:` fragments from
`~/.claude/rules/`; a `Bash(uv init*)` hook supplies the Python baseline
before a Python file exists. The 70 and 85 sources live in
`instructions/on-demand/`; 80 lives at
`skills/llm-application-engineering/references/agent-pipelines.md`. Content
outside the managed markers is never touched.
- `plugins/` packages the same skills as Claude plugins, one plugin per
category (each bundles its skills via symlinks into `skills/`).
`.claude-plugin/marketplace.json` makes the repo installable as a
plugin marketplace in Claude Code, claude.ai, Claude Desktop, and
Cowork. The `architecture` plugin additionally ships two read-only
analysis subagents (`coupling-analyst`, `cohesion-analyst`). The
hook-only `merge-guard` and `secret-guard` plugins carry the PR merge
guard and the secret read guard as `PreToolUse` hooks in `hooks/hooks.json`.
- `.claude/` makes the same skills, subagents and instruction fragments
available to Claude Code cloud sessions in this repo, which load neither
plugins nor `~/.claude/`: symlinks and rendered rules generated by
`scripts/build_project_claude.py` (CI checks drift), including the
`Bash(uv init*)` hook that reads `instructions/30-python.md`, plus Matt
Pocock's skills vendored by `scripts/vendor_mattpocock_skills.py`. See
`docs/maintainers/install-internals.md`.
- Reference material stays inside the skill that owns it, under
`skills/<skill>/references/`. SKILL.md names the pages it has; an agent
opens one only when it needs it. There is no lookup service in front of
them — plain progressive disclosure is the whole mechanism.
## Skill catalogue
Each skill carries a `category` frontmatter field; the sections below
group the catalogue by those categories.
Some categories ship a **router** skill (`activation: router`, named after
the category) as their single registered entry point. Its description is
deliberately broad, and its body routes to the specific sub-skill to read
before acting; the sub-skills nest under the router's `members/` directory
and load only when routed to (progressive disclosure), so the category adds
one trigger entry instead of many. The router's SKILL.md member table is
generated from `skills.json` by `scripts/build_routers.py` (CI checks it for
drift). The tables below still list every sub-skill individually.
Claude registers only top-level skills, so the members stay hidden there. Codex
discovers skills recursively and follows symlinks
([openai/codex#22275](https://github.com/openai/codex/issues/22275)), so it
would otherwise register each nested `members/<name>/SKILL.md` as its own skill;
`install.sh --target=codex` therefore disables every nested member by path in
`~/.codex/config.toml` (a managed `[[skills.config]]` block, `enabled = false`),
dropping them from the model's skill list. `--uninstall` removes the block.
### Architecture & design (`architecture`)
Registered through the [`architecture`](skills/architecture/SKILL.md) router.
| Skill | When to use |
|---|---|
| [architecture-pattern-advisor](skills/architecture-pattern-advisor/SKILL.md) | Choosing or restructuring the architecture of a new or existing repository — system topology (monolith, modular monolith, microservices, serverless, event-driven) and code organization (layered, by-domain, hexagonal, clean/onion). |
| [c4-modeling](skills/c4-modeling/SKILL.md) | Drafting a C4 model of a system interactively and rendering it as Mermaid diagrams — System Context, Container, and Component views plus landscape, dynamic, and deployment — per c4model.com best practices. |
| [coupling-cohesion](skills/coupling-cohesion/SKILL.md) | Measuring coupling or cohesion of existing code — a module's cohesion and LCOM, codebase-wide coupling metrics (instability, abstractness, Zones of Pain/Uselessness), or whether one specific dependency is balanced (Khononov strength/distance/volatility). |
| [ddd](skills/ddd/SKILL.md) | Domain-Driven Design across strategy and code — subdomain classification, context mapping, choosing an implementation pattern, and the correctness conventions for aggregates, value objects, domain events, and event sourcing. |
| [fitness-functions](skills/fitness-functions/SKILL.md) | Designing architecture fitness functions — automated, CI-wired checks (cycle detection, layer rules, metric thresholds, chaos/conformity monitors) that govern architecture characteristics. |
| [logical-component-design](skills/logical-component-design/SKILL.md) | Decomposing a new system or feature into named logical components — the iterative Workflow / Actor-Action identification cycle, the Entity-Trap antipattern, cohesion and coupling refinement, and the Law of Demeter. |
| [microservices-design](skills/microservices-design/SKILL.md) | Designing or reviewing how microservices interact — boundaries, coupling, communication style, contract versioning, cross-service code reuse, sagas, and resiliency patterns (timeouts, bulkheads, circuit breakers, retries) — via a distilled Newman ruleset. |
### Refactoring & code quality (`refactoring`)
| Skill | When to use |
|---|---|
| [improve-codebase](skills/improve-codebase/SKILL.md) | Reviewing a repository's architecture for deepening opportunities — a visual HTML report of candidates with before/after diagrams and a top recommendation, then a round-by-round interview on the one you pick, keeping the glossary and ADRs current. |
| [refactoring](skills/refactoring/SKILL.md) | Finding where to start refactoring in a codebase nobody knows well — ranking files by git churn, reading the hotspots, and keeping restructuring separate from behavior change. |
### AI & ML (`ai-ml`)
Registered through the [`ai-ml`](skills/ai-ml/SKILL.md) router.
| Skill | When to use |
|---|---|
| [llm-application-engineering](skills/llm-application-engineering/SKILL.md) | Diagnosing LLM output failures, ordering LLM app architecture builds, defining production monitoring metrics, or applying craft-level conventions for prompting, evaluation/LLM-judges, guardrails, finetuning, and training data. |
| [ml-project-lifecycle](skills/ml-project-lifecycle/SKILL.md) | Scoping an ML project, picking a model/baseline, handling missing data, or planning pipelines and staged deployment. |
### Workflow & planning (`workflow`)
| Skill | When to use |
|---|---|
| [natural-planning](skills/natural-planning/SKILL.md) | When a project feels stuck, vague, or overwhelming, or a to-do isn't yet a concrete physical next action. |
| [oss-scouting](skills/oss-scouting/SKILL.md) | Scouting one third-party open-source repo for issues worth a small contribution — policy gate, repro, root-cause analysis, fix diff, and a submit checklist, written locally for the user to submit themselves. |
| [poc-spec-loop](skills/poc-spec-loop/SKILL.md) | Bring a greenfield R, Python, or bash PoC to production readiness in two gated phases — interactive spec (SPEC.md + prd.json), then a per-task TDD loop with fresh context up to a pull request. |
| [pypet-snippets](skills/pypet-snippets/SKILL.md) | Curating pypet command snippets — creating, finding, editing, running and aliasing them on request, or proposing one for recurring terminal commands. |
| [release-pr](skills/release-pr/SKILL.md) | Turning the current branch into a release PR for an R or Python package — confirmed version bump, NEWS.md/CHANGELOG.md, checks, PR body — and, after merge, tagging and publishing the release (GitHub, Azure Repos, GitLab). |
| [repo-status](skills/repo-status/SKILL.md) | Generating a status update from recent activity — standup prep, yesterday/today/blockers, structuring rough notes into a shareable update. |
### Communication & writing (`communication`)
| Skill | When to use |
|---|---|
| [blue-team](skills/blue-team/SKILL.md) | Developing a raw early idea — tech decision, project pitch, LinkedIn thesis, personal choice — into a sharper version that holds up before its audience, with load points, reinforcements, and a hardness grade. |
| [communication-analysis](skills/communication-analysis/SKILL.md) | Analyzing or rewriting feedback, messages, or conversations for congruence, hidden appeals, clarity, or boundaries. |
| [documentation](skills/documentation/SKILL.md) | Writing or revising technical documentation for a named reader — README, API reference, runbook, architecture doc, or onboarding guide. |
| [html-artifacts](skills/html-artifacts/SKILL.md) | Producing a self-contained HTML file instead of a markdown reply when content has spatial, comparative, or interactive structure — comparisons, diagrams, timelines, decks, throwaway editors. |
| [ki-stil](skills/ki-stil/SKILL.md) | Checking a German draft for wording that reads generic or AI-typical — counted, located style signals from a bundled scanner, an evidence-tiered verdict, and concrete rewrites; a heuristic, never an authorship verdict. |
| [problem-first-explanation](skills/problem-first-explanation/SKILL.md) | Producing explanations — technical or not — that lead with the concrete problem before the solution. |
| [red-team](skills/red-team/SKILL.md) | Attacking a finished or near-finished artefact or decision — ADR, proposal, LinkedIn post, application, career move — through a fresh-context critic, a materiality gate, stakeholder lenses, and a categorical verdict. |
| [stakeholder-update](skills/stakeholder-update/SKILL.md) | Writing a status update for readers outside the immediate working group — weekly/monthly leadership status, launch announcement, risk escalation, or the same progress retold for partners and customers. |
| [tldr](skills/tldr/SKILL.md) | Compressing something too long to read into the few facts needed to decide or act, read instead of the source — the last message and the work behind it, or a named file, PR, document, or thread. |
| [was](skills/was/SKILL.md) | Re-pitching a short message that was read but not understood, in plain German — the missing context added first instead of shortening, short active sentences, the repo's glossary terms kept verbatim. |
### Personal & knowledge (`personal`)
| Skill | When to use |
|---|---|
| [hypertrophy-training](skills/hypertrophy-training/SKILL.md) | Experienced trainee: set volume, RIR/effort, auto-regulation, diagnosing a stalled lift, training under elevated injury risk, or returning after an injury (educational). |
For agents that auto-load `AGENTS.md` (Codex CLI, opencode, Aider): the
links above are valid relative paths and may be fetched on demand. For
machine consumption prefer `skills.json`.
## Conventions for skill authors
- A skill lives in `skills/<skill-name>/` and has a `SKILL.md` at its root.
- `SKILL.md` starts with YAML frontmatter providing at minimum:
- `name` — must match the directory name (`scripts/quick_validate.py` enforces it).
- `category` — one of `architecture`, `refactoring`,
`ai-ml`, `workflow`, `communication`, `personal` (the fixed list in
`scripts/catalogue.py`; `scripts/quick_validate.py` mirrors it so the
validator also works on skills outside this repo). Determines the
catalogue section, the `install.sh --category` subset, and which plugin
bundles the skill.
- `description` — single paragraph; the first sentence becomes the
`summary` in `skills.json` (for a router the whole description does, since
it is the category's entire trigger surface). Keep it within the description budget:
**≤250 chars** for most skills, **≤450 chars** for router skills, **≤400 chars**
for the small allowlist of high-traffic skills in
`scripts/check_descriptions.py`. Descriptions
are always-loaded metadata that competes for a tight context budget
(Codex CLI truncates the skill list past ~2% of context), so move
trigger lists and feature enumerations into the SKILL.md **body** (a
leading `## When to use` section) rather than the frontmatter. CI
enforces this with `python3 scripts/check_descriptions.py`, which also
caps the aggregate across all `auto` skills.
- Optional frontmatter fields:
- `activation` — `auto` (default) or `command`. `auto` skills are
model-triggered and their description counts toward the auto-trigger
budget. `command` skills are user-invoked only: OpenCode exposes them as
slash commands from the ordinary skills directory when `metadata` sets
`opencode/slash: "true"` and `opencode/autoinvoke: "false"`; Claude loads
them from the plugins as `/<category>:<name>`. Codex custom prompts are
deprecated, so under codex they install
into `~/.agents/skills/` like any skill, gated by an `agents/openai.yaml`
sidecar (`policy.allow_implicit_invocation: false`) that keeps Codex from
auto-triggering them. That sidecar is committed per skill, at
`skills/<name>/agents/openai.yaml` — `install.sh` links it, it does not
generate it. For Claude, pair `command` with
`disable-model-invocation: true` in the same frontmatter (the runtime
realization Claude honors; ignored elsewhere). CI enforces both with
`scripts/quick_validate.py`.
- `when_to_use` — trigger phrases for a **router**, as a single paragraph.
Claude Code appends it to the description in its skill listing (joined
with `" - "`, the two capped at 1,536 chars together), so it holds the
situations users actually type without spending the router's ≤450-char
description budget on them. Codex ignores the key entirely (verified with
`codex debug prompt-input`), which is why
`scripts/check_descriptions.py` keeps it out of the Codex-facing budgets
and gives it Claude's combined cap instead. A router's `skills.json`
summary appends it the same way Claude does, so the recall menu in
`eval-suite/recall` ([fabiandistler/eval-suite](https://github.com/fabiandistler/eval-suite))
shows what the client shows.
- `compatibility` — runtime / language requirements in plain prose.
- `environments` — comma-separated list of the environments the skill
belongs to: `coding`, `chat`, or both (e.g. `environments: coding, chat`).
`install.sh --env=coding|chat` uses this to install only the matching
subset. A skill without the field belongs to every environment.
- `targets` — comma-separated subset of `claude`, `codex`, `opencode`
(e.g. `targets: codex, opencode`). `install.sh` never links the skill for
an agent the field leaves out, and removes a link it had created there
before. Use it when a runtime already ships an equivalent of its own. A
skill without the field is installed for every target. Because `plugins/` is
the Claude distribution, a skill that excludes `claude` also gets no
plugin symlink (`scripts/check_plugins.py` knows this).
- `metadata.version` — semver-ish string.
- `argument-hint` — the argument a `command` skill takes, shown by Claude
Code next to the command name (e.g. `argument-hint: "<owner>/<repo>"`).
Other agents ignore it.
- `license`, `allowed-tools` — Agent Skills format fields that
`scripts/quick_validate.py` accepts. No skill here uses them yet.
- The body is plain Markdown. Avoid agent-specific vocabulary
(slash-commands, "the Skill tool", proprietary tool names, hardcoded
install paths, runtime error text). Prefer
describing the workflow in terms any reader can apply.
- Cross-skill references name only registered, model-invocable skills.
A `command` skill is user-invoked, so say suggest the user run it instead
of invoking it. A router member is read via its router file, never invoked
by a namespaced name; name the router and the member file to read.
CI enforces this with `python3 scripts/check_skill_refs.py`.
- Generated files — `skills.json`, the router member tables and the
`.claude/` mirror — are regenerated by the prek commit hooks
(`build-manifest`, `build-routers`, `build-project-claude` in
`.pre-commit-config.yaml`) whenever a commit touches a `SKILL.md`, an
instruction fragment or a plugin subagent. On drift the hook rewrites
the files and fails the commit; stage them and commit again. Without the
hooks installed (`prek install`), or after deleting a skill (deletions
never trigger a hook), regenerate by hand in this order:
`python3 scripts/build_manifest.py`, `python3 scripts/build_routers.py`,
`python3 scripts/build_project_claude.py`. CI's `--check` gates catch
whatever slips through.
- `prek install` also installs a commit-msg hook (`scripts/check_commit_msg.py`,
Conventional Commits subjects) and two pre-push hooks that run
`scripts/check_all.sh --skip prek,mermaid,bats` and
`scripts/check_all.sh --only bats`; set `PYTHON=` to a 3.11+ interpreter, or
the push stops with exit 4.
- Shell scripts are tested with Bats: one `test/<script>.bats` suite per
entry point (`install.sh` is split into `test/install*.bats`), run by
`test/bats/bats-core/bin/bats test/` after `git submodule update --init`.
- Shared setup lives in `test/test_helper.bash`. The bats-core, bats-support
- and bats-assert submodule pins are bumped by hand, to release tags.
+ The rule and its exemptions are `instructions/45-shell-scripts.md`; shared
+ setup lives in `test/test_helper.bash`. The bats-core, bats-support and
+ bats-assert submodule pins are bumped by hand, to release tags.
- The catalogue and plugin checks below read `skills.json`, not the
`SKILL.md` files, so a stale manifest makes them answer from stale
metadata — regenerate it before running them locally, and that is why
`build_manifest.py --check` is the first CI gate. Two readers stay
independent on purpose: `scripts/quick_validate.py` parses frontmatter
itself, so it validates the source rather than the generator's output,
and `install.sh` reads it in bash, so skill linking never depends on
`python3`.
- After adding, renaming, or removing a skill, update both catalogue
tables by hand — `README.md` and `AGENTS.md` (`## Skill catalogue`) —
keeping their text identical and each skill under the section matching
its `category`. CI enforces this with `python3 scripts/check_docs.py`.
- Keep the plugin in sync for **top-level** skills: add/rename/remove the
relative symlink `plugins/<category>/skills/<skill-name>` →
`../../../skills/<skill-name>`. A router member is a normal skill directory
under `skills/` but gets no plugin symlink: `build_routers.py` creates
`skills/<router>/members/<name>` and the generated member table, and the
category plugin contains only the router. CI enforces this with
`python3 scripts/check_plugins.py`.
- Fast loop for a docs or plugin change:
`scripts/check_all.sh --only docs,plugins`; `--list` shows every check name.
- A reference file over 100 lines carries a `## Contents` heading with
section links within its first 20 lines, so a partial read still shows its
scope. CI enforces this with `python3 scripts/check_reference_tocs.py`.
- A SKILL.md or reference states no dated facts (ISO dates, "as of 2026",
"verified 2026-09-07"): they turn false without notice. Dated provenance
(when a version was verified, a source revision, a re-check deadline) goes
into one paragraph per file that starts `As of 20YY-MM[-DD]`. Code spans,
code blocks and URLs are exempt. CI enforces this with
`python3 scripts/check_dated_claims.py`.
- No Markdown table in `skills/**/*.md` is wider than three columns, fenced
output templates included, because skills and the answers they shape are
read on a phone; use a nested list or a table of at most three columns. CI
enforces this with `python3 scripts/check_table_width.py`.
- Every `references/`, `scripts/`, `assets/`, `evals/` or `members/` path a
SKILL.md or reference names exists relative to the skill directory, and
every relative Markdown link exists relative to the linking file — code
spans and fenced commands included. CI enforces this with
`python3 scripts/check_skill_paths.py`.
- A GitHub step an agent executes names the operation (list open issues,
read an issue with comments, create a PR), then uses this canonical
sentence, keeping the `gh` command as the fallback for agents without the
GitHub MCP: "Use the GitHub MCP tools if the session has them; otherwise
`gh` …". GraphQL-backed `gh` porcelain (`gh issue`, `gh pr`, `gh search`,
`gh label`, `gh repo view`, `gh release list|view`) fails with HTTP 403 in
Claude Code cloud sessions; REST (`gh api`, `gh run`) works. A script that
runs headlessly cannot call MCP tools, so it uses `gh api` against the REST
endpoint. CI enforces this with `python3 scripts/check_gh_graphql.py`.
## Scripts an agent runs
Applies to any executable an agent invokes: `scripts/` in a skill or
plugin, hook commands, CI helpers. The seven rules that hold outside
this repo too — non-interactive input, `--help`, exit codes, named
writes, secrets, installed smoke test, bounded output — are also carried
globally by `instructions/on-demand/85-agent-scripts.md`; edit both when
they change.
- Never read from an interactive prompt. Agents run non-interactive
shells; a TTY prompt hangs the session until timeout. Take every input
as a flag, env var, or stdin. On a missing required input, exit
non-zero naming the flag and its allowed values.
- `--help` is the agent's only interface documentation — one usage line,
the flags, two examples. It is also context cost: keep it under ~25
lines.
- Data to stdout, diagnostics to stderr. Prefer JSON/TSV over
whitespace-aligned columns.
- Distinct exit code per failure class, documented in `--help`, so the
caller can branch without parsing prose.
- Idempotent by default: agents retry. "Create if not exists", never
"fail on duplicate".
- One named verb per write, narrowest stable ID, `--dry-run` first;
never hide writes in `fix`/`auto`/raw.
- Secrets from env or config, never a flag (shell history, `ps`); never
echo them, not in `--json` errors. CI flags a skill, instruction or
script example that passes a credential in argv with
`python3 scripts/check_secret_argv.py`.
- Smoke-test the installed command from `/tmp`, not the source folder.
- Bound the output. Harness output is truncated past roughly 10–30k
characters, silently. Default to a summary; offer `--output FILE` and
`--offset` for the rest.
- Python with third-party deps: PEP 723 inline block + `uv run
script.py`. No sibling requirements.txt, no install step. `uv add
--script` to edit, `uv lock --script` when the run must reproduce.
- A one-off command in SKILL.md (`uvx`, `npx`) is version-pinned, or it
is not a convention.
- Reference bundled skill scripts relative to the skill directory
(`python3 scripts/tool.py <repo-path>`), never via a repo-root path
(`skills/<name>/scripts/`, `members/<name>/scripts/`). The skill is
installed elsewhere, so the target repo is always passed as an argument.
- Every auto or router skill ships eval prompts in `skills/<name>/evals.json`
(>=3 `should_trigger`, >=1 `should_not_trigger`, optional
`expected_behavior`; see `docs/adr/0006-skill-eval-prompts.md`). Command
skills are exempt and may ship one. The `evals` check in
`scripts/check_all.sh` (the list CI calls) runs `check_evals.py --strict`,
so a missing or malformed file fails.
## Agent skills
### Issue tracker
Issues live as GitHub issues on fabiandistler/agents, managed via the `gh` CLI. See `docs/agents/issue-tracker.md`.
### Triage labels
The five canonical triage roles use their default label strings (`needs-triage`, `needs-info`, `ready-for-agent`, `ready-for-human`, `wontfix`). See `docs/agents/triage-labels.md`.
### Domain docs
Single-context: one `GLOSSARY.md` + `docs/adr/` at the repo root. See `docs/agents/domain.md`.
### Weekly skill audit
A scheduled Claude Code routine follows `docs/agents/skill-audit.md` every
week: the `repo-error-checker` subagent runs the CI checks repo-wide, and the
`skill-reviewer` subagent judges a rotating quarter of the skills (plus the
most-changed ones) against `docs/agents/skill-audit-checklist.md`. Findings
land in one rolling `skill-audit` issue; mechanical fixes in one
`claude/skill-audit-<date>` PR. Record a finding you decide to keep under the
issue's *Accepted* section so the audit stops reporting it.