README
¶
skillsrc
Your .agents-only skills manager.
It lets a project declare its agent skills without committing installed copies. Sources go in skills.toml. Locked Git
revisions and content hashes go in skills.lock. skillsrc installs the selected skills into .agents/skills.
Run skillsrc sync in another checkout to restore locked Git content, refresh declared local sources, and match the
installed set to the manifest. If skillsrc does not own an existing target, it stops rather than replacing it.
It manages .agents/skills and no other destination. It does not support agent-specific destinations or compatibility
layers.
Install
The only runtime dependency is git. To install from source, use Go 1.24 or later:
go install github.com/jordi9/skillsrc/cmd/skillsrc@latest
From a checkout:
make install
Quick start
Project skills
Run these commands from the directory that should own the skill configuration:
cd path/to/project
skillsrc init
skillsrc add owner/repository@skill-name
add writes the selected skill to the manifest, updates the lockfile, and installs the skill under .agents/skills.
If you do not know the skill name, inspect the repository first. discover is read-only and does not require a
skills.toml:
skillsrc discover owner/repository
skillsrc add owner/repository@skill-name
Commit skills.toml, skills.lock, and the root .gitignore. After cloning the project elsewhere, install its
configured skills with:
skillsrc sync
User skills
Use -g to manage skills under ~/.agents from anywhere:
skillsrc -g init
skillsrc -g add owner/repository@skill-name
You can also work directly from ~/.agents. In that directory, skillsrc selects user scope automatically, so you do
not need -g.
cd ~/.agents
skillsrc init
skillsrc add owner/repository@skill-name
Project files
skillsrc init creates the project metadata. After the first successful add or sync, the layout is:
project/
├── skills.toml
├── skills.lock # created by the first successful mutation
├── .gitignore
└── .agents/
├── .gitignore # generated by skillsrc
└── skills/ # managed installations
The root .gitignore keeps the generated .agents/.gitignore and installed managed skills untracked. The generated
ignore file names only managed skills, so Git still shows unmanaged or in-place skills under .agents/skills.
skills.toml
Each source selects one or more unique skill names and declares exactly one of repo or path.
version = 1
[[sources]]
repo = "owner/repository" # also accepts HTTPS and SSH Git URLs
ref = "main" # optional branch, tag, or full 40-character commit hash
skills = ["one", "two"]
[[sources]]
path = "../local-skills" # relative and absolute paths are supported, including ~/...
skills = ["private-skill"]
Override model invocation
If you want to override model invocation for a skill and disable it, prefix its name with ! or use the explicit form:
skills = [
"ordinary-skill",
"!manual-only",
{ name = "another-manual-skill", disable-model-invocation = true },
]
For entries marked with ! or disable-model-invocation = true, skillsrc sets the root disable-model-invocation: true key in the installed SKILL.md. It does not change the source or its lock hash. When skillsrc rewrites the
manifest, it uses the shorthand. It accepts disable-model-invocation = false and writes the entry as an ordinary skill
name. A logical skill name may appear only once, so "one" and "!one" are duplicates.
A local source cannot set ref. Selected skills must be discoverable in the source and cannot be selected by more than
one source.
Skill discovery is limited to:
- the source root when it contains
SKILL.md; - immediate child directories;
skills/*, plus one category level for grouped repositories;.agents/skills/*; and.claude/skills/*;- local skill paths declared by
.claude-plugin/marketplace.jsonor.claude-plugin/plugin.json, including conventionalskills/*directories; and - local skill paths declared by
.cursor-plugin/marketplace.jsonand.cursor-plugin/plugin.json.
Manifest paths must stay within the repository. skillsrc ignores remote paths, absolute paths, and paths that escape
the repository. Claude and Cursor metadata only tells skillsrc where to find skills. It handles the discovered skills
like any others.
When the same skill name appears in multiple discovery locations, the higher-priority location wins. skillsrc merges
identical marketplace copies. If marketplace copies conflict, the first declaration wins, and add or discover prints
the chosen and ignored paths. It rejects other conflicts at the same priority as ambiguous.
skillsrc copies safe relative file symlinks as regular files when they resolve inside the selected skill. It rejects
absolute, escaping, directory, broken, and cyclic symlinks.
Commands
skillsrc init # create skills.toml in the current directory
skillsrc discover SOURCE # list discovered skills without changing configuration
skillsrc discover SOURCE --ref REF # inspect a branch, tag, or full commit hash
skillsrc add SOURCE # install its sole skill, or list choices when there are multiple
skillsrc add SOURCE SKILL... # declare selected skills, update the lock, and install them
skillsrc add OWNER/REPO@SKILL # add one skill using the skills CLI shorthand
skillsrc add SOURCE SKILL... --invoke-user-only # add skills with automatic model invocation disabled
skillsrc add SOURCE --all # declare and install every skill discovered in the source
skillsrc add SOURCE --all --invoke-user-only # add every discovered skill with model invocation disabled
skillsrc add SOURCE SKILL... --ref REF # add from a branch, tag, or full 40-character commit hash
skillsrc remove SKILL... # remove declarations and their owned installations, then sync
skillsrc sync # restore the declared set at locked Git revisions and local content
skillsrc outdated [SOURCE|SKILL...] # report changed remote skills or local sources without modifying files
skillsrc update [SOURCE|SKILL...] # advance matching Git sources, update the lock, and sync installations
skillsrc list [--all] [--json] # show configured state, optionally including unmanaged skills or JSON
skillsrc doctor [--repair] [--json] # diagnose managed state, optionally repair it or emit JSON
skillsrc version # print the installed skillsrc version
Run skillsrc <command> --help for complete arguments and options.
Initialize a manifest
Project init creates skills.toml in the current directory, not an inferred Git root. It refuses nested
configuration, initialization directly in $HOME, and overwriting an existing manifest. skillsrc -g init initializes
~/.agents without creating repository Git ignore metadata. add requires an existing selected manifest.
Discover skills
discover lists the skills in a Git repository or local directory without changing a manifest, lockfile, or
installation. It works outside an initialized skillsrc project and accepts --ref for Git sources.
skillsrc discover owner/repository
skillsrc discover ../local-skills
skillsrc discover owner/repository --ref v1.2.0
Add and remove skills
A source can be GitHub shorthand, an HTTPS or SSH Git URL, or a relative, absolute, or ~ local path:
skillsrc add owner/repository # install its sole skill, or list multiple choices
skillsrc add owner/repository one two # add named skills
skillsrc add owner/repository@one # add one skill using shorthand
skillsrc add owner/repository --all # add every discovered skill
skillsrc add ../local-skills private-skill # add from a local directory
Use --ref with a Git source to select a branch, tag, or full commit hash. Use --invoke-user-only with named skills
or --all to write them with the ! shorthand and install them with model invocation disabled. --all cannot be
combined with explicit skill names.
With no skill names, add installs the skill automatically when the source contains exactly one unique skill name. If
there are zero or multiple skills, it only lists what the source contains. add validates selected skills before it
changes the manifest. It installs only newly selected skills and does not refresh or repair existing declarations. When
adding to an already locked Git source, it uses that source's locked commit. If the requested skill is absent there, run
skillsrc update <source> first, then retry add.
remove deletes the named declarations, removes empty source blocks, and prunes only installations owned by the
selected manifest. It does not update the remaining Git sources. rm is an alias for remove.
Check, synchronize, and update
These commands have different effects:
| Command | Changes locks? | Changes installations? | Purpose |
|---|---|---|---|
outdated |
No | No | Check remote skill updates and unsynchronized local changes |
sync |
Only creates missing entries | Yes | Reproduce the declared and locked skill set |
update |
Yes, for selected Git sources | Yes | Advance Git revisions and then synchronize |
sync reproduces locked Git commits, creates missing lock entries, refreshes local content, installs the declared set,
and prunes no-longer-declared managed skills. It does not advance an existing Git lock.
outdated fetches configured Git refs and compares each selected skill's content hash with its locked hash. It reports
a Git source as up to date when its selected skills have not changed, even if other files in the repository have.
Available updates show the changed skill names and short commit hashes. They also show exact tags when available, or
commit dates otherwise. The command does not change the manifest, lockfile, project metadata, or installed skills. It
reads local sources without changing them and reports whether their content matches the lock.
update refreshes all Git sources, or only sources matched by the supplied repository/path or skill selectors, and then
performs a sync. outdated accepts the same optional selectors. Local sources have no remote version; full commit refs
remain exact.
See docs/lockfile.md for the generated lock format.
Inspect and repair
skillsrc list # show configured skills and installation state
skillsrc list --all # also show valid standalone unmanaged skills
skillsrc doctor # report lock, install, cache, and project metadata problems
skillsrc doctor --repair # restore repairable managed state
skillsrc does not take ownership of standalone skills shown by list --all. When an unmanaged skill collides with a
declared name, the configured skill gets the collision state. list does not print a second unmanaged row. ls is an
alias for list.
doctor --repair restores repairable installations and project metadata. Unmanaged collisions must be resolved by the
user.
By default, the Git cache is the OS user cache directory followed by skillsrc/repos. On macOS, for example, it is
~/Library/Caches/skillsrc/repos. Use --cache to choose another directory. Concurrency lock files also stay in the
user cache instead of the project.
Scope selection
From the current directory, commands search upward for the nearest skills.toml. There is no fallback to user
configuration when project discovery fails. Running directly from ~/.agents is the exception: it selects user scope
and prints a short notice.
skillsrc sync # nearest project skills.toml
skillsrc -g sync # ~/.agents/skills.toml
Project commands do not migrate or change existing files in ~/.agents.
Safety and recovery
Each managed skill has a .skillsrc-managed.json marker tied to its owning manifest. skillsrc replaces or removes a
directory only when it has a valid marker for that owner. An existing file, symlink, unmarked directory, or directory
owned by another manifest causes a collision. skillsrc leaves it untouched and stops the operation. skills.lock
records the source and upstream content hashes.
Installs use staging directories, backups, and transaction journals. After an interrupted replacement or prune, the next
command that changes files runs recovery first. Use skillsrc doctor to report problems with locks, installations, the
cache, and project Git ignore files. skillsrc doctor --repair restores installation and project metadata when it can.
You must resolve unmanaged collisions yourself.
Locks and hashes make installation reproducible. They do not make upstream skill instructions trustworthy. Review
sources and lockfile changes before installing or updating them. See SECURITY.md for vulnerability
reporting and details about what skillsrc does and does not trust.
Releasing
Tags trigger releases. Maintainers can run these commands from a clean change directly on main when local main
matches origin/main:
./release.sh --dry-run
./release.sh
The release script uses git-cliff to prepend the next version to CHANGELOG.md, then opens the file with $VISUAL,
$EDITOR, or vi. Edit the generated section before confirming. The script commits and pushes the changelog, tags that
commit, and CI publishes the edited section as the GitHub release notes.
Contributing and license
See CONTRIBUTING.md before sending a contribution. skillsrc uses the MIT License.