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 ¶
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 ¶
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 ¶
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.
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 ¶
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 ¶
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
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 ¶
NewRegistry returns an empty registry governed by rules.
func (*Registry) Register ¶
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.
type Rules ¶
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 ¶
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 ¶
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 Parse ¶
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 ¶
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.