Curated local and upstream skills — plus agent definitions — for multiple coding agents.
This repo is both a curated catalog and the implementation of skm. It manages
owned local/composed skills and agent definitions with plan/apply, syncs a
global upstream baseline, deploys project-specific skill families, and renders
an HTML review console. The two upstream workflows delegate fetch and placement
to the external skills CLI; owned artifacts use skm's state and drift model.
It also carries agent definitions under agents/: one
agent.yaml + instructions.md per subagent, rendered per-harness by skm
into each agent's definitions dir (Claude, Codex, Copilot, Cursor, Gemini,
OpenCode) and optionally exported as a derived skill or a tprompt prompt.
These were absorbed from the retired custom_agents repo at cutover; running
its shared-agents tool after cutover is forbidden (see AGENTS.md).
Engine: a TypeScript CLI (
skm, undercli/) runs the whole surface, adding agent-scoped skills, private overlay repos, composed skills (one source rendered per consumer — routing tables, self-exclusion, compile-time posture; ADR 0010), gated (user-invoked-only) skills (disable-model-invocation: truetranslated to each agent's gate — frontmatter or a codex companion file — placed only into gate-honoring agents' own dirs; ADR 0011), and Terraform-style plan/apply with an ownership state file. Design: docs/skills-manager-design.md · decisions: docs/adr/ · usage: cli/README.md. The bash sync/deploy scripts were retired at the ADR 0014 final commit:skm upstream syncandskm deployreplace them (skmstill shells to the externalskillsCLI as the fetch/place engine).
Public-only review artifact generated from this repository.
It also supports an optional gitignored quick-tweak file for extra global skills, per-family additions, exclusions, and custom project families.
bun(runs theskmCLI undercli/)skillsCLI (skm shells to it as the fetch/place engine)gitcurlfor theagents-mdsync maintenance scriptjqis only needed to run the golden-backed parity suites'gitshim (dev/test), not at runtime
cd cli
bun install
bun src/cli.ts plan
bun src/cli.ts applyplan is read-only. apply creates or updates desired placements; stale owned
placements are removed only with apply --prune.
If this checkout moved from custom_skills to skills-manager, update any
registered root before running plan, apply, or status; a configured root
that no longer exists is a deliberate hard error:
cd cli
bun src/cli.ts root list
bun src/cli.ts root add ~/code/skills-manager public
bun src/cli.ts root remove ~/code/custom_skillsThe machine config is ~/.config/skills-manager/config.json (or under
$XDG_CONFIG_HOME). No migration is needed when that file does not exist: the
default public root is derived from the CLI's current checkout. Set
excludeLocalSkills there to omit named skills from all registered roots on
that host. Use excludeLocalAgents the same way for bundled or overlay agent
definitions.
Normalizes your global skill setup under ~/.agents/skills and ~/.claude/skills.
It will:
- remove globally installed skills that are no longer in the curated global catalog
- update existing global skills
- add any missing curated global skills
- audit selected upstream repos for coverage drift
- clean up broken symlinks in those global directories
Local repo skills are placed separately by skm (see below).
Use it when you want to update your personal baseline skill environment.
If .skills.local.json exists, its globalSpecs are merged into the desired
global set and its excludeGlobalSpecs remove explicit upstream skills, or
whole upstream repos after normalization, from that resolved global set before
stale-skill removal runs. Its preserveGlobalSkillNames protects named
handmade global skills from stale removal without adding them to the resolved
managed install set.
Exclusion-override behavior, resolved repo summaries, and the ^ full-coverage
marker are documented in docs/exclude-overrides.md.
The ^ marker means the final resolved set covers all current upstream skills
for that repo.
Examples:
cd cli && bun src/cli.ts upstream sync
cd cli && SKILLS_AGENTS="codex opencode" bun src/cli.ts upstream sync
cd cli && SKILLS_AUDIT_REPO_COVERAGE=0 bun src/cli.ts upstream syncSKILLS_AGENTS is a single space-separated override for upstream sync and
deploy. When unset, those verbs use the standard external-CLI target set:
codexopencodeclaude-code
github-copilot, gemini-cli, cursor, and droid are registry opt-in agents:
plan/apply place skills for them only on machines that list them in
optInAgents.
Override the list to scope a run to a subset of agents, or to opt into additional agents like Hermes (see below).
There are two separate target ids and control planes:
skm upstream syncandskm deploydrive the externalskillsCLI. Usehermes-agentinSKILLS_AGENTS(or deploy's--agents).- Local
skm plan/applyreads~/.config/skills-manager/config.json. Use the registry idhermesin that file'sagentsarray;SKILLS_AGENTSdoes not affect local placement.
For upstream sync, include hermes-agent in SKILLS_AGENTS:
cd cli && SKILLS_AGENTS="codex opencode claude-code hermes-agent" \
bun src/cli.ts upstream syncFor local placement, append hermes to the existing agents array in machine
config. Do not replace that array with the shorter upstream target set above;
local defaults also include other supported agents from registry/agents.json.
Hermes behavior is intentionally different:
- Hermes does not read
~/.agents/skillsby default. TheskillsCLI installs Hermes targets under~/.hermes/skills/<name>. Local repo artifacts are placed there byskmwhen hermes is enabled (add-only: skm never prunes hermes placements). ~/.hermes/skillsis treated as add-only. Stale-skill removal is scoped with-ato non-Hermes agents so the CLI never removes a Hermes entry on our behalf. Hermes packages and creates its own skills in that directory, and we don't manage what we didn't install. If the narrowed removal leaves~/.agents/skills/<name>behind (another detected agent still resolves it) and Hermes has no entry under that name, sync follows with an all-agentskills removeso the canonical dir and lock entry go too.- We do clean up our own dangling symlinks. After a stale removal, any
~/.hermes/skills/<name>symlink whose target resolves intoskills/or~/.agents/skills/is removed. Real directories and symlinks pointing elsewhere are left untouched. - Without
hermes-agentinSKILLS_AGENTS,skm upstream syncnever reads or writes~/.hermes/skills. To clean up past Hermes writes after opting out, opt back in for one run. - Running with
SKILLS_AGENTS="hermes-agent"alone is supported but is an edge case: the CLI installs as real directories under~/.hermes/skills, which look like Hermes-owned content on disk and won't be cleaned up by future runs. Use the additive form (standard +hermes-agent) for any install you want round-trip cleanup on. - A fresh Hermes session or
/resetis needed for Hermes to pick up newly-added skills. Local entries in~/.hermes/skillswin on name collisions with externally-configured skill roots (skills.external_dirsin~/.hermes/config.yaml).
Deploys curated skill families into a target directory with project-scoped skills add --copy installs.
Use it when a repo needs a focused set of skills, for example Expo or Convex, without making them part of your global always-on setup.
Behavior:
- targets the exact positional directory you choose
- expands current-user
~and~/...target paths - does not expand
~user/...target paths - works in plain directories and git repos
- copies skills into the project-managed agent directories
- installs only the selected families
- does not normalize or remove unrelated project skills
- audits selected curated family repos for upstream drift when coverage manifests are configured
- requires
gitduring planning only when a repo-wide spec or exclusion must be expanded; a real deploy may also enumerate during its advisory coverage audit - prints repo batches under
Planned installs;--dry-runstops before the coverage audit and makes no project changes
If .skills.local.json exists, its familySpecs extend curated families and
its excludeFamilySpecs remove explicit upstream skills from each curated
family's resolved contribution before the selected families are merged.
Exclusion-override and repo-expansion behavior is documented in docs/exclude-overrides.md.
The bash interactive prompt mode is dropped (skm is agent-first);
--list-families plus flags cover the human path:
cd cli && bun src/cli.ts deploy \
~/code/my-app \
--family expo \
--family convex \
--agents "codex claude-code" \
--yesList available families:
cd cli && bun src/cli.ts deploy --list-familiesLocal skills from skills/ (and overlay roots) are placed by the skm CLI —
symlinks into shared roots for unscoped skills, rendered per-agent trees for
gated ones, ownership-tracked and prunable:
cd cli
bun src/cli.ts plan # preview
bun src/cli.ts apply # placeUse status for drift, doctor for safety diagnostics (--fix only for its
supported repairs), and explain <skill> for source/scoping/visibility. review
writes the self-contained console to
$XDG_STATE_HOME/skills-manager/review.html by default; use --out <path> to
choose another privacy-checked destination.
The former ./link-skills.sh was retired once skm reached placement parity
(gate awareness, hermes add-only, stale-link pruning are covered by
cli/test).
Refreshes the forked agents-md local skill from upstream getsentry/skills@agents-md.
skills/agents-md/SKILL.md is generated output. Do not edit it by hand. The
sync exits nonzero if upstream structure no longer matches the maintained patch,
so the weekly workflow surfaces drift instead of retaining stale output.
bash maintenance/sync-agents-md.shThe source of truth is split by purpose; see
catalog/README.md for formats and verification:
catalog/global-specs.txtglobal skills managed byskm upstream syncupstream-coverage.jsonglobal upstream repos audited for skill drift duringskm upstream sync(whenSKILLS_AUDIT_REPO_COVERAGE=1)catalog/families.tsvfamily names and descriptions for project deploymentcatalog/families/*.txtexplicit per-family upstream skill specscatalog/family-coverage.jsonupstream repos that should be audited for family drift
Current project families:
expoconvexmattpocock-teachingreactsecurity
The global upstream catalog installs diffwarden, tmux, and agent-browser.
web-design-guidelines belongs to the React project family and is installed by
skm deploy <dir> --family react, alongside the React and React Native skills.
aurokin/diffwarden is listed in upstream-coverage.json so sync audits its
full upstream skill set for catalog drift.
Create .skills.local.json in the repo root to add personal skills without
changing the curated catalog. The file is gitignored; start from
.skills.local.json.example. The example file uses placeholder exclusions, so
copying it does not opt you out of curated skills until you replace those
values intentionally.
This gitignored .skills.local.json is only a quick-tweak layer for the
skm upstream sync / skm deploy upstream/family sets — it is not the
private overlay repo. Private
skills and agent definitions live in a separate registered overlay root (a real
repo, resolved by skm); see
ADR 0001.
Both upstream verbs validate the entire file when it exists. A malformed or invalid field can therefore block either command even if that field belongs to the other workflow.
Supported keys:
globalSpecsadditive upstream specs merged into theskm upstream syncdesired setexcludeGlobalSpecsupstream specs removed from the resolved global install setpreserveGlobalSkillNameshandmade global skill names protected from stale removalfamilySpecsadditive specs keyed by existing curated family nameexcludeFamilySpecsexplicit upstream specs removed from a curated family's resolved deploy setcustomFamiliesnew family definitions withdescriptionandspecs
See docs/exclude-overrides.md for the implemented exclusion-override semantics, normalization rules, resolved summary output, examples, and implementation notes.
Example:
{
"globalSpecs": [
"owner/repo@my-global-skill"
],
"excludeGlobalSpecs": [
"owner/repo@skill-to-exclude",
"owner/another-repo"
],
"preserveGlobalSkillNames": [
"my-handmade-global-skill"
],
"familySpecs": {
"expo": [
"owner/repo@my-expo-skill"
]
},
"excludeFamilySpecs": {
"expo": [
"owner/repo@family-skill-to-exclude"
]
},
"customFamilies": {
"acme-mobile": {
"description": "Company mobile workflow skills",
"specs": [
"owner/repo@release-ops"
]
}
}
}Rules:
excludeGlobalSpecsaccepts repo-wideowner/repoand explicitowner/repo@skill-nameentriespreserveGlobalSkillNamesaccepts exact skill names only, not upstream specsexcludeFamilySpecsonly accepts explicitowner/repo@skill-nameentriesfamilySpecscan only target existing curated familiesexcludeFamilySpecscan only target existing curated familiescustomFamiliescannot reuse a curated family name- duplicate specs are deduped with curated entries first
A variant is a second instance of an existing agent program with its own config
home (e.g. a CLAUDE_CONFIG_DIR profile of the claude binary). Since ADR 0016
this is pure data — no engine code changes:
- Probe first (registry entries are evidence-backed): a canary skill in the
variant's skills dir must load; dummies present only in
~/.claude/skillsand~/.agents/skillsmust NOT appear in the variant (and vice versa); the frontmatter gate and agent-def loading re-probed under the relocated home. Remove every probe dummy afterwards. - Registry entry (
registry/agents.json): a new directory id for its skills dir plus an agent entry — samedialectas the base program,firstParty: true(it renders per-dialect frontmatter),optIn: true(a variant's existence is per-machine; it must not auto-enable fleet-wide),unscopedOwnDir: trueif it should receive unscoped skills,probeClinaming the shared binary (so the gate-version drift probe works without an engine edit), its ownagentDefDir, and probe-backed evidence strings. Keep the entry generic: nothing machine- or proxy-specific, no model catalogs. - Machine opt-in (
~/.config/skills-manager/config.json): add the variant tooptInAgentson the hosts that run it. Allow lists, gated placement, and agent-def fan-out all intersect with enablement, so shared overlays naming the variant are inert on other hosts. - Scoping: trim per-skill with
deny(note: existing denies naming the base agent likely need the variant added too), and add it as a composed consumer where wanted —excludeProvidersexpresses providers the variant routes natively (their chains drop; the consumer file carries the replacement guidance).
Local repo-managed skills live in skills/<name>/SKILL.md.
Current local skills:
agents-mdbro— gated (disable-model-invocation: true); restates the previous response in plain language. Imported from Lauren Tan's PStackhandoff— gated (disable-model-invocation: true); writes session state to a Markdown file outside the checkout so another session or agent can continuehtml-artifact— creates self-contained HTML documents for plans, reports, comparisons, and UI mock variants; adapted fromhtml-communicationby Theo Brownehumanizer— gated (disable-model-invocation: true); rewrites AI-sounding prose while preserving its meaning. Locally forked; see credits below.ponytail— gated (disable-model-invocation: true); favors the simplest working coding solution. Locally forked; see credits below.unslop— gated (disable-model-invocation: true); removes AI writing patterns. Locally forked; see credits below.
to-prd and linear-yeet were retired 2026-07 (frontier agents produce
PRDs and drive the Linear MCP natively); split-to-prs, an exact fork of
the Cursor app's shipped skill, moved to the private overlay root. Gated
local skills are never placed in shared roots; skm renders them per-agent
(ADR 0011).
To add a new local skill:
- Create
skills/<name>/SKILL.md - Add frontmatter with
nameanddescription - Run
skm plan/skm apply(fromcli/, viabun)
The instruction bodies in these forks are unchanged from upstream. Their only
SKILL.md changes are invocation metadata: Unslop, Humanizer, and Ponytail
require explicit user invocation. All retain their upstream MIT license notices.
| Local fork | Author and upstream snapshot | License |
|---|---|---|
| Unslop | Lauren Tan, PStack in cursor/plugins at 93b00b89 |
MIT |
| Humanizer | Siqi Chen, blader/humanizer at e2e92e7b |
MIT |
| Ponytail | DietrichGebert, DietrichGebert/ponytail at 356918eb |
MIT |
These skills are local sources, not entries in catalog/global-specs.txt.
Upstream refreshes must preserve the local invocation metadata. Existing
external installations must be removed through their installer before
skm apply can place the local forks; skm will not overwrite foreign files.
The skm engine (including the upstream sync / deploy parity suites, now
golden-backed against the retired scripts' captured output) runs under bun:
cd cli && bun testThe one remaining shell test covers the agents-md fork sync:
bash maintenance/test-agents-md.sh