skills

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 14, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package skills implements the Agent Skills open standard. See https://agentskills.io for the specification.

Index

Constants

View Source
const (
	SkillFileName          = "SKILL.md"
	MaxNameLength          = 64
	MaxDescriptionLength   = 1024
	MaxCompatibilityLength = 500
)

Variables

View Source
var ErrSkillNotFound = errors.New("skill not found")

ErrSkillNotFound is returned when a skill ID is not part of the effective visible skill set.

Functions

func ApproxTokenCount

func ApproxTokenCount(s string) int

ApproxTokenCount returns a rough estimate of how many tokens a string occupies when sent to an LLM. Uses the common ~4-chars-per-token heuristic that approximates GPT/Claude tokenizers well enough for diagnostic logging.

func DiscoverFromConfig

func DiscoverFromConfig(cfg DiscoveryConfig) (allSkills, activeSkills []*Skill, states []*SkillState)

DiscoverFromConfig walks every path in cfg.Options.SkillsPaths (after home / env expansion), then dedups and filters by cfg.Options.DisabledSkills. It returns the three slices the rest of the system needs:

  • allSkills: deduplicated, pre-filter (includes disabled).
  • activeSkills: post-filter (DisabledSkills removed).
  • states: per-file discovery outcome for diagnostics/UI.

func DiscoverWithStates

func DiscoverWithStates(paths []string) ([]*Skill, []*SkillState)

DiscoverWithStates finds all valid skills in the given paths and also returns a per-file state slice describing parse/validation outcomes. Useful for diagnostics and UI reporting.

func PublishStates

func PublishStates(states []*SkillState)

PublishStates publishes a skill discovery event with the given states.

func SetLatestStates

func SetLatestStates(states []*SkillState)

SetLatestStates stores the given states in the package-level cache so that GetLatestStates can return them synchronously before the first pubsub event arrives.

func SubscribeEvents

func SubscribeEvents(ctx context.Context) <-chan pubsub.Event[Event]

SubscribeEvents returns a channel that receives events when skill discovery state changes.

func ToPromptXML

func ToPromptXML(skills []*Skill) string

ToPromptXML generates XML for injection into the system prompt. Skills with DisableModelInvocation set to true are excluded.

Types

type CatalogEntry

type CatalogEntry struct {
	ID          string     `json:"id"`
	Name        string     `json:"name"`
	Description string     `json:"description"`
	Label       string     `json:"label"`
	Source      SourceType `json:"source"`
	// Collection is the name of the enclosing skill repo (e.g. a cloned
	// collection like "seshat-skills" or "paperasse") when the skill is
	// nested under one. Empty for standalone skills placed directly under
	// a registered skills path.
	Collection    string `json:"collection,omitempty"`
	UserInvocable bool   `json:"user_invocable"`
}

CatalogEntry describes an effective visible skill for frontend display.

func Catalog

func Catalog(active []*Skill, skillPaths []string, workingDir string) []CatalogEntry

Catalog builds a slice of CatalogEntry values from pre-discovered skills. The skillPaths and workingDir parameters are used only for labelling (system / user / project); pass nil/empty when labels are not needed.

type DiscoveryConfig

type DiscoveryConfig struct {
	SkillsPaths    []string
	DisabledSkills []string
	WorkingDir     string
	// Resolver expands $VAR-style references in paths. May be nil.
	Resolver func(string) (string, error)
}

DiscoveryConfig contains the inputs DiscoverFromConfig needs. Using a dedicated struct (rather than importing internal/config) keeps the skills package's dependency graph small.

func (DiscoveryConfig) ResolvePaths

func (c DiscoveryConfig) ResolvePaths() []string

ResolvePaths expands home-directory and $VAR references in SkillsPaths. This is the canonical path-resolution logic used by DiscoverFromConfig; callers that need the resolved list (e.g. for Catalog labels) can call this directly.

type DiscoveryState

type DiscoveryState int

DiscoveryState represents the outcome of discovering a single skill file.

const (
	// StateNormal indicates the skill was parsed and validated successfully.
	StateNormal DiscoveryState = iota
	// StateError indicates discovery encountered a scan/parse/validate error.
	StateError
)

type Event

type Event struct {
	States []*SkillState
}

Event is published when skill discovery completes.

type Manager

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

Manager owns per-workspace skill discovery state: the latest discovery snapshot, the full skill metadata (with Instructions) for the coordinator, and a pubsub broker for change events. There is exactly one Manager per workspace.

Package-level helpers (GetLatestStates, SetLatestStates, PublishStates, SubscribeEvents) are preserved for callers that share a process with the TUI. To bridge a Manager to those globals, construct it with WithGlobalMirror. Only do this when the process hosts a single workspace (local mode or a client process); the backend server hosts multiple workspaces concurrently and must not enable mirroring.

func NewManager

func NewManager(allSkills, activeSkills []*Skill, states []*SkillState, opts ...ManagerOption) *Manager

NewManager constructs a workspace-scoped Manager with the given pre-computed discovery results. The slices are stored as-is; callers should not mutate them afterwards.

func (*Manager) ActiveSkills

func (m *Manager) ActiveSkills() []*Skill

ActiveSkills returns the post-filter list of active skills (after removing disabled entries).

func (*Manager) AllSkills

func (m *Manager) AllSkills() []*Skill

AllSkills returns the deduplicated list of all discovered skills.

func (*Manager) PublishStates

func (m *Manager) PublishStates(states []*SkillState)

PublishStates updates the manager's cached snapshot and publishes a discovery event to subscribers. Callers should not call SetLatestStates separately — PublishStates is the single mutation point, keeping Manager.States(), workspaceToProto, and (when WithGlobalMirror is set) skills.GetLatestStates consistent with what subscribers observe.

func (*Manager) ResolvedPaths

func (m *Manager) ResolvedPaths() []string

ResolvedPaths returns the expanded skills directory paths stored at construction time.

func (*Manager) SetLatestStates

func (m *Manager) SetLatestStates(states []*SkillState)

SetLatestStates updates the manager's cached discovery snapshot.

func (*Manager) Shutdown

func (m *Manager) Shutdown()

Shutdown releases broker resources.

func (*Manager) States

func (m *Manager) States() []*SkillState

States returns a clone of the latest discovery state snapshot.

func (*Manager) SubscribeEvents

func (m *Manager) SubscribeEvents(ctx context.Context) <-chan pubsub.Event[Event]

SubscribeEvents returns a channel of discovery events for the manager's workspace.

func (*Manager) WorkingDir

func (m *Manager) WorkingDir() string

WorkingDir returns the workspace working directory stored at construction time.

type ManagerOption

type ManagerOption func(*Manager)

ManagerOption configures a Manager at construction time.

func WithGlobalMirror

func WithGlobalMirror() ManagerOption

WithGlobalMirror causes the manager to forward SetLatestStates and PublishStates calls to the package-level cache and broker. Only safe when the process hosts at most one Manager (e.g. local mode or the client process).

func WithResolvedPaths

func WithResolvedPaths(paths []string) ManagerOption

WithResolvedPaths stores the expanded skills directory paths that were used during discovery. Catalog and ReadContent use these for source labelling.

func WithWorkingDir

func WithWorkingDir(dir string) ManagerOption

WithWorkingDir stores the workspace working directory. Catalog and ReadContent use it to distinguish project skills from user skills.

type Skill

type Skill struct {
	Name                   string            `yaml:"name" json:"name"`
	Description            string            `yaml:"description" json:"description"`
	UserInvocable          bool              `yaml:"user-invocable" json:"user_invocable"`
	DisableModelInvocation bool              `yaml:"disable-model-invocation" json:"disable_model_invocation"`
	License                string            `yaml:"license,omitempty" json:"license,omitempty"`
	Compatibility          string            `yaml:"compatibility,omitempty" json:"compatibility,omitempty"`
	Metadata               map[string]string `yaml:"metadata,omitempty" json:"metadata,omitempty"`
	Instructions           string            `yaml:"-" json:"instructions"`
	Path                   string            `yaml:"-" json:"path"`
	SkillFilePath          string            `yaml:"-" json:"skill_file_path"`
	Builtin                bool              `yaml:"-" json:"builtin"`
}

Skill represents a parsed SKILL.md file.

func Deduplicate

func Deduplicate(all []*Skill) []*Skill

Deduplicate removes duplicate skills by name. When duplicates exist, the last occurrence wins. This means user skills (appended after builtins) override builtin skills with the same name.

func Discover

func Discover(paths []string) []*Skill

Discover finds all valid skills in the given paths.

func Filter

func Filter(all []*Skill, disabled []string) []*Skill

Filter removes skills whose names appear in the disabled list.

func FindEffective

func FindEffective(active []*Skill, skillID string) (*Skill, error)

FindEffective returns the named skill from the given active skill set.

func Parse

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

Parse parses a SKILL.md file from disk.

func ParseContent

func ParseContent(content []byte) (*Skill, error)

ParseContent parses a SKILL.md from raw bytes.

func (*Skill) FormatInvocation

func (s *Skill) FormatInvocation() string

FormatInvocation generates XML for a skill when invoked as a user command.

func (*Skill) Validate

func (s *Skill) Validate() error

Validate checks if the skill meets spec requirements.

type SkillReadResult

type SkillReadResult struct {
	Name        string     `json:"name"`
	Description string     `json:"description"`
	Source      SourceType `json:"source"`
	Builtin     bool       `json:"builtin"`
}

SkillReadResult holds metadata about a skill returned alongside its content.

func ReadContent

func ReadContent(active []*Skill, skillPaths []string, workingDir string, skillID string) ([]byte, SkillReadResult, error)

ReadContent reads the contents of a visible skill by ID and returns the raw bytes along with metadata about the skill.

type SkillState

type SkillState struct {
	Name  string
	Path  string
	State DiscoveryState
	Err   error
}

SkillState represents the latest discovery status of a skill file.

func DeduplicateStates

func DeduplicateStates(all []*SkillState) []*SkillState

DeduplicateStates removes duplicate skill states by name. When duplicates exist, the last occurrence wins (consistent with Deduplicate for skills).

func GetLatestStates

func GetLatestStates() []*SkillState

GetLatestStates returns the latest discovery states.

type SourceType

type SourceType string

SourceType describes where a visible skill comes from.

const (
	SourceSystem  SourceType = "system"
	SourceUser    SourceType = "user"
	SourceProject SourceType = "project"
)

type Tracker

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

Tracker tracks which skills have been loaded (read) during a session. It is safe for concurrent use.

Note: Tracking is name-based and limited to active skills only. If a builtin skill is overridden by a user skill, only the user skill (which is active) can be marked as loaded. This prevents misattribution when reading builtin files that have been overridden.

func NewTracker

func NewTracker(activeSkills []*Skill) *Tracker

NewTracker creates a new skill tracker with the given active skill names. Only skills in activeSkills can be marked as loaded.

func (*Tracker) IsLoaded

func (t *Tracker) IsLoaded(name string) bool

IsLoaded returns true if the skill has been loaded.

func (*Tracker) LoadedCount

func (t *Tracker) LoadedCount() int

LoadedCount returns the number of unique skills that have been loaded. Safe to call on a nil Tracker (returns 0).

func (*Tracker) LoadedNames

func (t *Tracker) LoadedNames() []string

LoadedNames returns the names of all skills that have been loaded, sorted alphabetically. Safe to call on a nil Tracker (returns nil).

func (*Tracker) MarkLoaded

func (t *Tracker) MarkLoaded(name string)

MarkLoaded marks a skill as having been loaded. Only marks as loaded if the skill is in the active set (not overridden/disabled).

Jump to

Keyboard shortcuts

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