Skip to content

HTTP Provider (agentskills-http)

Loads skills from a static HTTP host or CDN. Connections are public-network-only by default. See Trust and Operability.

pip install agentskills-http

agentskills_http

HTTP-based skill providers for the Agent Skills format.

This package provides :class:HTTPStaticFileSkillProvider, a concrete implementation of :class:~agentskills_core.SkillProvider that fetches Agent Skills <https://agentskills.io>_ from a static HTTP file host (S3, Azure Blob Storage, CDN, GitHub Pages, or any web server serving raw files).

Install::

pip install agentskills-http

HTTPStaticFileSkillProvider

Bases: SkillProvider

Skill provider backed by a static HTTP file host.

The provider expects an HTTP server (S3, Azure Blob, CDN, Nginx, GitHub Pages, etc.) that hosts skill files at predictable URL paths. Resource names (scripts, assets, references) are discovered by the agent from the skill body, or from an optional per-skill index.json manifest -- see resource_manifest. The set of skills is likewise unknowable over plain HTTP unless the host publishes a root index.json -- see skill_manifest.

The provider owns an :class:httpx.AsyncClient for connection pooling. If you supply your own client the provider will use it without closing it. Otherwise call :meth:aclose or use async with when you are finished.

Parameters:

Name Type Description Default
base_url str

Root URL where the skill tree is hosted. A trailing slash is stripped automatically.

required
client AsyncClient | None

Optional pre-configured :class:httpx.AsyncClient. When provided, the caller is responsible for closing it. Requires explicit allow_private_network=True because the caller owns DNS, TLS, timeout, and network policy. Redirects remain disabled.

None
headers dict[str, str] | None

Optional extra headers sent with every request (e.g. Authorization).

None
params dict[str, str] | None

Optional query parameters appended to every request (e.g. SAS tokens for Azure Blob Storage).

None
require_tls bool

If True, reject http:// base URLs with a :class:ValueError. Defaults to False, which allows HTTP but emits a :class:UserWarning.

False
max_response_bytes int

Maximum allowed response size in bytes. Responses exceeding this limit raise :class:~agentskills_core.AgentSkillsError. Defaults to 10 MB.

DEFAULT_MAX_RESPONSE_BYTES
revalidate bool

If True, re-check cached SKILL.md content on every access using If-None-Match / If-Modified-Since. Costs one (usually empty) round trip per access but picks up republished skills. Defaults to False, which serves cached content until :meth:invalidate is called.

False
resource_manifest bool

Set True if the host publishes a per-skill index.json listing resource names. Enables :meth:list_resources. Defaults to False, because a plain static host cannot be enumerated and claiming otherwise would make missing manifests look like skills with no resources.

False
skill_manifest bool

Set True if the host publishes a root index.json with a "skills" list. Enables :meth:discover, and so :meth:SkillRegistry.register_all <agentskills_core.SkillRegistry.register_all>. Defaults to False for the same reason: without a manifest, "no skills found" would be a lie.

False
file_manifest bool

Set True if each skill's index.json has a complete "files" list of relative paths including SKILL.md. Enables lossless file access. Invalid or incomplete manifests fail instead of silently omitting entries. Clients that follow redirects are rejected in this mode to keep file reads on the configured host.

False
timeout float

Request timeout in seconds. Ignored when you supply your own client.

DEFAULT_TIMEOUT_SECONDS
max_retries int

Retries after the initial attempt, for retryable failures only (5xx, 408, 425, 429, timeouts, connection errors). 0 disables retrying.

DEFAULT_MAX_RETRIES
retry_backoff float

Base delay in seconds for exponential backoff. Actual sleeps are jittered across [0, delay] so that concurrent skill fetches do not retry in lockstep.

DEFAULT_RETRY_BACKOFF_SECONDS
max_retry_delay float

Ceiling on any single sleep. A Retry-After longer than this is not waited out -- the error is raised immediately with retry_after attached, because blocking a request path for minutes is worse than failing fast and letting the caller decide.

DEFAULT_MAX_RETRY_DELAY_SECONDS
allow_private_network bool

Explicitly allow internal destinations. Default owned transports pin validated public DNS addresses at connection time.

False
observer Callable[[DisclosureEvent], None] | None

Optional content-free operation observer. Never receives credentials.

None

SKILL.md responses are cached per provider instance, because a single skill is otherwise re-fetched up to five times in one agent session. Resource fetches (scripts, assets, references) are not cached: they are usually larger and read once.

Example::

async with HTTPStaticFileSkillProvider("https://cdn.example.com/skills") as provider:
    registry = SkillRegistry()
    await registry.register("incident-response", provider)

    skill = registry.get_skill("incident-response")
    meta = await skill.get_metadata()
    print(f"{meta['name']}: {meta['description']}")

aclose async

aclose() -> None

Close the underlying HTTP client if it is owned by this provider.

discover async

discover() -> list[str]

List the host's skills from the root index.json manifest.

Requires skill_manifest=True. The manifest is a JSON object at {base_url}/index.json with a "skills" list::

{"skills": ["incident-response", "api-style-guide"]}

It is the same file format as the per-skill resource manifest, one level up, so a host publishing both has one shape to generate rather than two. Other keys are ignored, and entries that are not valid skill IDs are dropped -- a manifest is host-supplied data and an ID is later interpolated into a URL.

Returns:

Type Description
list[str]

Sorted skill IDs. Empty when the manifest lists none.

Raises:

Type Description
DiscoveryNotSupportedError

If the provider was built without skill_manifest=True, or the host publishes no root manifest.

AgentSkillsError

If the manifest is not a JSON object.

get_asset async

get_asset(skill_id: str, name: str) -> bytes

Fetch a single asset file.

Parameters:

Name Type Description Default
skill_id str

Skill name.

required
name str

Asset filename.

required

Returns:

Type Description
bytes

Raw content as bytes.

Raises:

Type Description
ResourceNotFoundError

If the asset does not exist.

get_body async

get_body(skill_id: str) -> str

Fetch SKILL.md and return the markdown body.

Parameters:

Name Type Description Default
skill_id str

Skill name to look up.

required

Returns:

Type Description
str

Markdown instruction text.

Raises:

Type Description
SkillNotFoundError

If the skill's SKILL.md cannot be fetched.

get_metadata async

get_metadata(skill_id: str) -> dict[str, Any]

Fetch SKILL.md and return the parsed YAML frontmatter.

Parameters:

Name Type Description Default
skill_id str

Skill name to look up.

required

Returns:

Type Description
dict[str, Any]

Dictionary of frontmatter key-value pairs.

Raises:

Type Description
SkillNotFoundError

If the skill's SKILL.md cannot be fetched.

get_reference async

get_reference(skill_id: str, name: str) -> bytes

Fetch a single reference file.

Parameters:

Name Type Description Default
skill_id str

Skill name.

required
name str

Reference filename.

required

Returns:

Type Description
bytes

Raw content as bytes.

Raises:

Type Description
ResourceNotFoundError

If the reference does not exist.

get_script async

get_script(skill_id: str, name: str) -> bytes

Fetch a single script file.

Parameters:

Name Type Description Default
skill_id str

Skill name.

required
name str

Script filename.

required

Returns:

Type Description
bytes

Raw content as bytes.

Raises:

Type Description
ResourceNotFoundError

If the script does not exist.

invalidate

invalidate(skill_id: str | None = None) -> None

Drop cached SKILL.md content.

Parameters:

Name Type Description Default
skill_id str | None

Skill to forget. Clears the whole cache when omitted. Unknown IDs are ignored.

None

list_files async

list_files(skill_id: str) -> list[str]

Return the complete, sorted file list without fetching file contents.

The host must publish {"files": ["SKILL.md", "data/nested.bin"]} in the skill's index.json. This is separate from grouped resource listing and must include every supporting file.

list_resources async

list_resources(skill_id: str) -> dict[str, list[str]]

List a skill's resources from its index.json manifest.

Requires resource_manifest=True. The manifest is a JSON object at {base_url}/{skill_id}/index.json mapping resource kinds to name lists::

{"references": ["sev.md"], "scripts": ["run.sh"], "assets": []}

Unknown keys are ignored and missing kinds default to empty. Entries that are not valid resource names are dropped, since a manifest is host-supplied data and a name is later interpolated into a URL.

Parameters:

Name Type Description Default
skill_id str

Skill name.

required

Returns:

Type Description
dict[str, list[str]]

Mapping of resource kind to sorted resource names.

Raises:

Type Description
ResourceListingNotSupportedError

If the provider was built without resource_manifest=True, or the skill has no published manifest.

SkillNotFoundError

If the skill itself does not exist.

AgentSkillsError

If the manifest is not a JSON object.

read_file async

read_file(skill_id: str, path: str) -> bytes

Fetch exact file bytes, bypassing the parsed SKILL.md cache.

Paths are POSIX-relative to the skill directory. Nested paths are supported. Redirects and unsolicited conditional responses are refused.

NetworkPolicyError

Bases: AgentSkillsError

A destination or redirect violates configured outbound policy.