Repositories¶
See also: Skills and Hooks (what a repository provides), Projects (where a repository's skills get installed), and MCP Servers (a repository can also declare MCP presets).
Overview¶
A repository is any Git remote that contains one or more skills (and, optionally, MCP server presets - see MCP Servers). SkillKeeper clones it locally, resolves the skills it contains, and tracks it for updates.
Repository record fields: id, name, url, kind (github, bitbucket,
or generic - detected from the URL), transport (ssh or https -
likewise detected), lfs (whether Git LFS is required), localPath,
lastFetched, and an optional branch - a user-chosen branch to track
instead of the clone's default.
Adding and managing repositories¶
CLI:
skillkeeper repo add <url> [<local-path>] [--name <name>] [--lfs | --no-lfs]
skillkeeper repo remove <id>
skillkeeper repo list
skillkeeper repo update [id] [--all]
repo add clones immediately. The local path is optional: omit it and the
clone lands in a per-repository directory under the app's own repositories folder
(the same location the desktop app uses). Git LFS is enabled by default when the
git-lfs client is installed; --no-lfs opts out. The
desktop app splits this in two: adding a repository first records it (so its
card can appear right away) at an app-managed path under its own
repositories directory, then clones it as a second step; a repository whose
clone has not finished, or failed, still has a record and can be retried.
Either front end rejects an add whose URL (or, for the CLI, local path) is
already tracked.
repo update (CLI) or "sync" (desktop) refreshes a repository from its
remote; see "Update operations" below for how the two differ.
Branch tracking¶
A repository can track a specific branch instead of the clone's default. Setting or changing the tracked branch force-checks-out that branch in the clone (discarding any local edits); from then on, every sync first force-switches to the tracked branch, then force-pulls, so the clone always ends up on that branch even if something else changed it out from under SkillKeeper. Leaving the branch unset just means "whatever the remote's default branch is."
SSH transport and private repositories¶
SkillKeeper supports SSH transport for private GitHub and Bitbucket
repositories. Key material and passphrases are handled by the user's
ssh-agent; SkillKeeper never reads private keys. In the desktop app, a
repository's clone and sync run inside the app's own embedded terminal
session rather than silently in the background - so if the ssh-agent needs a
passphrase, the prompt surfaces there, and the app can open the terminal
automatically when input is needed. A "run ssh-add" action is available from
the same terminal to load a key into the agent. Update checks are partly
interactive: the background "check for updates" runs its fetch through
the same terminal-backed Git as a pull (visible, ssh-capable, and it can
prompt for an SSH passphrase); only the two rev-parse comparisons that
follow the fetch run through the silent Git invocation.
Example SSH URL:
skillkeeper repo add git@github.com:example/private-skills.git ./private-skills
Make sure your ssh-agent has the relevant key loaded before running this command; the CLI has no embedded terminal, so an interactive passphrase prompt there depends entirely on your own shell's ssh-agent integration.
Git LFS¶
If a repository declares Git LFS usage, SkillKeeper runs git lfs steps
during clone and sync. If the git-lfs client is absent, SkillKeeper reports
a clear, actionable error rather than silently producing an incomplete
checkout.
How Git is invoked¶
SkillKeeper invokes the system git binary as a subprocess with argument
arrays only - no shell string interpolation. This design:
- Reuses the user's existing SSH config, ssh-agent, and Git LFS setup.
- Keeps credential handling out of the application.
- Prevents shell injection.
- Reduces the dependency and attack surface compared to a Node Git library.
Supported operations: clone, fetch, pull (fast-forward only),
forcePull (fetch, then reset --hard @{upstream} plus clean -fd),
checkout <branch> (force-switch, discarding local edits), lfsPull,
setRemoteUrl, revParse, currentBranch, and listBranches.
Update detection¶
SkillKeeper uses two levels of update detection, matching repositories and skills separately:
Repository level (repoHasUpdate): fetch, then compare the local HEAD
to the tracked upstream ref (@{upstream}). If they differ, the repository
"can be updated." Read-only: a fetch alone never modifies the working tree.
Skill level (skillHasUpdate): compare the content hash of a resolved
skill's files in the working tree against the content hash recorded in its
InstallManifest (falling back to recomputing it from the manifest's file
hashes when no hash was recorded). A skill "can be updated" when the source
content differs from what is installed - a changed, added, or removed file.
This distinction matters: a repository may have new commits without any of the skills you have installed changing, or a skill's files may change without the tracked ref moving (for example after a force-push that lands at the same ref).
Update operations¶
The CLI and the desktop app expose different-shaped update operations over the same core primitives:
- CLI
repo updateruns a plain fast-forward-onlygit pullon one repository or every tracked repository (--all); it never touches individual skills or their installs. - CLI
skill update <id>re-resolves one installed skill from its source repository and reinstalls it (optionally limited to--agent), independent of any repository update. - Desktop "sync" on a repository card is the stronger operation: it
force-switches to the tracked branch (if set), then force-pulls - fetch
plus a hard reset to the upstream ref plus a clean of untracked files - so
an app-managed clone always ends up byte-identical to the remote and never
hits a merge conflict. It never modifies any already-installed skill by
itself; it only makes new/changed skill content visible for the next
install or update action. A repository's card also carries a background
"check for updates" (
repoHasUpdate) that fetches and compares refs without pulling, so the update indicator can appear well before the user chooses to sync. - Desktop project-mode skill updates are chosen per project, driven by which installed skills are stale relative to their source repository; the desktop app applies them the same way it applies fresh installs (see Projects).
Skill availability¶
listAvailableSkills resolves the skills in every cloned repository's
working tree (the same resolution schemes described in
Skills and Hooks) for the
Skills page's browsing tree. A repository whose clone is missing, or whose
working tree fails to resolve (for example a malformed
skillkeeper.repo.yaml), is skipped for that listing; the others still
appear.
Removing a repository¶
Removing a repository only drops its tracked record and best-effort deletes its local clone directory. Skills already installed from it are not uninstalled - they keep working, and the next reconciliation pass (see Skills and Hooks) remembers their last known repository id rather than treating them as freshly unmanaged. They simply stop being able to show an "update available" badge, since there is no longer a tracked repository to compare their content hash against.
Update modes¶
By default, SkillKeeper checks for updates on demand only. The updates
section of config.yaml controls this behavior. See
Configuration for details.