diff --git a/docs/arch/02-core-concepts.md b/docs/arch/02-core-concepts.md index 4e6a53f91b..e3fbce4885 100644 --- a/docs/arch/02-core-concepts.md +++ b/docs/arch/02-core-concepts.md @@ -430,6 +430,35 @@ ToolHive can automatically configure clients to use MCP servers: **Related concepts:** Workload, Group +### Skill + +A **skill** is an Agent Skill -- a markdown-based instruction set (SKILL.md) that extends an AI coding assistant's capabilities. Skills are not MCP servers; they provide knowledge and conventions rather than callable tools. + +**Key characteristics:** +- Defined by a `SKILL.md` file with YAML frontmatter +- Distributed as OCI artifacts (tar.gz layers) +- Can also be installed directly from git repositories +- Scoped to user (global) or project (local) +- Support multi-client installation (Claude Code, Cursor, etc.) + +**Lifecycle:** +1. **Discover** - Browse skills from registry catalog +2. **Build** - Package local SKILL.md into OCI artifact +3. **Publish** - Push OCI artifact to remote registry +4. **Install** - Pull from registry/git and extract to client skill directory +5. **Uninstall** - Remove files and metadata + +**Implementation:** +- Service: `pkg/skills/skillsvc/skillsvc.go` +- Types: `pkg/skills/types.go` +- Storage: `pkg/storage/sqlite/skill_store.go` +- CLI: `cmd/thv/app/skill*.go` +- API: `pkg/api/v1/skills.go` + +**For architecture details**, see [Skills System](12-skills-system.md). + +**Related concepts:** Registry, Group, Client + ## Verbs (Actions) ### Deploy @@ -769,6 +798,7 @@ Registry | **Session** | State tracking for MCP connections | | **Runtime** | Abstraction over container systems | | **Client** | Application that uses MCP servers | +| **Skill** | Agent Skill (SKILL.md) extending AI assistant capabilities | | **Deploy** | Create and start a workload | | **Proxy** (verb) | Forward traffic with middleware | | **Attach** | Connect to container stdin/stdout | diff --git a/docs/arch/06-registry-system.md b/docs/arch/06-registry-system.md index a7ddfdfdfa..4ec1d836db 100644 --- a/docs/arch/06-registry-system.md +++ b/docs/arch/06-registry-system.md @@ -987,6 +987,7 @@ kubectl get configmap company-registry-storage -o jsonpath='{.data.registry\.jso - [Deployment Modes](01-deployment-modes.md) - Registry usage per mode - [Groups](07-groups.md) - Groups in registry - [Operator Architecture](09-operator-architecture.md) - MCPRegistry CRD +- [Skills System](12-skills-system.md) - Skills discovery and distribution via registry ### External Documentation - [ToolHive User Documentation](https://docs.stacklok.com/toolhive/) - User-facing guides diff --git a/docs/arch/07-groups.md b/docs/arch/07-groups.md index 162e51937d..5c2e9c768e 100644 --- a/docs/arch/07-groups.md +++ b/docs/arch/07-groups.md @@ -140,3 +140,4 @@ Groups may serve as the foundation for additional features: - [Registry System](06-registry-system.md) - Groups in registry - [Workloads Lifecycle](08-workloads-lifecycle.md) - Group operations - [Virtual MCP Server Architecture](10-virtual-mcp-architecture.md) - Group-based aggregation +- [Skills System](12-skills-system.md) - Skills organized in groups diff --git a/docs/arch/12-skills-system.md b/docs/arch/12-skills-system.md new file mode 100644 index 0000000000..deb606717e --- /dev/null +++ b/docs/arch/12-skills-system.md @@ -0,0 +1,449 @@ +# Skills System + +The skills system lets ToolHive discover, build, distribute, install, and manage **Agent Skills** for AI coding assistants like Claude Code. Skills are not MCP servers -- they are markdown-based instructions (SKILL.md files) that extend an AI assistant's capabilities, packaged and distributed as OCI artifacts through the same registry infrastructure that serves MCP servers. + +## Why This Exists + +MCP servers provide tools and resources that AI assistants can call. Skills fill a different gap: they provide **instructions and knowledge** that shape how an AI assistant approaches tasks. A skill might teach Claude Code how to review PRs in your organization's style, how to run your test suite, or how to follow your team's coding conventions. + +Without ToolHive's skill system, teams would need to manually copy SKILL.md files between machines, track versions by hand, and have no central catalog for discovery. ToolHive brings the same managed lifecycle to skills that it already provides for MCP servers: a registry for discovery, OCI for distribution, scoped installation, and multi-client support. + +**Key design decision:** Skills and MCP servers are separate systems that share infrastructure (registry, groups, OCI distribution) but have distinct purposes, formats, and lifecycles. + +| Aspect | Skills | MCP Servers | +|--------|--------|-------------| +| **Purpose** | Agent instructions and knowledge | Remote tools and resources | +| **Protocol** | Agent Skills spec (SKILL.md) | Model Context Protocol (JSON-RPC) | +| **Format** | Markdown with YAML frontmatter | Container images or remote endpoints | +| **Runtime** | Read by AI client at prompt time | Executed as running processes | +| **Distribution** | OCI artifacts (tar.gz layers) | Container images | + +## Architecture + +```mermaid +graph TB + subgraph "Skill Sources" + OCI[OCI Registry
ghcr.io, Docker Hub] + Git[Git Repository
git://github.com/org/repo] + Local[Local Directory
SKILL.md + files] + RegistryAPI[Registry API
Skill Catalog] + end + + subgraph "ToolHive Skills Service" + SVC[SkillService
pkg/skills/skillsvc] + Lookup[SkillLookup
Registry name resolution] + GitRes[GitResolver
Git clone + extract] + OCIClient[OCI Registry Client
Pull/push artifacts] + Packager[SkillPackager
Build OCI artifacts] + Installer[Installer
Extract + validate] + Store[SkillStore
SQLite persistence] + end + + subgraph "Client Filesystem" + UserSkills["~/.claude/skills/
(user scope)"] + ProjectSkills[".claude/skills/
(project scope)"] + end + + subgraph "Access Layer" + CLI[thv skill CLI] + API[REST API
/api/v1beta/skills] + HTTPClient[Skills HTTP Client] + end + + OCI --> OCIClient + Git --> GitRes + RegistryAPI --> Lookup + Local --> Packager + + CLI --> SVC + API --> SVC + HTTPClient --> API + + SVC --> Lookup + SVC --> GitRes + SVC --> OCIClient + SVC --> Packager + SVC --> Installer + SVC --> Store + + Installer --> UserSkills + Installer --> ProjectSkills + + style SVC fill:#90caf9,stroke:#1565c0,stroke-width:2px + style Store fill:#e3f2fd + style UserSkills fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px + style ProjectSkills fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px + style CLI fill:#fff9c4 + style API fill:#fff9c4 +``` + +## Core Concepts + +### SKILL.md Format + +A skill is defined by a `SKILL.md` file with YAML frontmatter and a markdown body: + +```markdown +--- +name: code-review +description: Reviews code for best practices and security patterns +version: 1.0.0 +allowed-tools: Read Glob Grep +toolhive.requires: ghcr.io/org/base-skill:v1 +license: Apache-2.0 +compatibility: claude-code >= 1.0 +metadata: + author: team-name +--- + +# Code Review Skill + +Instructions for how the AI assistant should perform code reviews... +``` + +**Frontmatter fields:** + +| Field | Required | Description | +|-------|----------|-------------| +| `name` | Yes | 2-64 lowercase alphanumeric chars + hyphens | +| `description` | Yes | Human-readable description (max 1024 chars) | +| `version` | No | Semantic version | +| `allowed-tools` | No | Space or comma-delimited tool names | +| `toolhive.requires` | No | OCI references for skill dependencies | +| `license` | No | SPDX license identifier | +| `compatibility` | No | Client compatibility string (max 500 chars) | +| `metadata` | No | Arbitrary key-value pairs | + +**Implementation:** `pkg/skills/types.go` (SkillFrontmatter), `pkg/skills/parser.go`, `pkg/skills/validator.go` + +### Installation Scopes + +Skills install to one of two scopes: + +**User scope** (`~/.claude/skills//SKILL.md`): +- Available across all projects for the current user +- Default scope when no `--scope` flag is provided +- Useful for general-purpose skills (code review, testing, etc.) + +**Project scope** (`/.claude/skills//SKILL.md`): +- Available only within a specific project +- Requires `--project-root` or auto-detected git root +- Useful for project-specific conventions and workflows + +**Implementation:** `pkg/skills/types.go` (Scope), `pkg/skills/path_resolver.go` + +### Multi-Client Support + +Skills can be installed for multiple AI clients simultaneously. Each client has its own skill directory structure, so installing a skill for `claude-code` places files differently than for `cursor`. + +```bash +# Install for default client (first skill-supporting client) +thv skill install code-review + +# Install for specific client +thv skill install code-review --client claude-code + +# Install for multiple clients at once +thv skill install code-review --clients claude-code,cursor +``` + +The `PathResolver` interface maps (client, skill-name, scope, project-root) to the correct filesystem path for each client. + +**Implementation:** `pkg/skills/types.go` (PathResolver), `pkg/client/` + +## Skill Lifecycle + +### 1. Discovery + +Skills are discovered through the registry system: + +- **Registry API**: The `SkillsClient` queries the ToolHive Registry API at `/v0.1/x/dev.toolhive/skills` with pagination and search support. +- **Browsing API**: The `GET /registry/{name}/v0.1/x/dev.toolhive/skills` endpoint on the local API server exposes skills from the configured registry provider. +- **Local catalog**: The embedded registry includes curated skills. + +**Implementation:** `pkg/registry/api/skills_client.go` (SkillsClient), `pkg/api/v1/registry_v01_skills.go` + +### 2. Building + +Build a local skill directory into an OCI artifact: + +```bash +thv skill build ./my-skill/ # Build with auto-detected tag +thv skill build ./my-skill/ --tag v1.0.0 +``` + +**Build process:** +1. Load and parse `SKILL.md` from the directory +2. Validate the skill definition (name, frontmatter, filesystem safety) +3. Package all files into a tar.gz OCI layer +4. Store in the local OCI store with the specified tag + +**Implementation:** `pkg/skills/skillsvc/skillsvc.go` (Build), `toolhive-core/oci/skills` (SkillPackager) + +### 3. Publishing + +Push a locally-built artifact to a remote OCI registry: + +```bash +thv skill push ghcr.io/org/my-skill:v1.0.0 +``` + +**Implementation:** `pkg/skills/skillsvc/skillsvc.go` (Push), `toolhive-core/oci/skills` (RegistryClient) + +### 4. Installation + +```bash +thv skill install code-review # By name (registry lookup) +thv skill install ghcr.io/org/skill:v1.0.0 # By OCI reference +thv skill install git://github.com/org/repo@v1#skills/my-skill # From git +``` + +**Installation flow:** + +```mermaid +flowchart TD + A[Install Request] --> B{Reference Type?} + B -->|git://| C[Git Resolver] + B -->|OCI ref| D[OCI Pull] + B -->|Plain name| E[Registry Lookup] + + C --> F[Clone repo with timeout] + F --> G[Extract skill files] + + E --> H{Found in local store?} + H -->|Yes| I[Use local artifact] + H -->|No| J[Query registry/index] + J --> D + + D --> K[Pull from registry] + K --> L[Decompress + extract tar.gz] + G --> L + + I --> L + + L --> M[Validate: no symlinks, path traversal] + M --> N[Sanitize permissions] + N --> O[Write to client skill directory] + O --> P[Create DB record] + P --> Q{Group specified?} + Q -->|Yes| R[Add to group] + Q -->|No| S[Done] + R --> S + + style A fill:#e3f2fd + style S fill:#c8e6c9 + style M fill:#fff3e0 + style N fill:#fff3e0 +``` + +**Key details:** + +1. **Reference parsing**: The service determines the source type from the reference format: + - Starts with `git://` -> git resolver + - Contains `/`, `:`, or `@` -> OCI reference + - Otherwise -> plain name (registry lookup) + +2. **Per-skill locking**: A mutex map keyed by (scope, name, projectRoot) prevents concurrent installs of the same skill. + +3. **Supply chain validation**: For OCI installs, the skill name in the artifact must match the repository name in the reference. + +4. **Multi-client install**: When `--clients all` is specified, the skill is installed for every skill-supporting client in a single operation. + +**Implementation:** `pkg/skills/skillsvc/skillsvc.go` (Install) + +### 5. Uninstallation + +```bash +thv skill uninstall code-review +``` + +Removes the skill files from the filesystem, deletes the database record, and removes the skill from all groups. + +**Implementation:** `pkg/skills/skillsvc/skillsvc.go` (Uninstall), `pkg/groups/skills.go` (RemoveSkillFromAllGroups) + +## Git-Based Skill Resolution + +Skills can be installed directly from git repositories using the `git://` scheme: + +``` +git://github.com/org/repo # Repo root, default branch +git://github.com/org/repo@v1.0.0 # Specific tag +git://github.com/org/repo#skills/my-skill # Subdirectory +git://github.com/org/repo@main#skills/my-skill # Branch + subdirectory +``` + +**Resolution process:** +1. Parse the git reference (host, repo, ref, path) +2. Resolve authentication (host-scoped: `GITHUB_TOKEN` for github.com, `GITLAB_TOKEN` for gitlab.com, `GIT_TOKEN` as fallback) +3. Clone the repository (2-minute timeout, shallow clone) +4. Extract the skill directory files +5. Validate and install as normal + +**Security:** The resolver validates hosts against SSRF (no localhost, no private IPs unless in dev mode), validates refs against shell injection, and rejects path traversal. + +**Implementation:** `pkg/skills/gitresolver/` + +## Storage + +Skill installation records are persisted in SQLite: + +``` +skills table +├── scope (user | project) +├── project_root (path, empty for user scope) +├── skill_name (unique name) +├── client (target client app) +├── reference (OCI ref or git URL) +├── digest (OCI digest for upgrade detection) +├── status (installed | pending | failed) +├── installed_at (timestamp) +├── metadata_json (name, version, description, author, tags) +└── UNIQUE(scope, project_root, skill_name, client) + +skill_dependencies table +├── skill_name +├── scope +├── project_root +├── dep_reference (OCI ref) +└── dep_digest +``` + +**Implementation:** `pkg/storage/sqlite/skill_store.go`, `pkg/storage/interfaces.go` (SkillStore) + +## API + +### REST Endpoints + +**Skill management** (mounted at `/api/v1beta/skills`): + +| Method | Path | Description | +|--------|------|-------------| +| `GET` | `/` | List installed skills (filter by scope, client, project_root, group) | +| `POST` | `/` | Install a skill | +| `GET` | `/{name}` | Get skill info | +| `DELETE` | `/{name}` | Uninstall a skill | +| `POST` | `/validate` | Validate a SKILL.md | +| `POST` | `/build` | Build skill to OCI artifact | +| `POST` | `/push` | Push built skill to registry | +| `GET` | `/builds` | List local builds | +| `DELETE` | `/builds/{tag}` | Delete a local build | + +**Implementation:** `pkg/api/v1/skills.go` + +**Skill browsing** (mounted at `/registry/{name}/v0.1/x/dev.toolhive/skills`): + +| Method | Path | Description | +|--------|------|-------------| +| `GET` | `/` | List available skills from registry (search, pagination) | +| `GET` | `/{namespace}/{skillName}` | Get a specific skill from registry | + +**Implementation:** `pkg/api/v1/registry_v01_skills.go` + +### CLI Commands + +``` +thv skill +├── install [name] Install a skill from registry, OCI, or git +├── uninstall [name] Remove an installed skill +├── list List installed skills (text or JSON output) +├── info [name] Show detailed skill information +├── validate [path] Validate a SKILL.md file +├── build [path] Build skill to OCI artifact +├── push [reference] Push built skill to registry +├── builds List locally-built OCI artifacts +└── builds remove [tag] Delete a locally-built artifact +``` + +**Implementation:** `cmd/thv/app/skill*.go` + +### HTTP Client + +The `pkg/skills/client/` package provides an HTTP client that implements the `SkillService` interface, allowing remote skill management through the REST API. It auto-discovers the API server via `TOOLHIVE_API_URL` or a local discovery file. + +## Group Integration + +Skills can be organized into groups alongside MCP servers: + +```bash +thv skill install code-review --group dev-tools +thv skill list --group dev-tools +``` + +- `AddSkillToGroup()` adds a skill name to a group's Skills slice (deduplicated) +- `RemoveSkillFromAllGroups()` cleans up group references on uninstall + +Groups provide a shared organizational model for both skills and workloads. + +**Implementation:** `pkg/groups/skills.go` + +## Security Model + +The skills system applies defense-in-depth across multiple layers: + +### Archive Extraction Safety +- **Size limits**: 500MB total decompressed, 100MB per file, 1000 files max +- **Symlink rejection**: Archives containing symlinks or hardlinks are rejected +- **Path traversal prevention**: No `..` components, no absolute paths in archives +- **Permission sanitization**: Strips setuid/setgid/sticky bits, caps at 0644 +- **Pre-extraction validation**: Walks parent path components checking for symlinks before writing +- **Post-extraction verification**: Scans the extracted directory for filesystem anomalies + +### Dangerous Path Protection +- Refuses to remove filesystem roots, home directories, or shallow paths (< 4 components) +- Uses `Lstat` (not `Stat`) to detect symlinks without following them +- Resolves symlinks in parent components before applying depth checks + +### Supply Chain +- OCI artifact skill name must match repository name in the reference +- Git authentication is host-scoped (GitHub token only sent to github.com) +- SSRF prevention: rejects localhost and private IPs in git references + +### Input Validation +- Skill names: 2-64 chars, lowercase alphanumeric + hyphens, no consecutive hyphens +- Frontmatter size limit: 64KB +- Dependency limit: 100 per skill +- Git refs validated against shell injection characters + +**Implementation:** `pkg/skills/installer.go`, `pkg/skills/validator.go`, `pkg/skills/gitresolver/reference.go`, `pkg/skills/gitresolver/auth.go` + +## Dependency on toolhive-core + +The skills system depends on `github.com/stacklok/toolhive-core` for shared primitives: + +| Package | Purpose | +|---------|---------| +| `oci/skills.Store` | Local OCI artifact storage | +| `oci/skills.SkillPackager` | Building OCI artifacts from skill files | +| `oci/skills.RegistryClient` | Push/pull artifacts to/from OCI registries | +| `oci/skills.DecompressWithLimit` | Safe gzip decompression with size bounds | +| `oci/skills.ExtractTarWithLimit` | Safe tar extraction rejecting symlinks/traversal | +| `registry/types.Skill` | Canonical skill type for registry discovery | + +ToolHive owns the installation lifecycle, scoping model, CLI/API interfaces, and group integration. toolhive-core owns the OCI artifact format, registry protocol types, and low-level extraction utilities. + +## Key Files + +| Responsibility | Files | +|---|---| +| Type definitions | `pkg/skills/types.go` | +| Service interface | `pkg/skills/service.go` | +| Service implementation | `pkg/skills/skillsvc/skillsvc.go` | +| Options / DTOs | `pkg/skills/options.go` | +| Validation | `pkg/skills/validator.go` | +| Parsing | `pkg/skills/parser.go` | +| Extraction | `pkg/skills/installer.go` | +| Git resolution | `pkg/skills/gitresolver/` | +| Storage interface | `pkg/storage/interfaces.go` | +| SQLite backend | `pkg/storage/sqlite/skill_store.go` | +| REST API | `pkg/api/v1/skills.go` | +| Registry browsing API | `pkg/api/v1/registry_v01_skills.go` | +| HTTP client | `pkg/skills/client/` | +| CLI commands | `cmd/thv/app/skill*.go` | +| Group integration | `pkg/groups/skills.go` | + +## Related Documentation + +- [Core Concepts](02-core-concepts.md) - Platform nouns and verbs +- [Registry System](06-registry-system.md) - Registry architecture shared by skills and servers +- [Groups](07-groups.md) - Group concept used to organize skills and workloads +- [Architecture Overview](00-overview.md) - Platform overview diff --git a/docs/arch/README.md b/docs/arch/README.md index d44860860e..4c289f69a4 100644 --- a/docs/arch/README.md +++ b/docs/arch/README.md @@ -83,6 +83,14 @@ Welcome to the ToolHive architecture documentation. This directory contains comp - Atomic operations with Lua scripts - Configuration and security model +13. **[Skills System](12-skills-system.md)** + - Agent Skills lifecycle (discover, build, publish, install) + - SKILL.md format and validation + - OCI-based distribution and git resolution + - Installation scopes (user, project) and multi-client support + - Security model (archive safety, SSRF prevention, supply chain) + - Skills vs MCP servers design rationale + ### Existing Documentation For middleware architecture, see: **[docs/middleware.md](../middleware.md)** @@ -128,6 +136,10 @@ graph TB AuthStorage[11: Auth Server Storage
Memory & Redis backends] end + subgraph "Agent Skills" + Skills[12: Skills System
Build, publish, install] + end + %% Navigation paths Overview --> Concepts Overview --> Deployment @@ -149,6 +161,9 @@ graph TB Groups --> Workloads Groups --> vMCP + Groups --> Skills + + Registry --> Skills Workloads --> Operator vMCP --> Operator @@ -168,6 +183,7 @@ graph TB style Operator fill:#e0f2f1,stroke:#004d40,stroke-width:2px style vMCP fill:#e0f2f1,stroke:#004d40,stroke-width:2px style AuthStorage fill:#e0f2f1,stroke:#004d40,stroke-width:2px + style Skills fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px ``` **Color Legend:** @@ -217,6 +233,9 @@ Review all documents in order (00 → 01 → 02 → 03 → ...) **Extending ToolHive:** - [Middleware](../middleware.md) +**Agent Skills:** +- [Skills System](12-skills-system.md) + **Advanced Features:** - [Groups](07-groups.md) - [Workloads Lifecycle](08-workloads-lifecycle.md)