Add More Skill
A single workflow for installing, updating, and managing skills from external skill repositories. Because this repo is the canonical copy that install.py symlinks into every harness, "installing a skill" always means: copy it into the repo and re-run the installer. Two destinations exist:
<repo>/skills/<name>/— skills you intend to own and commit (your own or curated skills)<repo>/skills-external/<name>/— skills borrowed from other repos (gitignored, never committed; stays on this machine)
By default, skills from external repos install into skills-external/. Use skills/ only when the user explicitly wants a skill committed (e.g. "add it to the repo so others get it too"). Never copy skill dirs directly into harness directories (except in the degraded fallback, section 7).
All state — what was installed, from where, at which commit — is tracked in the gitignored prefs.local.json under skill_sources, so rerunning this skill detects upstream updates, newly added skills, and skills deleted upstream. Records drift from reality (hand-deleted dirs, copies made without a record, edits), so section 1 reconciles prefs.local.json against the disk before any add/update/sync/remove and prompts the user to fix anything out of place.
0. Resolve your setup first
Locate the canonical repo (try in order):
$AGENT_SKILLS_REPOenvironment variablerepo_dirinprefs.local.json(also check~/Documents/GitHub/agent-skills,~/code/agent-skills,~/.agents/agent-skills)- the current directory, if it contains
install.pyand askills/dir - ask the user
If no repo is found anywhere, fall back to section 7 (direct install). If repo_dir is missing from prefs, write it in now.
Load state: read <repo>/prefs.local.json. Pay attention to repo_dir and skill_sources (ignore keys starting with _ — they are comments/examples).
Cache: clone external repos to ~/.agents/cache/add-more-skill/<owner>__<repo>/. The cache is persistent so update checks are cheap. Create the directory as needed.
Local skill inventory (for conflict checks): collect skill names present in
<repo>/skills/(canonical copy, committed)<repo>/skills-external/(borrowed, gitignored)~/.agents/skills/,~/.config/opencode/skills/,~/.claude/skills/,~/.codex/skills/
When listing harness dirs, resolve symlinks with readlink — most entries point back into the canonical repo and must not be counted as duplicates.
Then run the state sanity check (section 1) before any add, update, sync, or remove — records in prefs.local.json are only trustworthy if they match the disk.
1. Sanity-check state before add / update / sync / remove
prefs.local.json records what was installed, but the bookkeeping can drift
from reality — a skill dir deleted by hand, a copy made without a record, an
edit that changed the hash. Operating on stale records makes adds and updates
miss the actual setup: they silently no-op, duplicate, or overwrite the wrong
thing. So before every add (section 2), sync (section 3), or remove (section 5),
reconcile every record against the disk and prompt the user to fix anything
out of place — either by adding (installing) the skill or by updating
prefs.local.json to match reality. Never proceed with known mismatches
unresolved.
1.1 Recorded skill missing on disk
For each skills[name] record in every source, check the install dir
(<repo>/skills-external/<name> when external: true, else
<repo>/skills/<name>):
test -d "<repo>/<dir>/<name>" # missing → the record is a ghost
Ask the user to fix it — either add the skill (copy it from the source
cache at the recorded commit if the clone exists and rel_path is still
valid, else re-clone the source first; then run the installer) or update
prefs (delete the entry from skill_sources so syncs stop chasing a ghost).
1.2 Skill on disk with no record
Scan every dir containing SKILL.md under <repo>/skills-external/ (and any
<repo>/skills/ dirs that are not this repo's own skills) and check that no
skill_sources[].skills entry claims it:
- In
skills-external/→ an untracked borrow. Ask the user to fix it — update prefs to record it (match the dir'slocal_hashagainst skills in~/.agents/cache/add-more-skill/*/to find the source, ask the user if unknown; write the entry with the rightrel_path,commit,local_hash,external: true) or remove it (back up to<repo>/.backups/<ts>/first). Otherwise later syncs will treat it as removable or duplicate it. - In
skills/→ usually your own curated skill; being untracked is fine andlist(section 4) marks ituntracked. Only if it looks borrowed (content matches a cached source) offer to record it asexternal: false.
1.3 Recorded hash ≠ on-disk hash
Compare each record's local_hash with the live fingerprint of its install
dir (same command as 2.8):
find "<repo>/<dir>/<name>" -type f | sort | xargs shasum -a 256 | shasum -a 256 | awk '{print $1}'
Mismatch → the skill changed since install (hand edit, partial copy, another
tool overwrote it). Ask the user which reality is correct: keep the local
edits (update local_hash in prefs so syncs treat it as locally modified and
never overwrite it silently) or restore the recorded state (reinstall from
the source cache at the recorded commit, then run the installer).
1.4 Source cache or commit mismatch
For each source, confirm the cache clone exists and sits at the recorded
last_commit:
test -d ~/.agents/cache/add-more-skill/<owner>__<repo>
git -C "$CACHE" rev-parse HEAD # should equal the recorded last_commit
Missing or different → updates and diff checks will be wrong. Fix by
re-cloning (2.2) or git fetch + checkout of the recorded commit. If the
recorded commit is unreachable upstream, ask: update prefs to the current
HEAD (the next sync treats everything as updated) or drop the source record.
1.5 Recorded rel_path invalid at the recorded commit
git -C "$CACHE" cat-file -e <last_commit>:<rel_path>/SKILL.md # fails → moved upstream
Ask the user to fix it: locate the new path
(git -C "$CACHE" ls-tree -r --name-only <last_commit> | grep '/SKILL.md$'),
update prefs with the new rel_path and re-apply the skill, or drop the
record.
1.6 Apply fixes, then proceed
For every mismatch, present the finding with its fix options, get the user's
pick (their harness's interactive prompt, like 2.6), apply it, and validate
prefs.local.json with python3 -m json.tool. Re-run this check once after
the fixes; only when it comes back clean, continue to add (section 2), sync
(section 3), or remove (section 5). If the user declines to fix a mismatch,
exclude the affected skill from the operation and say so explicitly.
2. add — install skills from a repo
2.1 Get the repo
The user may give a full URL, owner/repo, or nothing. If nothing, offer the curated discovery list (section 8) or ask them to share a repo. Normalize to a canonical source key owner/repo (strip scheme and trailing .git), and keep the display URL.
2.2 Clone into the cache
git clone --quiet <url> ~/.agents/cache/add-more-skill/<owner>__<repo>
BRANCH=$(git -C "$CACHE" rev-parse --abbrev-ref HEAD)
HEAD=$(git -C "$CACHE" rev-parse HEAD)
Clone fully (no --depth) so diffs work on later syncs. If a full clone is pathologically slow, use git clone --filter=blob:none and run git fetch --unshallow at the first sync.
2.3 Scan for skills
find "$CACHE" -name SKILL.md \
-not -path '*/.git/*' -not -path '*/node_modules/*' \
-not -path '*/.github/*' -not -path '*/.vscode/*' -not -path '*/docs/*'
Cap depth at ~4 levels. For each match:
- skill name = parent directory name (fall back to the repo name when
SKILL.mdsits at the repo root) - parse frontmatter
nameanddescription; if frontmatternamediffers from the dir name, use the frontmatter name and note the mismatch - record the skill's relative path inside the cache — needed for diffing on later syncs
2.4 Suggest relevance
Build local context: which harnesses are installed (opencode / claude / codex binaries), keys in prefs.env, MCP server names, and names + descriptions of already-installed skills. For each candidate score:
- +2 — description keywords match the user's context (e.g.
browser/chrome/playwrightwhen the user has those MCP servers or prefs keys;git/commitskills for this repo;notionwhen prefs mention it) - +1 — the skill fills a domain no installed skill covers (testing, docs, security, devops, web, data, design, marketing, …)
Present three groups:
- Recommended (score ≥ 2) with the reason, e.g. "matches your chrome MCP setup"
- Available — everything else, one line each
- Conflicts — see 2.5
Show each as name — description truncated to ~100 chars. Never install anything without an explicit user selection.
2.5 Conflict check (duplication handling)
For each candidate name, check the local inventory (both skills/ and skills-external/):
- Not installed anywhere → clean install.
- In
skills-external/, tracked to the same source → already installed; move to the sync path instead (section 3), don't re-add. - In
skills/, tracked to the same source → the user explicitly committed it; treat as already installed (sync path), don't re-add. - Tracked to a different source (name clash) → ask: skip / overwrite / install as
name-from-owner. Overwriting drops the other source's record — say so before doing it. - Present locally but not tracked (hand-written, or harness-only skills like codex's
playwright) → likely locally authored; default skip, offering: overwrite (back up to<repo>/.backups/<ts>/first) or rename.
2.6 Present & confirm
Number the final actionable list. Use your harness's interactive prompt (the Question tool in opencode; otherwise ask in chat and wait). Accept comma-separated ranges and all/none. Re-confirm when the selection overwrites anything.
2.7 Copy into the repo
By default (borrowed skills), install into the gitignored external dir:
cp -R "$CACHE/<rel_path>" "<repo>/skills-external/<name>"
If the user explicitly wants the skill committed so other users get it too, install into skills/ instead and mark the record "external": false. Copy the whole skill dir (scripts, references, templates included). Remove any stray dotfiles from the copy, keep the skill's own resources.
2.8 Record state
Update prefs.local.json (preserve every other key; validate with python3 -m json.tool):
"skill_sources": {
"<owner/repo>": {
"url": "<display url>",
"branch": "<branch>",
"added_at": "<now>",
"last_sync_at": "<now>",
"last_commit": "<HEAD>",
"skills": {
"<name>": {
"rel_path": "<path of skill dir inside the source clone>",
"external": true,
"installed_at": "<now>",
"updated_at": null,
"commit": "<HEAD>",
"local_hash": "<sha256>"
}
}
}
}
external records where the skill lives: true → <repo>/skills-external/<name> (gitignored, not committed), false/missing → <repo>/skills/<name>. local_hash is the fingerprint of the installed dir used to detect local edits on later syncs:
find "<repo>/skills-external/<name>" -type f | sort | xargs shasum -a 256 | shasum -a 256 | awk '{print $1}'
2.9 Wire it in & verify
Run the installer in the repo: ./install.sh (Unix) or .\install.ps1 (Windows), or python3 install.py. Use --dry-run first if unsure. Then verify at least one harness picked it up, e.g. ls -la ~/.config/opencode/skills/<name>. Remind the user that running harnesses must be restarted to see the new skill.
3. sync — update everything
Run the sanity check (section 1) first and resolve every mismatch — syncing against stale records misses the actual setup. Then, for each source recorded in skill_sources:
- Ensure the cache clone exists (clone it if missing, like 2.2).
git -C "$CACHE" fetch --quiet origin;NEW=$(git -C "$CACHE" rev-parse origin/$BRANCH).- Compare
NEWwith the recordedlast_commit:- Same commit → no upstream change. Still compare the recorded
local_hashagainst the installed dir; if they differ, the user edited the skill locally — flag it as "locally modified (your edits are preserved)". - New commit → classify each recorded skill:
- updated —
git -C "$CACHE" diff --quiet $last_commit..$NEW -- <rel_path>exits non-zero. If the local copy's hash no longer matches the recordedlocal_hash(user edits), ask before overwriting. - new —
SKILL.mddirs present at$NEWthat are not in this source's recordedskills - removed — recorded skills whose
rel_pathno longer exists at$NEW(git -C "$CACHE" cat-file -e $NEW:<rel_path>fails)
- updated —
- Same commit → no upstream change. Still compare the recorded
- Present a plan: "update X (n skills), add Y, remove Z" with one-line descriptions and counts. Let the user select; locally-modified items get a per-item choice (update / keep local).
- Apply: for updates and removals, back up the current dir to
<repo>/.backups/<ts>/first, thencp -Rthe new version orrm -rfthe agreed removal. Use each skill's recordedexternalflag to targetskills-external/vsskills/. New skills install exactly like 2.7. - Record: bump
last_sync_atandlast_committoNEW; per skill updateupdated_at,commit,local_hash; drop removed ones. - Re-run the installer (2.9), verify, remind about restarts.
If the user asks to update only a specific skill, treat just that one as the scope.
4. list — inventory & discovery
Print a table: skill name | source (repo key or local) | status. Status is one of: current / update available / locally modified / source deleted (upstream removed it, still installed) / untracked (in the canonical repo but not from any source). Mark skills in skills-external/ with a (external) tag so it's clear they aren't committed. Then, if the user wants more skills, offer the curated discovery list (section 8).
5. remove — uninstall a skill
Run the sanity check (section 1) first so records and disk agree on what is actually installed. Only remove skills that are tracked from a source, or that the user confirms are theirs to remove. Steps: confirm the exact name, back up <repo>/<skills-external or skills>/<name> (per the recorded external flag) to <repo>/.backups/<ts>/, delete it, drop the entry from skill_sources, re-run the installer. Never remove skills that ship with this repo (e.g. enhance-repo, add-more-skill) unless explicitly asked.
6. State schema
Top level of prefs.local.json (gitignored — never commit it):
repo_dir— path to the canonical repo (seeded by this skill if missing)skill_sources— map of<owner/repo>→ source record:url,branch,added_at,last_sync_at,last_commitskills— map of skill name →{ rel_path, external, installed_at, updated_at, commit, local_hash };external: true= lives in gitignoredskills-external/(not committed)
_*keys are comments/examples; ignore them.
Section 1 reconciles every record against the disk before any add/update/sync/remove: a record without a matching install dir, an install dir without a record, a local_hash that no longer matches, a cache clone that isn't at last_commit, or a rel_path that no longer exists at the recorded commit are all flagged and fixed (reinstall / record / remove) before the operation proceeds.
7. Direct-install fallback (no canonical repo found)
If the canonical repo cannot be located, install by copying each chosen skill dir into ~/.agents/skills/<name>/ and, for each installed harness, into its own skills dir (~/.config/opencode/skills, ~/.claude/skills, ~/.codex/skills). Track state in ~/.agents/add-more-skill.json with the same schema. Warn the user this is a degraded mode — no repo-based wiring or central management. If the repo exists, always prefer skills-external/ over this fallback.
8. Discovery seeds (well-known public collections)
| Repo | What's in it |
|---|---|
| anthropics/skills | official, tested skills (documents, design, presentations…) |
| obra/superpowers | TDD-driven development methodology skills (very popular) |
| ComposioHQ/awesome-claude-skills | 78+ general-purpose skills (SaaS, docs, business automation) |
| alirezarezvani/claude-skills | 200+ skills across 9 domains |
| coreyhaines31/marketingskills | marketing, SEO, copywriting, ads |
| vadimcomanescu/agents-skills | engineering workflow skills (debugging, TDD, verification) |
| wshobson/agents | agents + skill packs |
These are public repos — verify the repo actually exists before cloning (repos get renamed or moved). Always run the relevance + conflict steps on their contents; never install a whole collection blindly.
9. Guardrails
- Safety review before install: skim each selected
SKILL.md(and any scripts it references) and flag anything that exfiltrates data, steals credentials, hides commands, or is destructive. Present findings and let the user decide. Never install a skill the user hasn't explicitly picked. - Sanity-check state first: run section 1 before every add/update/sync/remove; never trust
prefs.local.jsonrecords that contradict the disk. Resolve mismatches with the user (add the skill or update the records) before proceeding. - Never write secrets;
prefs.local.jsonis gitignored — never commit it. - Back up anything you replace (
.backups/<ts>/, matching the installer's convention). - Prefer the smallest change: install only the selected skills, update only what changed, remove only what the user agreed to.
- Preserve the repo's conventions and formatting; validate edited JSON with
python3 -m json.tool. - After every change, the installer must run successfully — verify the result and report it.