Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Maintains the minpeter/minpeter-skills repository — minpeter's collection of Agent Skills in the open SKILL.md format. Use this when adding a new skill there, editing or refining one, splitting an oversized SKILL.md into references/, renaming or removing a skill, or fixing drift between SKILL.md frontmatter, README.md's index table, and skills.sh.json groupings. Also use it when the user says "add a skill", "update the skills repo", or "write a skill for X". Covers the mandatory workflow (throwa
.claude/skills/minpeter-minpeter-skills-maintainer/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 258% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 115% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 32% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 63% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 234% | 0% |
This repo is a skill collection, not an app. There is no build, no test runner, and no package.json. The "product" is a set of Markdown files that other agents load, so correctness means: valid frontmatter, discoverable descriptions, and three files that agree with each other.
This repo is public. Everything committed here is world-readable forever, and git history keeps it even after a later deletion. Treat every skill as a published document — see §4.
AGENTS.md # short house rules (keep authoritative, keep short)
README.md # install instructions + the skill index table
skills.sh.json # skills.sh repo-page groupings
skills/<kebab-name>/SKILL.md # one skill (flat layout, filename UPPERCASE)
skills/<kebab-name>/references/ # templates, deep-dives, checklistsThe invariant: every skill directory has exactly one SKILL.md, and its frontmatter name appears in both README.md's table and one groupings[].skills array in skills.sh.json. Drift in any of the three is the most common bug in this repo — check all three on every change.
Do not edit an existing local checkout of this repo in place, and never commit to main. Every change — new skill, refinement, rename, removal — starts with a throwaway clone named after the skill being touched:
bashSKILL=<kebab-name> # the skill you're adding or updating KIND=skill # skill | docs | chore (see below) BRANCH=$KIND/$SKILL # removals: BRANCH=chore/remove-$SKILL WORK=/tmp/minpeter-skills-$SKILL rm -rf "$WORK" git clone https://github.com/minpeter/minpeter-skills.git "$WORK" cd "$WORK" git switch -c "$BRANCH"
KIND picks the branch prefix and the commit type, driven by the operation:
| Operation | KIND | Branch | Commit subject | |---|---|---|---| | New skill | skill | skill/<name> | feat(skills): add <name> | | Edit / refine | docs | docs/<name> | docs(<name>): <what changed> | | Rename | chore | chore/<name> | chore(skills): rename … | | Remove | chore | chore/remove-<name> | chore(skills): remove … |
Why the clone: it is always current with origin/main (a stale working copy is how you end up with a conflicting README row), it isolates scratch work from whatever the user has open, and rm -rf "$WORK" is a safe reset when an attempt goes sideways.
Do all the work below inside $WORK, then finish with a PR:
bashSUBJECT="feat(skills): add $SKILL" # use the subject for your KIND git add skills/$SKILL README.md skills.sh.json AGENTS.md git commit -m "$SUBJECT" git push -u origin HEAD # pushes the checked-out branch by name gh pr create --fill
Push HEAD rather than a re-derived $KIND/$SKILL so the pushed name always matches the branch you created — they differ for removals. Keep the PR title under ~70 chars and put the detail (what the skill covers, what was verified) in the body.
Opening the PR is not the end. The merged version still has to be installed on this machine — see §6.
bash cd "$WORK/skills" && npx skills init <kebab-name> That writes skills/<kebab-name>/SKILL.md with valid frontmatter. Replace the placeholder body; keep the frontmatter keys.
name (lowercase-hyphen, must equal thedirectory name) and description. Optional and used here: license: MIT, metadata.author: minpeter. The description is the activation contract — it is the only text a cold agent sees before deciding to load the file, so pack the triggers into it. See references/authoring.md.
needs; push templates, long checklists, and rationale into references/*.md and link them with relative paths.
README.md — add a row to the Skills table, matching the existingthree columns (linked skill name / what it does / when to use).
skills.sh.json — add <name> to the right groupings[].skills,or add a new grouping (title + description + skills) if none fits.
Once it is merged, install it locally (§6).
Read the whole SKILL.md plus its references/ before changing anything — these files cross-reference each other by section number (§N) and by relative link, and both break silently.
name? Then rename the directory, update the README link andcell text, update skills.sh.json, and grep for the old name repo-wide.
description too. A staledescription means the skill stops getting activated for the cases it now handles.
references/? Add the link from SKILL.md; an orphanreference file is dead weight the agent never loads.
skills.sh.json entry (drop the grouping entirely if it goes empty — skills requires minItems: 1). After merge, uninstall it locally too (§6).
bash# frontmatter parses, name matches dir, and the CLI can enumerate every skill npx skills add . --list # no description exceeds the spec's 1024-char limit (see references/maintenance.md §3b) python3 - <<'EOF' import re, sys, pathlib bad = 0 for p in sorted(pathlib.Path('skills').glob('*/SKILL.md')): fm = p.read_text().split('---')[1] m = re.search(r'^description: >-\n((?: .*\n)+)', fm, re.M) n = len(' '.join(l.strip() for l in m.group(1).strip().split('\n'))) print(f"{n:5d} {'OVER' if n > 1024 else 'ok':4} {p.parent.name}") bad |= n > 1024 sys.exit(bad) EOF
Then confirm by hand:
name == directory name, lowercase-hyphen, SKILL.md uppercasedescription names the triggers, in one YAML block scalar (>-), and isunder 1024 characters — aim for ≤ 950 so later edits have room
SKILL.md under ~500 lines; heavy detail in references/references/ file is linked from SKILL.md, and every link resolvesskills.sh.json grouping (check withjq -r '.groupings[].skills[]' skills.sh.json, not a bare grep — a plain quoted-string grep also matches the JSON keys)
Full procedure, including the link-check and drift-check one-liners: references/maintenance.md.
This repo is public, and git history is effectively permanent — deleting a line in a later commit does not unpublish it. A skill is a published document, so write it for a stranger reading it on GitHub.
Never commit:
"throwaway" ones. NPM_TOKEN, gh[pousr]_…, sk-…, AKIA…, Bearer headers, .npmrc auth lines, private keys.
private registry endpoints, internal package names, IP addresses, database connection strings, S3 bucket names, ticket URLs.
/home/<user>/…, /Users/…, C:\Users\…) — both aprivacy leak and a portability break.
machine. Sanitize them or rewrite them as generic examples.
Use placeholders instead, and make them obviously fake: <your-org>, <repo>, you@example.com, <registry-host>, <path-to-checkout>, $HOME. example.com / example.org are reserved for exactly this.
When a skill documents a real service, name only what is already public (the npm registry, github.com, a published package name). The test: would this line be fine in a blog post? If not, it does not belong in a skill.
Scan before every commit ($META skips this skill, which necessarily spells out the shapes it forbids):
bashMETA="!**/minpeter-skills-maintainer/**" # credential shapes rg -n -i --glob "$META" 'gh[pousr]_[A-Za-z0-9]{16,}|sk-[A-Za-z0-9]{20,}|AKIA[0-9A-Z]{16}|npm_[A-Za-z0-9]{20,}|-----BEGIN [A-Z ]*PRIVATE KEY|Bearer [A-Za-z0-9._-]{20,}' skills/ # emails that are not example.com, and machine-local paths rg -n --glob "$META" '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' skills/ | rg -v 'example\.(com|org)' rg -n -i --glob "$META" '/home/[A-Za-z0-9]|/Users/[A-Za-z0-9]|C:\\Users\\[A-Za-z0-9]' skills/
Each must come back empty. The path scan runs case-insensitively (-i) with one [A-Za-z0-9] class for all three bases, so a real path is caught however it was written — /home/Alice, /users/admin, c:\users\bob — while a documented placeholder passes, since < and … are not alphanumeric in any case. A guardrail that fires on its own examples gets ignored. Private-IP and internal-hostname patterns are in references/maintenance.md §4b.
If a secret does land on main: treat it as compromised and rotate it immediately. Removing the line in a follow-up commit is not enough — the value stays in history and in anyone's existing clone. Tell the user; do not attempt a history rewrite (filter-repo, force-push) on your own.
The PR is for the user to read. Do not merge it yourself unless they ask — merging is their call, and the skill body is exactly the kind of thing that wants a human read-through before it starts steering other agents.
When they do ask:
bashgh pr merge <n> --squash --delete-branch
A merged PR changes nothing locally. The installed copy lives at ~/.agents/skills/<name> and is tracked in ~/.agents/.skill-lock.json. Until you reinstall, every agent on this machine keeps reading the pre-merge version.
The one thing to get right: add for a skill's first install, update afterwards. npx skills update only iterates over skills already present in .skill-lock.json, so running it for a brand-new skill is a silent no-op that looks like success.
bashcd <path-to-local-checkout> && git switch main && git pull npx skills add -g minpeter/minpeter-skills --skill <name> -a '*' -y # NEW npx skills update -g <name> # EXISTING
Then verify by reading the installed files (not by grepping the colorized skills ls output), and drop the scratch clone. After a rename or removal, also npx skills remove -g <old-name> — the old directory and lock entry do not disappear on their own.
Full step-by-step, including the install layout, the flag table, and what to check when a reinstall looks like it did nothing: references/maintenance.md §7.
docs(typescript-package): add OIDC PR-creation gate gotcha, feat(skills): add minpeter-skills-maintainer. Repo-wide changes use docs(repo): or chore(repo):. The branch prefix follows the same operation (§0).
/tmp/minpeter-skills-<name> once the PR is merged and the skillis reinstalled locally (§6).
then the reasoning. Mark hard rules as hard rules and list what to flag in review. Avoid hedging — a skill that says "consider maybe" gives the reading agent nothing to act on.
pkg@1.2.3 into a skill; instruct the agentto resolve @latest at execution time. Same for GitHub Action majors.
lines, it belongs in this skill; keep AGENTS.md a pointer-length digest and update it when an invariant changes.
Nested skill directories (skills/a/b/SKILL.md) · lowercase skill.md · name that disagrees with the directory · a skill missing from README or skills.sh.json · descriptions that describe the topic but not the trigger · descriptions over 1024 characters · 1000-line SKILL.md with no references/ · pinned tool versions · references/ files nothing links to · commits pushed straight to main · edits made in a long-lived local checkout instead of a fresh /tmp clone · stopping at the merged PR and leaving the machine on the stale installed copy · real emails, tokens, private hostnames, internal URLs, or /home/<user>/ paths where a placeholder belongs.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 25,314 | 10,221 | -60% | 1 | 1 | 0% | 3,592 | 4,479 | +25% | 0 | 0 | — |
case-02 | fail→fail | 6,134 | 8,490 | +38% | 1 | 1 | 0% | 376 | 4,111 | +993% | 0 | 0 | — |
case-03 | fail→fail | 21,722 | 8,661 | -60% | 1 | 1 | 0% | 2,780 | 4,076 | +47% | 0 | 0 | — |
case-04 | fail→pass | 10,010 | 15,129 | +51% | 1 | 1 | 0% | 1,715 | 6,133 | +258% | 0 | 0 | — |
case-05 | fail→pass | 18,747 | 6,973 | -63% | 1 | 1 | 0% | 2,404 | 5,170 | +115% | 0 | 0 | — |
case-06 | fail→pass | 21,175 | 2,603 | -88% | 1 | 1 | 0% | 3,084 | 4,083 | +32% | 0 | 0 | — |
case-07 | pass→pass | 14,530 | 4,913 | -66% | 1 | 1 | 0% | 2,252 | 4,451 | +98% | 0 | 0 | — |
case-08 | fail→pass | 14,546 | 5,922 | -59% | 1 | 1 | 0% | 2,905 | 4,739 | +63% | 0 | 0 | — |
case-20 | fail→fail | 16,768 | 13,509 | -19% | 1 | 1 | 0% | 3,111 | 6,028 | +94% | 0 | 0 | — |
case-09 | fail→pass | 9,483 | 6,465 | -32% | 1 | 1 | 0% | 1,384 | 4,618 | +234% | 0 | 0 | — |
case-10 | pass→pass | 12,056 | 14,114 | +17% | 1 | 1 | 0% | 2,124 | 6,266 | +195% | 0 | 0 | — |
case-11 | pass→pass | 9,616 | 8,787 | -9% | 1 | 1 | 0% | 1,426 | 5,072 | +256% | 0 | 0 | — |
case-12 | fail→pass | 23,529 | 4,548 | -81% | 1 | 1 | 0% | 1,932 | 4,536 | +135% | 0 | 0 | — |
case-13 | fail→pass | 16,716 | 4,495 | -73% | 1 | 1 | 0% | 2,896 | 4,607 | +59% | 0 | 0 | — |
case-14 | fail→pass | 7,523 | 4,903 | -35% | 1 | 1 | 0% | 1,332 | 4,444 | +234% | 0 | 0 | — |
case-15 | pass→pass | 10,458 | 6,466 | -38% | 1 | 1 | 0% | 1,875 | 4,803 | +156% | 0 | 0 | — |
case-16 | pass→pass | 11,411 | 6,297 | -45% | 1 | 1 | 0% | 2,009 | 4,905 | +144% | 0 | 0 | — |
case-17 | pass→pass | 14,253 | 6,279 | -56% | 1 | 1 | 0% | 1,957 | 4,701 | +140% | 0 | 0 | — |
case-18 | fail→pass | 8,912 | 4,975 | -44% | 1 | 1 | 0% | 1,663 | 4,657 | +180% | 0 | 0 | — |
case-19 | pass→pass | 11,765 | 7,669 | -35% | 1 | 1 | 0% | 2,102 | 5,179 | +146% | 0 | 0 | — |
case-21 | fail→fail | 18,458 | 21,030 | +14% | 1 | 1 | 0% | 3,217 | 7,160 | +123% | 0 | 0 | — |
case-22 | fail→fail | 18,281 | 16,918 | -7% | 1 | 1 | 0% | 2,726 | 6,136 | +125% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 19 counted toward the lift figure. The other 3 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +41 percentage points is the difference between those two pass rates over the 19 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.