skillreg

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Aug 19, 2026 License: AGPL-3.0 Imports: 7 Imported by: 0

Documentation

Overview

Package skillreg loads filesystem-based skills from disk and exposes them to the model via a jungi built-in tool.

A skill is a directory containing a SKILL.md file with YAML frontmatter:

---
name: example
description: One-line summary the model uses to decide when to invoke.
---
# Body of the skill — instructions the model follows once invoked.

Skills implement progressive disclosure: only the name and description are injected into the system prompt at startup. The body is loaded into the model's context only when the model invokes the skill tool by name.

The harness reads SKILL.md files in-process (bypassing the model sandbox). This is safe because the registry is built once at startup with the allowlist fixed; the model can only request skills that were present then.

Storage, merge, frontmatter splitting, and directory loading are shared with agentreg and promptreg via internal/core/mdreg; this package supplies only the Skill value type, its YAML frontmatter shape, and a SKILL.md subdir directory layout.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func LoadFromFS

func LoadFromFS(fsys fs.FS, dir string) (*Registry, []LoadWarning, error)

LoadFromFS reads skills from an fs.FS-rooted tree. dir is the directory inside the FS whose immediate children are treated as skill directories, each containing a SKILL.md. This is the embed.FS-compatible counterpart to LoadRegistry; both share frontmatter parsing and warning semantics.

Used by jungi-bundled skill packages (e.g. internal/plan) to register their built-in skills via //go:embed without writing to ~/.config.

func LoadRegistry

func LoadRegistry(dir string) (*Registry, []LoadWarning, error)

LoadRegistry scans dir for skill subdirectories and returns a Registry plus any warnings about skipped files.

Each immediate child of dir is treated as a skill directory. If it contains a readable SKILL.md with valid frontmatter, the skill is registered under the name given in the frontmatter (NOT the directory name). Invalid files — missing fences, malformed YAML, missing required fields, invalid names, or duplicate names — produce a LoadWarning and are skipped without aborting the load. Symlinks are skipped with a warning regardless of their target.

A non-existent dir is not an error: the returned Registry is empty and no warnings are generated. Other I/O errors (permissions, etc.) are returned.

func MergeRegistries

func MergeRegistries(regs ...*Registry) (*Registry, []LoadWarning)

MergeRegistries returns a new Registry combining the skills from each input in order, with first-wins semantics on name collision: a later registry's skill is dropped (and warned about) if an earlier registry already provided one with the same name.

The intended usage is embedded skills first, then project-level skills, then user-level skills, so that bundled skills (which power the jungi slash commands) cannot be shadowed by a user file that happens to share a name. Warnings let main.go surface the conflict.

nil registries are tolerated and treated as empty — callers can pass the result of LoadRegistry without nil-checking when registry load failed and the package returned an empty fallback.

func MetadataXML

func MetadataXML(skills []Skill) string

MetadataXML returns the <available-skills> XML block listing each skill's name and description. The result is intended to be spliced into the system prompt before </system> so the model can see the catalog without paying the token cost of every skill body.

An empty input yields an empty string so callers can unconditionally concatenate without producing dangling tags.

Types

type LoadWarning

type LoadWarning = mdreg.Warning

LoadWarning describes a SKILL.md file that was skipped during registry construction. Warnings are returned alongside the registry so the caller can surface them through whatever logging mechanism it uses, rather than the skill package taking a logger dependency.

type Registry

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

Registry holds the set of skills available for the lifetime of a session. It is built once at startup; subsequent filesystem changes are ignored.

func EmptyRegistry

func EmptyRegistry() *Registry

EmptyRegistry returns a Registry with no skills. It is used when the skills directory is missing or unreadable so callers can avoid nil checks.

func MustLoadEmbedded

func MustLoadEmbedded(fsys fs.FS, dir string) *Registry

MustLoadEmbedded loads skills from an embedded fs.FS via LoadFromFS and panics on any load error or warning. Meant for jungi-bundled skill packages (e.g. internal/skills) whose //go:embed'd files are static: any failure to parse them is a build defect, not a runtime condition.

func (*Registry) Dir

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

Dir returns the filesystem directory path for the named skill, or an empty string if the skill is not registered or was loaded from an embedded FS.

func (*Registry) List

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

List returns the registered skills in load order. The caller may use the slice for prompt injection; it is freshly allocated and safe to mutate.

func (*Registry) Load

func (r *Registry) Load(name, arguments string) (string, bool)

Load returns the body of the named skill with $ARGUMENTS substituted. The bool result is false if the name is not registered, letting the caller distinguish "skill missing" from "skill returned empty body".

Substitution is a literal string replacement; arguments is inserted as-is without quoting or escaping. An empty arguments value collapses the placeholder to nothing, matching Claude Code's no-arg behavior.

type Skill

type Skill struct {
	Name        string
	Description string
	Body        string
	Dir         string
}

Skill is one entry in the registry: metadata for prompt injection plus the raw SKILL.md body that will be returned to the model on invocation.

Body still contains the literal $ARGUMENTS placeholder; substitution happens at Load time so a single Skill can satisfy multiple invocations.

Dir is the absolute path to the skill's directory on the real filesystem. It is empty for skills loaded from an embedded FS (embed.FS), since those have no real directory. Tools that need to read or execute files from the skill directory should check for an empty Dir and return an appropriate error.

Source Files

  • prompt.go
  • skill.go

Jump to

Keyboard shortcuts

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