Skip to main content

agentskills-testing

Conformance suite and test doubles for Agent Skills providers.

SkillProvider is an abstract base class, which enforces that five methods exist and nothing whatsoever about what they do. The requirements that actually matter are the ones an ABC cannot express: that an unknown skill ID raises SkillNotFoundError rather than returning {}, that ../../etc/passwd is refused rather than resolved, and that a provider advertising resource listing can actually list. This package turns those into tests you inherit.

pip install agentskills-testing

Conformance suite

Subclass ProviderConformanceSuite, supply a provider fixture, and pytest collects the entire provider contract against your implementation:

import pytest

from agentskills_testing import ProviderConformanceSuite

from my_package import MyProvider


class TestMyProvider(ProviderConformanceSuite):
    @pytest.fixture
    def provider(self):
        return MyProvider(...)

Fixture contract

The provider fixture must expose exactly one skill:

id conformance-skill
metadata name == "conformance-skill", plus a non-empty description
body non-empty markdown
references/ notes.md containing b"# Notes\n\nA reference document.\n"
scripts/ run.sh containing b"#!/bin/sh\necho conformance\n"
assets/ diagram.svg containing b"<svg></svg>\n"

It must not define a skill called no-such-skill-anywhere, or any resource called no-such-resource.txt.

Every name and byte string above is exported as a constant (SKILL_ID, REFERENCE_NAME, REFERENCE_BYTES, and so on), so a fixture can be built from them rather than from copied literals. CONTRACT holds the same description as a string, and is what the default fixture prints when you forget to override it.

What it checks

  • Metadata carries name and a non-empty description, and does not carry the body — a metadata call that includes the body has already spent the tokens progressive disclosure exists to save.
  • Metadata is not shared mutable state: one caller mutating the returned dict must not affect the next.
  • Repeated reads agree. A provider that streams without buffering passes the first read and returns empty on the second; caching bugs look the same.
  • Each resource getter returns exact bytes, not str. A resource may be a PNG, and decoding on the way out makes that unreachable.
  • Unknown skills raise SkillNotFoundError; unknown resources raise ResourceNotFoundError.
  • list_resources() agrees with supports_resource_listing. Callers branch on that flag, so a provider whose flag and behaviour disagree breaks them whichever way it lies.
  • discover() agrees with supports_discovery, and everything it reports can actually be read. register_all() validates the whole list, so one phantom ID fails the entire registration.
  • Traversal identifiers are refused — parent traversal, absolute paths, Windows separators, percent-encoded traversal, and embedded NUL bytes, as both skill IDs and resource names. These are not opt-out.
  • Concurrent reads through a single instance return consistent content, which catches per-call state stored on self.

Size limits

ContentLimitConformanceSuite is separate and opt-in. A size limit is not part of the universal contract — an in-memory provider has no external source to bound, and demanding one would assert a filesystem's constraints against a dict. It is required of any provider that reads bytes it did not author: from disk, from a network, from anywhere a caller can grow without asking.

from agentskills_testing import ContentLimitConformanceSuite


class TestMyProviderLimits(ContentLimitConformanceSuite):
    @pytest.fixture
    def limited_provider(self):
        return MyProvider(..., max_bytes=8)

The fixture holds the same skill, with a limit small enough that the skill exceeds it.

Test doubles

InMemorySkillProvider is a real, spec-compliant provider backed by a dict — it passes the conformance suite above. Prefer it to an AsyncMock: a mock agrees with whatever the test asserts, including the assertions that are wrong.

from agentskills_core import SkillRegistry
from agentskills_testing import InMemorySkillProvider, build_skill

provider = InMemorySkillProvider(
    {
        "incident-response": build_skill(
            "incident-response",
            description="Diagnose and mitigate a production incident.",
            body="# Incident Response\n\nPage the on-call engineer.\n",
            references={"severity-levels.md": b"SEV1 is customer-visible.\n"},
        )
    }
)

registry = SkillRegistry()
await registry.register_all(provider)

A string value is taken as the body, for the common case where the content does not matter:

provider = InMemorySkillProvider({"a": "body of a", "b": "body of b"})
provider.add("c")  # a default skill named "c"

build_skill() produces frontmatter that passes validate_skill(), so a test that does not care about metadata does not have to invent any. render_skill_md(skill) renders one back to SKILL.md text, which is how you populate a temporary directory for the filesystem provider.

To emulate a backend that cannot enumerate — a static HTTP host without a manifest, for instance — pass supports_resource_listing=False, or supports_discovery=False, or both.

Fixtures

Installing the package registers a pytest plugin, so these are available with no import and no conftest.py entry:

Fixture What you get
sample_skill An InMemorySkill with one reference, one script, and one asset
skill_provider An InMemorySkillProvider serving sample_skill
skill_registry A SkillRegistry with that skill already registered
async def test_my_agent(skill_registry):
    catalog = await skill_registry.get_skills_catalog()
    assert "incident-response" in catalog

License

MIT — see LICENSE.

Part of the Agent Skills SDK.

Download files

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

Source Distribution

agentskills_testing-0.5.0.tar.gz (10.9 kB view details)

Uploaded Source

Built Distribution

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

agentskills_testing-0.5.0-py3-none-any.whl (12.6 kB view details)

Uploaded Python 3

File details

Details for the file agentskills_testing-0.5.0.tar.gz.

File metadata

  • Download URL: agentskills_testing-0.5.0.tar.gz
  • Upload date:
  • Size: 10.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for agentskills_testing-0.5.0.tar.gz
Algorithm Hash digest
SHA256 afc64831d37f0e6ca8beabb57eb334e9849a52e394e93ca2e70a9d483e15448f
MD5 77189e92789a77f3ee6dd3beb2d645c4
BLAKE2b-256 b54843d5e90d3132d2a965e76050f0535ece2f9b43c49737f7fb178d79712693

See more details on using hashes here.

Provenance

The following attestation bundles were made for agentskills_testing-0.5.0.tar.gz:

Publisher: publish.yml on pratikxpanda/agentskills-sdk

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

File details

Details for the file agentskills_testing-0.5.0-py3-none-any.whl.

File metadata

File hashes

Hashes for agentskills_testing-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 10138c4f21fa776f2ad649ede3907104c41adf0c898fbf02caa1505ed815d048
MD5 d80b890d2fd0f67b00bbf86ea31582b7
BLAKE2b-256 090e77d8f62a87f2d03e9c237e6b60b0fc3030132bfe38d8c8aa38c031e9ec69

See more details on using hashes here.

Provenance

The following attestation bundles were made for agentskills_testing-0.5.0-py3-none-any.whl:

Publisher: publish.yml on pratikxpanda/agentskills-sdk

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

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 files

0.4.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page