ollama/docs/skill-registry-design.md

9.2 KiB

Skill Registry Design

Overview

Skills are distributable capability packages for Ollama agents. They can be:

  • Bundled with agents at creation time (local paths)
  • Pulled from the registry (skill references)
  • Pushed to the registry for sharing

User Experience

Push a Skill

# Push a local skill directory to the registry
ollama skill push myname/calculator:1.0.0 ./skills/calculator-skill

# Output:
# Creating skill layer for skill/myname/calculator:1.0.0
# pushing sha256:abc123... 1.2KB
# pushing sha256:def456... 220B
# pushing manifest
# Successfully pushed skill/myname/calculator:1.0.0

Pull a Skill

# Pull a skill from the registry
ollama skill pull calculator:1.0.0

# Output:
# pulling manifest
# pulling sha256:abc123... 1.2KB
# extracting skill...
# Successfully pulled skill/calculator:1.0.0

List Installed Skills

ollama skill list

# Output:
# NAME                      TAG     SIZE     MODIFIED
# skill/calculator          1.0.0   1.2 KB   2 hours ago
# skill/myname/hello        latest  0.8 KB   1 day ago

Remove a Skill

ollama skill rm calculator:1.0.0
# Deleted 'skill/calculator:1.0.0'

Use Skills in Agentfile

FROM llama3.2:3b

AGENT_TYPE conversational
SKILL skill/calculator:1.0.0    # Registry reference
SKILL ./local-skill             # Local path (for development)

SYSTEM You are a helpful assistant.

Technical Implementation

Skill Manifest Format

{
  "schemaVersion": 2,
  "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
  "config": {
    "mediaType": "application/vnd.docker.container.image.v1+json",
    "digest": "sha256:config...",
    "size": 220
  },
  "layers": [
    {
      "mediaType": "application/vnd.ollama.image.skill",
      "digest": "sha256:skill...",
      "size": 1234
    }
  ]
}

Skill Config Format

{
  "name": "calculator",
  "description": "A skill for performing calculations",
  "architecture": "amd64",
  "os": "linux"
}

Storage Layout

Skills use a 5-part manifest structure: host/namespace/kind/model/tag

~/.ollama/models/
├── blobs/
│   └── sha256-<skill-digest>           # Skill tar.gz blob
├── manifests/
│   └── registry.ollama.ai/
│       └── library/
│           └── skill/                  # Kind = skill
│               └── calculator/
│                   └── 1.0.0
│       └── myname/
│           └── skill/                  # User skills
│               └── my-skill/
│                   └── latest
└── skills/
    └── sha256-<digest>/                # Extracted skill cache
        ├── SKILL.md
        └── scripts/

Name Structure

Skills use a 5-part name structure with kind to distinguish from models:

Skill Reference Namespace Kind Model Tag
skill/calculator:1.0.0 library skill calculator 1.0.0
myname/skill/calc:latest myname skill calc latest

Media Type

const MediaTypeSkill = "application/vnd.ollama.image.skill"

Key Types

// SkillRef represents a skill reference in agent config
type SkillRef struct {
    Name   string `json:"name,omitempty"`   // "calculator-skill" or "myname/skill/calc:1.0.0"
    Digest string `json:"digest,omitempty"` // "sha256:abc..." (set when bundled)
}

// model.Name represents a parsed 5-part name
type Name struct {
    Host      string // "registry.ollama.ai"
    Namespace string // "library" or "myname"
    Kind      string // "skill" or "agent" or "" for models
    Model     string // "calculator"
    Tag       string // "1.0.0"
}

Implementation Files

Client (ollama)

File Purpose
server/skill.go Skill blob handling, path parsing, extraction
cmd/skill_cmd.go CLI commands (push, pull, list, rm, show)
cmd/skills.go Skill loading and catalog management
server/create.go Skill layer creation during agent create
server/images.go Skill extraction during pull
types/model/config.go SkillRef type definition

Registry (ollama.com)

File Purpose
ollamadotcom/registry/store.go MediaTypeSkill constant
ollamadotcom/store/store.go RecordPush handles skill layers

Registry Integration

What Works

  • Blob uploads (content-addressable, no auth required)
  • Layer indexing (skill layers stored with mediatype)
  • Manifest structure (4-part path compatible)

What's Needed

  1. Namespace Configuration: The skill namespace needs to be configured with:

    • Public read access
    • Authenticated write access
  2. Permission Model: Decide who can push to skill/ namespace:

    • Only Ollama team (curated library)
    • Verified publishers
    • Anyone (open registry)

Pull Flow

Agent with Bundled Skills

ollama pull my-agent
    → GET manifest (includes skill layers)
    → Download all blobs (model + skills)
    → Extract skill blobs to ~/.ollama/models/skills/
    → Ready to run

Standalone Skill

ollama skill pull calculator:1.0.0
    → Parse as skill/calculator:1.0.0
    → Convert to model.Name{Namespace: "skill", Model: "calculator", Tag: "1.0.0"}
    → GET manifest from registry
    → Download skill blob
    → Extract to ~/.ollama/models/skills/sha256-<digest>/
    → Available for agents to reference

Push Flow

ollama skill push myname/calculator:1.0.0 ./my-skill
    → Validate SKILL.md exists
    → Create tar.gz of skill directory
    → Compute SHA256 digest
    → Store blob locally
    → Create skill manifest with config layer
    → Store manifest locally
    → Push blobs to registry
    → Push manifest to registry

Backward Compatibility

  • Old agents with Skills: []string (paths) continue to work
  • New agents use Skills: []SkillRef with name and digest
  • Parser detects format and handles both

Local Registry Testing

To test push/pull locally, you need MinIO and the Docker registry running:

# 1. Start MinIO (for blob storage)
minio server ~/.minio-data --console-address ':9001' &

# 2. Create the ollama-dev bucket (first time only)
mc config host add local http://localhost:9000 minioadmin minioadmin
mc mb local/ollama-dev

# 3. Start the registry (from ollama.com repo)
cd /path/to/ollama.com/registry
go run cmd/registry/main.go serve config-dev.yml &

# 4. Verify registry is running
curl http://localhost:6000/v2/

Important: The config-dev.yml must have matching ports:

http:
  addr: :6000
  host: http://localhost:6000  # Must match addr!

Test Commands

# Push skill from local folder
ollama skill push localhost:6000/testuser/skill/calculator:1.0.0 ./skills/calculator-skill --insecure

# Pull skill from registry
ollama skill pull localhost:6000/testuser/skill/calculator:1.0.0 --insecure

# List skills
ollama skill list

# Show skill
ollama skill show localhost:6000/testuser/skill/calculator:1.0.0

Architecture Diagram

graph TB
    subgraph "Skill Naming Structure"
        A["skill/calculator:1.0.0"] --> B["host: registry.ollama.ai"]
        A --> C["namespace: library"]
        A --> D["kind: skill"]
        A --> E["model: calculator"]
        A --> F["tag: 1.0.0"]
    end

    subgraph "Storage Layout"
        G["~/.ollama/models/"]
        G --> H["blobs/"]
        H --> I["sha256-<skill-digest>"]
        G --> J["manifests/"]
        J --> K["registry.ollama.ai/"]
        K --> L["library/skill/calculator/1.0.0"]
        K --> M["myname/skill/my-skill/latest"]
        G --> N["skills/"]
        N --> O["sha256-<digest>/"]
        O --> P["SKILL.md"]
        O --> Q["scripts/"]
    end

    subgraph "Push Flow"
        R["User Command: ollama skill push"]
        R --> S["Validate SKILL.md"]
        S --> T["Create tar.gz of skill dir"]
        T --> U["Compute SHA256 digest"]
        U --> V["Store blob locally"]
        V --> W["Create skill manifest"]
        W --> X["Store manifest locally"]
        X --> Y["Push blobs to registry"]
        Y --> Z["Push manifest to registry"]
    end

    subgraph "Pull Flow - Standalone Skill"
        AA["User Command: ollama skill pull"]
        AA --> AB["Parse name structure"]
        AB --> AC["GET manifest from registry"]
        AC --> AD["Download skill blob"]
        AD --> AE["Extract to skills/ directory"]
        AE --> AF["Available for agents"]
    end

    subgraph "Pull Flow - Agent with Skills"
        AG["Pull Agent: ollama pull my-agent"]
        AG --> AH["GET manifest (includes skill layers)"]
        AH --> AI["Download all blobs (model + skills)"]
        AI --> AJ["Extract skill blobs"]
        AJ --> AK["Ready to run"]
    end

    subgraph "Agentfile Integration"
        AL["Agentfile"]
        AL --> AM["FROM llama3.2:3b"]
        AL --> AN["SKILL skill/calculator:1.0.0"]
        AL --> AO["SKILL ./local-skill"]
        AO --> AP["Local path (development)"]
        AN --> AQ["Registry reference"]
    end

    subgraph "Registry Components"
        AR["Registry Server"]
        AR --> AS["Blob Storage (MinIO)"]
        AR --> AT["Layer Indexing"]
        AR --> AU["Manifest Storage"]
        AR --> AV["Namespace Config"]
    end

    Z --> AR
    AC --> AR
    AH --> AR