docs / scenarios
Scenario guide
A hands-on guide organized by task. Each scenario ships a command sequence you can copy as is; the full flag vocabulary lives in the command reference, and the reading of exit codes and JSON output in automation & CI. When the exact spelling of a flag needs confirming for the installed version, run skillmod <command> --help.
Choose a scope
Project scope is the default. SKILL.mod and SKILL.lock stay in the current directory, and installations go into .agents/skills/.
--global is only for user-wide skills: global declarations live below the skillmod store, and installations normally go into the user's own agent skill directories. Project and global declarations are two separate things, and ordinary commands do not merge them.
Adopt existing skills
Adopting the user-wide skills and adopting a project are two independent steps: each scope has its own manifest, either can be done alone, and the order does not matter.
Adopt the user-wide skills
The user-wide skills are where a machine's shared skills live:
It declares everything in ~/.agents/skills/ into ~/.agents/skillmod/global/SKILL.mod, recovering provenance from the previous installer's recorded sources and from the shared snapshot cache.
A skill the previous installer recorded from a web discovery endpoint has no Git repository behind it: the record names the web origin, the entry is reported as unresolved, and the skill is kept as a local declaration. Adding the repository that publishes it to known_sources lets a later init adopt it as a Git dependency, because the content is then verified against that repository. A record the previous installer already marked local is not a gap at all: it stays a plain local declaration, with no note and no unresolved count.
Adopt the current project
After that, keep both scopes aligned. The two manifests are independent, so a command that should affect the user's machine needs --global:
Bootstrap an existing project
Use init when skill directories already exist but are not declared:
init scans .agents/skills/ in the selected scope without changing existing directories, links, or files: directory links are followed for content verification, while broken links, unverifiable contents, and invalid directory names are reported and skipped. Identical entries across targets are merged, with every candidate path kept for provenance recovery.
Provenance is recovered from matching lock records or verified snapshots, including monorepo subdirectories and aliases. init --global also imports the upstream installer's .skill-lock.json, while project init reads skills-lock.json. A recorded Git source and revision stay authoritative even when the installed directory has drifted; when an upstream record omits its revision, init adopts the latest immutable resolution only if the contents match exactly. Sources that cannot be resolved safely are kept as local baselines, so one unresolved entry does not discard the rest of the import.
The import writes both SKILL.mod and SKILL.lock. Replacing an existing declaration requires --force, which first backs it up as SKILL.mod.bak:
Use global scope only when requested:
Add a remote skill
An address has this form: <repository>[//<subdirectory-or-skill-name>][@<version>]. The repository is always named; // then selects the skill inside it:
| Form | Command | Notes |
|---|---|---|
| Path inside the repository | skillmod get github.com/acme/agent-skills//skills/review@v1.2.0 | a subdirectory after //, optionally with @version |
| Skill name inside the repository | skillmod get github.com/acme/agent-skills//review | the name stands in for the path; two short words locate the skill in a collection |
| The repository is itself a skill | skillmod get github.com/acme/single-skill | no // needed |
An exact subdirectory always wins over a name, and a unique name resolves to the skill's real path, so source records github.com/acme/agent-skills//skills/review rather than the shorthand that was typed. When several skills in the repository answer the same name, skillmod reports the candidate paths and refuses to guess.
Omitting a version asks skillmod to resolve the latest immutable tag, with a pseudo-version fallback for a repository that has no tag at all. A branch name is rejected, and the address must be credential-free.
On an interactive terminal each candidate gets one line: ↑/← and ↓/→ to move, Space to toggle a selection, D to show or hide the current description and command, and Enter to confirm. --all installs every discovered skill without asking, so use it only when the selection is already clear; for a repository that holds several skills, interactive selection is preferable unless the user asked for all of them. --yes is not the same thing: it answers the confirmations that follow the selection, and a non-interactive run of a multi-skill repository has to say --all to get past the selection step. On a terminal, --yes still lets the user pick skills; it skips only the later confirmations. The same rule applies to share and remove.
When two sources publish the same skill name, install the additional entry with an explicit directory alias:
Long-running get and update runs show a compact animated status block on interactive terminals. Remote version checks request only HEAD, branch, and tag refs; update deduplicates equivalent repository URLs and checks up to four distinct repositories concurrently; and a repository snapshot is integrity-checked once per command and reused across skill discovery.
Reproduce a declared environment
After cloning a project that contains SKILL.mod and SKILL.lock:
sync installs or aligns declared content and is idempotent. It does not silently overwrite local modifications. If it returns exit code 3, inspect the per-target results: some work completed, while conflicting targets were kept.
Use sync --relink only to deliberately recreate matching remote installations using the configured install mode:
Inspect state and provenance
Use list for the complete declaration overview:
list, why, and verify classify every installation directory the same way, so they cannot disagree about a target. They also inspect local entries against the recorded baseline: an edited local entry is reported as local-drift, not as a plain local, and an unreadable directory is unverifiable everywhere.
| Classification | Meaning |
|---|---|
local | A local entry that matches the recorded baseline |
local-drift | A local entry that was edited and no longer matches the recorded baseline |
unverifiable | The directory cannot be read, so it cannot be verified |
Use why for one published name or installation alias:
why reports the source, resolved version, commit, dirhash, installation directory, and each configured target's status. Prefer it over manually interpreting links inside .agents/skills/.
Verify in CI
Interpret the exits this way:
| Exit | Meaning |
|---|---|
0 | All checked entries are consistent |
1 | Operational or input error |
2 | Drift detected |
3 | Partial completion for commands that safely preserved targets |
For machine consumption, add --json and branch on the command and action identifiers rather than on translated notes or terminal text. The full action vocabulary and the report shape are on the automation & CI page.
Update dependencies
Inspect current state first, then update all remote entries or selected names:
A published name can represent more than one aliased declaration; an installation alias selects its corresponding entry. Review the output whenever the selector may not be unique.
update shares get's latest semantics: every remote entry moves to the highest semantic-version tag (subdirectory tags first, then root), and only a repository without any tag advances to a new pseudo-version at default-branch HEAD. Entries pinned to a commit — pseudo-versions and SHAs — migrate to that tag as well, so machines that adopted the same skill differently converge on the same version.
skillmod refuses an accidental semantic-version downgrade of a tag lock when newer tags have disappeared. Use --allow-downgrade only after confirming that the remote tag removal was intentional:
Remove a dependency
Use remove when the declaration itself should go away:
Names may be published names or installation aliases — passed as positional arguments or through --skill (-s), which is repeatable and comma-separated exactly like share's — and a run that names nothing opens a selection over what SKILL.mod declares:
--all takes every declared entry without asking. A bare remove picks from the declarations interactively, so it needs a terminal; --yes is not a substitute for either, because it answers the deletion confirmation rather than choosing what to delete.
Use --agent when only sharing should stop while the managed skill and its declaration stay:
Without skill names, the picker offers only skills shared to the named agents and starts with nothing checked. With --all, all matching skills are unshared; skills shared only to other agents are unaffected. Agent values may repeat or use comma-separated names. Names and --all cannot be combined.
Clean managed installations are removed transactionally. Locally modified or unverifiable directories are preserved and reported as partial completion.
Use prune when declarations were already edited and stale installations or lock records remain:
Do not replace either command with manual cache deletion. prune never deletes link targets or shared snapshots, and there is no automatic cache eviction; read the storage notes in the repository's reference docs before deleting a snapshot by hand.
Share installed skills with other agents
skillmod manages one directory, .agents/skills/, so an agent that reads another convention needs a link there. share creates those links and records the agents it linked each skill to on that skill's entry in SKILL.mod, which is what makes the setup reproducible on another machine — and lets one skill go to claude while another goes to codex:
A selected skill missing from SKILL.mod is adopted in the same run: a verified lock baseline or cache snapshot preserves its remote source and version; otherwise it is recorded as a local entry with its current content hash in SKILL.lock. Only selected skills are adopted, existing declared baselines are preserved, and --dry-run reports the adoption without writing state or links. Existing unrecorded mirror links are included in the adopted agent list.
With --agent, the skill picker checks only skills already shared to every requested agent: share --agent workbuddy does not check a skill shared only to codex, and a new agent starts with nothing checked. With multiple agents, accepting the defaults keeps existing links without adding any.
Omitting --skill and --agent lists the installed skills and the agent directories for interactive selection, and both lists open on the state that already holds: the skills already linked to an agent are checked, and so is every agent all of the chosen skills already name. Confirming an unchanged selection is therefore a no-op, and adding one agent to several skills is a matter of checking the skills and then the agent.
An agent is named by one directory segment and read from .<name>/skills under the scope root, so the name is all a declaration needs: --agent workbuddy links into .workbuddy/skills and is recorded like any other. That is also why the manifest never stores a path — a name reproduces on another machine, a path would not.
A destination that already holds identical content or a link to the managed copy is kept; one that holds different content is a conflict, settled with the same per-conflict policy get, sync, and update use (--on-conflict=overwrite or =skip). .agents/skills/ is refused as a destination, because linking there would shadow the directory verify reads.
Once the declaration exists, the links maintain themselves: sync recreates a link that was replaced or drifted, verify reports a missing one under an agent directory that exists on this machine, and removing a skill takes its mirror links down with it.
To stop sharing, share --remove --agent does the same as remove --agent:
Destinations holding foreign content are left alone, and an entry left with no agents loses the field entirely. --remove is now a switch; the agent value belongs to --agent. Both forms preserve managed copies and declarations, including when their share links were already missing. A state write failure restores staged links.
Installation modes
auto prefers links to immutable shared snapshots and falls back to copies when links are unavailable. copy creates independent directories. Override the configured mode for an intentional migration:
Use copies when the user needs to edit an installed skill. Do not edit a shared snapshot through a linked installation: a link points at content shared with every other project on the machine. Ordinary sync preserves matching installations and is idempotent, while --relink deliberately recreates remote installations in the selected mode. Both respect local modifications, and --yes never forces a conflicting file to be overwritten. Local entries are recorded and verified without automatic migration.
--json output, and the action vocabulary are in automation & CI; errors and odd states are in troubleshooting.