Registries API Reference
A registry materializes skill packages into a local directory that
SkillsCapability hands to harness. See Skill Registries for
the guide.
Bases: ABC
Abstract base for skill registries.
Implement sync to fetch skill packages and
lay them out as immediate child directories of a returned library path. Nothing else
is required — parsing, validation and instruction rendering all belong to harness.
Convenience methods :meth:filtered, :meth:prefixed, and :meth:renamed return
lightweight wrapper views; the underlying registry is never modified.
Source code in pydantic_ai_skills/registries/_base.py
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | |
sync
abstractmethod
sync() -> Path
Materialize this registry's skills and return the local library directory.
The returned path is a library: its immediate children are skill package
directories, each holding a SKILL.md. It is passed straight to harness's
Skills, so it must satisfy harness's rules — in particular the library itself
must not contain a SKILL.md.
Implementations should be idempotent and safe to call repeatedly: a second call
refreshes the local copy (a git pull, a re-sync) rather than starting over.
Returns:
| Type | Description |
|---|---|
Path
|
Path to the local skill-library directory. |
Source code in pydantic_ai_skills/registries/_base.py
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | |
skill_infos
skill_infos() -> list[SkillInfo]
Return the catalog fields of every skill package in this registry.
Syncs first, then reads each immediate child's SKILL.md. Used by
filtered and by callers that want
to know what a registry holds without constructing an agent.
Returns:
| Type | Description |
|---|---|
list[SkillInfo]
|
One |
list[SkillInfo]
|
by name. |
Source code in pydantic_ai_skills/registries/_base.py
67 68 69 70 71 72 73 74 75 76 77 78 79 80 | |
skill_names
skill_names() -> list[str]
Return the names of every skill package in this registry, sorted.
Source code in pydantic_ai_skills/registries/_base.py
82 83 84 | |
filtered
filtered(predicate: Callable[[SkillInfo], bool]) -> FilteredRegistry
Return a view of this registry limited to skills matching predicate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
predicate
|
Callable[[SkillInfo], bool]
|
A callable that accepts a
|
required |
Returns:
| Name | Type | Description |
|---|---|---|
A |
FilteredRegistry
|
|
FilteredRegistry
|
view backed by the same underlying source. |
Source code in pydantic_ai_skills/registries/_base.py
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | |
prefixed
prefixed(prefix: str) -> PrefixedRegistry
Return a view of this registry with prefix prepended to every skill name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prefix
|
str
|
String to prepend to every skill name. The result must still be a valid skill name, so a prefix normally ends with a hyphen. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
A |
PrefixedRegistry
|
|
PrefixedRegistry
|
view backed by the same underlying source. |
Source code in pydantic_ai_skills/registries/_base.py
102 103 104 105 106 107 108 109 110 111 112 113 114 115 | |
renamed
renamed(name_map: dict[str, str]) -> RenamedRegistry
Return a view of this registry with skills renamed per name_map.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name_map
|
dict[str, str]
|
Mapping of |
required |
Returns:
| Name | Type | Description |
|---|---|---|
A |
RenamedRegistry
|
|
RenamedRegistry
|
view backed by the same underlying source. |
Source code in pydantic_ai_skills/registries/_base.py
117 118 119 120 121 122 123 124 125 126 127 128 129 | |
__or__
__or__(other: SkillRegistry) -> CombinedRegistry
Return a registry that merges this one with other.
Earlier registries win on a duplicate skill name, matching
:class:~pydantic_ai_skills.registries.combined.CombinedRegistry.
Source code in pydantic_ai_skills/registries/_base.py
131 132 133 134 135 136 137 138 139 | |
The catalog fields of one skill package, as seen before harness validates it.
This is what a FilteredRegistry
predicate receives. It is deliberately shallow — no bundled files, no instructions
body — because filtering happens while staging directories, well before any skill is
handed to an agent.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
The package's directory name, NFKC-normalized. This, not the frontmatter
|
description |
str
|
The frontmatter |
directory |
Path
|
The package directory. |
Source code in pydantic_ai_skills/_parsing.py
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | |
Bases: SkillRegistry
Skills registry backed by a Git repository cloned with GitPython.
:meth:sync clones the repository on first call and performs a git pull on
subsequent ones (or a full re-clone if the local copy is corrupted or missing), then
returns the directory holding the skill packages.
The registry only reads the filesystem after cloning — it never calls any hosting platform's REST/GraphQL API — so it works with any git host accessible over HTTPS or SSH (GitHub, GitLab, Bitbucket, self-hosted, etc.).
It does not parse SKILL.md: the directory it produces is handed to
:class:~pydantic_ai_skills.SkillsCapability, and validating and rendering the
packages inside it is pydantic-ai-harness's job.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
repo_url
|
str
|
Full URL of the Git repository to clone (e.g.
|
required |
target_dir
|
str | Path | None
|
Local directory where the repository is cloned. Defaults to
a temporary directory scoped to the registry instance. A directory you
pass persists across :meth: |
None
|
path
|
str
|
Sub-path inside the repository that contains the skill directories.
Defaults to the repository root ( |
''
|
token
|
str | None
|
Personal access token (or any HTTPS password) used for
authentication. When |
None
|
ssh_key_file
|
str | Path | None
|
Path to a private SSH key for SSH-based authentication.
When provided, |
None
|
clone_options
|
GitCloneOptions | None
|
Fine-grained GitPython configuration. See
:class: |
None
|
auto_install
|
bool
|
When |
True
|
Examples:
Basic usage — clone a repository and expose all its skills:
from pydantic_ai_skills import GitSkillsRegistry, SkillsCapability
capability = SkillsCapability(
registries=[
GitSkillsRegistry(
repo_url="https://github.com/anthropics/skills",
path="skills",
target_dir="./cached-skills",
),
]
)
Blobless shallow clone with a PAT, only the pdf sub-path:
from pydantic_ai_skills.registries.git import GitSkillsRegistry, GitCloneOptions
registry = GitSkillsRegistry(
repo_url="https://github.com/anthropics/skills",
path="skills/pdf",
token="ghp_...",
clone_options=GitCloneOptions(
depth=1,
single_branch=True,
sparse_paths=["skills/pdf"],
multi_options=["--filter=blob:none"],
),
)
Filter to only PDF-related skills:
pdf_registry = registry.filtered(lambda info: "pdf" in info.name)
Prefix all skill names from this registry:
prefixed_registry = registry.prefixed("anthropic-")
# "pdf" skill is now accessible as "anthropic-pdf"
SSH authentication with a custom key:
registry = GitSkillsRegistry(
repo_url="git@github.com:my-org/private-skills.git",
ssh_key_file="~/.ssh/id_ed25519_skills",
)
Offline / air-gapped — pre-clone manually, disable auto-install so
:meth:sync never reaches the network:
registry = GitSkillsRegistry(
repo_url="https://github.com/anthropics/skills",
target_dir="/opt/skills-mirror",
auto_install=False,
)
Source code in pydantic_ai_skills/registries/git.py
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 | |
sync
sync() -> Path
Clone or pull the repository and return its skill-library directory.
The returned path is target_dir joined with path, whose immediate children
are the skill packages. With auto_install=False nothing is fetched and
whatever is already on disk is returned, which is what an air-gapped deployment
wants.
Returns:
| Type | Description |
|---|---|
Path
|
Path to the local skill-library directory. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
On git or network errors. |
ValueError
|
When the configured |
Source code in pydantic_ai_skills/registries/git.py
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 | |
revision
revision() -> str | None
Return the commit SHA the local clone is on, or None if it is not cloned.
Useful for recording exactly which version of a remote skill library an agent ran
with, since :meth:sync otherwise tracks a moving branch.
Source code in pydantic_ai_skills/registries/git.py
445 446 447 448 449 450 451 | |
Low-level GitPython configuration for clone and fetch operations.
All fields map directly to arguments accepted by git.Repo.clone_from or
git.Remote.fetch / git.Remote.pull, so developers who know GitPython can
use the full API without any wrapper layer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
depth
|
int | None
|
Create a shallow clone with history truncated to this many commits.
Passed as |
None
|
branch
|
str | None
|
Name of the remote branch, tag, or ref to check out after cloning
( |
None
|
single_branch
|
bool
|
When |
False
|
sparse_paths
|
list[str]
|
List of path patterns to include in a sparse checkout
( |
list()
|
env
|
dict[str, str]
|
Mapping of environment variables forwarded to every git sub-process
(e.g. |
dict()
|
multi_options
|
list[str]
|
Extra |
list()
|
git_options
|
dict[str, Any]
|
Mapping forwarded as keyword arguments directly to
|
dict()
|
Source code in pydantic_ai_skills/registries/git.py
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | |
Bases: SkillRegistry
Skills registry backed by an S3 bucket, downloaded with boto3.
:meth:sync lists and downloads every object under bucket/prefix into a local
cache directory, then returns the directory holding the skill packages. Each sync
mirrors the remote prefix — the cached subtree is cleared first, so skills removed
from the bucket no longer appear locally.
Works with Amazon S3 and any S3-compatible store (MinIO, Ceph, Cloudflare R2,
etc.). All connection details — credentials, endpoint_url, region, TLS,
and path-style addressing — are configured on the boto3 client you pass via
boto3_client. When omitted, a default boto3.client("s3") is built,
which uses boto3's standard credential resolution chain.
It does not parse SKILL.md: the directory it produces is handed to
:class:~pydantic_ai_skills.SkillsCapability, and validating and rendering the
packages inside it is pydantic-ai-harness's job.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
bucket
|
str
|
Name of the S3 bucket containing the skills. |
required |
prefix
|
str
|
Key prefix inside the bucket where skill directories live.
Defaults to the bucket root ( |
''
|
target_dir
|
str | Path | None
|
Local directory where objects are downloaded. Defaults to a
temporary directory scoped to the registry instance. A directory you pass
persists across :meth: |
None
|
boto3_client
|
Any | None
|
A pre-built boto3 S3 client. Use this to configure
credentials, |
None
|
auto_install
|
bool
|
When |
True
|
Examples:
Amazon S3 with the ambient credential chain:
from pydantic_ai_skills import S3SkillsRegistry, SkillsCapability
capability = SkillsCapability(
registries=[S3SkillsRegistry(bucket="my-skills", prefix="skills")]
)
MinIO (or any S3-compatible store) with a custom client:
import boto3
from botocore.config import Config
from pydantic_ai_skills.registries.s3 import S3SkillsRegistry
client = boto3.client(
"s3",
endpoint_url="http://localhost:9000",
aws_access_key_id="minioadmin",
aws_secret_access_key="minioadmin",
config=Config(s3={"addressing_style": "path"}),
)
registry = S3SkillsRegistry(bucket="skills", boto3_client=client)
Source code in pydantic_ai_skills/registries/s3.py
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | |
sync
sync() -> Path
Download the bucket prefix and return its skill-library directory.
The returned path is target_dir joined with prefix, whose immediate
children are the skill packages. With auto_install=False nothing is
downloaded and whatever is already on disk is returned.
Returns:
| Type | Description |
|---|---|
Path
|
Path to the local skill-library directory. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
On S3 listing or download errors. |
ValueError
|
When the prefix holds no synced skill library — usually a
|
Source code in pydantic_ai_skills/registries/s3.py
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | |
revision
revision(skill_name: str) -> str | None
Return the newest object modification time for one skill, ISO-formatted.
Useful for recording which version of a remote skill an agent ran with, since
:meth:sync otherwise tracks a moving prefix. Returns None before the first sync
or when the skill has no objects in the cached listing.
Source code in pydantic_ai_skills/registries/s3.py
234 235 236 237 238 239 240 241 | |
Bases: SkillRegistry
A registry backed by a skill library already present on the filesystem.
Passing a local directory straight to SkillsCapability(directories=...) is simpler
and does the same thing. Use this when a local library needs to be composed — merged
with a remote one, prefixed, or filtered — since composition operates on registries.
Attributes:
| Name | Type | Description |
|---|---|---|
path |
str | Path
|
The skill-library directory. Its immediate children are skill packages. |
Example
from pydantic_ai_skills import GitSkillsRegistry
from pydantic_ai_skills.registries import LocalSkillsRegistry
# Local skills take precedence over the ones published upstream.
combined = LocalSkillsRegistry('./skills') | GitSkillsRegistry(
'https://github.com/anthropics/skills', path='skills'
)
Source code in pydantic_ai_skills/registries/local.py
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | |
sync
sync() -> Path
Return the library directory, checking that it exists.
Raises:
| Type | Description |
|---|---|
ValueError
|
When the path does not exist or is not a directory. |
Source code in pydantic_ai_skills/registries/local.py
42 43 44 45 46 47 48 49 50 51 52 53 | |
Composition Wrappers
Each wrapper syncs the registry it wraps, then stages a new library holding the packages it wants under the names it wants. The wrapped registry is never modified.
Bases: SkillRegistry
A registry that wraps another registry and delegates to it.
:meth:sync is forwarded to wrapped. Subclasses that present a different library
than the one they wrap override it to stage their own.
Attributes:
| Name | Type | Description |
|---|---|---|
wrapped |
SkillRegistry
|
The registry being decorated. |
target_dir |
str | Path | None
|
Where a subclass stages its composed library. When None, a process-lifetime temporary directory is used. |
Source code in pydantic_ai_skills/registries/wrapper.py
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | |
sync
sync() -> Path
Delegate sync to the wrapped registry.
Source code in pydantic_ai_skills/registries/wrapper.py
34 35 36 | |
Bases: WrapperRegistry
A registry that exposes only the skills matching a predicate.
Syncs the wrapped registry, then stages a library containing just the packages for
which predicate(info) is True. The wrapped registry's own copy is never
modified.
Example
pdf_only = registry.filtered(lambda info: 'pdf' in info.name)
Source code in pydantic_ai_skills/registries/filtered.py
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | |
sync
sync() -> Path
Stage a library holding only the skills that pass the predicate.
Source code in pydantic_ai_skills/registries/filtered.py
36 37 38 39 40 41 42 43 44 45 46 47 48 49 | |
Bases: WrapperRegistry
A registry that prepends a prefix to every skill name.
Because harness derives a skill's name from its directory — and rejects a SKILL.md
whose frontmatter name disagrees with it — renaming means staging the package under
the new directory name and rewriting that key. Both happen here.
Example
anthropic = registry.prefixed('anthropic-')
# the "pdf" skill is exposed to the model as "anthropic-pdf"
Source code in pydantic_ai_skills/registries/prefixed.py
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | |
sync
sync() -> Path
Stage a library whose skills are all renamed with the prefix.
Raises:
| Type | Description |
|---|---|
ValueError
|
When the prefix yields a name harness would reject. |
Source code in pydantic_ai_skills/registries/prefixed.py
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | |
Bases: WrapperRegistry
A registry that exposes skills under names from a mapping.
Skills the map does not mention keep their original name. As with
:class:~pydantic_ai_skills.registries.prefixed.PrefixedRegistry, renaming stages the
package under its new directory name and rewrites the frontmatter name so harness
finds the two in agreement.
Attributes:
| Name | Type | Description |
|---|---|---|
name_map |
dict[str, str]
|
Mapping of |
Example
registry.renamed({'anthropic-pdf': 'pdf'})
Source code in pydantic_ai_skills/registries/renamed.py
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
sync
sync() -> Path
Stage a library with the mapped skills renamed.
Raises:
| Type | Description |
|---|---|
ValueError
|
When a new name is one harness would reject, when the map names an original skill this registry does not hold, or when two skills would end up sharing a name. |
Source code in pydantic_ai_skills/registries/renamed.py
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
Bases: SkillRegistry
A registry that merges several registries into one library.
Every child is synced and its packages staged into a single directory. Earlier
registries win on a duplicate skill name, and the shadowed one is reported with a
UserWarning — merging silently would hand harness a library whose contents depend on
directory iteration order.
Passing the merged library to SkillsCapability is equivalent to passing each child's
own library, except that this resolves the collisions itself rather than letting
harness reject the duplicate.
Attributes:
| Name | Type | Description |
|---|---|---|
registries |
Sequence[SkillRegistry]
|
The registries to merge, in precedence order. |
target_dir |
str | Path | None
|
Where to stage the merged library. When None, a process-lifetime temporary directory is used. |
Example
from pydantic_ai_skills.registries import CombinedRegistry
combined = CombinedRegistry(registries=[internal_registry, public_registry])
Source code in pydantic_ai_skills/registries/combined.py
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
sync
sync() -> Path
Sync every child registry and stage their skills into one library.
Source code in pydantic_ai_skills/registries/combined.py
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |