Skip to main content

Filesystem-based agent skill loader: spec + reference implementation.

Project description

skillfull

Filesystem-based agent skill loader. One spec, one reference implementation, with a first-party adapter for pydantic-ai.

A skill is a folder containing a SKILL.md file — YAML frontmatter describing what the skill does plus a markdown body explaining how to do it. skillfull discovers skills (arbitrary nesting supported), validates them against the spec, and renders a system-prompt-ready manifest. The pydantic-ai adapter wires the manifest into an Agent's instructions and registers a load_skill tool the model uses to fetch a skill's body on demand (plus opt-in tools for listing skills and reading skill resources). Two lines of glue and the model can route to the right skill.

References

Spec & ecosystem:

Pydantic-AI:

Status

v0.2 — spec stabilising. Adds optional when_to_use and always_load frontmatter fields and a pydantic-ai adapter alongside the framework-agnostic registry. v0.1 skills continue to validate unchanged.

Quickstart

from pathlib import Path
from skillfull import SkillRegistry

# Either pass roots directly...
reg = SkillRegistry([Path("./skills")])

# ...or load them from a config file that lives with your skills:
reg = SkillRegistry.from_config("./skills/skills.yaml")

# Level 1: render the manifest for the system prompt.
print(reg.manifest_xml())

# Level 2: load a skill's body on demand. (The `search` skill ships
# with the example bundle under examples/agent_demo/skills/.)
body = reg.load("search")

SkillRegistry walks every directory under its roots, treats any directory containing SKILL.md as a skill, and validates against the spec. Reserved subdirectories inside a skill (references/, scripts/, assets/) are not descended into. Arbitrary nesting is supported — the path from a skill root to a skill's parent directory is the category path. The same loader handles flat layouts and N-level categories without a nested=True flag.

skills.yaml

A small declarative config (lives inside your skills directory, so the bundle is portable):

# skills/skills.yaml
roots:
  - .                  # paths are resolved relative to this file
  # - ../shared-skills # optional extra roots

SkillRegistry.from_config(path) resolves the listed paths relative to the config file's directory.

Pydantic-AI integration

Install the extra:

pip install "skillfull[pydantic-ai]"

Attach a registry to an existing Agent:

from pydantic_ai import Agent
from skillfull.pydanticai import attach_skills

agent = Agent("anthropic:claude-sonnet-4-6")
attach_skills(agent, "skills/skills.yaml")

Or build an Agent with skills already wired up:

from skillfull.pydanticai import skill_aware_agent

agent = skill_aware_agent(
    "anthropic:claude-sonnet-4-6",
    skills="skills/skills.yaml",
)

What attach_skills adds (each independently togglable):

  • Instructions (Level 1, on by default): an @agent.instructions function that returns the rendered <available_skills> manifest, sorted for deterministic prompt caching.
  • load_skill(name) tool (Level 2, on by default): the model calls this to fetch a skill body on demand. Path-traversal-safe.
  • Inlined always-loaded bodies (on by default): any skill with always_load: true in its frontmatter has its body inlined into the instructions. Independent of the manifest flag — bodies are inlined even when the manifest is suppressed.
  • list_skills tool (opt-in): re-renders the manifest at runtime.
  • read_skill_resource tool (Level 3, opt-in): exposes files under a skill's references/, scripts/, assets/ with path safety.

attach_skills is not idempotent — calling it twice on the same Agent raises SkillError. Build a new Agent if you need a different skill set.

Try it

A self-contained demo lives under examples/agent_demo/ — four skills across three nesting depths, an offline plumbing check, and a real routing eval against Claude Sonnet 4.6.

pip install -e ".[pydantic-ai]"

# Plumbing check (no API key). Verifies the manifest + load_skill
# round-trip, NOT whether an LLM routes correctly.
python examples/agent_demo/run_demo.py

# Real routing eval against an actual model.
export ANTHROPIC_API_KEY=...
python examples/agent_demo/run_live.py

See examples/agent_demo/README.md for the two-script split and what each one does / doesn't prove.

Install

pip install -e .

Python 3.12+. One runtime dep: PyYAML.

Spec

See SPEC.md for the canonical rules: directory layout, frontmatter schema, validation, manifest format, progressive disclosure.

Layout

skillfull/
├── SPEC.md
├── README.md
├── LICENSE
├── pyproject.toml
├── src/skillfull/
│   ├── __init__.py     # public API
│   ├── errors.py       # typed exceptions
│   ├── models.py       # Skill dataclass
│   ├── parser.py       # frontmatter extraction
│   ├── validator.py    # spec §3 rules
│   ├── manifest.py     # XML + markdown renderers
│   ├── registry.py     # discovery + composition
│   └── pydanticai.py   # optional pydantic-ai adapter
├── examples/
│   └── agent_demo/     # end-to-end demo + offline & live runners
├── tests/
└── .github/workflows/
    └── publish.yml     # PyPI publish on Release

Development

pip install -e ".[dev]"
pytest

Release

Publishing is automated via .github/workflows/publish.yml. To cut a release:

  1. Bump version in pyproject.toml and __version__ in src/skillfull/__init__.py (keep them in sync — the workflow checks the tag against pyproject.toml).
  2. Commit, merge to main.
  3. On GitHub, Releases → Draft a new release, create a tag matching the bumped version (e.g. v0.2.1), publish.

The workflow runs the test suite, builds sdist + wheel, and uploads to PyPI via trusted publishing (OIDC — no API token in secrets).

One-time PyPI setup (only needed on the first release): on PyPI, Your projects → skillfull → Publishing → Add a new publisher:

Field Value
Owner phiweger
Repository skillfull
Workflow filename publish.yml
Environment name pypi

For the very first release (before the project exists on PyPI), use the pending publisher flow under Your account → Publishing → Add a pending publisher.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

skillfull-0.2.0.tar.gz (36.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

skillfull-0.2.0-py3-none-any.whl (17.4 kB view details)

Uploaded Python 3

File details

Details for the file skillfull-0.2.0.tar.gz.

File metadata

  • Download URL: skillfull-0.2.0.tar.gz
  • Upload date:
  • Size: 36.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for skillfull-0.2.0.tar.gz
Algorithm Hash digest
SHA256 038ea651b2fc9e7ec0773050be49ef3bb5010a3f8a77c3c4fae6081f4d5b7ee7
MD5 21b69caddef8fbd7b756a95442f0d97c
BLAKE2b-256 30b76846eecba58fd4d19ae82301992737ec1b8646fd3f9c9f16cde68e221e43

See more details on using hashes here.

Provenance

The following attestation bundles were made for skillfull-0.2.0.tar.gz:

Publisher: publish.yml on phiweger/skillfull

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file skillfull-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: skillfull-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 17.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for skillfull-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 33e3562957ccdce7aacc7ca5b1dfd1db5539c2fccea7f90595d29b26d39eacb7
MD5 3f69760cba25feec4854a677fd8e528c
BLAKE2b-256 c03970d4236381a44eb853e7e683b617fb623e278344ebf4b9fc5008eff4193b

See more details on using hashes here.

Provenance

The following attestation bundles were made for skillfull-0.2.0-py3-none-any.whl:

Publisher: publish.yml on phiweger/skillfull

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page