Help us shape the future of Go! Take the 2026 Go Developer Survey

skillkit

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

README

SkillKit

skillkit discovers and gates portable SKILL.md packages for a host application. It is a catalog and availability module, not a plugin execution runtime.

Boundary

SkillKit can:

  • scan explicit, host-configured roots for <skill-name>/SKILL.md;
  • parse standard fields and the namespaced metadata.goagents extension;
  • compute a stable package digest over SKILL.md and allowlisted resources;
  • reject duplicate-name conflicts, invalid manifests, escaping resources, and untrusted roots;
  • evaluate a skill against host OS, features, and already-authorized tools.
  • activate an explicit, gated name@digest selection at run start and recheck package content before loading its instruction body;
  • read an activated allowlisted resource through a path-free skill://name@digest/path URI.

SkillKit never executes scripts/, installs dependencies, performs network requests, grants tools, or exposes local filesystem paths through catalog entries.

Use

package main

import (
	"runtime"

	"github.com/eruca/goagents/skillkit"
)

func activateWorkspaceSkill() error {
	catalog, err := skillkit.Discover([]skillkit.Root{{
		ID:      "workspace",
		Dir:     ".agents/skills",
		Scope:   skillkit.ScopeWorkspace,
		Trusted: true,
		Enabled: true,
	}})
	if err != nil {
		return err
	}

	activation, err := catalog.Activate(skillkit.ActivationRequest{
		Skills: []skillkit.Ref{{Name: "clinical-summary"}},
		GateContext: skillkit.GateContext{
			OS:             runtime.GOOS,
			HostFeatures:   map[string]bool{"artifacts.v1": true},
			AllowedToolIDs: map[string]bool{"artifact.read": true},
		},
	})
	if err != nil {
		return err
	}

	skill := activation.Skills()[0] // Ref always includes its resolved digest.
	uri, err := activation.ResourceURI(skill.Ref, "references/output-schema.md")
	if err != nil {
		return err
	}
	_, err = activation.ReadResource(uri)
	if err != nil {
		return err
	}
	return nil
}

The host chooses roots and marks each root as trusted. A declaration such as required: [artifact.read] is only a prerequisite: it does not make the tool available unless the host has already registered and authorized it for the run. The host should construct its request-scoped tool registry from the same authorization decision; SkillKit does not register or remove tools.

Agent adapter

The optional agentadapter.Provider maps a host-resolved activation to agentcore.SkillProvider. Its resolver receives each RunRequest, so the host can keep activation selection request-scoped:

provider := agentadapter.Provider{Resolve: func(ctx context.Context, req agentcore.RunRequest) (*skillkit.Activation, error) {
	return activation, nil
}}
agent, err := agentcore.NewAgent(
	agentcore.WithLLM(llm),
	agentcore.WithSkillProvider(provider),
)

The adapter only injects already activated instruction bodies. It does not implement ToolProvider, inspect RunRequest.Metadata, or change the agent tool registry.

SKILL.md extension

The portable name, description, license, and metadata fields remain unchanged. SkillKit reads only the namespaced extension below:

---
name: clinical-summary
description: Produce a bounded clinical summary.
metadata:
  goagents:
    requires:
      os: [darwin, linux]
      host_features: [artifacts.v1]
      tools:
        required: [artifact.read]
        optional: [web.search]
    resources:
      allow: [references/output-schema.md]
---

Unknown metadata is preserved. Resource references are forward-slash relative paths; absolute paths, .., duplicate entries, and links escaping the skill directory are rejected.

Instruction bodies are limited to 128 KiB at discovery. Resource reads return at most 1 MiB; larger packages must be split into explicit, separately allowlisted references. A changed package digest fails activation and resource reads rather than silently loading a newer file.

Current scope

SkillKit includes catalog discovery, availability evaluation, run-start activation, bounded resource reads, and agentcore.SkillProvider wiring. The host-api example adds safe catalog exposure, durable workflow skill_refs, a single explicit local-root bootstrap, and a host-side evaluation gate. Remote registries, dependency installation, request-scoped tool projection, dynamic activation, and script sandboxing remain separate future slices.

Verify

go test ./...

Documentation

Overview

Package skillkit discovers and gates portable SKILL.md packages.

It does not execute skill scripts, install dependencies, or grant tools.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidSkillManifest = errors.New("invalid skill manifest")
	ErrInvalidSkillResource = errors.New("invalid skill resource")
	ErrSkillNotFound        = errors.New("skill not found")
	ErrSkillAmbiguous       = errors.New("skill name is ambiguous")
	ErrSkillUnavailable     = errors.New("skill is unavailable")
	ErrSkillDigestMismatch  = errors.New("skill content changed")
)

Functions

func ValidateManifest

func ValidateManifest(directory string, manifest Manifest) error

ValidateManifest checks the subset of the Agent Skills format needed for a safe local catalog. It does not inspect the filesystem.

Types

type ActivatedSkill

type ActivatedSkill struct {
	Ref             Ref
	Name            string
	Description     string
	Content         string
	RequiredToolIDs []string
	OptionalToolIDs []string
}

ActivatedSkill is the safe, path-free view of one activated skill.

type Activation

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

Activation is an immutable run-start selection. It retains private catalog records only so it can revalidate content before returning a resource.

func (*Activation) GoString

func (a *Activation) GoString() string

GoString keeps %#v diagnostics path-free for the same reason as String.

func (*Activation) ReadResource

func (a *Activation) ReadResource(uri string) ([]byte, error)

ReadResource returns a copy of one current, allowlisted resource. It checks the full package digest again so source mutations fail closed.

func (*Activation) ResourceURI

func (a *Activation) ResourceURI(ref Ref, resource string) (string, error)

ResourceURI returns the only supported resource reference form. The target must belong to the current activation and be explicitly allowlisted.

func (*Activation) Skills

func (a *Activation) Skills() []ActivatedSkill

Skills returns a copy of the activated model-facing instructions.

func (*Activation) String

func (a *Activation) String() string

String avoids exposing private catalog roots through host diagnostics.

type ActivationRequest

type ActivationRequest struct {
	Skills      []Ref
	GateContext GateContext
}

ActivationRequest is the host-controlled selection and capability context for one run. Declared requirements never add to GateContext permissions.

type Availability

type Availability string

Availability is the host-relative result of checking one catalog entry.

const (
	AvailabilityEligible    Availability = "eligible"
	AvailabilityUnavailable Availability = "unavailable"
	AvailabilityInvalid     Availability = "invalid"
	AvailabilityAmbiguous   Availability = "ambiguous"
)

type AvailabilityReport

type AvailabilityReport struct {
	State   Availability
	Reasons []Reason
}

AvailabilityReport is deterministic and safe to expose to an operator.

func Evaluate

func Evaluate(entry Entry, context GateContext) AvailabilityReport

Evaluate applies fail-closed entry and capability checks without performing I/O. Declared capabilities are requirements, never authorization grants.

type Catalog

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

Catalog is an immutable snapshot produced by Discover.

func Discover

func Discover(roots []Root) (*Catalog, error)

Discover reads enabled roots and returns a deterministic catalog snapshot. It performs no process execution, dependency installation, network I/O, or environment mutation.

func (*Catalog) Activate

func (c *Catalog) Activate(request ActivationRequest) (*Activation, error)

Activate resolves, gates, and rechecks each requested skill before exposing its instruction body. It never executes files or grants tools.

func (*Catalog) GoString

func (c *Catalog) GoString() string

GoString keeps %#v diagnostics path-free for the same reason as String.

func (*Catalog) List

func (c *Catalog) List() []Entry

List returns a deep copy ordered by name, digest, and root ID.

func (*Catalog) Resolve

func (c *Catalog) Resolve(ref Ref) (Entry, error)

Resolve returns an exact skill when digest is supplied. A digest-less ref succeeds only for one ready digest with the requested name.

func (*Catalog) String

func (c *Catalog) String() string

String avoids exposing the private canonical roots when a catalog reaches host diagnostics or logs.

type Entry

type Entry struct {
	Ref           Ref
	Manifest      Manifest
	RootID        string
	SourceRootIDs []string
	Scope         Scope
	Trusted       bool
	State         EntryState
	Reasons       []Reason
}

Entry is a catalog-safe skill description. It intentionally omits local filesystem paths and source contents.

type EntryState

type EntryState string

EntryState describes whether an entry can be considered by a gate.

const (
	EntryReady     EntryState = "ready"
	EntryInvalid   EntryState = "invalid"
	EntryAmbiguous EntryState = "ambiguous"
)

type GateContext

type GateContext struct {
	OS             string
	HostFeatures   map[string]bool
	AllowedToolIDs map[string]bool
}

GateContext contains only host-owned capability facts for one run.

type Manifest

type Manifest struct {
	Name         string
	Description  string
	License      string
	Requirements Requirements
	Resources    []string
	Metadata     map[string]any
}

Manifest is the portable SKILL.md metadata interpreted by skillkit. Metadata preserves unrecognized fields so the package remains portable.

func ParseManifest

func ParseManifest(directory string, source []byte) (Manifest, error)

ParseManifest reads the YAML frontmatter at the start of a SKILL.md file. It intentionally does not execute, install, or resolve any referenced file.

type Reason

type Reason struct {
	Code    string
	Subject string
}

Reason is a stable, non-sensitive explanation suitable for operator output.

type Ref

type Ref struct {
	Name   string
	Digest string
}

Ref identifies a specific immutable skill package by name and digest.

type Requirements

type Requirements struct {
	OS              []string
	HostFeatures    []string
	RequiredToolIDs []string
	OptionalToolIDs []string
}

Requirements describes capabilities a skill needs from its host. These are declarations only; they never grant a tool or permission.

type Root

type Root struct {
	ID      string
	Dir     string
	Scope   Scope
	Trusted bool
	Enabled bool
}

Root is an explicit host-provided directory that may contain skill folders.

type Scope

type Scope string

Scope identifies a host-configured skill root. A scope does not imply trust.

const (
	ScopeBuiltin   Scope = "builtin"
	ScopeUser      Scope = "user"
	ScopeWorkspace Scope = "workspace"
)

Directories

Path Synopsis
Package agentadapter adapts host-approved skillkit activations to the goagent SkillProvider contract.
Package agentadapter adapts host-approved skillkit activations to the goagent SkillProvider contract.

Jump to

Keyboard shortcuts

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