agentskills-http 0.2.2__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,221 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentskills-http
3
+ Version: 0.3.0
4
+ Summary: HTTP-based skill providers for the Agent Skills format (https://agentskills.io)
5
+ License: MIT
6
+ Author: Pratik Panda
7
+ Requires-Python: >=3.12,<4.0
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Classifier: Topic :: Software Development :: Libraries
16
+ Requires-Dist: agentskills-core (>=0.3.0,<1.0)
17
+ Requires-Dist: httpx (>=0.27,<1.0)
18
+ Requires-Dist: pyyaml (>=6.0,<7.0)
19
+ Project-URL: Homepage, https://agentskills.io
20
+ Project-URL: Repository, https://github.com/pratikxpanda/agentskills-sdk
21
+ Description-Content-Type: text/markdown
22
+
23
+ # agentskills-http
24
+
25
+ [![PyPI](https://img.shields.io/pypi/v/agentskills-http)](https://pypi.org/project/agentskills-http/)
26
+ [![Python 3.12 | 3.13](https://img.shields.io/pypi/pyversions/agentskills-http)](https://pypi.org/project/agentskills-http/)
27
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/pratikxpanda/agentskills-sdk/blob/main/LICENSE)
28
+
29
+ > HTTP static-file skill provider for the [Agent Skills SDK](https://github.com/pratikxpanda/agentskills-sdk).
30
+
31
+ Serves [Agent Skills](https://agentskills.io) from any static HTTP file host - S3, Azure Blob, CDN, GitHub Pages, Nginx, etc. Expects the same directory-tree layout as the filesystem provider, served over HTTP.
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ pip install agentskills-http
37
+ ```
38
+
39
+ Requires Python 3.12 or newer. Installs `agentskills-core`, `httpx`, and `pyyaml` as dependencies.
40
+
41
+ ## Expected URL Layout
42
+
43
+ ```text
44
+ https://cdn.example.com/skills/
45
+ ├── incident-response/
46
+ │ ├── SKILL.md
47
+ │ ├── references/severity-levels.md
48
+ │ ├── scripts/page-oncall.sh
49
+ │ └── assets/flowchart.mermaid
50
+ └── another-skill/
51
+ └── SKILL.md
52
+ ```
53
+
54
+ ## Usage
55
+
56
+ ```python
57
+ from agentskills_core import SkillRegistry
58
+ from agentskills_http import HTTPStaticFileSkillProvider
59
+
60
+ async with HTTPStaticFileSkillProvider("https://cdn.example.com/skills") as provider:
61
+ registry = SkillRegistry()
62
+ await registry.register("incident-response", provider)
63
+
64
+ skill = registry.get_skill("incident-response")
65
+ meta = await skill.get_metadata()
66
+ body = await skill.get_body()
67
+ ```
68
+
69
+ ### Custom Headers
70
+
71
+ Pass authentication or other headers:
72
+
73
+ ```python
74
+ from agentskills_http import HTTPStaticFileSkillProvider
75
+
76
+ provider = HTTPStaticFileSkillProvider(
77
+ "https://cdn.example.com/skills",
78
+ headers={"Authorization": "Bearer <token>"},
79
+ )
80
+ ```
81
+
82
+ ### Bring Your Own Client
83
+
84
+ Supply a pre-configured `httpx.AsyncClient` for full control over timeouts, proxies, etc.:
85
+
86
+ ```python
87
+ import httpx
88
+ from agentskills_http import HTTPStaticFileSkillProvider
89
+
90
+ client = httpx.AsyncClient(timeout=30, headers={"Authorization": "Bearer <token>"})
91
+ provider = HTTPStaticFileSkillProvider("https://cdn.example.com/skills", client=client)
92
+ # caller is responsible for closing the client
93
+ ```
94
+
95
+ > **Note:** `client` and `headers` are mutually exclusive. Configure headers on the client directly when providing your own.
96
+
97
+ ## API
98
+
99
+ ### `HTTPStaticFileSkillProvider(base_url, *, client=None, headers=None, params=None, require_tls=False, max_response_bytes=10_485_760, revalidate=False)`
100
+
101
+ | Parameter | Type | Default | Description |
102
+ | --- | --- | --- | --- |
103
+ | `base_url` | `str` | - | Root URL where the skill tree is hosted |
104
+ | `client` | `AsyncClient \| None` | `None` | Pre-configured httpx client (caller manages lifecycle) |
105
+ | `headers` | `dict \| None` | `None` | Extra headers sent with every request |
106
+ | `params` | `dict \| None` | `None` | Query parameters appended to every request |
107
+ | `require_tls` | `bool` | `False` | Reject `http://` URLs with `ValueError` |
108
+ | `max_response_bytes` | `int` | `10_485_760` | Maximum allowed response size in bytes |
109
+ | `revalidate` | `bool` | `False` | Re-check cached `SKILL.md` on every access with `If-None-Match` / `If-Modified-Since` |
110
+ | `resource_manifest` | `bool` | `False` | Enable `list_resources()` by reading a per-skill `index.json` |
111
+ | `timeout` | `float` | `30.0` | Request timeout in seconds (ignored when you supply `client`) |
112
+ | `max_retries` | `int` | `2` | Retries after the initial attempt, for retryable failures only |
113
+ | `retry_backoff` | `float` | `0.5` | Base delay in seconds for exponential backoff |
114
+ | `max_retry_delay` | `float` | `30.0` | Ceiling on any single backoff sleep |
115
+
116
+ > **Note:** `client` and `headers`/`params` are mutually exclusive. Configure headers and params on the client directly when providing your own.
117
+
118
+ | Method | Returns | Description |
119
+ | --- | --- | --- |
120
+ | `get_metadata(skill_id)` | `dict[str, Any]` | Parsed YAML frontmatter from `SKILL.md` |
121
+ | `get_body(skill_id)` | `str` | Markdown body after the frontmatter |
122
+ | `get_script(skill_id, name)` | `bytes` | Raw script content |
123
+ | `get_asset(skill_id, name)` | `bytes` | Raw asset content |
124
+ | `get_reference(skill_id, name)` | `bytes` | Raw reference content |
125
+ | `list_resources(skill_id)` | `dict[str, list[str]]` | Resource names from `index.json` (requires `resource_manifest=True`) |
126
+ | `invalidate(skill_id=None)` | `None` | Drop cached `SKILL.md` content for one skill, or all skills |
127
+ | `aclose()` | `None` | Close the HTTP client (if owned by the provider) |
128
+
129
+ Supports `async with` for automatic cleanup.
130
+
131
+ ## Resource Discovery
132
+
133
+ A static file host cannot be enumerated: there is no portable directory listing over plain HTTP. By default this provider therefore reports that it *cannot* list resources — `list_resources()` raises `ResourceListingNotSupportedError` — rather than returning an empty mapping that would look like a skill with no resources.
134
+
135
+ If you control the host, publish a small manifest at `{base_url}/{skill_id}/index.json`:
136
+
137
+ ```json
138
+ {
139
+ "references": ["severity-levels.md"],
140
+ "scripts": ["page-oncall.sh"],
141
+ "assets": ["flowchart.mermaid"]
142
+ }
143
+ ```
144
+
145
+ Then opt in:
146
+
147
+ ```python
148
+ provider = HTTPStaticFileSkillProvider(BASE, resource_manifest=True)
149
+ listing = await provider.list_resources("incident-response")
150
+ ```
151
+
152
+ Missing categories default to empty lists. A manifest is host-supplied data whose entries are later interpolated into URLs, so names failing the identifier-safety check are dropped. If a given skill has no `index.json`, `list_resources()` raises `ResourceListingNotSupportedError` for that skill — again, not an empty result.
153
+
154
+ ## Caching
155
+
156
+ `SKILL.md` responses are cached per provider instance. Without it a single skill costs up to five round-trips per agent session — twice during registration, once per catalog build, and again on each tool call. Scripts, assets and references are not cached.
157
+
158
+ By default the cache is served until you call `invalidate()`. If your host serves mutable skills and the process is long-lived, opt into conditional revalidation instead:
159
+
160
+ ```python
161
+ provider = HTTPStaticFileSkillProvider(BASE, revalidate=True)
162
+ ```
163
+
164
+ That sends `If-None-Match` / `If-Modified-Since` on every access and reuses the cached body on `304`. It costs one cheap round-trip per access, so prefer the default plus an explicit `invalidate()` when you control publishing.
165
+
166
+ ## Error Handling
167
+
168
+ | Scenario | Exception | Retried |
169
+ | --- | --- | --- |
170
+ | `404` / `410` on `SKILL.md` | `SkillNotFoundError` | No |
171
+ | `404` / `410` on a resource | `ResourceNotFoundError` | No |
172
+ | `5xx`, `408`, `425`, `429` | `SkillUnavailableError` | Yes |
173
+ | Timeouts, connection and protocol errors | `SkillUnavailableError` | Yes |
174
+ | `401` / `403` | `AgentSkillsError` | No |
175
+ | Other `4xx`, oversized responses | `AgentSkillsError` | No |
176
+
177
+ All exceptions inherit from `AgentSkillsError`.
178
+
179
+ The split between `SkillNotFoundError` and `SkillUnavailableError` is the point of the taxonomy: a `503` means the skill may well exist and the same request could succeed in a moment, whereas a `404` means it is gone. Collapsing both into "not found" turns a retryable blip into a permanent-looking failure, and nothing downstream can tell the difference.
180
+
181
+ ### Retries
182
+
183
+ Retryable failures are retried with exponential backoff and full jitter:
184
+
185
+ ```python
186
+ provider = HTTPStaticFileSkillProvider(
187
+ BASE,
188
+ max_retries=2, # attempts after the first; 0 disables
189
+ retry_backoff=0.5, # base delay in seconds
190
+ max_retry_delay=30.0, # ceiling on any single sleep
191
+ )
192
+ ```
193
+
194
+ Jitter matters because a registry builds its catalog concurrently — without it, every skill fetch would retry in lockstep and hit the recovering server as one wave.
195
+
196
+ `Retry-After` is honoured in both the delay-seconds and HTTP-date forms. If the server asks for longer than `max_retry_delay`, the request is **not** retried: blocking a request path for minutes is worse than failing fast. The advised delay is still available to the caller as `SkillUnavailableError.retry_after`, so a scheduler can act on it.
197
+
198
+ ## Security
199
+
200
+ - **Input validation** - Skill IDs and resource names are validated against a safe-character pattern (`^[a-zA-Z0-9][a-zA-Z0-9._-]*$`) to prevent path-traversal and injection attacks.
201
+ - **TLS warnings** - A `UserWarning` is emitted when `base_url` uses unencrypted HTTP. Set `require_tls=True` to reject HTTP URLs entirely.
202
+ - **Redirect protection** - The internally-created HTTP client does not follow redirects by default, preventing open-redirect SSRF.
203
+ - **Timeouts** - Default 30-second timeout on all HTTP requests. Configure via `timeout`.
204
+ - **Response size limits** - Responses exceeding 10 MB (default) are rejected before processing. Configure via `max_response_bytes`.
205
+ - **Error-message sanitization** - Messages carry the status code and the path *relative to `base_url`* — never the host, never a query string. The underlying `httpx` exception is deliberately **not** chained (`from None`), because `httpx.HTTPStatusError` renders the full request URL including its query string, which is exactly where SAS tokens and signed-URL signatures live. Chaining it leaked credentials into every traceback.
206
+
207
+ For the full security policy, see [SECURITY.md](https://github.com/pratikxpanda/agentskills-sdk/blob/main/SECURITY.md).
208
+
209
+ ## Deployment Considerations
210
+
211
+ - **Rate limiting** - The SDK does not enforce rate limits on MCP tool
212
+ calls or HTTP requests. Deploy behind a reverse proxy or API gateway
213
+ that provides rate limiting in production environments.
214
+ - **Credential management** - Do not store secrets (API keys, SAS
215
+ tokens, Authorization headers) in config files committed to version
216
+ control. Use environment variables or a secret manager instead.
217
+
218
+ ## License
219
+
220
+ MIT
221
+
@@ -0,0 +1,198 @@
1
+ # agentskills-http
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/agentskills-http)](https://pypi.org/project/agentskills-http/)
4
+ [![Python 3.12 | 3.13](https://img.shields.io/pypi/pyversions/agentskills-http)](https://pypi.org/project/agentskills-http/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/pratikxpanda/agentskills-sdk/blob/main/LICENSE)
6
+
7
+ > HTTP static-file skill provider for the [Agent Skills SDK](https://github.com/pratikxpanda/agentskills-sdk).
8
+
9
+ Serves [Agent Skills](https://agentskills.io) from any static HTTP file host - S3, Azure Blob, CDN, GitHub Pages, Nginx, etc. Expects the same directory-tree layout as the filesystem provider, served over HTTP.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ pip install agentskills-http
15
+ ```
16
+
17
+ Requires Python 3.12 or newer. Installs `agentskills-core`, `httpx`, and `pyyaml` as dependencies.
18
+
19
+ ## Expected URL Layout
20
+
21
+ ```text
22
+ https://cdn.example.com/skills/
23
+ ├── incident-response/
24
+ │ ├── SKILL.md
25
+ │ ├── references/severity-levels.md
26
+ │ ├── scripts/page-oncall.sh
27
+ │ └── assets/flowchart.mermaid
28
+ └── another-skill/
29
+ └── SKILL.md
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ```python
35
+ from agentskills_core import SkillRegistry
36
+ from agentskills_http import HTTPStaticFileSkillProvider
37
+
38
+ async with HTTPStaticFileSkillProvider("https://cdn.example.com/skills") as provider:
39
+ registry = SkillRegistry()
40
+ await registry.register("incident-response", provider)
41
+
42
+ skill = registry.get_skill("incident-response")
43
+ meta = await skill.get_metadata()
44
+ body = await skill.get_body()
45
+ ```
46
+
47
+ ### Custom Headers
48
+
49
+ Pass authentication or other headers:
50
+
51
+ ```python
52
+ from agentskills_http import HTTPStaticFileSkillProvider
53
+
54
+ provider = HTTPStaticFileSkillProvider(
55
+ "https://cdn.example.com/skills",
56
+ headers={"Authorization": "Bearer <token>"},
57
+ )
58
+ ```
59
+
60
+ ### Bring Your Own Client
61
+
62
+ Supply a pre-configured `httpx.AsyncClient` for full control over timeouts, proxies, etc.:
63
+
64
+ ```python
65
+ import httpx
66
+ from agentskills_http import HTTPStaticFileSkillProvider
67
+
68
+ client = httpx.AsyncClient(timeout=30, headers={"Authorization": "Bearer <token>"})
69
+ provider = HTTPStaticFileSkillProvider("https://cdn.example.com/skills", client=client)
70
+ # caller is responsible for closing the client
71
+ ```
72
+
73
+ > **Note:** `client` and `headers` are mutually exclusive. Configure headers on the client directly when providing your own.
74
+
75
+ ## API
76
+
77
+ ### `HTTPStaticFileSkillProvider(base_url, *, client=None, headers=None, params=None, require_tls=False, max_response_bytes=10_485_760, revalidate=False)`
78
+
79
+ | Parameter | Type | Default | Description |
80
+ | --- | --- | --- | --- |
81
+ | `base_url` | `str` | - | Root URL where the skill tree is hosted |
82
+ | `client` | `AsyncClient \| None` | `None` | Pre-configured httpx client (caller manages lifecycle) |
83
+ | `headers` | `dict \| None` | `None` | Extra headers sent with every request |
84
+ | `params` | `dict \| None` | `None` | Query parameters appended to every request |
85
+ | `require_tls` | `bool` | `False` | Reject `http://` URLs with `ValueError` |
86
+ | `max_response_bytes` | `int` | `10_485_760` | Maximum allowed response size in bytes |
87
+ | `revalidate` | `bool` | `False` | Re-check cached `SKILL.md` on every access with `If-None-Match` / `If-Modified-Since` |
88
+ | `resource_manifest` | `bool` | `False` | Enable `list_resources()` by reading a per-skill `index.json` |
89
+ | `timeout` | `float` | `30.0` | Request timeout in seconds (ignored when you supply `client`) |
90
+ | `max_retries` | `int` | `2` | Retries after the initial attempt, for retryable failures only |
91
+ | `retry_backoff` | `float` | `0.5` | Base delay in seconds for exponential backoff |
92
+ | `max_retry_delay` | `float` | `30.0` | Ceiling on any single backoff sleep |
93
+
94
+ > **Note:** `client` and `headers`/`params` are mutually exclusive. Configure headers and params on the client directly when providing your own.
95
+
96
+ | Method | Returns | Description |
97
+ | --- | --- | --- |
98
+ | `get_metadata(skill_id)` | `dict[str, Any]` | Parsed YAML frontmatter from `SKILL.md` |
99
+ | `get_body(skill_id)` | `str` | Markdown body after the frontmatter |
100
+ | `get_script(skill_id, name)` | `bytes` | Raw script content |
101
+ | `get_asset(skill_id, name)` | `bytes` | Raw asset content |
102
+ | `get_reference(skill_id, name)` | `bytes` | Raw reference content |
103
+ | `list_resources(skill_id)` | `dict[str, list[str]]` | Resource names from `index.json` (requires `resource_manifest=True`) |
104
+ | `invalidate(skill_id=None)` | `None` | Drop cached `SKILL.md` content for one skill, or all skills |
105
+ | `aclose()` | `None` | Close the HTTP client (if owned by the provider) |
106
+
107
+ Supports `async with` for automatic cleanup.
108
+
109
+ ## Resource Discovery
110
+
111
+ A static file host cannot be enumerated: there is no portable directory listing over plain HTTP. By default this provider therefore reports that it *cannot* list resources — `list_resources()` raises `ResourceListingNotSupportedError` — rather than returning an empty mapping that would look like a skill with no resources.
112
+
113
+ If you control the host, publish a small manifest at `{base_url}/{skill_id}/index.json`:
114
+
115
+ ```json
116
+ {
117
+ "references": ["severity-levels.md"],
118
+ "scripts": ["page-oncall.sh"],
119
+ "assets": ["flowchart.mermaid"]
120
+ }
121
+ ```
122
+
123
+ Then opt in:
124
+
125
+ ```python
126
+ provider = HTTPStaticFileSkillProvider(BASE, resource_manifest=True)
127
+ listing = await provider.list_resources("incident-response")
128
+ ```
129
+
130
+ Missing categories default to empty lists. A manifest is host-supplied data whose entries are later interpolated into URLs, so names failing the identifier-safety check are dropped. If a given skill has no `index.json`, `list_resources()` raises `ResourceListingNotSupportedError` for that skill — again, not an empty result.
131
+
132
+ ## Caching
133
+
134
+ `SKILL.md` responses are cached per provider instance. Without it a single skill costs up to five round-trips per agent session — twice during registration, once per catalog build, and again on each tool call. Scripts, assets and references are not cached.
135
+
136
+ By default the cache is served until you call `invalidate()`. If your host serves mutable skills and the process is long-lived, opt into conditional revalidation instead:
137
+
138
+ ```python
139
+ provider = HTTPStaticFileSkillProvider(BASE, revalidate=True)
140
+ ```
141
+
142
+ That sends `If-None-Match` / `If-Modified-Since` on every access and reuses the cached body on `304`. It costs one cheap round-trip per access, so prefer the default plus an explicit `invalidate()` when you control publishing.
143
+
144
+ ## Error Handling
145
+
146
+ | Scenario | Exception | Retried |
147
+ | --- | --- | --- |
148
+ | `404` / `410` on `SKILL.md` | `SkillNotFoundError` | No |
149
+ | `404` / `410` on a resource | `ResourceNotFoundError` | No |
150
+ | `5xx`, `408`, `425`, `429` | `SkillUnavailableError` | Yes |
151
+ | Timeouts, connection and protocol errors | `SkillUnavailableError` | Yes |
152
+ | `401` / `403` | `AgentSkillsError` | No |
153
+ | Other `4xx`, oversized responses | `AgentSkillsError` | No |
154
+
155
+ All exceptions inherit from `AgentSkillsError`.
156
+
157
+ The split between `SkillNotFoundError` and `SkillUnavailableError` is the point of the taxonomy: a `503` means the skill may well exist and the same request could succeed in a moment, whereas a `404` means it is gone. Collapsing both into "not found" turns a retryable blip into a permanent-looking failure, and nothing downstream can tell the difference.
158
+
159
+ ### Retries
160
+
161
+ Retryable failures are retried with exponential backoff and full jitter:
162
+
163
+ ```python
164
+ provider = HTTPStaticFileSkillProvider(
165
+ BASE,
166
+ max_retries=2, # attempts after the first; 0 disables
167
+ retry_backoff=0.5, # base delay in seconds
168
+ max_retry_delay=30.0, # ceiling on any single sleep
169
+ )
170
+ ```
171
+
172
+ Jitter matters because a registry builds its catalog concurrently — without it, every skill fetch would retry in lockstep and hit the recovering server as one wave.
173
+
174
+ `Retry-After` is honoured in both the delay-seconds and HTTP-date forms. If the server asks for longer than `max_retry_delay`, the request is **not** retried: blocking a request path for minutes is worse than failing fast. The advised delay is still available to the caller as `SkillUnavailableError.retry_after`, so a scheduler can act on it.
175
+
176
+ ## Security
177
+
178
+ - **Input validation** - Skill IDs and resource names are validated against a safe-character pattern (`^[a-zA-Z0-9][a-zA-Z0-9._-]*$`) to prevent path-traversal and injection attacks.
179
+ - **TLS warnings** - A `UserWarning` is emitted when `base_url` uses unencrypted HTTP. Set `require_tls=True` to reject HTTP URLs entirely.
180
+ - **Redirect protection** - The internally-created HTTP client does not follow redirects by default, preventing open-redirect SSRF.
181
+ - **Timeouts** - Default 30-second timeout on all HTTP requests. Configure via `timeout`.
182
+ - **Response size limits** - Responses exceeding 10 MB (default) are rejected before processing. Configure via `max_response_bytes`.
183
+ - **Error-message sanitization** - Messages carry the status code and the path *relative to `base_url`* — never the host, never a query string. The underlying `httpx` exception is deliberately **not** chained (`from None`), because `httpx.HTTPStatusError` renders the full request URL including its query string, which is exactly where SAS tokens and signed-URL signatures live. Chaining it leaked credentials into every traceback.
184
+
185
+ For the full security policy, see [SECURITY.md](https://github.com/pratikxpanda/agentskills-sdk/blob/main/SECURITY.md).
186
+
187
+ ## Deployment Considerations
188
+
189
+ - **Rate limiting** - The SDK does not enforce rate limits on MCP tool
190
+ calls or HTTP requests. Deploy behind a reverse proxy or API gateway
191
+ that provides rate limiting in production environments.
192
+ - **Credential management** - Do not store secrets (API keys, SAS
193
+ tokens, Authorization headers) in config files committed to version
194
+ control. Use environment variables or a secret manager instead.
195
+
196
+ ## License
197
+
198
+ MIT
@@ -1,16 +1,16 @@
1
- """HTTP-based skill providers for the Agent Skills format.
2
-
3
- This package provides :class:`HTTPStaticFileSkillProvider`, a concrete
4
- implementation of :class:`~agentskills_core.SkillProvider` that fetches
5
- `Agent Skills <https://agentskills.io>`_ from a static HTTP file host
6
- (S3, Azure Blob Storage, CDN, GitHub Pages, or any web server serving
7
- raw files).
8
-
9
- Install::
10
-
11
- pip install agentskills-http
12
- """
13
-
14
- from agentskills_http.static import HTTPStaticFileSkillProvider
15
-
16
- __all__ = ["HTTPStaticFileSkillProvider"]
1
+ """HTTP-based skill providers for the Agent Skills format.
2
+
3
+ This package provides :class:`HTTPStaticFileSkillProvider`, a concrete
4
+ implementation of :class:`~agentskills_core.SkillProvider` that fetches
5
+ `Agent Skills <https://agentskills.io>`_ from a static HTTP file host
6
+ (S3, Azure Blob Storage, CDN, GitHub Pages, or any web server serving
7
+ raw files).
8
+
9
+ Install::
10
+
11
+ pip install agentskills-http
12
+ """
13
+
14
+ from agentskills_http.static import HTTPStaticFileSkillProvider
15
+
16
+ __all__ = ["HTTPStaticFileSkillProvider"]