skill

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jun 21, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package skill loads invokable playbooks ("skills") from Markdown files. A skill is a named, described prompt body the model can invoke via the run_skill tool (or the user via "/<name>"): an "inline" skill folds its body into the turn as a tool result, a "subagent" skill runs in an isolated child loop and returns only its final answer. Project scope wins over global; only names+descriptions enter the cache-stable system-prompt index (see index.go) — bodies load on demand. Discovery scans several conventions (.ok / .agents / .agent / .claude under the project root and the home dir — see config.ConventionDirs) so skills authored for other agent tools migrate in unchanged, and follows symlinks, so a linked skill directory or flat <name>.md is picked up like a real one.

Package skill — security validation for skill bodies.

Every skill body passes through these checks at load time (hand-written skills) and at auto-generation time (evolution skills). Layer 0 checks structural completeness; Layer 1 scans for dangerous shell patterns.

Unlike evolution.Engine's validation pipeline, these checks run before any skill enters the store — malicious skills are rejected at the gate.

Index

Constants

View Source
const (
	// SkillsDirname is the directory under each root that holds skills.
	SkillsDirname = "skills"
	// SkillFile is the canonical filename inside a directory-layout skill.
	SkillFile = "SKILL.md"
)
View Source
const IndexMaxChars = 2000

IndexMaxChars caps the pinned skills-index block so it can't bloat the cache-stable system-prompt prefix; bodies never enter the prefix.

Variables

This section is empty.

Functions

func ApplyIndex

func ApplyIndex(basePrompt string, skills []Skill) string

ApplyIndex appends the skills index to basePrompt, or returns it unchanged when there are no skills. Only names + descriptions (+ a subagent tag) are listed; bodies load on demand via run_skill.

func BuiltinNames

func BuiltinNames() []string

BuiltinNames returns the built-in skill names, used by callers that wire dedicated subagent tools for the subagent built-ins.

func BuiltinSubagentTools

func BuiltinSubagentTools(store *Store, runner SubagentRunner) []tool.Tool

BuiltinSubagentTools returns top-level wrapper tools for the built-in subagent skills, named after the verb so the model picks them naturally (affordance > prompt rules). Each is skipped when its underlying skill isn't present (e.g. a user disabled it), so the tool set never advertises a phantom skill.

func IsValidName

func IsValidName(name string) bool

IsValidName reports whether name is a usable skill identifier.

func KnownTools

func KnownTools() []string

KnownTools returns the canonical set of tool names a skill may reference.

func LooksLikeToolName

func LooksLikeToolName(s string) bool

func NewInstallSkillTool

func NewInstallSkillTool(store *Store, onInstalled InstalledHook) tool.Tool

NewInstallSkillTool builds the skill-authoring tool. onInstalled may be nil.

func NewRunSkillTool

func NewRunSkillTool(store *Store, runner SubagentRunner) tool.Tool

NewRunSkillTool builds the general skill-invocation tool. runner may be nil (subagent skills then error).

func Render

func Render(sk Skill, args string) string

Render builds a skill's invocation text: a header (name, description, source) followed by the body and any arguments. Used directly when a user invokes a skill via "/<name>" (sent as a turn); the run_skill tool wraps the same text in a skill-pin sentinel (see renderInline).

func ValidateReferences

func ValidateReferences(body string, knownTools []string) error

ValidateReferences checks that the skill body only references known tool names. Unknown tool references may indicate hallucination.

func ValidateSafety

func ValidateSafety(body string) error

ValidateSafety scans the skill body for dangerous shell patterns. Returns nil when the skill appears safe.

func ValidateStructure

func ValidateStructure(body string) error

ValidateStructure checks a skill body for structural completeness. Returns nil when the skill is well-formed enough to be installed.

Types

type InstalledHook

type InstalledHook func(name, path string, scope Scope)

InstalledHook fires after install_skill writes a new file, so a host can refresh UI (e.g. a skills sidebar) without a reload. nil is fine.

type Options

type Options struct {
	HomeDir         string
	ProjectRoot     string
	CustomPaths     []string
	DisableBuiltins bool // suppress shipped built-ins (test-only knob)
}

Options configure a Store. ProjectRoot "" reads only the global + custom scopes. HomeDir "" resolves to the OS home dir (tests point it at a tmpdir).

type PathStatus

type PathStatus string

PathStatus describes a root directory's readability, surfaced by `/skill paths`.

const (
	StatusOK           PathStatus = "ok"
	StatusMissing      PathStatus = "missing"
	StatusNotDirectory PathStatus = "not-directory"
	StatusUnreadable   PathStatus = "unreadable"
)

type Root

type Root struct {
	Dir      string
	Scope    Scope
	Priority int
	Status   PathStatus
}

Root is one discovery directory with its scope, priority, and status.

type RunAs

type RunAs string

RunAs selects how an invoked skill executes. Inline folds the body into the parent turn; subagent spawns an isolated child loop and returns only the final answer (its tool calls and reasoning never enter the parent context).

const (
	RunInline   RunAs = "inline"
	RunSubagent RunAs = "subagent"
)

type Scope

type Scope string

Scope records where a skill was loaded from. Higher-priority scopes win on a name collision: project > custom > global > builtin.

const (
	ScopeProject Scope = "project"
	ScopeCustom  Scope = "custom"
	ScopeGlobal  Scope = "global"
	ScopeBuiltin Scope = "builtin"
)

type Skill

type Skill struct {
	Name        string // canonical identifier; matches the directory / filename stem
	Description string // one-liner shown in the pinned index
	Body        string // full markdown body (post-frontmatter), loaded eagerly
	Scope       Scope  // where it came from
	Path        string // absolute path to the SKILL.md / <name>.md, or "(builtin)"
	// AllowedTools, when non-empty, scopes a subagent skill's tool registry to
	// these literal tool names (from the `allowed-tools` frontmatter).
	AllowedTools []string
	RunAs        RunAs  // inline | subagent
	Model        string // optional model override for runAs=subagent (frontmatter `model:`)
}

Skill is a loaded playbook.

type Store

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

Store resolves skills across the configured roots.

func New

func New(opts Options) *Store

New builds a Store. Relative custom paths and a relative project root are made absolute; "~" in a custom path expands to the home dir.

func (*Store) Create

func (s *Store) Create(name string, scope Scope) (string, error)

Create scaffolds a new skill stub at the chosen scope. Refuses to overwrite.

func (*Store) CreateWithContent

func (s *Store) CreateWithContent(name string, scope Scope, content string) (string, error)

CreateWithContent writes caller-supplied file contents as a new flat <name>.md skill, refusing to clobber an existing flat or directory-layout skill of the same name. Returns the written path.

func (*Store) HasProjectScope

func (s *Store) HasProjectScope() bool

HasProjectScope reports whether the store was configured with a project root.

func (*Store) List

func (s *Store) List() []Skill

List returns every discoverable skill, deduped by name (first/highest-priority root wins) with built-ins folded in last, sorted by name so the prefix index stays stable and cacheable.

func (*Store) Read

func (s *Store) Read(name string) (Skill, bool)

Read resolves one skill by name, scanning the roots in priority order then the built-ins. ok is false when no such skill exists or the file is unreadable.

func (*Store) Roots

func (s *Store) Roots() []Root

Roots exposes the discovery directories with their status for `/skill paths`.

type SubagentRunner

type SubagentRunner func(ctx context.Context, sk Skill, task string) (string, error)

SubagentRunner runs a runAs=subagent skill: it spawns an isolated child loop with the skill body as system prompt and `task` as its only input, returning the final answer. boot wires this over the agent's sub-agent machinery; nil means subagent skills are unavailable in this session (they error rather than silently inlining, which would lose the isolation the author asked for).

Jump to

Keyboard shortcuts

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