Skip to content

Skill Packs

Skill packs are distributable bundles of markdown skills embedded via Go's embed package. They implement the pack.SkillPack interface, allowing skills to be shared as Go modules.

Overview

┌───────────────────────────────────────────┐
│              Skill Pack Module            │
│  ┌─────────────────────────────────────┐  │
│  │          //go:embed skills/*        │  │
│  │              skillsFS               │  │
│  └─────────────────────────────────────┘  │
│                    │                      │
│  ┌─────────────────┴───────────────────┐  │
│  │         pack.SkillPack              │  │
│  │   Name() | Version() | FS()         │  │
│  └─────────────────────────────────────┘  │
└───────────────────────────────────────────┘
┌───────────────────────────────────────────┐
│              Agent Runtime                │
│         agent.WithSkillPack(fs.FS)        │
└───────────────────────────────────────────┘

The SkillPack Interface

package pack

import "embed"

// SkillPack defines the interface for markdown skill bundles.
type SkillPack interface {
    // Name returns the pack identifier (e.g., "omniagent-skills").
    Name() string

    // Version returns the pack version (e.g., commit hash or semver).
    Version() string

    // FS returns the embedded filesystem containing skills.
    // Skills should be in a "skills/" subdirectory.
    FS() embed.FS
}

Creating a Skill Pack

1. Project Structure

my-skill-pack/
├── go.mod
├── pack.go           # SkillPack implementation
├── VERSION           # Version file (optional)
└── skills/
    ├── weather/
    │   └── SKILL.md
    ├── github/
    │   └── SKILL.md
    └── tmux/
        └── SKILL.md

2. Implement SkillPack

package myskills

import (
    "embed"
    "strings"

    "github.com/plexusone/omniskill/pack"
)

//go:embed skills/*
var skillsFS embed.FS

//go:embed VERSION
var version string

// Pack implements pack.SkillPack for this skill bundle.
type Pack struct{}

func (Pack) Name() string {
    return "my-skill-pack"
}

func (Pack) Version() string {
    return strings.TrimSpace(version)
}

func (Pack) FS() embed.FS {
    return skillsFS
}

// Default returns a new Pack instance.
func Default() *Pack {
    return &Pack{}
}

// Ensure Pack implements pack.SkillPack
var _ pack.SkillPack = (*Pack)(nil)

3. Add Skills

Create SKILL.md files in the skills/ directory:

---
name: weather
description: Get weather forecasts
metadata:
  emoji: "🌤️"
  requires:
    bins: ["curl"]
---

# Weather Skill

Check the weather using curl:

## Current Weather

```bash
curl "wttr.in/London?format=3"
### 4. Version File

Create a `VERSION` file with the current version:
v1.0.0
Or use a git commit hash during build:

```bash
git rev-parse HEAD > VERSION

Using a Skill Pack

With OmniAgent

import (
    "github.com/plexusone/omniagent/agent"
    skills "github.com/example/my-skill-pack"
)

agent, err := agent.New(config,
    agent.WithSkillPack(skills.Default().FS()),
)

With Filtering

agent, err := agent.New(config,
    agent.WithSkillPack(skills.Default().FS()),
    agent.WithSkillIncludes("weather", "github"),
)

Multiple Packs

import (
    defaultSkills "github.com/plexusone/omniagent-skills"
    customSkills "github.com/example/my-skill-pack"
)

agent, err := agent.New(config,
    agent.WithSkillPack(defaultSkills.Default().FS()),
    agent.WithSkillPack(customSkills.Default().FS()),
)

Directory Structure Requirements

The embedded filesystem must have skills in a skills/ subdirectory:

skills/
├── skill-name/
│   └── SKILL.md
├── another-skill/
│   └── SKILL.md

Each skill directory must contain a SKILL.md file with YAML frontmatter.

Best Practices

1. Use Semantic Versioning

Tag releases with semantic versions (v1.0.0, v1.1.0, etc.) so consumers can pin specific versions.

2. Document Requirements

Each skill should declare its requirements in the YAML frontmatter:

metadata:
  requires:
    bins: ["curl", "jq"]
    env: ["API_KEY"]

3. Include Install Hints

Help users install missing dependencies:

metadata:
  install:
    - name: curl
      brew: curl
      apt: curl

4. Test Skills

Verify skills load correctly:

func TestPackFS(t *testing.T) {
    p := Default()
    fsys := p.FS()

    entries, err := fs.ReadDir(fsys, "skills")
    if err != nil {
        t.Fatalf("ReadDir failed: %v", err)
    }

    if len(entries) == 0 {
        t.Error("No skills found")
    }
}

Available Packs

Pack Description Install
omniagent-skills Default pack with 18 skills go get github.com/plexusone/omniagent-skills

Validation

Added in v0.11.0. Validate a SKILL.md tree before packaging it, catching errors and warnings separately:

import "github.com/plexusone/omniskill/pack"

result, err := pack.ValidatePack(pack.ValidateConfig{
    SkillsDir: "./skills",
    Strict:    true, // treat warnings as errors
})
if !result.Valid {
    for _, e := range result.Errors {
        fmt.Printf("[%s] %s: %s: %s\n", e.Severity, e.Skill, e.Field, e.Message)
    }
}

Publishing

Added in v0.11.0. PrepareForPublish validates a skills directory and produces a checksummed tarball ready to distribute:

bundle, err := pack.PrepareForPublish(pack.PublishConfig{
    SkillsDir: "./skills",
    PackName:  "my-pack",
    OutputDir: "./dist",
    Strict:    true, // treat validation warnings as errors
})
// bundle.BundlePath, bundle.Checksum, bundle.Size

Scaffolding

Added in v0.11.0. Generate a new SkillPack Go source file from a skills directory:

result, err := pack.Scaffold(pack.ScaffoldConfig{
    SkillsDir:      "./skills",
    PackageName:    "skills",
    PackName:       "my-pack",
    OutputDir:      ".",
    IncludeVersion: true, // embed the git commit hash as the pack version
})
// result.OutputPath

See Also

  • Skills - Creating individual skills
  • Registry - Skill registration and discovery