agentskills-core
Core abstractions for the Agent Skills SDK - provider interface, registry, validation, and skill model.
This package provides the foundational building blocks for working with the Agent Skills format. It is storage-agnostic - concrete providers (filesystem, HTTP, database, etc.) live in separate packages.
Installation
pip install agentskills-core
Requires Python 3.12 or newer.
What's Included
| Export | Description |
|---|---|
SkillProvider |
Abstract base class that every skill backend must implement |
Skill |
Lightweight runtime handle to a single registered skill |
SkillRegistry |
Unified index with explicit registration and catalog builder |
validate_skill |
Validates a skill against the Agent Skills specification |
validate_version |
Validates an optional semver version frontmatter value |
get_logger |
Returns a logger in the shared agentskills.* namespace |
redact_url |
Strips credentials from a URL before it is logged or raised |
split_frontmatter |
Parses YAML frontmatter from SKILL.md content |
AgentSkillsError |
Base exception for all library errors |
SkillNotFoundError |
Raised when a skill does not exist |
ResourceNotFoundError |
Raised when a resource within a skill does not exist |
ResourceListingNotSupportedError |
Raised when a provider cannot enumerate a skill's resources |
SkillUnavailableError |
Raised when a backend is unreachable or fails transiently |
Usage
Registering Skills
from agentskills_core import SkillRegistry
# provider: any SkillProvider - agentskills-fs, agentskills-http, or your own
registry = SkillRegistry()
await registry.register("incident-response", provider) # validates on registration
Or register multiple skills at once:
await registry.register([
("incident-response", fs_provider),
("api-style-guide", http_provider),
])
Batch registration is atomic - if any skill fails validation, none are registered.
Accessing Skills
skill = registry.get_skill("incident-response")
meta = await skill.get_metadata() # YAML frontmatter as dict
body = await skill.get_body() # Markdown instructions
script = await skill.get_script("run.sh")
Building a Catalog
Generate a catalog string for system-prompt injection:
xml_catalog = await registry.get_skills_catalog(format="xml") # <available_skills> XML
md_catalog = await registry.get_skills_catalog(format="markdown") # Markdown list
Metadata for every registered skill is fetched concurrently, which matters when providers are network-backed. Bound the fan-out at construction time:
registry = SkillRegistry(catalog_concurrency=4) # default: 8
Skill Versions (optional, non-spec)
A skill may declare a version in its frontmatter. It is optional — skills without one remain
valid and behave exactly as before:
---
name: incident-response
description: Standard operating procedures for production incident management.
version: "1.2.0"
---
When present, the value must be a quoted semver string. Registration fails otherwise:
from agentskills_core import validate_version
validate_version("2.1.0-rc.1") # None
validate_version("1.0") # "version '1.0' is not valid semver. ..."
validate_version(1.0) # "version must be a quoted string, got float ..."
The quoting requirement is not pedantry: YAML parses an unquoted 1.0 as a float and 2024-01-15
as a date, so the three most likely authoring mistakes never reach the validator as strings. The
error message names the cause rather than reporting a bare type mismatch.
Versions appear in both catalog formats when set, and are omitted entirely when not — unversioned skills cost no extra prompt tokens.
versionis not part of the upstream Agent Skills specification. It is supported here because consumers cannot pin, compare, or detect drift without it. The field is being raised upstream rather than kept as a permanent proprietary extension.
Implementing a Custom Provider
from agentskills_core import SkillProvider
class DatabaseSkillProvider(SkillProvider):
async def get_metadata(self, skill_id: str) -> dict: ...
async def get_body(self, skill_id: str) -> str: ...
async def get_script(self, skill_id: str, name: str) -> bytes: ...
async def get_asset(self, skill_id: str, name: str) -> bytes: ...
async def get_reference(self, skill_id: str, name: str) -> bytes: ...
All methods are async so implementations backed by network I/O can be non-blocking.
Resource Discovery (optional capability)
Some backends can enumerate a skill's resources; a static file host generally cannot. list_resources() is therefore an optional capability, paired with a declared flag (ADR 0002):
class DatabaseSkillProvider(SkillProvider):
supports_resource_listing = True
async def list_resources(self, skill_id: str) -> dict[str, list[str]]:
return {"references": [...], "scripts": [...], "assets": [...]}
The default implementation raises ResourceListingNotSupportedError rather than returning {}. "I cannot enumerate this skill" and "this skill has no resources" are different facts, and conflating them would silently hide resources from the agent.
Consumers should branch on the capability, not guess:
from agentskills_core import ResourceListingNotSupportedError
try:
listing = await skill.list_resources()
except ResourceListingNotSupportedError:
listing = None # fall back to names mentioned in the skill body
Providers that support listing always return all three keys — references, scripts, assets — with empty lists for unused categories, so callers need no key checks.
Encoding Resources for Tool Output
Resources are bytes, but tool interfaces return text. encode_resource_content() is the shared conversion used by every integration, so behaviour cannot drift between them:
from agentskills_core import encode_resource_content
text = encode_resource_content("architecture.png", raw_bytes)
Valid UTF-8 passes through unchanged. Anything else returns a JSON envelope carrying the media type and base64 content, so binaries are never silently corrupted. Binaries above max_inline_binary_bytes (default 64 KiB) are described but not inlined.
Logging
Every package in the SDK logs under one agentskills.* namespace, and the library attaches only a NullHandler — output is entirely the host's decision:
import logging
logging.getLogger("agentskills").setLevel(logging.DEBUG)
DEBUG covers fetch, parse and cache events; INFO covers registration outcomes; WARNING covers degraded-but-recovered behaviour such as a retried HTTP request. There is no ERROR level: anything that fails raises instead, so failures are never reported twice.
Custom providers should join the namespace rather than creating their own. Pass __name__ — the distribution prefix is rewritten, so agentskills_http.static logs as agentskills.http.static:
from agentskills_core import get_logger, redact_url
_logger = get_logger(__name__)
_logger.debug("GET %s", redact_url(url, relative_to=base_url))
redact_url() drops the query string, fragment and userinfo, which is where credentials actually live — SAS tokens, signed-URL signatures, basic-auth passwords. With relative_to it drops the scheme and host as well, leaving only the path beneath that base.
Security
- Frontmatter size limits -
split_frontmatter()rejects YAML frontmatter blocks exceeding 256 KB (MAX_FRONTMATTER_BYTES) to prevent memory-exhaustion attacks. - Metadata validation -
validate_skill()checks types of known optional fields (license,compatibility,metadata,allowed-tools,version) and logs warnings for unknown top-level metadata keys. - Safe XML generation -
get_skills_catalog(format="xml")usesxml.etree.ElementTreefor catalog generation, avoiding XML injection via string concatenation. - Credential-safe logging - the SDK never logs request headers, and URLs pass through
redact_url()before reaching a log record or an exception message.
For the full security policy, see SECURITY.md.
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agentskills_core-0.3.0.tar.gz.
File metadata
- Download URL: agentskills_core-0.3.0.tar.gz
- Upload date:
- Size: 19.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
26435d4abe0a565b8c6f66783e096d9c076c3eabe05076ed6e894854c1059f4b
|
|
| MD5 |
074c4135ab381e972a4248c727ec84f8
|
|
| BLAKE2b-256 |
5f76274950325242714a1a52e43f6137ed344dd92bec60149c3b11bca3ec158f
|
Provenance
The following attestation bundles were made for agentskills_core-0.3.0.tar.gz:
Publisher:
publish.yml on pratikxpanda/agentskills-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agentskills_core-0.3.0.tar.gz -
Subject digest:
26435d4abe0a565b8c6f66783e096d9c076c3eabe05076ed6e894854c1059f4b - Sigstore transparency entry: 2298806147
- Sigstore integration time:
-
Permalink:
pratikxpanda/agentskills-sdk@8c402728312bf75b0a4457f4adf917cc18651a70 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/pratikxpanda
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8c402728312bf75b0a4457f4adf917cc18651a70 -
Trigger Event:
push
-
Statement type:
File details
Details for the file agentskills_core-0.3.0-py3-none-any.whl.
File metadata
- Download URL: agentskills_core-0.3.0-py3-none-any.whl
- Upload date:
- Size: 22.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
278f6c937140686d65af1a90e0d15b5dcef7f0645f85f92c72bf9bfa804aeaaa
|
|
| MD5 |
631e916d3a59fc2534249ea5371e571b
|
|
| BLAKE2b-256 |
1ae3b63b8f91b9473fb0c92974004581a46a8284776882a184dedfa490f07814
|
Provenance
The following attestation bundles were made for agentskills_core-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on pratikxpanda/agentskills-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agentskills_core-0.3.0-py3-none-any.whl -
Subject digest:
278f6c937140686d65af1a90e0d15b5dcef7f0645f85f92c72bf9bfa804aeaaa - Sigstore transparency entry: 2298806190
- Sigstore integration time:
-
Permalink:
pratikxpanda/agentskills-sdk@8c402728312bf75b0a4457f4adf917cc18651a70 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/pratikxpanda
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8c402728312bf75b0a4457f4adf917cc18651a70 -
Trigger Event:
push
-
Statement type: