Documentation
¶
Overview ¶
Package skills provides types and utilities for loading, parsing, and managing PromptKit skills defined via the AgentSkills.io SKILL.md format.
Index ¶
- Constants
- Variables
- func BuildSkillActivateDescriptor() *tools.ToolDescriptor
- func BuildSkillActivateDescriptorWithIndex(index string) *tools.ToolDescriptor
- func BuildSkillDeactivateDescriptor() *tools.ToolDescriptor
- func BuildSkillReadResourceDescriptor() *tools.ToolDescriptor
- func DefaultSkillsProjectDir() (string, error)
- func DefaultSkillsUserDir() (string, error)
- func IsLocalPath(arg string) bool
- func SkillFilterFromContext(ctx context.Context) string
- func WithSkillFilter(ctx context.Context, filter string) context.Context
- type Executor
- func (e *Executor) Activate(name string) (instructions string, addedTools []string, retErr error)
- func (e *Executor) ActivateWithFilter(name, filter string) (instructions string, addedTools []string, retErr error)
- func (e *Executor) ActiveSkills() []string
- func (e *Executor) ActiveTools() []string
- func (e *Executor) Deactivate(name string) (removedTools []string, retErr error)
- func (e *Executor) ReadResource(skillName, path string) ([]byte, error)
- func (e *Executor) SetFilter(glob string) []string
- func (e *Executor) SetNewSelector(sel selection.Selector)
- func (e *Executor) SkillIndex(skillsDir string) string
- func (e *Executor) SkillIndexFiltered(ctx context.Context, query, skillsDir string) string
- type ExecutorConfig
- type InstalledSkill
- type Installer
- func (inst *Installer) Install(ref SkillRef, projectLevel bool) (string, error)
- func (inst *Installer) InstallInto(ref SkillRef, targetDir string) (string, error)
- func (inst *Installer) InstallLocal(srcPath string, projectLevel bool) (string, error)
- func (inst *Installer) InstallLocalInto(srcPath, targetDir string) (string, error)
- func (inst *Installer) List() ([]InstalledSkill, error)
- func (inst *Installer) Remove(ref SkillRef) error
- func (inst *Installer) Resolve(ref SkillRef) (string, error)
- type ModelDrivenSelector
- type Registry
- func (r *Registry) Discover(sources []SkillSource) error
- func (r *Registry) Has(name string) bool
- func (r *Registry) List() []SkillMetadata
- func (r *Registry) ListForDir(dir string) []SkillMetadata
- func (r *Registry) Load(name string) (*Skill, error)
- func (r *Registry) PreloadedSkills() []*Skill
- func (r *Registry) ReadResource(name, resourcePath string) ([]byte, error)
- func (r *Registry) ResolveRef(ref SkillRef) (string, error)
- type Skill
- type SkillMetadata
- type SkillRef
- type SkillSelector
- type SkillSource
- type TagSelector
- type ToolExecutor
Constants ¶
const ( SkillActivateTool = "skill__activate" SkillDeactivateTool = "skill__deactivate" SkillReadResourceTool = "skill__read_resource" SkillNamespace = "skill" SkillExecutorName = "skill" )
Tool name constants for the skill__ namespace.
Variables ¶
var ErrPathTraversal = errors.New("resource path escapes skill directory")
ErrPathTraversal is returned when a resource path attempts to escape the skill directory.
Functions ¶
func BuildSkillActivateDescriptor ¶
func BuildSkillActivateDescriptor() *tools.ToolDescriptor
BuildSkillActivateDescriptor returns the tool descriptor for skill__activate.
func BuildSkillActivateDescriptorWithIndex ¶
func BuildSkillActivateDescriptorWithIndex(index string) *tools.ToolDescriptor
BuildSkillActivateDescriptorWithIndex returns a skill__activate descriptor whose Description includes the available-skills index so the LLM can discover which skills are available.
func BuildSkillDeactivateDescriptor ¶
func BuildSkillDeactivateDescriptor() *tools.ToolDescriptor
BuildSkillDeactivateDescriptor returns the tool descriptor for skill__deactivate.
func BuildSkillReadResourceDescriptor ¶
func BuildSkillReadResourceDescriptor() *tools.ToolDescriptor
BuildSkillReadResourceDescriptor returns the tool descriptor for skill__read_resource.
func DefaultSkillsProjectDir ¶
DefaultSkillsProjectDir returns the project-level skills directory.
func DefaultSkillsUserDir ¶
DefaultSkillsUserDir returns the XDG-compliant user-level skills directory.
func IsLocalPath ¶
IsLocalPath returns true if the argument looks like a local filesystem path rather than a skill reference (starts with "./", "../", or "/").
func SkillFilterFromContext ¶ added in v1.4.5
SkillFilterFromContext returns the skill filter from context, or "" if not set.
Types ¶
type Executor ¶
type Executor struct {
// contains filtered or unexported fields
}
Executor manages the skill activation lifecycle and provides functions that implement the skill__ namespaced tools.
func NewExecutor ¶
func NewExecutor(cfg ExecutorConfig) *Executor
NewExecutor creates a new Executor from the given configuration. If Selector is nil, a ModelDrivenSelector is used.
func (*Executor) Activate ¶
Activate loads a skill's instructions and returns them. It extends the active tool set with the skill's allowed-tools (capped by pack tools). If the skill is already active, it returns the instructions again (idempotent). Returns error if skill not found or at max active limit.
func (*Executor) ActivateWithFilter ¶ added in v1.4.5
func (e *Executor) ActivateWithFilter(name, filter string) (instructions string, addedTools []string, retErr error)
ActivateWithFilter is like Activate but applies the given filter instead of the executor's default filter. This supports per-run filtering in concurrent scenarios.
func (*Executor) ActiveSkills ¶
ActiveSkills returns the names of currently active skills, sorted.
func (*Executor) ActiveTools ¶
ActiveTools returns the aggregate set of tools added by all active skills (each capped by pack tools). The result is deduplicated and sorted.
func (*Executor) Deactivate ¶
Deactivate removes a skill from the active set. Returns the tools that should be removed from the active tool set. A tool is only removed if no other active skill also needs it.
func (*Executor) ReadResource ¶
ReadResource reads a file from within a skill's directory. Delegates to the underlying registry.
func (*Executor) SetFilter ¶ added in v1.4.5
SetFilter sets a glob pattern that restricts which skills can be activated. Empty string means all skills are available. "none" (case-insensitive) disables all. Returns names of skills that were deactivated because they no longer match.
func (*Executor) SetNewSelector ¶ added in v1.4.5
SetNewSelector replaces the external selector after construction. It is safe to call between Send()s; callers typically wire this at capability-registration time based on RuntimeConfig.
func (*Executor) SkillIndex ¶
SkillIndex returns the Phase 1 skill index string for inclusion in the skill__activate tool description. It is a thin wrapper over SkillIndexFiltered with no query, so it preserves historical behavior when no external selector is configured.
func (*Executor) SkillIndexFiltered ¶ added in v1.4.5
SkillIndexFiltered returns the skill index string, optionally narrowed by the configured external Selector. When no selector is configured, or the selector returns an error or an empty result, the full eligible set is returned — PromptKit never crashes a conversation because selection failed.
query is the current-turn context the selector may rank against; when empty, the selector is skipped entirely (there's nothing to rank against, so all eligible skills surface).
type ExecutorConfig ¶
type ExecutorConfig struct {
Registry *Registry
Selector SkillSelector // nil = ModelDrivenSelector
NewSelector selection.Selector // optional external selector for narrowing the skill index
PackTools []string // all tools declared in the pack
MaxActive int // 0 = unlimited
ConfigDir string // base directory for computing relative skill paths in filters
}
ExecutorConfig configures the skill executor.
type InstalledSkill ¶
type InstalledSkill struct {
Org string // e.g., "anthropic"
Name string // e.g., "pdf-processing"
Location string // "user" or "project"
Path string // filesystem path to the skill directory
}
InstalledSkill describes a skill found in user-level or project-level directories.
type Installer ¶
type Installer struct {
UserDir string // ~/.config/promptkit/skills/
ProjectDir string // .promptkit/skills/
GitCloneFunc func(url, dest string) error // injectable for testing
GitCheckout func(dir, ref string) error // injectable for testing
CopyDirFunc func(src, dest string) error // injectable for testing
}
Installer manages installing, removing, listing, and resolving shared skills.
func NewInstaller ¶
NewInstaller creates an Installer with default XDG-compliant paths.
func (*Installer) Install ¶
Install clones a skill from its Git repository into the appropriate directory. If projectLevel is true, installs to .promptkit/skills/; otherwise to user-level. Returns the installation path.
func (*Installer) InstallInto ¶
InstallInto clones a skill from its Git repository directly into a target directory (e.g., a workflow stage directory like ./skills/billing/). The skill is placed at <targetDir>/<name>/. Returns the installation path.
func (*Installer) InstallLocal ¶
InstallLocal copies a skill from a local path into the appropriate directory. Returns the installation path.
func (*Installer) InstallLocalInto ¶
InstallLocalInto copies a skill from a local path directly into a target directory. Returns the installation path.
func (*Installer) List ¶
func (inst *Installer) List() ([]InstalledSkill, error)
List returns all installed skills from both user and project directories.
type ModelDrivenSelector ¶
type ModelDrivenSelector struct{}
ModelDrivenSelector is the default selector — it returns all available skills, letting the model decide which to activate via skill__activate. Effective for up to ~50 skills. Safe for concurrent use.
func NewModelDrivenSelector ¶
func NewModelDrivenSelector() *ModelDrivenSelector
NewModelDrivenSelector creates a new ModelDrivenSelector.
func (*ModelDrivenSelector) Select ¶
func (s *ModelDrivenSelector) Select( _ context.Context, _ string, available []SkillMetadata, ) ([]string, error)
Select returns all skill names from available.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry holds discovered skills and provides access by name and directory.
func (*Registry) Discover ¶
func (r *Registry) Discover(sources []SkillSource) error
Discover scans skill sources and registers all found skills. Sources are processed in order: the first source to register a skill name wins for path/metadata, but a later source may upgrade the preload flag from false to true. This supports the common pattern of a broad `path: skills/` entry followed by narrower per-directory entries that mark specific skills as preload.
func (*Registry) List ¶
func (r *Registry) List() []SkillMetadata
List returns metadata for all registered skills, sorted by name.
func (*Registry) ListForDir ¶
func (r *Registry) ListForDir(dir string) []SkillMetadata
ListForDir returns metadata for skills whose virtual path is under the given directory. If dir is empty, returns all skills. Results are sorted by name.
Matching uses the virtual path (i.e. honoring MountAs), which is what the workflow filter and consumers see. Inline skills are skipped.
func (*Registry) Load ¶
Load returns the full skill by name, reading instructions from disk on demand.
func (*Registry) PreloadedSkills ¶
PreloadedSkills returns fully loaded skills marked with preload: true.
func (*Registry) ReadResource ¶
ReadResource reads a file from within a skill's directory. Returns error if the path escapes the skill directory (path traversal prevention).
type Skill ¶
type Skill struct {
SkillMetadata
Instructions string `json:"instructions"` // Markdown body from SKILL.md
// Path is the consumer-facing skill directory. For sources without
// MountAs this is the real on-disk path. For sources with MountAs it
// is the *virtual* path (MountAs prefix + relative subpath under the
// source dir) — workflow glob filters and ListForDir match against
// this. To read files from the skill, always go through
// Registry.ReadResource; do not treat Path as a filesystem path.
Path string `json:"path"`
}
Skill holds a fully loaded skill — metadata + instructions + path. This is the Phase 2 data — loaded on activation.
func ParseSkillFile ¶
ParseSkillFile parses a SKILL.md file at the given path into a Skill. It extracts YAML frontmatter and markdown body.
type SkillMetadata ¶
type SkillMetadata struct {
Name string `yaml:"name" json:"name"`
Description string `yaml:"description" json:"description"`
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"`
AllowedTools []string `yaml:"allowed-tools,omitempty" json:"allowed_tools,omitempty"`
}
SkillMetadata holds the YAML frontmatter from a SKILL.md file. This is the Phase 1 data — loaded at discovery time (~50 tokens per skill).
func ParseSkillContent ¶
func ParseSkillContent(content []byte) (*SkillMetadata, string, error)
ParseSkillContent parses SKILL.md content from bytes. It returns the parsed metadata, the markdown body, and any error.
func ParseSkillMetadata ¶
func ParseSkillMetadata(path string) (*SkillMetadata, error)
ParseSkillMetadata parses only the YAML frontmatter from a SKILL.md file. Used for Phase 1 discovery — avoids loading the full body.
type SkillRef ¶
type SkillRef struct {
Org string // e.g., "anthropic"
Name string // e.g., "pdf-processing"
Version string // e.g., "v1.0.0" (empty = latest)
}
SkillRef represents a parsed skill reference like @org/skill-name@v1.0.0.
func ParseSkillRef ¶
ParseSkillRef parses "@org/name[@version]" into a SkillRef.
type SkillSelector ¶
type SkillSelector interface {
// Select returns the names of skills that should appear in the Phase 1 index.
// The query is typically the latest user message or conversation context.
// Available contains all skills that passed directory filtering for the current state.
Select(ctx context.Context, query string, available []SkillMetadata) ([]string, error)
}
SkillSelector determines which skills from the available set should be presented to the model in the Phase 1 index. Implementations can filter, rank, or transform the available skill list.
type SkillSource ¶
type SkillSource struct {
// For directory-based skills.
// Dir is the real on-disk directory to walk for SKILL.md files. Path is a
// YAML/JSON alias accepted for legacy schemas; if both are set Dir wins.
Dir string `yaml:"dir,omitempty" json:"dir,omitempty"`
Path string `yaml:"path,omitempty" json:"path,omitempty"`
// For inline skills — Name is required and uniquely identifies the
// skill in the registry. Description and Instructions populate the
// in-memory Skill directly; no SKILL.md is read.
Name string `yaml:"name,omitempty" json:"name,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Instructions string `yaml:"instructions,omitempty" json:"instructions,omitempty"`
// MountAs, when set on a directory-based source, presents discovered
// skills to the registry, workflow filters, and Skill.Path consumers
// as if they lived under this virtual directory prefix instead of
// their real on-disk location. ReadResource always uses the real
// path — MountAs only affects display and glob matching, never IO
// or path-containment checks.
//
// Subdirectory structure under Dir is preserved: a skill at
// /foo/agentskills/billing/payments/SKILL.md discovered with
// Dir: "/foo/agentskills" and MountAs: "skills" is exposed as
// virtual path "skills/billing/payments", which means a workflow
// state with `skills: "skills/billing/*"` will match it.
//
// MountAs must be a literal directory prefix — glob metacharacters
// (* ? [) and ".." segments are rejected at Discover time. Setting
// MountAs on an inline source (Name set, Dir empty) is also rejected.
MountAs string `yaml:"mount_as,omitempty" json:"mount_as,omitempty"`
// Preload, when true, causes the skill's instructions to be loaded
// into the system prompt at session start instead of being activated
// on demand via skill__activate. Use sparingly — preloaded skills
// consume context budget every turn. Across duplicate sources Preload
// is OR-combined: a later source can upgrade preload from false to
// true, but never the reverse.
Preload bool `yaml:"preload,omitempty" json:"preload,omitempty"`
}
SkillSource describes one source of skills to register with a Registry.
A source is either:
- directory-based — set Dir (or Path as an alias). The registry walks the directory for SKILL.md files and registers each one found. MountAs and Preload apply.
- inline — set Name, Description, and Instructions. The skill is registered as if it had been read from disk. MountAs is rejected here.
Multiple SkillSources can be passed to Registry.Discover. They are processed in order; the first source to register a given skill name wins for path and metadata. Preload is OR-combined: a later source can upgrade preload from false to true but never the reverse.
func (*SkillSource) EffectiveDir ¶
func (s *SkillSource) EffectiveDir() string
EffectiveDir returns the real on-disk source directory, preferring Dir over the legacy Path alias. Returns the empty string for inline sources. This is always the *real* path; MountAs has no effect here.
type TagSelector ¶
type TagSelector struct {
// contains filtered or unexported fields
}
TagSelector pre-filters skills based on metadata tags. Skills whose Metadata map contains a "tags" key with a comma-separated list are matched against the selector's required tags. A skill is included if it has at least one tag in common with the selector's required tags. If a skill has no "tags" metadata key, it is excluded. Safe for concurrent use.
func NewTagSelector ¶
func NewTagSelector(tags []string) *TagSelector
NewTagSelector creates a TagSelector that matches skills having at least one of the specified tags. Duplicate tags are deduplicated automatically.
func (*TagSelector) Select ¶
func (s *TagSelector) Select( _ context.Context, _ string, available []SkillMetadata, ) ([]string, error)
Select returns the names of skills whose metadata["tags"] contains at least one tag matching the selector's required tags.
type ToolExecutor ¶
type ToolExecutor struct {
// contains filtered or unexported fields
}
ToolExecutor handles execution of skill__ tools by delegating to the Executor.
func NewToolExecutor ¶
func NewToolExecutor(exec *Executor) *ToolExecutor
NewToolExecutor creates a new ToolExecutor wrapping the given skills Executor.
func (*ToolExecutor) Execute ¶
func (e *ToolExecutor) Execute( ctx context.Context, tool *tools.ToolDescriptor, args json.RawMessage, ) (json.RawMessage, error)
Execute dispatches a skill tool call to the appropriate executor method.
func (*ToolExecutor) Name ¶
func (e *ToolExecutor) Name() string
Name returns the executor name used for mode matching.