skill

package
v0.36.1 Latest Latest
Warning

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

Go to latest
Published: Sep 14, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package skill implements ogcode's lazy-loaded instruction system.

A skill is a directory holding a SKILL.md file: YAML frontmatter that names and describes it, and a markdown body carrying the instructions themselves. The agent never sees a body unless it asks for one — its system prompt lists only names and descriptions, and the "skill" tool pulls one body into context on demand. Listing bodies instead would cost the full token weight of every skill the agent never uses, re-sent on every step of every turn.

Index

Constants

View Source
const (
	// Filename is the file that marks a directory as a skill.
	Filename = "SKILL.md"

	// MaxNameLen bounds the frontmatter name, in characters. The name is a
	// lookup key the model types back verbatim, so it stays short and
	// typo-resistant.
	MaxNameLen = 64
	// MaxDescriptionLen bounds the frontmatter description, in characters.
	// Descriptions are carried in the system prompt for every skill on every
	// step, so a runaway one is clamped rather than paid for.
	MaxDescriptionLen = 1024
)

Variables

This section is empty.

Functions

func GlobalRoots

func GlobalRoots() []string

GlobalRoots returns the user-scoped skill directories, ordered so that later entries win. "~/.config/ogcode/skills" is ogcode's own, beside the config.json it already reads there; "~/.ogcode/skills" sits with the rest of ogcode's home state; the ".agents" and ".claude" pair mirror the project locations so a user's existing library is found without being moved.

func ProjectRoots

func ProjectRoots(dir string) []string

ProjectRoots returns the project-scoped skill directories in effect for dir, walking up to the repo root so a skill still resolves when ogcode is launched from a subdirectory. Roots are returned outermost-first, so a caller registering them in order lets the innermost — the one closest to the work — take precedence.

func SiblingFiles

func SiblingFiles(dir string, limit int) ([]string, bool)

SiblingFiles returns up to limit files shipped alongside a skill's SKILL.md, as paths relative to the skill directory. The skill body routinely points at scripts and references by relative path; listing what is actually there means the agent reads the file that exists instead of guessing at a name.

The second return reports whether the listing was cut short, so the caller can say so rather than presenting a sample as the whole set.

Types

type Action

type Action string

Action is what a skill's configured permission rule allows.

const (
	// Allow: listed in the prompt, loads without interruption. The default for
	// any skill no rule matches.
	Allow Action = "allow"
	// Deny: hidden from the prompt entirely, and refused if called anyway.
	Deny Action = "deny"
	// Ask: listed in the prompt; the user approves the load at call time.
	Ask Action = "ask"
)

type Config

type Config struct {
	// Paths are extra skill directories. A path may point at a library of skill
	// directories or straight at one skill directory. Relative paths resolve
	// against the project directory.
	Paths []string
	// URLs are index.json manifests to fetch skills from. Empty — the default —
	// means no network work is ever done.
	URLs []string
	// Permissions maps a name pattern to allow, deny, or ask.
	Permissions map[string]string
}

Config is the "skills" section of ogcode.json.

func (Config) Enabled

func (c Config) Enabled() bool

Enabled reports whether any configured source could contribute skills beyond the standard directories. It exists so a caller can tell an entirely default configuration from a customized one.

type Loader

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

Loader resolves the skills available for a project directory.

Directory scans run per call, cheaply and always current: a skill the user writes mid-session is picked up on the next turn, the same way an edited AGENT.md is. Remote URLs are resolved once per process and cached on disk, because a network round trip inside the turn's critical path is not something to repeat.

func NewLoader

func NewLoader(cfg Config) *Loader

NewLoader returns a Loader for cfg. Remote skills are cached under ~/.ogcode/cache/skills; when the home directory cannot be determined, remote URLs are skipped and everything else still works.

func (*Loader) Load

func (l *Loader) Load(dir string) *Registry

Load returns the skills in effect for a project directory.

Sources are registered lowest-precedence first, so a later one shadows an earlier one of the same name: built-in, then remote, then the user's global directories, then configured paths, then the project's own — innermost last. A skill the user wrote in their project always wins.

Nothing here fails the caller. A malformed SKILL.md, an unreadable directory or an unreachable URL costs that one source and is logged; the rest of the skills still load, because a broken skill file should not take the working ones down with it.

func (*Loader) SetPermissions added in v0.34.0

func (l *Loader) SetPermissions(perms map[string]string)

SetPermissions replaces the loader's skill permission rules. The next Load — the next turn of any session — resolves both the prompt listing (Visible) and the skill tool's deny check against the new rules, so a skill switched off in the UI drops out of the prompt without a restart. The map is copied, so the caller may keep mutating its own.

type Manifest

type Manifest struct {
	Version string          `json:"version"`
	Skills  []ManifestSkill `json:"skills"`
}

Manifest is the index.json a skills URL serves.

{
  "version": "2026-08-01",
  "skills": [
    {"name": "git-release", "files": ["SKILL.md", "scripts/release.sh"]}
  ]
}

Version identifies the contents: a cached copy of a version is reused as-is, so publishing a change means publishing a new version string.

type ManifestSkill

type ManifestSkill struct {
	Name        string   `json:"name"`
	Description string   `json:"description"`
	Files       []string `json:"files"`
}

ManifestSkill describes one skill in a Manifest. Name and Description are advisory — the downloaded SKILL.md is parsed like any other, and its frontmatter is what ogcode actually uses, so a manifest cannot describe a skill as one thing and ship another.

type Registry

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

Registry is the set of skills resolved for one project directory, together with the permission rules that apply to them.

It is built fresh by Loader.Load and never mutated afterwards, so the prompt listing and the skill tool always read the same snapshot.

func NewRegistry

func NewRegistry(rules Rules) *Registry

NewRegistry returns an empty registry governed by rules.

func (*Registry) Action

func (r *Registry) Action(name string) Action

Action returns the configured permission action for a name.

func (*Registry) Get

func (r *Registry) Get(name string) (Skill, bool)

Get returns the skill by name.

func (*Registry) Len

func (r *Registry) Len() int

Len reports how many skills are registered, denied ones included.

func (*Registry) List

func (r *Registry) List() []Skill

List returns every registered skill, sorted by name.

func (*Registry) Register

func (r *Registry) Register(s Skill)

Register adds a skill, replacing any skill already registered under the same name. Sources are added least-specific first — built-in, then remote, then global, then config paths, then the project — so the closest one to the user wins, and a project skill can shadow a built-in of the same name.

func (*Registry) Visible

func (r *Registry) Visible() []Skill

Visible returns the skills the agent may be told about, sorted by name. Denied skills are withheld: naming one in the prompt would advertise a call that is refused the moment it is made.

type Rules

type Rules map[string]string

Rules maps a name pattern to an action, as written in ogcode.json:

"skills": { "permissions": { "*": "allow", "internal-*": "deny" } }

Patterns use shell globbing, so "internal-*" covers internal-docs and internal-deploy alike.

func (Rules) Evaluate

func (r Rules) Evaluate(name string) Action

Evaluate returns the action configured for a skill name.

The most specific matching pattern wins, not the first: these rules arrive as a JSON object, Go map iteration is randomized, and "first match" over an unordered map would give the same config different meanings on different runs. Specificity is the ordering the data can actually support — an exact name beats any glob, and among globs the one with more literal characters beats the one with fewer, so "*" is always the last resort.

A name no pattern matches is allowed: skills are opt-in files the user put in their own project, and the permission layer exists to carve exceptions out of that, not to gate every skill behind a rule.

An unrecognized action string is treated as Ask rather than ignored. A typo in a rule the user wrote to restrict something must not silently widen access back to allow.

func (Rules) Invalid

func (r Rules) Invalid() []string

Invalid returns the rules ogcode cannot honor as written, so the caller can report them. A rule the user cannot see failing is a rule they will assume is working.

Two things make a rule unusable: an action string that is not allow, deny or ask — those are evaluated as Ask — and a pattern that is not a valid glob, which matches nothing at all, so a deny written that way protects nothing.

type Skill

type Skill struct {
	Name        string
	Description string
	// Dir is the absolute path to the skill's directory. Relative paths inside
	// the body (scripts/, references/) resolve against it, which is why the tool
	// hands it to the model along with the body.
	Dir string
	// Path is the absolute path to the SKILL.md itself. Empty for embedded
	// skills, which have no file.
	Path string
	// Content is the markdown body — everything after the frontmatter.
	Content string
	Source  Source
}

Skill is one parsed SKILL.md.

func Embedded

func Embedded() ([]Skill, []error)

Embedded returns the built-in skills, parsed once per process.

func Load

func Load(path string) (Skill, error)

Load reads and parses the SKILL.md at path.

func Parse

func Parse(dir, path string, data []byte) (Skill, error)

Parse reads a SKILL.md's bytes and returns the skill it defines. dir is the directory holding the file; the frontmatter name must match its base name, so that the name in the prompt, the name the model passes to the tool, and the directory on disk are always the same string.

func ScanRoot

func ScanRoot(root string, source Source) ([]Skill, []error)

ScanRoot reads one skill root and returns the skills it holds, sorted by name, alongside a diagnostic per file that failed to parse.

A root is normally a directory of skill directories, each holding a SKILL.md. A root that holds a SKILL.md directly is taken as a single skill, so a configured path may point either at a library or at one skill.

A missing root is not an error — most of the locations ogcode looks in do not exist in any given project.

type Source

type Source string

Source labels where a skill was found, for diagnostics and for the tool's output. It has no effect on lookup.

const (
	SourceProject  Source = "project"
	SourceGlobal   Source = "global"
	SourceConfig   Source = "config"
	SourceRemote   Source = "remote"
	SourceEmbedded Source = "built-in"
)

Jump to

Keyboard shortcuts

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