Deterministic, repo-local skill deps for your CLI workflow.

Repo-local · Deterministic · No registry

brew install skill-vendor/tap/skv
skv init
skv add https://github.com/acme/skill-foo
skv sync
Commit skv.cue, skv.lock, and .skv/.

Why SKV?

Skills are becoming a shared standard across tools (Claude Code, Codex CLI, OpenCode), but there is no good ecosystem for dependency management. SKV brings a Go-modules-like workflow to skills:

The problem

  • Skills scattered across repos with no versioning
  • No way to pin exact versions across a team
  • Manual copy-paste leads to drift
  • No CI verification that skills match expectations

SKV's approach

  • CUE-based spec with JSON lock file
  • Deterministic installs (pinned commits + checksums)
  • Vendored skills committed to the repo
  • Works with any Git host—no registry required

Supported Tools

Native support

  • Claude Code (.claude/skills/)
  • OpenAI Codex (.codex/skills/)
  • OpenCode (.opencode/skill/)

Compatible

  • Cursor (via Codex/Claude-compatible skills handling)

Workflow

Go from spec to vendored skills and tool links in one repeatable flow.

1

Spec

Declare skills in skv.cue with repo, ref, and path.

2

Vendor

skv sync fetches and pins exact commits into .skv/skills/.

3

Link

SKV wires symlinks into each tool's skill directory automatically.

4

Commit

Commit skv.cue, skv.lock, and .skv/ to your repo.

5

Verify

Run skv verify in CI to ensure skills match the lock.


How It Works

skv.cue          skv sync         .skv/skills/
(your spec)  ──────────────►  (vendored content)
                    │
                    ▼
               skv.lock
           (commits + checksums)
                    │
                    ▼
    .claude/skills/  .codex/skills/  .opencode/skill/
                  (symlinks)
  1. skv sync reads your skv.cue spec
  2. Skills are vendored into .skv/skills/<name>/
  3. skv.lock records the resolved commit SHA and checksum
  4. Symlinks are created in each tool’s skill directory

Commands

Command Description
skv init Scaffold spec, lock, and .skv/skills/ directory
skv add <repo>[#ref][:path] Add a skill to the spec
skv sync Vendor skills, update lock, refresh symlinks
skv sync --offline Verify and link without network access
skv sync --refresh Re-fetch and overwrite vendored content
skv sync --accept-local Treat local content as source of truth
skv update [name] Update floating refs (branches/tags)
skv update --all Update all non-commit-pinned skills
skv verify Check vendored skills match the lock (CI-friendly)
skv list List all skills with their status
skv remove <name> Remove a skill from spec, lock, and disk
skv import <path> Move a local skill into SKV management

Adding Skills

# Single-skill repo (expects SKILL.md at root)
skv add https://github.com/acme/skill-foo

# Skill from a monorepo path
skv add https://github.com/acme/skill-pack:skills/skill-foo

# Pinned to a tag
skv add https://github.com/acme/skill-pack#v1.2.3:skills/skill-foo

# Override the skill name
skv add https://github.com/acme/skill-pack:skills/skill-foo --name release-notes

Managing Skills

List installed skills:

$ skv list
skill-foo      https://github.com/acme/skill-foo (abc1234)
release-notes  https://github.com/acme/skill-pack:skills/release-notes#v1.2.3 (def5678)
local-helper   local:.skv/skills/local-helper

Remove a skill:

$ skv remove skill-foo
Removed skill-foo from spec, lock, and .skv/skills/

Configuration

The spec file skv.cue defines your skill dependencies:

skv: {
  // Exclude specific tools (all enabled by default)
  tools: {
    exclude: ["opencode"]
  }

  skills: [
    {
      name: "skill-foo"
      repo: "https://github.com/acme/skill-pack"
      path: "skills/skill-foo"   // subdirectory in repo
      ref:  "v1.2.3"             // optional: tag, branch, or commit
    },
    {
      name:  "local-helper"
      local: "./.skv/skills/local-helper"  // local skill, not fetched
    },
  ]
}

Fields:

Field Required Description
name Always Unique skill identifier
repo For remote skills Git repository URL
path No Subdirectory containing the skill
ref No Tag, branch, or commit (defaults to repo default branch)
local For local skills Path to local skill directory (mutually exclusive with repo)

Lock File

skv.lock is a machine-managed JSON file that ensures deterministic installs. It captures:

Why checksums matter:

Checksums use SHA-256 over a deterministic directory hash (sorted file paths + file mode + file contents). This provides:

Tags are expected to be stable. If a tag resolves to a different commit, skv update warns and aborts unless you re-run with --force.


CI Integration

Add skv verify to your CI pipeline to ensure vendored skills match the lock file:

# .github/workflows/ci.yml
name: CI
on: [push, pull_request]

jobs:
  verify-skills:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install skv
        run: |
          curl -sL https://github.com/skill-vendor/skv/releases/latest/download/skv-linux-amd64 -o skv
          chmod +x skv
          sudo mv skv /usr/local/bin/

      - name: Verify skills
        run: skv verify

For ARM64 runners, use skv-linux-arm64 instead.

If vendored content doesn’t match the lock, skv verify exits non-zero with details about the mismatch.


Troubleshooting

Missing SKILL.md

error: skill directory must contain SKILL.md at its root

Every skill directory must have a SKILL.md file. If adding a single-skill repo, ensure SKILL.md is at the repo root. For monorepos, specify the path to the skill directory.

Lock mismatch

error: vendored content does not match lock

The vendored files have changed since the lock was written. Options:

Network unavailable

error: fetch required but running in offline mode

skv sync --offline can only verify and link already-vendored skills. If a skill hasn’t been fetched yet, you’ll need network access.


Installation

Homebrew (macOS and Linux):

brew install skill-vendor/tap/skv

Go:

go install github.com/skill-vendor/skv/cmd/skv@latest

Binary:

Download from GitHub Releases:

curl -sL https://github.com/skill-vendor/skv/releases/latest/download/skv-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m) -o skv
chmod +x skv
sudo mv skv /usr/local/bin/


Built with Jekyll and hosted on GitHub Pages