Documentation
¶
Overview ¶
Package skills loads SKILL.md bundles from .agents/skills/<name>/ and exposes them as an ADK Toolset the agent can invoke.
The schema mirrors Anthropic's published SKILL.md frontmatter so users can drop existing skill bundles directly into a project.
Bodies load lazily on invocation — we keep cold-start fast by skipping skill.WithCompletePreloadSource.
Index ¶
Constants ¶
const SkillDirName = "skills"
SkillDirName is the project-local directory holding skill bundles.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Option ¶
type Option func(*loadOptions)
Option configures a Load / LoadAll call. All options are optional; the zero-options call matches the pre-#322 loader behavior exactly.
func WithContentRoots ¶ added in v2.9.0
WithContentRoots supplies operator-declared external directories whose <root>/skills/ subtrees compose into the skill overlay just after the project source — so precedence on a name collision is project > content_roots (in listed order) > home-agents > user. Unlike instruction @include, skills are read from a directory FS (not @include'd), so no scope-confinement relaxation is involved. A root with no skills/ subdir is silently skipped. Empty is legal and equals "no external skill sources."
func WithHomeAgentsSkillsDir ¶ added in v2.8.0
WithHomeAgentsSkillsDir supplies an extra user-scope skills root — typically $HOME/.agents/ (LoadAll appends the "skills" suffix itself, same as it does for the positional args). This source layers between the project-scoped source and the ~/.core-agent/ fallback, so precedence is project > home-agents > core-home. Empty is legal and equals "no home-agents source."
func WithInterpolator ¶
WithInterpolator supplies a string transform applied to every .md file loaded from a skill directory — SKILL.md and referenced files under references/. Used to substitute ${env:VAR} references declared in .agents/env.yaml (see pkg/agentenv). Passing nil is legal and equals "no interpolation."
type Skills ¶
type Skills struct {
Toolset adktool.Toolset
Infos []Info
// contains filtered or unexported fields
}
Skills bundles the discovered skills' toolset (for agent.WithToolsets) alongside the metadata list.
func Load ¶
func Load(ctx context.Context, agentsDir string, gate *permissions.Gate, opts ...Option) (Skills, error)
Load discovers skills under agentsDir/skills/ only. A missing directory (or empty agentsDir) yields a zero Skills with no error.
Deprecated since v2.1: use LoadAll to also pick up user-global skills from userCoreHome/skills/. Load remains as a one-source wrapper around LoadAll for callers that explicitly don't want the global path.
gate (optional) wraps the resulting toolset so skill invocations go through the permission system. Pass nil to skip gating.
func LoadAll ¶
func LoadAll(ctx context.Context, projectAgentsDir, userCoreHome string, gate *permissions.Gate, opts ...Option) (Skills, error)
LoadAll discovers skills from up to three sources and merges them into a single toolset:
- projectAgentsDir/skills/ — project-scoped skills, checked in to the repo (or wherever .agents/ lives). Takes precedence on name collision.
- WithHomeAgentsSkillsDir/skills/ — portable user-scope skills (typically $HOME/.agents/skills/), layered under project scope but above the ~/.core-agent/ fallback. Off unless the option is passed. See the note at WithHomeAgentsSkillsDir.
- userCoreHome/skills/ — user-global skills (typically ~/.core-agent/skills/). Bottom layer.
Any path may be "" to skip that source. Missing directories (vs missing parent) are silently treated as empty — most operators won't have any populated.
Sources are merged via nested overlayFS so the underlying skilltoolset sees a single virtual root; higher-precedence entries win on name collision. Every source shares the same sanitizingFS wrapper so extended-frontmatter properties get filtered the same way.
gate (optional) wraps the resulting toolset so skill invocations go through the permission system. Pass nil to skip gating.
func (Skills) Scoped ¶ added in v2.9.0
Scoped returns a Skills exposing only the named skills — the mechanism declarative subagents use to narrow the parent's skill surface (docs/declarative-subagents-design.md). It builds a fresh skill toolset over a name-filtered view of the same composed source the full toolset was built from, so no filesystem re-walk and no second LoadAll happen; the toolset carries the same permission gate the parent's did.
The skill toolset is a three-tool facade (list_skills / load_skill / load_skill_resource) over a skill.Source — individual skills are *data*, not tools — so scoping is a Source filter, not a tool-name filter: the scoped facade's list_skills enumerates only the allowed skills and its load_skill can only reach them.
allow is the exact set of skill names to expose. An empty (but non-nil) allow grants none of the skill dimension and returns a zero Skills (Empty() == true), so the caller adds no skill toolset at all. Callers that want the full surface must NOT call Scoped — they reuse the parent Skills directly (nil-vs-empty "inherit vs grant-none" lives in the caller). Every name in allow must be a skill that was actually loaded; an unknown name is a config error (fail loud rather than silently exposing an empty scope).