Skill Registries
Skill registries let you discover, install, and manage skills from remote sources — such as Git repositories — without manually downloading or organizing skill directories. Registries integrate seamlessly with SkillsToolset, so skills from a remote repo appear alongside local and programmatic skills.
Installation
Git-backed registries require GitPython:
pip install pydantic-ai-skills[git]
Quick Start
Load Skills from a Git Repository
from pydantic_ai import Agent, RunContext
from pydantic_ai_skills import SkillsToolset
from pydantic_ai_skills.registries import GitSkillsRegistry, GitCloneOptions
# Clone Anthropic's public skills repo (shallow, single-branch)
registry = GitSkillsRegistry(
repo_url='https://github.com/anthropics/skills',
path='skills',
target_dir='./anthropics-skills',
clone_options=GitCloneOptions(depth=1, single_branch=True),
)
# Pass the registry to the toolset — skills are available immediately
skills_toolset = SkillsToolset(registries=[registry])
agent = Agent(
model='openai:gpt-5.2',
instructions='You are a helpful assistant with access to a variety of skills.',
toolsets=[skills_toolset],
)
@agent.instructions
async def add_skills(ctx: RunContext) -> str | None:
return await skills_toolset.get_instructions(ctx)
View the complete example: git_registry_usage.py
GitSkillsRegistry
GitSkillsRegistry is the primary concrete registry. It clones a Git repository, discovers SKILL.md files, and exposes the skills to your agent.
Constructor Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
repo_url |
str |
— | Full URL of the Git repository (HTTPS or SSH). |
target_dir |
str \| Path \| None |
None |
Local clone directory. Defaults to a temporary directory. |
path |
str |
"" |
Sub-path inside the repo containing skill directories. |
token |
str \| None |
None |
Personal access token. Falls back to GITHUB_TOKEN env var. |
ssh_key_file |
str \| Path \| None |
None |
Path to SSH private key for SSH authentication. |
clone_options |
GitCloneOptions \| None |
None |
Fine-grained Git clone configuration. |
validate |
bool |
True |
Validate SKILL.md frontmatter after cloning. |
auto_install |
bool |
True |
Clone/pull automatically on first access. |
GitCloneOptions
Fine-tune the Git clone operation:
from pydantic_ai_skills.registries import GitCloneOptions
options = GitCloneOptions(
depth=1, # Shallow clone (1 commit)
branch='main', # Specific branch
single_branch=True, # Only fetch one branch
sparse_paths=['skills/pdf'], # Sparse checkout (specific paths only)
multi_options=['--filter=blob:none'], # Blobless clone
env={'GIT_SSH_COMMAND': '...'}, # Custom env vars for git
git_options={}, # Extra kwargs for GitPython
)
Authentication
# Explicit token
registry = GitSkillsRegistry(
repo_url='https://github.com/my-org/private-skills.git',
token='ghp_...',
)
# Or via environment variable
# export GITHUB_TOKEN=ghp_...
registry = GitSkillsRegistry(
repo_url='https://github.com/my-org/private-skills.git',
)
registry = GitSkillsRegistry(
repo_url='git@github.com:my-org/private-skills.git',
ssh_key_file='~/.ssh/id_ed25519_skills',
)
Offline / Air-Gapped Mode
Disable automatic cloning for environments without network access:
# Pre-clone the repo manually, then point the registry at it
registry = GitSkillsRegistry(
repo_url='https://github.com/anthropics/skills',
target_dir='/opt/skills-mirror',
auto_install=False,
)
Skill Metadata Enrichment
Skills loaded from a registry automatically receive extra metadata:
skill = await registry.get('pdf')
print(skill.metadata)
# {
# 'source_url': 'https://github.com/anthropics/skills/tree/main/skills/pdf',
# 'registry': 'GitSkillsRegistry',
# 'repo': 'https://github.com/anthropics/skills',
# 'version': 'abc123...', # HEAD commit SHA
# }
Registry Composition
Registries support lightweight views — wrappers that transform skill names or visibility without modifying the underlying registry. These mirror the composition patterns from Pydantic AI's toolset system.
Filtering Skills
Restrict which skills are visible:
# Only expose skills with 'pdf' in their name
pdf_registry = registry.filtered(lambda skill: 'pdf' in skill.name.lower())
# Only skills with a specific tag in metadata
tagged = registry.filtered(
lambda s: 'analytics' in (s.metadata or {}).get('tags', [])
)
Prefixing Skill Names
Avoid name collisions when combining multiple registries:
# All skill names get prefixed: 'pdf' → 'anthropic-pdf'
anthropic = registry.prefixed('anthropic-')
skill = await anthropic.get('anthropic-pdf') # works
skill = await anthropic.get('pdf') # raises SkillNotFoundError
Renaming Skills
Apply explicit name mappings:
# Map new names to original names
renamed = registry.renamed({
'doc-tool': 'pdf', # 'pdf' is now accessible as 'doc-tool'
'sheet-tool': 'xlsx', # 'xlsx' is now accessible as 'sheet-tool'
})
skill = await renamed.get('doc-tool') # fetches 'pdf'
skill = await renamed.get('xlsx') # still works (unmapped names pass through)
Combining Registries
Aggregate multiple registries into a single source:
from pydantic_ai_skills.registries import CombinedRegistry, GitSkillsRegistry
github_registry = GitSkillsRegistry(
repo_url='https://github.com/anthropics/skills',
path='skills',
target_dir='./cache/anthropic',
)
internal_registry = GitSkillsRegistry(
repo_url='https://github.com/my-org/internal-skills',
target_dir='./cache/internal',
)
combined = CombinedRegistry(registries=[github_registry, internal_registry])
# Searches fan out to all registries in parallel
results = await combined.search('pdf')
# get/install/update try each registry in order
skill = await combined.get('pdf')
When multiple registries provide a skill with the same name, the first registry wins (based on the order passed to CombinedRegistry).
Chaining Composition
Wrappers can be chained for complex setups:
# Start with a Git registry
registry = GitSkillsRegistry(
repo_url='https://github.com/anthropics/skills',
path='skills',
target_dir='./cached-skills',
)
# Filter to only document-related skills, then prefix them
doc_skills = (
registry
.filtered(lambda s: s.name in ('pdf', 'docx', 'pptx'))
.prefixed('docs-')
)
# doc_skills now has: 'docs-pdf', 'docs-docx', 'docs-pptx'
Mixing Registries with Local Skills
SkillsToolset supports all three skill sources simultaneously. Priority order: programmatic skills > directory skills > registry skills.
from pydantic_ai_skills import SkillsToolset, Skill
from pydantic_ai_skills.registries import GitSkillsRegistry
# 1. Programmatic skill (highest priority)
custom_skill = Skill(
name='my-tool',
description='Custom in-code skill',
content='Instructions for my-tool...',
)
# 2. Git registry (lowest priority)
registry = GitSkillsRegistry(
repo_url='https://github.com/anthropics/skills',
path='skills',
target_dir='./cached-skills',
)
# All three sources combined
toolset = SkillsToolset(
skills=[custom_skill], # Programmatic skills
directories=['./skills'], # Local filesystem skills
registries=[registry], # Remote registry skills
)
If a skill name appears in multiple sources, the higher-priority source wins and a duplicate warning is emitted for directory-level conflicts.
Creating Custom Registries
Implement the SkillRegistry abstract base class to create your own registry backed by any source (REST API, database, cloud storage, etc.):
from pathlib import Path
from pydantic_ai_skills.registries import SkillRegistry
from pydantic_ai_skills.types import Skill
class MyApiRegistry(SkillRegistry):
"""Registry backed by a custom REST API."""
def __init__(self, api_url: str):
self._api_url = api_url
self._skills: list[Skill] = []
async def search(self, query: str, limit: int = 10) -> list[Skill]:
# Implement search against your API
...
async def get(self, skill_name: str) -> Skill:
# Fetch a single skill by name
...
async def install(self, skill_name: str, target_dir: str | Path) -> Path:
# Download and install the skill
...
async def update(self, skill_name: str, target_dir: str | Path) -> Path:
# Update an installed skill
...
def get_skills(self) -> list[Skill]:
# Return all available skills (synchronous, called during init)
return self._skills
You can also extend WrapperRegistry to create custom composition wrappers:
from pydantic_ai_skills.registries import WrapperRegistry
from pydantic_ai_skills.types import Skill
class LoggingRegistry(WrapperRegistry):
"""Registry that logs all operations."""
async def search(self, query: str, limit: int = 10) -> list[Skill]:
print(f'Searching for: {query}')
results = await self.wrapped.search(query, limit)
print(f'Found {len(results)} results')
return results
Registry API
All registries implement the following interface:
| Method | Description |
|---|---|
search(query, limit) |
Search for skills by keyword (async) |
get(skill_name) |
Retrieve a single skill by name (async) |
install(skill_name, target_dir) |
Copy a skill to a local directory (async) |
update(skill_name, target_dir) |
Update an installed skill (async) |
get_skills() |
Return all available skills (sync, used by SkillsToolset) |
filtered(predicate) |
Return a filtered view of this registry |
prefixed(prefix) |
Return a view with prefixed skill names |
renamed(name_map) |
Return a view with renamed skills |
Security Considerations
- Trusted sources only: Only use registries from sources you trust. Malicious skills can execute code or invoke tools in unintended ways.
- Token handling: Tokens are embedded in clone URLs but never exposed in
repr()or logs. The_sanitize_url()helper redacts credentials. - Path traversal: Both source and destination paths are validated during
install()to prevent symlink-based escapes. - SSH key permissions: A warning is emitted if SSH key files have permissions wider than
0o600. - Skill validation: By default, all discovered skills pass through
validate_skill_metadata()after cloning.
Warning
Skills loaded from remote registries carry the same security implications as any third-party code. Always audit skills from untrusted sources before use. See Security & Deployment for detailed guidance.
See Also
- Quick Start — Get started with basic skills
- Core Concepts — Understanding the skill system
- Advanced Features — Decorators, templates, dependency injection
- API Reference — Registries — Full API documentation
- Security & Deployment — Production security guidance