ai-registry
Resolve a stable alias to a concrete AI deployment — provider, model, account, endpoint — and stop there.
ai-registry is the configuration layer under your AI stack, not another client.
It answers one question — "which provider, which model, whose key, what URL?" —
and hands the answer to whatever SDK you already use.
It makes no network requests, defines no chat interface, ships no gateway, and cannot hold a literal API key. The runtime dependency closure is six packages.
from ai_registry import Registry
registry = Registry.from_project() # reads ./.ai-registry/registry.yaml
resolution = registry.resolve("chat-default")
| What you get | Example | Why it matters |
|---|---|---|
resolution.provider_id |
'deepseek' |
Which provider was chosen. |
resolution.model_id |
'deepseek-chat' |
The id to send, and to log. |
resolution.account_id |
'deepseek-primary' |
Which key was chosen. |
resolution.endpoint |
'https://api.deepseek.com/anthropic' |
Where to send it. |
resolution.model.capabilities |
tools=True, reasoning=False, … |
What the model can do. |
resolution.resolve_credential() |
'sk-…' |
Resolved lazily, only at the adapter boundary. |
The model, provider, account, or endpoint behind "chat-default" can change in
configuration without touching application code.
Why a resolver instead of a client
Most tools in this space fuse two separate concerns: deciding what to call and calling it. Fusing them means you adopt someone's request translation, error types, retry semantics, and dependency tree in order to get their configuration model.
That fusion has a well-known failure mode. From openai/codex#1370, on Azure deployment names:
No logic should inspect the user's deployment name when making assumptions about model capabilities.
That is exactly the split this library enforces. A deployment is where you
send the request. A model is what the model can do. They are different
objects, and Resolution gives you both.
Install
pip install ai-registry # core: pydantic + pyyaml only
pip install "ai-registry[cli]" # + ai-registry command
pip install "ai-registry[openai]" # + OpenAI SDK adapter
pip install "ai-registry[pydantic-ai]" # + Pydantic AI adapter
pip install "ai-registry[langchain]" # + LangChain chat/embeddings adapter
Requires Python 3.11+.
Configure
Projects keep configuration in .ai-registry/ at the repository root, resolved
from any subdirectory:
<project-root>/
└── .ai-registry/
├── providers/ # OPTIONAL — override or add providers
├── registry.yaml # default
├── registry.dev.yaml # OPTIONAL — profile "dev"
└── registry.prod.yaml # OPTIONAL — profile "prod"
# .ai-registry/registry.yaml
accounts:
- id: deepseek-primary
provider_id: deepseek
credential: env:DEEPSEEK_API_KEY # a reference, never a key
enabled_models: [deepseek-chat, deepseek-reasoner]
- id: uniapi-chat
provider_id: uniapi
credential: env:UNIAPI_API_KEY
enabled_models: [deepseek-v4-flash]
aliases:
- id: chat-default
deployments:
- account_id: deepseek-primary # preferred
model_id: deepseek-chat
- account_id: uniapi-chat # used when the first is cooling down
model_id: deepseek-v4-flash
routing: {priority: 1}
Select a profile with Registry.from_project(profile="prod") or
AI_REGISTRY_PROFILE=prod.
Use the result
Build a client yourself, or use an optional adapter:
from ai_registry import ClientFactory
factory = ClientFactory.from_project()
# An openai.OpenAI client, pointed at the resolved endpoint and key:
client = factory.openai_client("chat-default")
# A Pydantic AI model — a framework with no config-file registry of its own:
model = factory.pydantic_ai_model("chat-default")
# Registry routing becomes Pydantic AI request-time failover:
model = factory.pydantic_ai_fallback_model("chat-default")
# A LangChain model — LangGraph states take it directly as a node model:
model = factory.langchain_chat_model("chat-default")
Or drive failover yourself — candidates() returns every healthy deployment in
preference order:
for resolution in factory.registry.candidates("chat-default"):
try:
response = call(resolution)
except TransientError:
factory.registry.record_failure(resolution) # cools this target down everywhere
continue
factory.registry.record_success(resolution)
break
Inspect it
$ ai-registry explain chat-default
1. deepseek-primary/deepseek-chat -> https://api.deepseek.com/anthropic (credential: env (ok))
2. uniapi-chat/deepseek-v4-flash -> https://uni-api.cstcloud.cn/v1 (credential: env (unresolved))
$ ai-registry models --type chat --tools --min-context 500000
deepseek deepseek-v4-flash chat 1000000 reasoning,structured_output,tools
resolve and explain report whether a credential resolves, never its name or
value.
Features
- Alias-first resolution, with an explicit
account-id/model-idescape hatch. - Multiple accounts and keys per provider, as reusable first-class objects.
- Deterministic deployment selection: priority, weight, disabled, plus a health store with time-based cooldown and exponential backoff.
- Capability-aware catalog queries — find a chat model with tools and a 200k window without hardcoding a model id.
- Secret references, not secrets:
env:/secret_ref:, resolved lazily, with a pluggableSecretResolverfor Vault, AWS, or Kubernetes. - Secret-safe by construction: literal keys rejected;
repr, dumps, and errors redacted; credential-bearing URLs refused. - Bring your own catalog:
ai_registry.catalog.load_models_dev()imports a models.devapi.json, and the built-in catalog takes its whole model set from a vendored snapshot — provider files carry only endpoints, settings, and deltas. Maintainers refresh it withai-registry catalog diff|sync. - Observability built in:
Resolution.otel_attributes()emits OpenTelemetry GenAI attributes plus which alias and account were selected. - Testable:
ai_registry.testingships supported fakes.
Why not X?
| Alias layer | Resolution separable from invocation | Multiple keys per provider | In-process | Rejects literal secrets | |
|---|---|---|---|---|---|
| ai-registry | config file | yes, that's all it does | yes, as Account |
yes (6 pkgs) | yes |
| LiteLLM Router | model_name groups |
yes, via get_available_deployment() |
yes, by repeating entries | yes (49 pkgs) | no |
llm (simonw) |
aliases.json |
yes, llm.get_model() |
yes, api_key_name |
yes | no (plaintext keys.json) |
| Pydantic AI | 'openai:gpt-4o' string |
no — returns a live model | no | yes | n/a |
| Vercel AI SDK registry | customProvider (code) |
no — returns a live model | no | yes (TS) | n/a |
| Portkey / Helicone / Bifrost / Kong | gateway config | no | yes | no — network hop | varies |
Use LiteLLM instead if you want one completion() call across providers,
request translation, retries, spend tracking, or a proxy. It does far more than
this library and does it well.
Use ai-registry if you already have SDKs you like and only want the
configuration layer — especially if the dependency footprint of the component
that touches every API key you own is something you care about. For scale: the
resolved closure is 49 packages for litellm, 107 for litellm[proxy], and 6
here. In March 2026 two litellm releases were
compromised on PyPI
with a .pth file that harvested cloud credentials on every Python start. Fewer
moving parts near your keys is a real property, not an aesthetic one.
The two are not exclusive: point an Account at a LiteLLM proxy and use this to
decide which one.
Documentation
| Guide | Contents |
|---|---|
| Overview | The idea, concepts, architecture, goals and non-goals. |
| Getting started | Install, first resolution, loading files, built-in data. |
| Configuration | Complete file format, field reference, validation. |
| Use cases | Failover, weighted routing, embeddings, custom endpoints, secret resolvers. |
| API reference | Every public class, function, field, and behavior. |
| Security | Secret-handling guarantees, redaction rules, limitations. |
| Development | Environment, checks, conventions, testing. |
Non-goals
This package does not make network requests, define a unified AI response interface, translate or retry requests, or ship a gateway. Deployment selection is deterministic and based on configuration plus recorded health; request-time concerns belong to the caller or the adapter.
License
MIT.
Metadata
Release files for ai-registry 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ai_registry-0.3.1.tar.gz | 59.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ai_registry-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 131.5 kB
Release files / ai_registry-0.3.1.tar.gz
| Download URL | ai_registry-0.3.1.tar.gz |
|---|---|
| Size | 59.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bf00c0f23e92693eedc5df366c83b52965c4c407b00fee34377dcab61a0908dc
|
|
BLAKE2b-256 checksum How to use checksums |
8d8766841cf128ce6ff73d95a88834d89cee807470d93ee9ed7ad4bf4bd9d64d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.
Transparency logRelease files / ai_registry-0.3.1-py3-none-any.whl
| Download URL | ai_registry-0.3.1-py3-none-any.whl |
|---|---|
| Size | 72.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dc18866ddd640c728acfe12b617532ef4439544576c42ff3dad85234d657dc24
|
|
BLAKE2b-256 checksum How to use checksums |
0e225212a9d142dad4d29c0e00c71ae28678e55adfcd022a40d3559724367e20
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.
Transparency log