Skip to content

Getting started

AbstractSkill is a small, dependency-light library (PyYAML only) for working with Agent Skills (SKILL.md) in AbstractFramework.

Install

pip install abstractskill

For local development:

python -m pip install -e ".[test]"
python -m pytest -q

Parse a skill

from pathlib import Path
from abstractskill import parse_skill_md

doc = parse_skill_md(Path("my-skill/SKILL.md").read_text(encoding="utf-8"))
print(doc.metadata.name, doc.metadata.description)
print(doc.content_hash)

The parser accepts LF, CRLF, and CR line endings and enforces the Agent Skills spec: name (1-64 chars, lowercase alphanumeric and single hyphens, no leading/trailing/consecutive hyphens), description (1-1024 chars), and compatibility (≤500 chars). Invalid input raises SkillValidationError or SkillParseError with a message naming the problem.

Discover skills on disk

from pathlib import Path
from abstractskill import FilesystemSkillLoader

loader = FilesystemSkillLoader([Path.home() / ".abstract" / "skills", Path(".abstract/skills")])

# Metadata only (progressive disclosure); later roots override earlier ones.
for meta in loader.discover(on_warning=print):
    print(meta.name, "-", meta.description)

# Full document on demand.
loaded = loader.load("my-skill")
print(loaded.document.body)

discover() and load() resolve identically: a broken skill copy never shadows a valid one, and invalid folders are skipped with a #FALLBACK warning (delivered to on_warning and logged) rather than silently dropped.

Hash and inspect a skill folder

from abstractskill import hash_skill_tree, inspect_skill_dir

tree_hash = hash_skill_tree("my-skill")            # whole-tree tamper hash
inv = inspect_skill_dir("my-skill")
print(inv.tree_hash, inv.total_bytes, inv.has_scripts)

has_scripts is a structural fact (any file under scripts/), not a frontmatter claim — so a "requires enablement" badge cannot be lied to.

Compose tools with an operator grant

from abstractskill import effective_tools

grant = ["read_file", "write_file", "web_search"]
result = effective_tools(grant, active_skills)   # active_skills: list[SkillMetadata]
print(result.allowed)              # grant ∩ union(declared) — never wider than the grant
print(result.warnings)             # #FALLBACK for any dropped token

Skills can only narrow the toolset below the grant, never widen it. A skill with no allowed-tools contributes nothing (pure knowledge). For per-skill least privilege use effective_tools_for_skill.

Evaluate trust

from abstractskill import TrustRegistry, evaluate_trust, inspect_skill_dir

registry = TrustRegistry.load(
    validations_path="registry/validations.yaml",
    advisories_path="registry/advisories.yaml",
    guidance_path="registry/guidance.yaml",
)
inv = inspect_skill_dir("my-skill")
verdict = evaluate_trust(
    registry, tree_hash=inv.tree_hash, name="my-skill", source="first-party",
    has_scripts=inv.has_scripts,
)
print(verdict.level, verdict.blocked, verdict.requires_review, verdict.attachable)
for reason in verdict.reasons:
    print("-", reason)

The verdict is fail-closed: only a validated, advisory-free, script-free skill is attachable. See the trust model for the full semantics.

Activate skills into a context (the composed pipeline)

For activation, do not wire the primitives by hand — use the ONE pipeline so the ordering (load → hash → trust-gate → compose) cannot be skipped, and pass the activation-description overrides so upstream wrong-audience text never reaches a prompt:

from abstractskill import TrustRegistry, format_available_skills_xml, select_skills_for_context

registry = TrustRegistry.load(
    validations_path="registry/validations.yaml",
    advisories_path="registry/advisories.yaml",
)
selection = select_skills_for_context(
    registry, shelf_root="registry/skills",
    names=["coredoc", "verification-before-completion"],  # names-only is enough
    enabled=[],  # operator-enabled requires_review skills for THIS context
)
block = format_available_skills_xml(
    list(selection.active),
    descriptions=selection.activation_descriptions,  # REQUIRED for honest prompts:
    # without it the UPSTREAM description renders verbatim (wrong-audience leak)
)

To add new third-party skills to the shelf, use the curated catalog path — see the curated skills catalog.