Skip to main content

skill-groups

Organize AI-agent skills into named groups and mount them per project — the dotfiles of the AI skill world

中文 · CI

Collect the skills you actually use into named groups (e.g. python, web, sql), declare which groups a project needs, and let one command mount the right skills into the right agent directory. Zero dependencies, works on Python 3.9+.

Why

Skill libraries grow fast. When your global store has 160 skills and every new project needs a different subset, you stop re-picking them by hand and start asking "which project already solved this?"

skill-groups gives you three layers instead of one pile:

Layer Where it lives What it holds
Global SG_HOME (default ~/.sg) every skill you've ever collected, cached by content
Group SG_HOME/groups/<name>.json a named, reusable bundle of skills with sources
Project .sg.json + a skills dir which groups this project mounts, and where

Projects stay portable because a project declares groups, not raw paths. The skills dir that gets mounted (.agents/skills, .claude/skills, ...) is a real agent-recognized location, so there is zero per-agent configuration: the agent already scans that directory. The group definitions and the cache live outside the project, so the project itself stays clean, and the mounts are re-creatable with one command.

Supported agents

Each agent already reads a conventional skills directory inside the project root. skill-groups just mounts skills into that directory, so it works with any agent that scans these paths.

Agent Skills directory
Standard (Cursor, Gemini CLI, Copilot CLI, others) .agents/skills
Claude Code .claude/skills
Codex .codex/skills
OpenCode .opencode/skills

Pick the target with sg init --agent claude (choices: agents, claude, codex, opencode; default agents). --agent is repeatable — a project can mount into several agents at once: sg init --agent claude --agent opencode serves both .claude/skills and .opencode/skills from one declaration.

Claude Code users: you MUST run sg init --agent claude — Claude Code does not scan .agents/skills yet (tracked in anthropics/claude-code#16345); the default would silently load nothing. And after mounting, fully restart your agent — skills are registered at process start; a new session inside a long-running agent (e.g. /new in OpenCode) does not re-scan.

Install

The package is a zero-dependency Python 3.9+ CLI named sg.

pip install skill-groups

After install, sg is on your PATH and sg --help works from any directory.

Developers: from a clone of this repo, pip install -e . installs in editable mode (the build backend is hatchling; offline use pip install -e . --no-build-isolation).

Zero-install alternative: you don't have to install anything. From the repo root, python -m sg runs the same CLI directly, because the sg package is importable from the current directory. Every example below works with either sg ... or python -m sg ....

Quickstart

Run these in a new project directory. Expected output is shown below each command.

# 1. turn the current directory into a skill-groups project
sg init
# initialized C:\path\to\project

This writes .sg.json (schema v2) and adds the agent skills dir (.agents/skills by default) to your .gitignore. Use sg init --agent claude --agent opencode to serve several agents from one project; sg init --force --agent codex retargets an existing project (groups and standalone skills are kept).

# 2. create a group
sg group create python --description "Python tooling"
# created group python
# 3. add skills to the group from local folders
sg group add python lint --type local --path C:\path\to\lint-skill
# added lint to group python

sg group add python format --type local --path C:\path\to\format-skill
# added format to group python
# 4. mount every skill in the group into this project
sg use python
# used: python
# 4b. mount a standalone skill too (no group required)
sg use python --skill git-commit-writer --path "C:\path\to\git-commit-writer"
# used: python + git-commit-writer

--skill/--path can be repeated (they must come in pairs). Standalone skills are recorded in .sg.json under skills (group is ungrouped in sg ls) and are fully covered by sg status/sg sync/sg unuse --skill <id>.

# 5. see what's mounted
sg ls
# format (python, local)
# lint (python, local)
# 6. check status while the skills are mounted
sg status
# format (python): ok
# lint (python): ok
# 7. drop the group again (unmounts its skills)
sg unuse python
# unused: python
# 8. repair mounts to match the declaration
sg sync
# format: unchanged
# lint: unchanged
# 9. refresh git-sourced skills to their latest upstream
sg update
# lint: unchanged
# pytest: updated

sg status prints one line per mounted skill (skill (group): state, where state is ok, missing-link, drift, conflict, or stale), and sg sync repairs mounts to match the declaration (actions: unchanged, remounted, relinked, renewed, removed, skipped). Both exit 0; sg status --check exits 1 as soon as any skill is not ok — the hook for CI and pre-commit compliance checks. sg update re-fetches every git-source skill (branch/tag/default-branch revs; pinned commit shas and local sources are left alone), reporting updated when the resolved sha moved, and rewrites sg.lock accordingly.

Group definitions (schema v1)

A group is a JSON file at <SG_HOME>/groups/<name>.json. You can build it with sg group add, or write it by hand:

{
  "name": "python",
  "description": "Python tooling",
  "skills": [
    {
      "id": "lint",
      "source": { "type": "local", "path": "C:/skills/lint" }
    },
    {
      "id": "pytest",
      "source": {
        "type": "git",
        "repo": "owner/repo",
        "path": "skills/pytest",
        "rev": "main"
      }
    }
  ]
}

Rules enforced on every read:

  • name is a non-empty string and may not contain / or \.
  • Skill id must be unique within the group.
  • local sources require a string path; git sources require a string repo (path and rev are optional).

Inspect your groups with sg group list and sg group show python. Remove a group (its definition file) with sg group rm python — note that projects whose .sg.json still declares the removed group will report unknown group on the next sg use/sg sync.

Cache and mount mechanism

Every skill is fetched once into a content-addressed cache, then mounted into the project. The flow is: group → source → cache → mount.

  • Cache layout: <SG_HOME>/cache/<key>/<skill_id>/
  • <key> is a 10-hex sha256 of the source identity. For git sources the requested rev is part of the identity, so asking for a new rev gets a fresh cache directory and a stale cache can never be served for the wrong rev.
  • Local sources are copied on first fetch (gated by the presence of SKILL.md, so re-running is a no-op). Git sources are shallow-cloned once into <skill_dir>/.repo and reused on later calls.

Mounting happens in one of three modes, set with sg init --mode ...:

Mode Behavior
auto (default) Windows: junction, falling back to symlink, then copy. Other platforms: symlink, falling back to copy.
symlink Always a directory symlink.
copy Always a full copy.

When auto falls back to copy, it prints a warning to stderr (warning: fell back to copy for <skill_id>). Prefer junction/symlink over copy: copies go stale when the cached skill changes, and sg unuse has to delete real files instead of one link.

sg use is all-or-nothing. Before any mount it resolves every source and pre-flights every target link; if the same skill id is declared by two groups with different sources, or a target path already exists with different content, the whole batch aborts and nothing is changed.

Windows notes

  • Junctions need no admin rights. mklink /J works in a normal user session, which is why auto tries junctions first on Windows.
  • Symlinks need Developer Mode (Settings → Privacy & Security → For developers → Developer Mode) or an elevated shell. If a symlink can't be created, auto silently falls back to a copy.
  • Paths with spaces are safe. All git and mount commands use subprocess list form, never shell string concatenation, so a repo path like C:\My Skills\repo works.
  • Unmounting never touches the target: junctions are removed as reparse points (os.rmdir / cmd /c rmdir), never with a recursive delete.

Exit codes

Code Meaning Example
0 Success any command that completes
1 User error: bad input, conflicts, unknown group error: group already exists: python
2 Environment error or unexpected failure; also CLI usage errors error: git not found on PATH, unknown command

User errors print error: <message> to stderr and leave your state untouched. Environment errors (missing git, unwritable cache, corrupt config) print the same way but signal a setup problem, not an input problem.

Git sources

sg group add web serve --type git --repo owner/repo --path skills/web --rev v1
# added serve to group web
  • repo accepts an owner/repo shorthand (resolved to https://github.com/<owner/repo>.git), a full URL, or a local repository path.
  • path selects a subdirectory of the repo as the skill content; omit it to use the repo root.
  • rev accepts a branch name, a tag, or a full 40-character commit sha. A branch/tag becomes a shallow --branch clone; a sha is fetched and checked out directly.
  • The lock (sg.lock) records the actual resolved HEAD in resolved_sha, so sg status can later tell you whether the mounted skill matches what the declaration resolved to.
  • sg update refreshes branch/tag/default-branch sources in place (fetch first, so a network failure leaves your mounts untouched); a pinned sha is immutable by definition and never refreshed.

Troubleshooting: sg doctor

sg doctor reports the environment, which is the first stop when a git source won't fetch or a mount fails:

> sg doctor
python: 3.13.3
git: available
sg_home: C:\Users\me\.sg
sg_home_writable: yes
junction: supported
Line Healthy If not
git available install git and put it on PATH; git sources cannot fetch without it
sg_home your expected home path set SG_HOME to redirect all global state, e.g. $env:SG_HOME="$env:TEMP\sg-test" in PowerShell
sg_home_writable yes fix permissions on SG_HOME; the cache and groups live there
junction supported on Windows mounts fall back to symlink/copy automatically

The default SG_HOME is ~/.sg. Its layout: config.json (global config), groups/ (group definitions), cache/ (fetched skills).

Development

python -m unittest discover tests -v

The suite runs 236 tests covering the CLI surface, group validation, caching, git sources, updating, mounting, multi-agent projects, standalone skills, and isolation.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

skill_groups-0.2.0.tar.gz (45.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

skill_groups-0.2.0-py3-none-any.whl (30.4 kB view details)

Uploaded Python 3

File details

Details for the file skill_groups-0.2.0.tar.gz.

File metadata

  • Download URL: skill_groups-0.2.0.tar.gz
  • Upload date:
  • Size: 45.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.3

File hashes

Hashes for skill_groups-0.2.0.tar.gz
Algorithm Hash digest
SHA256 07167c696015efdf7dd05faf773591af8317be1abcef8a7db61dfae2dabd1b78
MD5 7ff640e1150187b6ba9f1da22be15976
BLAKE2b-256 7d08f9373a6f24e152a1b97f483c39d6139dbe80419107543830a5a6f83a2fda

See more details on using hashes here.

File details

Details for the file skill_groups-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: skill_groups-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 30.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.3

File hashes

Hashes for skill_groups-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 acde37b0381f521d8f6b6df6c40b9bf4de4b9730f92ede21f0687f8a9df99e55
MD5 0fc9ecc97d562ccde980d44f1b0497b0
BLAKE2b-256 75a127cac1f2cfee9e06babbbaa9fc41b7a09acab036fb945e7807b2a7a3da50

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page