skills

package module
v0.0.0-...-56d1a36 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 31, 2026 License: MIT Imports: 16 Imported by: 0

README

skills-go

Go library and CLI for managing agent skills — reusable instruction sets that extend AI coding agent capabilities.

Format-compatible with vercel-labs/skills (npx skills). Designed to be embedded into your own tooling for managing private skill repositories.

Use cases

  • Embed skill install/discovery into your own CLI or internal platform
  • Manage private skill registries (GitHub, GitLab, local, or custom backends like S3, Google Drive, Confluence, etc.)
  • Automate skill deployment across teams and agents

Install

As a library
go get github.com/ka2n/skills-go
As a CLI
go install github.com/ka2n/skills-go/cmd/skills@latest

Library usage

High-level API (sk package)

The sk package provides one-step workflows with built-in providers. When opts is nil, DefaultProviders (git fetcher, GitHub hash provider, well-known endpoint support) is used automatically.

import (
    skills "github.com/ka2n/skills-go"
    "github.com/ka2n/skills-go/sk"
)

// Install from GitHub
results, _ := sk.Install(ctx,
    skills.SourceFrom("vercel-labs/agent-skills"),
    []skills.AgentType{skills.AgentClaudeCode},
    nil,
)

// Install from a local directory
results, _ = sk.Install(ctx,
    skills.SourceFromLocal("./my-skills"),
    []skills.AgentType{skills.AgentClaudeCode},
    nil,
)

// Install from an embedded filesystem
//go:embed skills
var skillsFS embed.FS

results, _ = sk.Install(ctx,
    skills.SourceFromFS(skillsFS),
    []skills.AgentType{skills.AgentClaudeCode},
    nil,
)

// Install and update project lock file
results, _ = sk.Install(ctx,
    skills.SourceFrom("owner/repo"),
    []skills.AgentType{skills.AgentClaudeCode},
    nil,
)
lock, _ := sk.ProjectLock(".")
lock.ApplyResults(results)
sk.WriteProjectLock(lock, ".")

// Restore from skills-lock.json (like npm install)
lock, _ := sk.ProjectLock(".")
sk.RestoreFromProjectLock(ctx, lock, agents, nil)

// Check for updates and apply them
globalLock, _ := sk.GlobalLock()
updates, _ := sk.CheckUpdates(ctx, globalLock, nil)
if len(updates) > 0 {
    sk.UpdateGlobal(ctx, globalLock, agents, nil)
    sk.WriteGlobalLock(globalLock)
}
Low-level API (skills package)

The skills package provides composable primitives for custom workflows (e.g. custom storage backends for lock files, non-standard directory layouts).

import (
    skills "github.com/ka2n/skills-go"
    "github.com/ka2n/skills-go/provider/git"
)

// 1. Parse source — "owner/repo" is resolved to a GitHub git URL
source, _ := skills.ParseSource("your-org/private-skills")

// 2. Clone — Fetcher downloads the repo to a temp directory
fetcher := &git.Fetcher{}
dir, cleanup, _ := fetcher.Fetch(ctx, source)
defer cleanup()

// 3. Discover — find all SKILL.md files in the cloned repo
found, _ := skills.Discover(dir, "", nil)

// 4. Install — copy/symlink into the agent's skills directory
home, _ := os.UserHomeDir()
dest := &skills.DestOptions{
    Cwd:     ".",
    HomeDir: home,
    Agents:  skills.DefaultAgents(home),
}
for _, s := range found {
    result := skills.Install(s, skills.AgentClaudeCode, nil, dest)
    fmt.Println(result.Path)
}

// 5. Update lock — write to any io.Writer
lock, _ := skills.ReadGlobalLockFile(skills.GlobalLockPath(home))
lock.ApplyResults(results)
lock.WriteTo(myCustomWriter) // S3, database, etc.
Custom providers
opts := &sk.InstallOptions{
    Providers: &skills.Providers{
        Fetcher:      skills.MultiFetcher(&azdo.Fetcher{}, &wellknown.Fetcher{}, &git.Fetcher{}),
        HashProvider: skills.MultiHashProvider(&azdo.HashProvider{}, &github.HashProvider{}),
        SourceParser: func(input string) (skills.ParsedSource, bool, error) {
            if strings.HasPrefix(input, "azdo:") {
                return skills.ParsedSource{
                    Type: "azdo",
                    URL:  "https://dev.azure.com/...",
                }, true, nil
            }
            return skills.ParsedSource{}, false, nil
        },
    },
}
results, _ := sk.Install(ctx, skills.SourceFrom("azdo:my-project/repo"), agents, opts)

Example CLI usage

skills add owner/repo                     # GitHub shorthand
skills add owner/repo@skill-name          # specific skill
skills add https://github.com/owner/repo  # full URL
skills add ./local/path                   # local directory
skills add https://example.com            # well-known endpoint

skills install                            # restore from skills-lock.json
skills install owner/repo                 # same as add

skills list                               # list project skills
skills list -g                            # list global skills
skills list --json                        # JSON output

skills remove skill-name                  # remove by name

skills init my-skill                      # create SKILL.md template

skills check                              # check project skills for updates
skills check -g                           # check global skills for updates
skills update                             # update project skills
skills update -g                          # update global skills
Add options
-g, --global         Install globally (~/) instead of project-level
-a, --agent <name>   Target specific agents (use '*' for all)
-s, --skill <name>   Install specific skills (use '*' for all)
-y, --yes            Skip confirmation prompts
--copy               Copy files instead of symlinking
--all                Shorthand for --skill '*' --agent '*' -y
--full-depth         Search all subdirectories

Source formats

Format Example
GitHub shorthand owner/repo
GitHub with skill owner/repo@skill-name
GitHub with subpath owner/repo/path/to/skills
GitHub URL https://github.com/owner/repo
GitHub tree URL https://github.com/owner/repo/tree/main/skills/x
GitLab URL https://gitlab.com/group/repo
GitLab shorthand gitlab:group/repo
Local path ./path or /absolute/path
Well-known endpoint https://example.com (RFC 8615)
Git URL git@github.com:owner/repo.git

SKILL.md format

---
name: my-skill
description: Brief description of what this skill does
---

# My Skill

Instructions for the agent.

Fully compatible with the vercel-labs/skills format.

Directory structure

Skills are installed using the same layout as npx skills:

project/
├── .agents/skills/my-skill/SKILL.md   # canonical copy
├── .claude/skills/my-skill            # symlink → ../../.agents/skills/my-skill
├── .cursor/skills/my-skill            # symlink (if selected)
└── skills-lock.json                   # project lock (version 1)

Global installs go to ~/.agents/skills/ with a lock at ~/.agents/.skill-lock.json (version 3).

Supported agents

Agent Project Dir Universal
AdaL .adal/skills
Amp .agents/skills yes
Antigravity .agents/skills yes
Augment .augment/skills
Claude Code .claude/skills
Cline .agents/skills yes
CodeBuddy .codebuddy/skills
Codex .agents/skills yes
Command Code .commandcode/skills
Continue .continue/skills
Cortex Code .cortex/skills
Crush .crush/skills
Cursor .agents/skills yes
Deep Agents .agents/skills yes
Droid .factory/skills
Firebender .agents/skills yes
Gemini CLI .agents/skills yes
GitHub Copilot .agents/skills yes
Goose .goose/skills
Junie .junie/skills
Kilo Code .kilocode/skills
Kimi Code CLI .agents/skills yes
Kiro CLI .kiro/skills
Kode .kode/skills
MCPJam .mcpjam/skills
Mistral Vibe .vibe/skills
Mux .mux/skills
Neovate .neovate/skills
OpenClaw skills
OpenCode .agents/skills yes
OpenHands .openhands/skills
Pi .pi/skills
Pochi .pochi/skills
Qoder .qoder/skills
Qwen Code .qwen/skills
Roo Code .roo/skills
Trae .trae/skills
Trae CN .trae/skills
Warp .agents/skills yes
Windsurf .windsurf/skills
Zencoder .zencoder/skills
iFlow CLI .iflow/skills

Agents marked "Universal" share the .agents/skills/ directory; others get symlinks from their own directory.

Architecture

github.com/ka2n/skills-go
├── skill.go           # SKILL.md parsing, Skill type
├── source.go          # Source type + source string parsing
├── agent.go           # Agent definitions (45+ agents)
├── discover.go        # Skill discovery (priority dirs + recursive)
├── installer.go       # Install (symlink/copy), list, uninstall
├── hash.go            # Folder/content hashing (SHA-256)
├── lock.go            # Lock file read/write + ApplyResults
├── provider.go        # Fetcher/HashProvider/Providers + Multi* combinators
├── plugin.go          # .claude-plugin manifest support
├── init.go            # SKILL.md template generation
├── sk/                # High-level orchestration (Install, Update, Restore, Reconcile)
├── provider/
│   ├── git/           # Fetcher — git clone (exec)
│   ├── go-git/        # Fetcher — go-git v6 (pure Go, no git CLI)
│   ├── github/        # HashProvider — GitHub Trees API + token resolution
│   ├── local/         # Fetcher — local path + folder hashing
│   └── wellknown/     # Fetcher — RFC 8615 well-known endpoint
└── cmd/
    └── skills/        # CLI
Provider abstraction

Git is not a hard dependency. Core interfaces allow any backend:

type Providers struct {
    Fetcher      Fetcher        // retrieves skills from remote sources
    HashProvider HashProvider   // checks remote hashes for update detection
    SourceParser SourceParser   // custom source format parser
}

// Combine multiple implementations with Multi* constructors:
// skills.MultiFetcher(&wellknown.Fetcher{}, &git.Fetcher{})
// skills.MultiHashProvider(hp1, hp2)
// skills.MultiSourceParser(parser1, parser2)

type Fetcher interface {
    Fetch(ctx context.Context, source ParsedSource) (localDir string, cleanup func(), err error)
}

type HashProvider interface {
    FetchFolderHash(ctx context.Context, ownerRepo, skillPath string) (string, error)
}

type SourceParser func(input string) (ParsedSource, bool, error)

Built-in providers:

Package Interface Description Requires
provider/git Fetcher git clone via exec git CLI
provider/go-git Fetcher Pure Go clone (go-git v6) nothing
provider/local Fetcher Local filesystem path nothing
provider/github HashProvider GitHub Trees API (update check) nothing
provider/wellknown Fetcher RFC 8615 well-known endpoint nothing

Lock file format

Fully compatible with npx skills.

Project (skills-lock.json):

{
  "version": 1,
  "skills": {
    "skill-name": {
      "source": "owner/repo",
      "sourceType": "github",
      "computedHash": "sha256..."
    }
  }
}

Global (~/.agents/.skill-lock.json):

{
  "version": 3,
  "skills": {
    "skill-name": {
      "source": "owner/repo",
      "sourceType": "github",
      "sourceUrl": "https://github.com/owner/repo.git",
      "skillPath": "skills/skill-name/SKILL.md",
      "skillFolderHash": "gitTreeSHA",
      "installedAt": "2024-01-15T10:30:00Z",
      "updatedAt": "2024-01-15T10:30:00Z"
    }
  }
}

Compatibility

Cross-validated against npx skills — identical SKILL.md content, file trees, and lockfile structure. See crossval_test.go.

License

MIT

Documentation

Overview

Package skills provides a library for managing agent skills - reusable instruction sets that extend AI coding agent capabilities.

Skills are defined as SKILL.md files with YAML frontmatter containing name and description fields. They can be installed from various sources (GitHub, GitLab, well-known endpoints, local paths, or custom providers) into multiple agent directories.

Index

Constants

View Source
const (
	AgentsDir          = ".agents"
	SkillsSubdir       = "skills"
	UniversalSkillsDir = ".agents/skills"
)
View Source
const GlobalLockVersion = 3

GlobalLockVersion is the current version of the global lock file format.

View Source
const ProjectLockVersion = 1

ProjectLockVersion is the current version of the project lock file format.

Variables

This section is empty.

Functions

func ComputeContentHash

func ComputeContentHash(content string) string

ComputeContentHash computes a SHA-256 hash of a string.

func ComputeFolderHash

func ComputeFolderHash(dir string) (string, error)

ComputeFolderHash computes a SHA-256 hash from all files in a directory. Files are sorted by relative path for deterministic output. Directories named .git and node_modules are skipped.

func ComputeFolderHashFS

func ComputeFolderHashFS(fsys fs.FS, dir string) (string, error)

ComputeFolderHashFS computes a SHA-256 hash from all files in a directory within an fs.FS. Files are sorted by relative path for deterministic output. Directories named .git and node_modules are skipped.

func DefaultAgents

func DefaultAgents(homeDir string) map[AgentType]AgentConfig

DefaultAgents returns all known agent configurations. homeDir is the user's home directory (e.g. from os.UserHomeDir()).

func GetPluginGroupings

func GetPluginGroupings(basePath string) map[string]string

GetPluginGroupings returns a map of absolute skill directory path to plugin name.

func GlobalLockPath

func GlobalLockPath(homeDir string) string

GlobalLockPath returns the default path for the global lock file. It checks XDG_STATE_HOME first, then falls back to ~/.agents/.skill-lock.json. homeDir is the user's home directory.

func ProjectLockPath

func ProjectLockPath(projectDir string) string

ProjectLockPath returns the path for the project lock file in the given directory.

func ResolveInstallPath

func ResolveInstallPath(skillName string, agentType AgentType, dest *DestOptions) (string, error)

ResolveInstallPath returns the directory where a skill would be installed for the given agent type and options, without actually installing anything.

func SanitizeName

func SanitizeName(name string) string

SanitizeName sanitizes a skill name for use as a directory name.

func Uninstall

func Uninstall(skillName string, agentTypes []AgentType, dest *DestOptions) error

Remove removes a skill from all specified agents.

Types

type AgentConfig

type AgentConfig struct {
	Name                string
	DisplayName         string
	SkillsDir           string // relative to project root
	GlobalSkillsDir     string // absolute path, empty if global not supported
	ShowInUniversalList bool
	DetectInstalled     func() bool
}

AgentConfig describes where an agent stores skills.

type AgentType

type AgentType = string

AgentType is a string identifier for a supported agent.

const (
	AgentAmp           AgentType = "amp"
	AgentAntigravity   AgentType = "antigravity"
	AgentAugment       AgentType = "augment"
	AgentClaudeCode    AgentType = "claude-code"
	AgentOpenClaw      AgentType = "openclaw"
	AgentCline         AgentType = "cline"
	AgentCodeBuddy     AgentType = "codebuddy"
	AgentCodex         AgentType = "codex"
	AgentCommandCode   AgentType = "command-code"
	AgentContinue      AgentType = "continue"
	AgentCortex        AgentType = "cortex"
	AgentCrush         AgentType = "crush"
	AgentCursor        AgentType = "cursor"
	AgentDeepAgents    AgentType = "deepagents"
	AgentDroid         AgentType = "droid"
	AgentFirebender    AgentType = "firebender"
	AgentGeminiCLI     AgentType = "gemini-cli"
	AgentGitHubCopilot AgentType = "github-copilot"
	AgentGoose         AgentType = "goose"
	AgentJunie         AgentType = "junie"
	AgentIFlowCLI      AgentType = "iflow-cli"
	AgentKilo          AgentType = "kilo"
	AgentKimiCLI       AgentType = "kimi-cli"
	AgentKiroCLI       AgentType = "kiro-cli"
	AgentKode          AgentType = "kode"
	AgentMCPJam        AgentType = "mcpjam"
	AgentMistralVibe   AgentType = "mistral-vibe"
	AgentMux           AgentType = "mux"
	AgentNeovate       AgentType = "neovate"
	AgentOpenCode      AgentType = "opencode"
	AgentOpenHands     AgentType = "openhands"
	AgentPi            AgentType = "pi"
	AgentQoder         AgentType = "qoder"
	AgentQwenCode      AgentType = "qwen-code"
	AgentReplit        AgentType = "replit"
	AgentRoo           AgentType = "roo"
	AgentTrae          AgentType = "trae"
	AgentTraeCN        AgentType = "trae-cn"
	AgentWarp          AgentType = "warp"
	AgentWindsurf      AgentType = "windsurf"
	AgentZencoder      AgentType = "zencoder"
	AgentPochi         AgentType = "pochi"
	AgentAdal          AgentType = "adal"
	AgentUniversal     AgentType = "universal"
)

Known agent types.

func DetectInstalledAgents

func DetectInstalledAgents(agents map[AgentType]AgentConfig) []AgentType

DetectInstalledAgents returns agent types that appear to be installed.

func NonUniversalAgents

func NonUniversalAgents(agents map[AgentType]AgentConfig) []AgentType

NonUniversalAgents returns agent types that use agent-specific directories.

func UniversalAgents

func UniversalAgents(agents map[AgentType]AgentConfig) []AgentType

UniversalAgents returns agent types that use the universal .agents/skills directory.

type DestOptions

type DestOptions struct {
	Global  bool
	Cwd     string
	HomeDir string
	Mode    InstallMode
	Agents  map[AgentType]AgentConfig
	// Scope controls which scopes ListInstalled searches.
	// Default (ScopeAll) returns project+global when Global=false, global-only when Global=true.
	Scope ListScope
}

DestOptions configures where and how skills are installed.

type DiscoverOptions

type DiscoverOptions struct {
	IncludeInternal bool
	FullDepth       bool
	// Agents is used to derive priority search directories from AgentConfig.SkillsDir.
	// If nil, DefaultAgents with the current user's home directory is used.
	Agents map[AgentType]AgentConfig
	// OnParseError is called when a SKILL.md file cannot be parsed.
	// If nil, parse errors are silently ignored (legacy behavior).
	OnParseError func(path string, err error)
	// OnDuplicate is called when a skill with the same name is found in multiple directories.
	// path1 is the path of the first occurrence, path2 is the duplicate being skipped.
	// If nil, duplicates are silently ignored (legacy behavior).
	OnDuplicate func(name, path1, path2 string)
}

DiscoverOptions controls skill discovery behavior.

type Fetcher

type Fetcher interface {
	// Fetch retrieves skills from the given parsed source into a local directory.
	// It returns the path to the local directory containing the fetched content.
	// The caller is responsible for calling Cleanup when done.
	Fetch(ctx context.Context, source ParsedSource) (localDir string, cleanup func(), err error)
}

Fetcher is the core abstraction for fetching skills from a source. This replaces the direct git dependency, allowing any storage backend.

func MultiFetcher

func MultiFetcher(fetchers ...Fetcher) Fetcher

MultiFetcher combines multiple Fetchers. Each is tried in order; the first that succeeds is used.

type GlobalLock

type GlobalLock struct {
	Version            int                        `json:"version"`
	Skills             map[string]GlobalLockEntry `json:"skills"`
	Dismissed          map[string]bool            `json:"dismissed,omitempty"`
	LastSelectedAgents []string                   `json:"lastSelectedAgents,omitempty"`
}

GlobalLock represents the global skill lock file (~/.agents/.skill-lock.json).

func NewGlobalLock

func NewGlobalLock() *GlobalLock

NewGlobalLock creates a new empty global lock.

func ReadGlobalLock

func ReadGlobalLock(r io.Reader) (*GlobalLock, error)

ReadGlobalLock decodes a global lock from an io.Reader.

func ReadGlobalLockFile

func ReadGlobalLockFile(path string) (*GlobalLock, error)

ReadGlobalLockFile reads the global lock file from the given path.

func (*GlobalLock) ApplyResults

func (l *GlobalLock) ApplyResults(results []InstallResult)

ApplyResults applies successful install results to the global lock. It does not write to disk; the caller is responsible for persistence.

func (*GlobalLock) RemoveSkill

func (l *GlobalLock) RemoveSkill(name string)

RemoveSkill removes a skill entry from the global lock.

func (*GlobalLock) SetSkill

func (l *GlobalLock) SetSkill(name string, entry GlobalLockEntry)

SetSkill adds or updates a skill entry in the global lock.

func (*GlobalLock) WriteFile

func (l *GlobalLock) WriteFile(path string) error

WriteFile writes the global lock file to the given path.

func (*GlobalLock) WriteTo

func (l *GlobalLock) WriteTo(w io.Writer) (int64, error)

WriteTo writes the global lock as JSON to an io.Writer.

type GlobalLockEntry

type GlobalLockEntry struct {
	Source          string `json:"source"`
	SourceType      string `json:"sourceType"`
	SourceURL       string `json:"sourceUrl"`
	SkillPath       string `json:"skillPath"`
	SkillFolderHash string `json:"skillFolderHash,omitempty"`
	InstalledAt     string `json:"installedAt"`
	UpdatedAt       string `json:"updatedAt"`
	PluginName      string `json:"pluginName,omitempty"`
}

GlobalLockEntry represents a single skill entry in the global lock file.

type HashProvider

type HashProvider interface {
	// FetchFolderHash returns the hash for a skill folder in a remote source.
	// ownerRepo is "owner/repo", skillPath is the path within the repo.
	FetchFolderHash(ctx context.Context, ownerRepo string, skillPath string) (string, error)
}

HashProvider abstracts how skill folder hashes are obtained for update checking.

func MultiHashProvider

func MultiHashProvider(providers ...HashProvider) HashProvider

MultiHashProvider combines multiple HashProviders. Each is tried in order; the first that succeeds is used.

type InstallMode

type InstallMode string

InstallMode determines how skills are installed.

const (
	InstallSymlink InstallMode = "symlink"
	InstallCopy    InstallMode = "copy"
)

type InstallResult

type InstallResult struct {
	Success       bool
	Path          string
	CanonicalPath string
	Mode          InstallMode
	SymlinkFailed bool
	Error         string
	// SkillName is the name of the skill that was installed.
	SkillName string
	// Err is the structured error (nil on success). Use this for errors.Is/As.
	Err error
	// SkippedFiles lists files that were skipped during remote install (e.g. unsafe paths).
	SkippedFiles []string
	// GlobalLockEntry is populated when a global install succeeds, for lock file updates.
	GlobalLockEntry *GlobalLockEntry
	// ProjectLockEntry is populated when a project install succeeds, for lock file updates.
	ProjectLockEntry *ProjectLockEntry
}

InstallResult describes the outcome of an install operation.

func Install

func Install(skill *Skill, agentType AgentType, src *SourceRef, dest *DestOptions) InstallResult

Install installs a skill for a single agent. If skill.Files is set, the in-memory file contents are written to disk. Otherwise, the skill directory at skill.Path is copied (or symlinked).

type InstalledSkill

type InstalledSkill struct {
	Name          string      `json:"name"`
	Description   string      `json:"description"`
	Path          string      `json:"path"`
	CanonicalPath string      `json:"canonicalPath"`
	Scope         string      `json:"scope"`
	Agents        []AgentType `json:"agents"`
	// DirName is the actual directory name on disk. If it differs from
	// SanitizeName(Name), the install path has diverged from the frontmatter name.
	DirName string `json:"dirName,omitempty"`
}

InstalledSkill represents a skill installed on disk.

func ListInstalled

func ListInstalled(dest *DestOptions) ([]*InstalledSkill, error)

ListInstalled lists all installed skills from canonical and agent directories. The scope can be controlled via dest.Scope (ScopeAll by default, which returns both project and global when dest.Global is false, or global-only when dest.Global is true). For explicit control, set dest.Scope to ScopeProject, ScopeGlobal, or ScopeAll.

func (*InstalledSkill) AddAgent

func (is *InstalledSkill) AddAgent(t AgentType)

AddAgent adds an agent to the installed skill if not already present.

func (*InstalledSkill) NameDiverged

func (is *InstalledSkill) NameDiverged() bool

NameDiverged returns true if the on-disk directory name differs from what SanitizeName would produce for the skill's frontmatter name.

type ListScope

type ListScope int

ListScope controls which scopes ListInstalled returns.

const (
	// ScopeAll returns both project and global skills (default for backward compat).
	ScopeAll ListScope = iota
	// ScopeProject returns only project-scoped skills.
	ScopeProject
	// ScopeGlobal returns only globally-installed skills.
	ScopeGlobal
)

type ParsedSource

type ParsedSource struct {
	Type        SourceType
	URL         string // For local sources, this is the absolute path.
	Subpath     string
	Ref         string
	SkillFilter string
}

ParsedSource is the result of parsing a source string.

func ParseSource

func ParseSource(input string) (ParsedSource, error)

ParseSource parses a source string into a structured format. Supports: local paths, GitHub URLs/shorthand, GitLab URLs, well-known URLs, git URLs.

func ParseSourceWith

func ParseSourceWith(input string, parser SourceParser) (ParsedSource, error)

ParseSourceWith parses a source string, trying a custom parser first. If parser is non-nil and recognizes the input, its result is returned. Otherwise the built-in logic is used.

func (ParsedSource) OwnerRepo

func (ps ParsedSource) OwnerRepo() string

OwnerRepo extracts owner/repo from the parsed source for lockfile tracking.

type PathTraversalError

type PathTraversalError struct {
	Subpath string
}

PathTraversalError is returned when a subpath attempts to escape the base directory.

func (*PathTraversalError) Error

func (e *PathTraversalError) Error() string

type ProjectLock

type ProjectLock struct {
	Version int                         `json:"version"`
	Skills  map[string]ProjectLockEntry `json:"skills"`
}

ProjectLock represents the project-scoped lock file (skills-lock.json).

func NewProjectLock

func NewProjectLock() *ProjectLock

NewProjectLock creates a new empty project lock.

func ReadProjectLock

func ReadProjectLock(r io.Reader) (*ProjectLock, error)

ReadProjectLock decodes a project lock from an io.Reader.

func ReadProjectLockFile

func ReadProjectLockFile(path string) (*ProjectLock, error)

ReadProjectLockFile reads the project lock file from the given path.

func (*ProjectLock) ApplyResults

func (l *ProjectLock) ApplyResults(results []InstallResult)

ApplyResults applies successful install results to the project lock. It does not write to disk; the caller is responsible for persistence.

func (*ProjectLock) RemoveSkill

func (l *ProjectLock) RemoveSkill(name string)

RemoveSkill removes a skill entry from the project lock.

func (*ProjectLock) SetSkill

func (l *ProjectLock) SetSkill(name string, entry ProjectLockEntry)

SetSkill adds or updates a skill entry in the project lock.

func (*ProjectLock) WriteFile

func (l *ProjectLock) WriteFile(path string) error

WriteFile writes the project lock file to the given path.

func (*ProjectLock) WriteTo

func (l *ProjectLock) WriteTo(w io.Writer) (int64, error)

WriteTo writes the project lock as JSON to an io.Writer.

type ProjectLockEntry

type ProjectLockEntry struct {
	Source       string `json:"source"`
	SourceType   string `json:"sourceType"`
	ComputedHash string `json:"computedHash,omitempty"`
}

ProjectLockEntry represents a single skill entry in the project lock file.

type Providers

type Providers struct {
	// Fetcher retrieves skills from remote sources (git, well-known endpoints, etc.).
	// Use [MultiFetcher] to combine multiple fetchers.
	Fetcher Fetcher
	// HashProvider checks remote hashes for update detection.
	HashProvider HashProvider
	// SourceParser parses source strings into ParsedSource.
	// Tried before the built-in logic.
	SourceParser SourceParser
}

Providers bundles the provider interfaces needed by high-level APIs. All fields are optional; nil fields cause the corresponding functionality to be skipped or use defaults.

To combine multiple implementations, use MultiFetcher, MultiHashProvider, and MultiSourceParser.

type Skill

type Skill struct {
	// Name is the unique identifier for the skill (lowercase, hyphens allowed, 1-64 chars).
	Name string `yaml:"name" json:"name"`
	// Description is a brief explanation of the skill's functionality.
	Description string `yaml:"description" json:"description"`
	// Metadata contains optional fields.
	Metadata SkillMetadata `yaml:"metadata,omitempty" json:"metadata,omitempty"`
	// RawFrontmatter preserves all frontmatter fields (including unknown ones like
	// allowed-tools, disable-model-invocation) for round-trip fidelity in Marshal().
	RawFrontmatter map[string]any `yaml:"-" json:"-"`
	// Body is the markdown content after the frontmatter.
	Body string `yaml:"-" json:"-"`
	// RawContent is the original SKILL.md content for hashing.
	RawContent string `yaml:"-" json:"-"`
	// Path is the directory containing the SKILL.md file (absolute on disk, or FS-relative).
	// When Files is set, Path may be empty.
	Path string `yaml:"-" json:"path,omitempty"`
	// Files holds in-memory file contents for skills fetched from remote providers.
	// When non-nil, Install writes these to disk instead of copying from Path.
	// Keys are relative file paths (e.g. "SKILL.md", "helper.sh").
	Files map[string]string `yaml:"-" json:"files,omitempty"`
	// PluginName is the name of the plugin this skill belongs to (if any).
	PluginName string `yaml:"-" json:"pluginName,omitempty"`
	// SourceURL is the URL of the source (set by remote providers).
	SourceURL string `yaml:"-" json:"sourceUrl,omitempty"`
	// ProviderID identifies which provider fetched this skill.
	ProviderID string `yaml:"-" json:"providerId,omitempty"`
	// SourceIdentifier is a provider-specific identifier for the source.
	SourceIdentifier string `yaml:"-" json:"sourceIdentifier,omitempty"`
}

Skill represents a parsed SKILL.md file.

func Discover

func Discover(basePath string, subpath string, opts *DiscoverOptions) ([]*Skill, error)

Discover finds all SKILL.md files in the given directory.

func DiscoverFS

func DiscoverFS(fsys fs.FS, subpath string, opts *DiscoverOptions) ([]*Skill, error)

DiscoverFS finds all SKILL.md files in the given fs.FS. Paths within the FS use forward slashes (path.Join). Skill.Path is set to the FS-relative path (e.g. "skills/my-skill").

func Filter

func Filter(skills []*Skill, names []string) []*Skill

Filter filters skills by name (case-insensitive).

func ParseSkill

func ParseSkill(r io.Reader) (*Skill, error)

ParseSkill parses a SKILL.md file from a reader.

func ParseSkillBytes

func ParseSkillBytes(data []byte) (*Skill, error)

ParseSkillBytes parses a SKILL.md file from bytes.

func ParseSkillFile

func ParseSkillFile(path string) (*Skill, error)

ParseSkillFile parses a SKILL.md file from the filesystem.

func (*Skill) Marshal

func (s *Skill) Marshal() ([]byte, error)

Marshal serializes a Skill back to SKILL.md format (YAML frontmatter + markdown body). Unknown frontmatter fields from the original parse are preserved.

type SkillMetadata

type SkillMetadata struct {
	Internal bool `yaml:"internal,omitempty" json:"internal,omitempty"`
}

SkillMetadata contains optional metadata fields for a skill.

type Source

type Source struct {
	// contains filtered or unexported fields
}

Source describes where to obtain skills for installation. Create instances using SourceFrom, SourceFromFS, or SourceFromLocal.

func SourceFrom

func SourceFrom(s string) Source

SourceFrom creates a Source from a string that will be parsed automatically. Supports GitHub shorthand ("owner/repo"), Git URLs, well-known endpoints, and local paths. The string may include subpath and skill filter (e.g. "owner/repo/path/to/skills@skill-name").

func SourceFromFS

func SourceFromFS(fsys fs.FS) Source

SourceFromFS creates a Source backed by an fs.FS (e.g. embed.FS).

func SourceFromLocal

func SourceFromLocal(path string) Source

SourceFromLocal creates a Source from a local directory path. Unlike SourceFrom, this always treats the path as local without running it through source parsing.

func (Source) FS

func (s Source) FS() fs.FS

FS returns the fs.FS for FS-backed sources, or nil.

func (Source) IsFS

func (s Source) IsFS() bool

IsFS reports whether this source is backed by an fs.FS.

func (Source) Raw

func (s Source) Raw() string

Raw returns the raw source string.

type SourceParser

type SourceParser func(input string) (ParsedSource, bool, error)

SourceParser is a function that attempts to parse a source string. It returns a ParsedSource and true if the input was recognized, or false if not. Custom parsers are tried before the built-in logic, allowing extension for formats like Azure DevOps, Bitbucket shorthand, etc.

func MultiSourceParser

func MultiSourceParser(parsers ...SourceParser) SourceParser

MultiSourceParser combines multiple SourceParsers. Each is tried in order; the first that recognizes the input wins.

type SourceRef

type SourceRef struct {
	// FS is the source filesystem for reading skill files.
	// When set, skill.Path is treated as an FS-relative path and files are read
	// from FS instead of the OS filesystem. Writing still goes to the OS.
	// If nil, skill.Path is treated as an OS absolute path (backward compat).
	FS fs.FS
	// Parsed is the parsed source used for this install, used to populate lock entries in InstallResult.
	Parsed *ParsedSource
	// FetchRoot is the root directory of the fetched source (e.g. the clone directory).
	// Used to compute repo-relative skill paths for lock entries.
	FetchRoot string
}

SourceRef describes where a skill comes from.

type SourceType

type SourceType string

SourceType identifies how a source was parsed.

const (
	SourceGitHub    SourceType = "github"
	SourceGitLab    SourceType = "gitlab"
	SourceGit       SourceType = "git"
	SourceLocal     SourceType = "local"
	SourceWellKnown SourceType = "well-known"
)

Directories

Path Synopsis
cmd
skills command
internal
cmd/docgen command
Command docgen regenerates marker sections in README.md from Go source.
Command docgen regenerates marker sections in README.md from Go source.
provider
git
Package git implements skills.Fetcher using the git command-line tool.
Package git implements skills.Fetcher using the git command-line tool.
github
Package github implements skills.HashProvider using the GitHub Trees API.
Package github implements skills.HashProvider using the GitHub Trees API.
go-git
Package gogit implements skills.Fetcher using go-git v6 (pure Go git implementation).
Package gogit implements skills.Fetcher using go-git v6 (pure Go git implementation).
local
Package local implements skills.Fetcher for local filesystem paths and provides local disk hashing for skill folders.
Package local implements skills.Fetcher for local filesystem paths and provides local disk hashing for skill folders.
wellknown
Package wellknown implements skills.Fetcher for RFC 8615 well-known endpoints.
Package wellknown implements skills.Fetcher for RFC 8615 well-known endpoints.
Package sk provides high-level orchestration functions for skill management.
Package sk provides high-level orchestration functions for skill management.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL