Documentation
¶
Overview ¶
Package skills implements discovery of Agent Skills. A skill is a folder containing a SKILL.md whose YAML frontmatter (name, description) is parsed at startup; the body is read lazily by the model via the Read tool.
The on-disk format intentionally matches the contract shared by the standard, so a folder authored for any of them drops in unchanged.
Index ¶
- func CleanupDynamic() error
- func ExpandShorthand(input, repository string) string
- func LoadSkillMetadata(skillDir, dirName string, scope agentdomain.SkillScope, pluginName string) (*agentdomain.Skill, *agentdomain.SkillLoadError)
- func SeedBuiltins(destDir string, overwrite bool) error
- func SkillTreeURL(repository, skill string) string
- func Uninstall(name, destBase string) (string, error)
- type CatalogClient
- func (c *CatalogClient) DownloadSkill(ctx context.Context, name string) (string, error)
- func (c *CatalogClient) Index(ctx context.Context) []catalogEntry
- func (c *CatalogClient) Lookup(ctx context.Context, name string) (*catalogEntry, bool)
- func (c *CatalogClient) Release() (release, updated string)
- func (c *CatalogClient) ResolveInstallURL(ctx context.Context, input string) (string, bool)
- func (c *CatalogClient) Search(ctx context.Context, query string, limit int) []agentdomain.Skill
- type GitHubLocation
- type Installer
- type Service
- func (s *Service) CleanupDynamic(_ context.Context) error
- func (s *Service) Discover(ctx context.Context, name string) (agentdomain.Skill, bool)
- func (s *Service) Errors() []agentdomain.SkillLoadError
- func (s *Service) Get(name string) (agentdomain.Skill, bool)
- func (s *Service) List() []agentdomain.Skill
- func (s *Service) Load(ctx context.Context) error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CleanupDynamic ¶
func CleanupDynamic() error
CleanupDynamic removes all dynamically downloaded skills from the temporary skills directory. Called after the session ends.
func ExpandShorthand ¶
ExpandShorthand turns shorthand install targets into full GitHub tree URLs, resolving them against the configured "<owner>/<repo>" skills repository (config.DefaultSkillsRepository when empty). For the default repository:
- "<skill>" → https://github.com/inference-gateway/skills/tree/main/skills/<skill>
- "<org>/<skill>" → https://github.com/<org>/skills/tree/main/skills/<skill>
- any http(s):// URL → returned unchanged
The two-segment form keeps the repository *name* from the configured value and swaps only the owner, so a renamed fork stays reachable as "<org>/<skill>".
Anything else (3+ slash-separated segments, empty segments, etc.) is returned unchanged so ParseGitHubTreeURL produces its existing error.
func LoadSkillMetadata ¶
func LoadSkillMetadata(skillDir, dirName string, scope agentdomain.SkillScope, pluginName string) (*agentdomain.Skill, *agentdomain.SkillLoadError)
LoadSkillMetadata reads <skillDir>/SKILL.md, parses frontmatter, validates the fields, and returns the populated agentdomain.Skill. Returns (nil, nil) when the directory has no SKILL.md, (nil, err) when SKILL.md is invalid. pluginName is set only for plugin-scoped skills.
func SeedBuiltins ¶
SeedBuiltins writes each embedded built-in skill under destDir, mirroring the embedded tree (destDir/<name>/SKILL.md, plus any helper files). A file is written only when it is absent, unless overwrite is set - so a user's edits to a seeded skill survive a re-run of `infer init` (seed-if-absent). destDir is the user-scope skills directory (~/.infer/skills), the same directory the loader reads user skills from.
func SkillTreeURL ¶
SkillTreeURL returns the GitHub tree URL of skill inside the given "<owner>/<repo>" skills repository. It is the single place the skills-repo layout (<ref>/<subdir>/<skill>) is encoded.
func Uninstall ¶
Uninstall removes the skill folder named `name` from `destBase`. The name must match the on-disk skill-name regex (lowercase letters, digits and hyphens) so callers can't smuggle in path-traversal payloads like `../`. Returns an error if the folder doesn't exist or isn't a directory.
Types ¶
type CatalogClient ¶
type CatalogClient struct {
// contains filtered or unexported fields
}
CatalogClient fetches skill metadata from the centralized skills registry. It implements progressive discovery: only the index (name + description) is fetched up front; the full skill body is downloaded only on activation.
func NewCatalogClient ¶
func NewCatalogClient(cfg *config.Config) *CatalogClient
NewCatalogClient returns a CatalogClient for the configured skills repository. Both the index and the skill bodies come from that one repo, so agent.skills.repository is the only knob needed to point the CLI at a fork.
func (*CatalogClient) DownloadSkill ¶
DownloadSkill fetches the full skill folder from the catalog and writes it to the dynamic skills directory. Returns the path to the downloaded SKILL.md.
func (*CatalogClient) Index ¶
func (c *CatalogClient) Index(ctx context.Context) []catalogEntry
Index fetches the catalog index (name + description for every published skill) and caches it for the process lifetime. Returns nil on any failure - the catalog is best-effort, never fatal. No body download.
func (*CatalogClient) Lookup ¶
func (c *CatalogClient) Lookup(ctx context.Context, name string) (*catalogEntry, bool)
Lookup queries the catalog index for a skill with the given name. Returns the entry metadata and true on success, or false when the skill is not found.
func (*CatalogClient) Release ¶
func (c *CatalogClient) Release() (release, updated string)
Release returns the catalog's published release version and update timestamp as of the last Index fetch. Both are empty when the catalog has not been fetched or does not publish them. Individual skills carry no version of their own - the catalog is versioned as a whole.
func (*CatalogClient) ResolveInstallURL ¶
ResolveInstallURL maps a bare catalog skill name to the GitHub tree URL in its catalog `source`, so `skills install <name>` fetches the body from wherever the skill actually lives instead of the hardcoded <repo>/skills/<name> convention. ok is false for inputs that already carry their own location - a full URL or an "<org>/<skill>" shorthand, both of which contain "/" or ":" - and for names the catalog does not list, leaving the caller's shorthand expansion in charge.
func (*CatalogClient) Search ¶
func (c *CatalogClient) Search(ctx context.Context, query string, limit int) []agentdomain.Skill
Search matches query against the catalog, best match first, capped at limit. An empty query returns the head of the index so the command doubles as a browse.
Ranking, in order: names fuzzy-matched by score, then entries whose description literally contains the query. Fuzzy runs over names ONLY - a subsequence match against a paragraph of prose is meaningless ("rust" matches r..u..s..t in most English sentences), which makes description matching substring-only.
Matching is local over the cached index because catalog.json is a single static file with no server-side query support - see NewCatalogClient.
type GitHubLocation ¶
GitHubLocation identifies a directory inside a public GitHub repository, parsed out of a /tree/<ref>/<path> URL.
func ParseGitHubTreeURL ¶
func ParseGitHubTreeURL(rawURL string) (*GitHubLocation, error)
ParseGitHubTreeURL accepts URLs of the form
https://github.com/<owner>/<repo>/tree/<ref>/<path-to-skill>
Refs containing a literal "/" (e.g. "feature/foo" branches) are not supported; pass the URL of a tag or single-segment branch instead.
type Installer ¶
type Installer struct {
Client *http.Client
APIBase string
RawBase string
Token string
// Repository is the "<owner>/<repo>" skills repository shorthand install
// targets resolve against. Empty means config.DefaultSkillsRepository.
Repository string
}
Installer downloads a skill folder from a GitHub repo into a local destination directory. When Token is non-empty its requests are authenticated, which raises the GitHub API rate limit from 60 to 5,000 requests/hour and allows access to private repositories the token can see.
func NewInstaller ¶
NewInstaller returns an Installer pointed at github.com with a 30s HTTP timeout, resolving shorthand targets against the given "<owner>/<repo>" skills repository (empty = config.DefaultSkillsRepository). The GitHub token is read from the environment (GITHUB_TOKEN, then GH_TOKEN); when neither is set requests are made unauthenticated. Tests substitute APIBase / RawBase to point at httptest.Server.
func (*Installer) InstallFromGitHub ¶
func (i *Installer) InstallFromGitHub(ctx context.Context, rawURL, destBase string, overwrite bool) (string, error)
InstallFromGitHub downloads the skill folder at rawURL into <destBase>/<dirname>/, where dirname is the last path segment of the repo URL. Existing folders are rejected unless overwrite is true.
The downloaded folder is post-validated with LoadSkillMetadata - if frontmatter fails the spec checks, the folder is removed and the validation error is returned. There is never a half-installed state.
Returns the absolute path of the installed skill on success.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service discovers SKILL.md files and exposes the parsed metadata. Loading is gated by config.AgentSkillsConfig - when disabled the scan is skipped entirely so there is zero token / IO cost.
func (*Service) CleanupDynamic ¶
CleanupDynamic removes dynamically downloaded skills from disk. When cleanup is enabled in config, this removes all skills that were fetched from the catalog during this session. No-op when discovery is disabled or cleanup is explicitly turned off.
func (*Service) Discover ¶
Discover resolves a skill by name, downloading its body from the centralized catalog when the loaded entry is a metadata-only catalog placeholder (empty Path, seeded by Load). Any skill already backed by a file on disk - local or previously downloaded - is returned as-is, so this is the safe replacement for Get on the activation path. Returns false when the name is unknown, or when it is only resolvable via the catalog and discovery is disabled.
func (*Service) Errors ¶
func (s *Service) Errors() []agentdomain.SkillLoadError
Errors returns a defensive copy of validation failures from the last Load.
func (*Service) Get ¶
func (s *Service) Get(name string) (agentdomain.Skill, bool)
Get returns the loaded skill with the given name. Lookup is exact (names are validated to the lowercase `[a-z0-9-]+` charset at load time).
func (*Service) List ¶
func (s *Service) List() []agentdomain.Skill
List returns a defensive copy of the loaded skills.