agentskills

package module
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Mar 5, 2026 License: MIT Imports: 12 Imported by: 0

README

Agent Skills Runtime for Go

Go Report Card lint test

  • Runtime + filesystem skill runtime implementation for "AgentSkills" in Go.
  • An "AgentSkill" is a directory/location containing a SKILL.md file with YAML frontmatter. Full specification at the official site.
  • The tools are implemented using the specification and data types provided in llmtools-go repo.

Table of contents

Features at a glance

  • A runtime that hosts a catalog of skills and manages session-scoped active skills.

  • Progressive disclosure:

    • the catalog exposes metadata only
    • a session "loads" a skill to disclose its full SKILL.md body into the prompt
  • A provider abstraction (spec.SkillProvider) and a hardened reference provider:

    • providers/fsskillprovider: skills backed by a local filesystem directory
  • Tool wiring via llmtools-go:

    • skills.load, skills.unload, skills.readresource, skills.runscript
    • A runtime prompt API Runtime.SkillsPromptXML(...) which can emit:
      • <availableSkills>...</availableSkills>
      • <activeSkills>...</activeSkills>
      • or a wrapper <skillsPrompt>...</skillsPrompt> when both are requested.

Filesystem skill provider

Quickstart
  • Create a runtime with the filesystem provider

    fsp, _ := fsskillprovider.New() // RunScript disabled by default
    
    rt, _ := agentskills.New(
      agentskills.WithProvider(fsp),
    )
    
  • Add a skill to the catalog

    rec, err := rt.AddSkill(ctx, spec.SkillDef{
      Type:     "fs",
      Name:     "hello-skill",
      // This is base dir containing SKILL.md for "hello-skill".
      // Typically, base dir name and skill name should match.
      Location: "/abs/path/to/hello-skill",
    })
    _ = rec
    _ = err
    
  • Build the “available skills” prompt XML (metadata only)

    xml, _ := rt.SkillsPromptXML(ctx, &agentskills.SkillFilter{
      Activity: spec.SkillActivityInactive, // with no SessionID: treated as "all skills"
    })
    // <availableSkills> ... </availableSkills>
    
  • Create a session with initial active skills (progressive disclosure)

    sid, active, err := rt.NewSession(ctx,
      agentskills.WithSessionActiveSkills([]spec.SkillDef{rec.Def}),
    )
    _ = sid
    _ = active // []spec.SkillDef
    _ = err
    
  • Build “active skills” prompt XML

    activeXML, _ := rt.SkillsPromptXML(ctx, &agentskills.SkillFilter{
      SessionID: sid,
      Activity:  spec.SkillActivityActive,
    })
    // <activeSkills>
    //   <skill name="hello-skill"><![CDATA[ ... SKILL.md body ... ]]></skill>
    // </activeSkills>
    
  • Build a combined prompt (active + available/inactive) for a session

    xml, _ := rt.SkillsPromptXML(ctx, &agentskills.SkillFilter{
      SessionID: sid,
      Activity:  spec.SkillActivityAny,
    })
    // <skillsPrompt>
    //   <availableSkills>...</availableSkills>
    //   <activeSkills>...</activeSkills>
    // </skillsPrompt>
    
  • Create a tool registry for an LLM session

    reg, _ := rt.NewSessionRegistry(ctx, sid)
    // Registry includes: skills.load / skills.unload / skills.readresource / skills.runscript
    _ = reg
    
Security model notes (FS provider)

The FS provider is intentionally thin and delegates most sandboxing/hardening to llmtools-go:

  • skills.readresource uses llmtools-go/fstool and is scoped to the skill root via:
    • allowedRoots = [skillRoot]
    • workBaseDir = skillRoot
  • skills.runscript uses llmtools-go/exectool and is scoped similarly
  • RunScript is disabled by default; enable explicitly via fsskillprovider.WithRunScripts(true)

End to end examples

Working end-to-end examples live in:

  • fs test
    • Demonstrates: create runtime, add skill, list/prompt, create session with initial actives, run tools.

Development

  • Formatting follows gofumpt and golines via golangci-lint. Rules are in .golangci.yml.
  • Useful scripts are defined in taskfile.yml; requires Task.
  • Bug reports and PRs are welcome:
    • Keep the public API small and intentional.
    • Avoid leaking provider‑specific types through the public surface; put them under internal/.
    • Please run tests and linters before sending a PR.

License

Copyright (c) 2026 - Present - Pankaj Pipada

All source code in this repository, unless otherwise noted, is licensed under the MIT License. See LICENSE for details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Option

type Option func(*runtimeOptions) error

func WithLogger

func WithLogger(l *slog.Logger) Option

func WithMaxActivePerSession

func WithMaxActivePerSession(n int) Option

func WithMaxSessions

func WithMaxSessions(maxSessions int) Option

func WithProvider

func WithProvider(p spec.SkillProvider) Option

func WithProvidersByType added in v0.7.0

func WithProvidersByType(m map[string]spec.SkillProvider) Option

func WithSessionTTL

func WithSessionTTL(ttl time.Duration) Option

type Runtime

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

func New

func New(opts ...Option) (*Runtime, error)

func (*Runtime) AddSkill

func (r *Runtime) AddSkill(ctx context.Context, def spec.SkillDef) (spec.SkillRecord, error)

AddSkill indexes and registers a skill into the runtime-owned catalog.

IMPORTANT CONTRACT:

  • This is a HOST/LIFECYCLE API.
  • It accepts and returns only the user-provided skill definition (spec.SkillDef).
  • Provider canonicalization/cleanup is internal only and MUST NOT be exposed via this API.

func (*Runtime) CloseSession

func (r *Runtime) CloseSession(ctx context.Context, sid spec.SessionID) error

func (*Runtime) ListSkills

func (r *Runtime) ListSkills(ctx context.Context, filter *SkillListFilter) ([]spec.SkillRecord, error)

ListSkills lists skills for HOST/LIFECYCLE usage.

IMPORTANT CONTRACT:

  • Returns only user-provided skill definitions in SkillRecord.Def.
  • Filters (NamePrefix/LocationPrefix) apply to user-provided Def fields (not LLM-facing names).

func (*Runtime) NewSession

func (r *Runtime) NewSession(ctx context.Context, opts ...SessionOption) (spec.SessionID, []spec.SkillDef, error)

NewSession creates a new session.

IMPORTANT CONTRACT:

  • This is a HOST/LIFECYCLE API.
  • It accepts and returns skill definitions (spec.SkillDef), never LLM handles.

func (*Runtime) NewSessionRegistry

func (r *Runtime) NewSessionRegistry(
	ctx context.Context,
	sid spec.SessionID,
	opts ...llmtools.RegistryOption,
) (*llmtools.Registry, error)

func (*Runtime) ProviderTypes

func (r *Runtime) ProviderTypes() []string

ProviderTypes returns the registered provider type keys (e.g. "fs").

func (*Runtime) RemoveSkill

func (r *Runtime) RemoveSkill(ctx context.Context, def spec.SkillDef) (spec.SkillRecord, error)

RemoveSkill removes a skill from the catalog (and prunes it from all sessions).

IMPORTANT CONTRACT:

  • This is a HOST/LIFECYCLE API.
  • Removal is by the exact user-provided definition that was added.
  • No canonicalization-based matching is performed (to avoid internal cleanup becoming user-facing).

func (*Runtime) SkillsPromptXML added in v0.6.0

func (r *Runtime) SkillsPromptXML(ctx context.Context, f *SkillFilter) (string, error)

SkillsPromptXML is the single prompt API.

Output compatibility rules (to preserve previous XML “standards” as much as possible):

  • If only one section is requested, the root is exactly one of:
  • <availableSkills>...</availableSkills>
  • <activeSkills>...</activeSkills> (matching the historical outputs from internal/catalog XML builders).
  • If both sections are requested simultaneously, the output is wrapped in: <skillsPrompt> ... </skillsPrompt>

type SessionOption added in v0.6.0

type SessionOption func(*newSessionOptions) error

SessionOption configures Runtime.NewSession.

func WithSessionActiveSkills added in v0.7.0

func WithSessionActiveSkills(defs []spec.SkillDef) SessionOption

WithSessionActiveSkills sets the initial active skills for the new session (host/lifecycle defs). These are activated during session creation.

func WithSessionMaxActivePerSession added in v0.6.0

func WithSessionMaxActivePerSession(n int) SessionOption

WithSessionMaxActivePerSession overrides the max active skills for this session only. If n <= 0, it is ignored (defaults apply).

type SkillFilter

type SkillFilter struct {
	// Types restricts to provider types (e.g. ["fs"]). Empty means "all".
	Types []string

	// NamePrefix restricts to LLM-visible names with this prefix.
	NamePrefix string

	// LocationPrefix restricts to skills whose (user-provided) location starts with this prefix.
	LocationPrefix string

	// AllowSkills restricts to an explicit allowlist of host/lifecycle skill defs. Empty means "all".
	AllowSkills []spec.SkillDef

	// SessionID optionally scopes active/inactive filtering.
	SessionID spec.SessionID

	// Activity defaults to spec.SkillActivityAny.
	Activity spec.SkillActivity
}

SkillFilter is an optional filter for listing/prompting skills (LLM/prompt-facing).

Semantics:

  • Types/NamePrefix/LocationPrefix/AllowSkills always apply.
  • SessionID (optional) allows filtering/annotating by "active in this session".
  • Activity controls whether to include active, inactive, or both.

Defaults:

  • Activity defaults to "any".
  • If SessionID is empty, no active skills exist.

IMPORTANT CONTRACT:

  • NamePrefix matches the LLM-visible computed handle name (not the host skill def name).
  • LocationPrefix matches the user-provided location (not provider-canonicalized).

type SkillListFilter added in v0.7.0

type SkillListFilter struct {
	Types          []string
	NamePrefix     string
	LocationPrefix string
	AllowSkills    []spec.SkillDef

	SessionID spec.SessionID
	Activity  spec.SkillActivity
}

SkillListFilter is a HOST/LIFECYCLE listing filter. Unlike SkillFilter (prompt), NamePrefix applies to the user-provided skill name (def.name), not the LLM-visible computed handle name.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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