Skip to main content

Install Agent Skills from Git repositories using symlinks

Project description

SkillHost

SkillHost manages Agent Skills from Git repositories. Git repositories are the source of truth for skill content, symlinks are the install mechanism, and ~/.skillhost/config.json is the persistent source of truth for registered agents, projects, and skill repositories.

SkillHost is intentionally small: it does not run code from skill repositories, does not scan your whole disk, and does not overwrite user-owned existing skills.

Install

pipx install skillhost
uv tool install skillhost
pip install skillhost

From a checkout:

uv tool install .
pip install .

SkillHost does not need an initialization step. Regular commands create the default ~/.skillhost state they need on demand; commands that do not need persistent config can run before config.json exists.

Current command list

skillhost [-h] [--version]
  upgrade

  register --project <name> --git <project-git-url>
  register --agent <name> --user-dir <path> [--project-dir <path>]

  unregister --project <name>
  unregister --agent <name>

  add <skill-git-repo> [--project <name>] [--name <repo-name>]

  update [repo-name] [--project <name>] [--agent {codex,claude,opencode,openclaw,hermes}] [--all]

  remove <repo-name> [--project <name>]

  relink [repo-name] [--project <name>] [--agent {codex,claude,opencode,openclaw,hermes}] [--all]

  unlink [repo-name] [--project <name>] [--agent {codex,claude,opencode,openclaw,hermes}] [--all]

  clean

  list [--project <name>]
  projects
  agents
  doctor [--project <name>]
  config

There are no user, project, register-project, config path, or config edit subcommands. Older flags such as --dry-run, --force, --all-projects, --all-skills, --include, and --exclude are not part of the current CLI.

Scope model

User scope is the default. These commands operate on user-level skill repositories unless --project <name> is provided:

skillhost add <repo>
skillhost update
skillhost relink
skillhost unlink <repo-name>
skillhost list
skillhost doctor
skillhost remove <repo-name>

Project scope is selected only with --project <name>:

skillhost add <repo> --project nsdk
skillhost update --project nsdk
skillhost relink --project nsdk
skillhost unlink --project nsdk --all
skillhost list --project nsdk
skillhost doctor --project nsdk
skillhost remove nsdk-skills --project nsdk

--all means all skill repositories in the selected scope. For update, relink, list, and doctor, omitting repo-name already means all repositories in the selected scope. For relink, omitting repo-name also opens the target selector in an interactive terminal unless --agent is provided. For unlink, omitting both repo-name and --all is refused to avoid accidental bulk unlinking.

State layout

Default state lives under ~/.skillhost:

~/.skillhost/
  config.json
  user_repos/
    <repo-name>/
  project_repos/
    <project-name>/
      <repo-name>/

skillhost config prints only the absolute path to config.json.

config.json stores:

version
home
agents
user_repos
projects
projects.<project>.remotes
projects.<project>.repos
repo URLs
normalized URLs
local repo paths

Each agent target directory also has a target-local .skillhost-links.json manifest. This manifest is separate from config.json and is used so unlink and remove only touch SkillHost-managed symlinks.

Agent targets

Built-in agents are initialized in config:

codex    user: ~/.agents/skills                 project: .agents/skills
claude   user: ~/.claude/skills                 project: .claude/skills
opencode user: ~/.config/opencode/skills        project: .opencode/skills
openclaw user: ~/.openclaw/skills               project: —
hermes   user: ~/.hermes/skills                 project: —

Register another agent target:

skillhost register --agent cursor --user-dir ~/.cursor/skills --project-dir .cursor/skills
skillhost agents
skillhost unregister --agent cursor

OpenClaw and Hermes Agent are user-level targets only; SkillHost intentionally does not create project-level links for them. Claude Cowork currently exposes personal skills through its UI rather than a documented stable local user skills directory, so SkillHost does not link to Claude Cowork yet.

Agent registration updates config only. It does not link automatically; run skillhost relink when you want to refresh links.

User-level workflow

skillhost add git@github.com:org/company-skills.git
skillhost list
skillhost update
skillhost relink
skillhost unlink company-skills --agent codex
skillhost clean
skillhost remove company-skills

add clones the skill repository into ~/.skillhost/user_repos/<repo-name>, records it in config.json, discovers skills, and then prompts where to link the added skills: Codex, Claude Code, OpenCode, OpenClaw, Hermes Agent, or All. In non-interactive shells it keeps the safe previous behavior and relinks all enabled user-level agent targets when possible.

Use --name when you want the local repo name to differ from the Git URL basename:

skillhost add git@github.com:org/company-skills.git --name shared-skills

Project-level workflow

First register the project remote:

skillhost register --project nsdk --git git@github.com:org/nsdk.git

Then run project-scoped commands from inside the matching project checkout when you want project links to be created or removed:

cd ~/code/nsdk
skillhost add git@github.com:org/nsdk-skills.git --project nsdk
skillhost update --project nsdk
skillhost relink --project nsdk
skillhost unlink --project nsdk --all
skillhost remove nsdk-skills --project nsdk

Project relink and project unlink validate the current Git repository root and its origin remote against the registered project. SkillHost does not search the disk for project checkouts and does not perform cross-project bulk cleanup.

If you add or update a project skill repository outside the matching checkout, the repository is still recorded under ~/.skillhost/project_repos/<project>/<repo-name>, and SkillHost prints the command to run inside the project checkout.

Command details

skillhost upgrade

skillhost upgrade

Updates the installed SkillHost package using the installer that appears to own the current command: pipx upgrade skillhost for pipx-managed installs, uv tool upgrade skillhost for uv tool installs, and python -m pip install --upgrade skillhost as the fallback for ordinary pip or virtualenv installs.

skillhost register

skillhost register --project <name> --git <project-git-url>
skillhost register --agent <name> --user-dir <path> [--project-dir <path>]

Project registration normalizes and stores the project Git remote and creates ~/.skillhost/project_repos/<name>. Agent registration stores user and project target directories. --project and --agent are mutually exclusive.

skillhost unregister

skillhost unregister --project <name>
skillhost unregister --agent <name>

Removes the config entry only. It does not delete user-owned files and does not scan disk for unknown checkouts.

skillhost add

skillhost add <skill-git-repo> [--project <name>] [--name <repo-name>]

Clones a skill repository into the selected scope and records it in config. Without --name, the repo name is derived from the Git URL basename with .git stripped. GitHub HTTPS URLs are cloned through SSH automatically, so https://github.com/org/repo and git@github.com:org/repo.git both work for users with SSH access. If no skills are discovered, add leaves config and repo storage unchanged and exits with an error. On success, it prints how many skills were added and suggests skillhost list.

After a successful interactive add, SkillHost opens a small terminal selector for where to link the newly added skills. Use ↑/↓ to move, Space to select or unselect, and Enter to confirm. Leaving nothing selected defaults to all enabled targets. If the terminal cannot run the selector, SkillHost falls back to a text prompt where you can enter one number, multiple comma-separated numbers such as 1,3, or all/blank for all. Non-interactive add defaults to all enabled targets.

skillhost update

skillhost update [repo-name] [--project <name>] [--agent {codex,claude,opencode,openclaw,hermes}] [--all]

Before updating, update uses the same target selection flow as add and relink unless --agent is provided. It removes existing SkillHost-managed links for the selected repository or repositories only in the selected agent targets, so renamed or deleted skill directories do not leave stale symlinks behind. Then it runs git pull --ff-only for one repository or all repositories in the selected scope. It does not merge or rebase. After updating, it relinks the same selected agent targets when possible. Non-interactive update defaults to all enabled targets.

skillhost remove

skillhost remove <repo-name> [--project <name>]

Unlinks SkillHost-managed symlinks for that repo where safely discoverable, deletes the cloned repo under ~/.skillhost, and removes the repo entry from config. The repo argument can be the local repo name or a Git URL such as https://github.com/org/repo / git@github.com:org/repo.git; URLs are resolved to their repo basename. It does not support --all.

skillhost relink

skillhost relink [repo-name] [--project <name>] [--agent {codex,claude,opencode,openclaw,hermes}] [--all]

Creates or updates SkillHost-managed symlinks for one repo or all repos in the selected scope. Omitting repo-name means all registered repos in the selected scope; for example, skillhost relink refreshes every user-level repo, and skillhost relink --project nsdk refreshes every repo registered under project nsdk. Existing unmanaged files or directories are skipped. In an interactive terminal, relink uses the same target selector as add unless --agent is provided; non-interactive relink defaults to all enabled targets.

skillhost unlink

skillhost unlink [repo-name] [--project <name>] [--agent {codex,claude,opencode,openclaw,hermes}] [--all]

Removes only symlinks recorded in .skillhost-links.json. To unlink all repos in a scope, pass --all explicitly:

skillhost unlink --all
skillhost unlink --project nsdk --all

skillhost clean

skillhost clean

Scans all enabled user-level agent skill directories and removes broken symlinks. If you run it from inside a Git repository, it also scans that repo root's supported project-level agent skill directories, such as .agents/skills, .claude/skills, and .opencode/skills. If a broken symlink or missing destination is recorded in .skillhost-links.json, clean also removes the stale manifest entry. OpenClaw and Hermes are user-level-only targets, so they are not cleaned as project-level directories.

skillhost list, projects, agents, doctor, config

skillhost list [--project <name>]
skillhost projects
skillhost agents
skillhost doctor [--project <name>]
skillhost config

list shows repos and discovered skills in the selected scope. projects shows registered projects and normalized remotes. agents shows registered agent user/project target directories. doctor checks config, repos, duplicate skill names, targets, manifests, broken symlinks, and missing sources. config prints the absolute config path only.

Supported skill repository layouts

Single skill repo:

my-skill/
  SKILL.md

Collection repo:

company-skills/
  skills/
    git/
      SKILL.md
    db/
      SKILL.md

Flat collection repo:

company-skills/
  git/
    SKILL.md
  db/
    SKILL.md

Skill discovery is shallow. SkillHost checks root SKILL.md, direct children under skills/, or direct children under the repo root. It ignores hidden directories and obvious non-skill directories such as tests, docs, examples, scripts, references, and assets.

Git URL normalization

Common SSH and HTTPS Git URL forms normalize to host/org/repo:

git@github.com:org/repo.git      -> github.com/org/repo
git@github.com:org/repo          -> github.com/org/repo
https://github.com/org/repo.git  -> github.com/org/repo
https://github.com/org/repo      -> github.com/org/repo
ssh://git@github.com/org/repo.git -> github.com/org/repo

Project matching uses the current Git root plus git remote get-url origin, normalized with the same rules.

Safety rules

SkillHost does not execute code from skill repositories. It only clones repositories, pulls with git pull --ff-only, reads SKILL.md metadata, and creates or removes manifest-managed symlinks.

SkillHost never overwrites unmanaged existing targets, never removes user-owned skill directories, and never performs full-disk project discovery or cross-project bulk operations.

Project details


Download files

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

Source Distribution

skillhost-0.1.6.tar.gz (63.2 kB view details)

Uploaded Source

Built Distribution

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

skillhost-0.1.6-py3-none-any.whl (21.4 kB view details)

Uploaded Python 3

File details

Details for the file skillhost-0.1.6.tar.gz.

File metadata

  • Download URL: skillhost-0.1.6.tar.gz
  • Upload date:
  • Size: 63.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for skillhost-0.1.6.tar.gz
Algorithm Hash digest
SHA256 6ae200fe1bebf6a81604f7248ea977ed8999d15e9ecc83ed3c02cc25368d9342
MD5 c518dfc4f34472174f54ab2dc766f71d
BLAKE2b-256 c43e120aeecf7b9bfa785ab46f982cc85902a23c688ccd4cad88a48d03048646

See more details on using hashes here.

File details

Details for the file skillhost-0.1.6-py3-none-any.whl.

File metadata

  • Download URL: skillhost-0.1.6-py3-none-any.whl
  • Upload date:
  • Size: 21.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for skillhost-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 ce543f74df53bae94ac005e352cb7b2517ae6a211b37f4594ee9a6d9ba90df81
MD5 b05ea3111798401f74dcee8eb82ba885
BLAKE2b-256 2bcfbb2c8929942f14518f94e55a155f11506e408efe2e1a311c2cb85f307b94

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