Skip to main content

ai-registry

PyPI Python versions CI Ruff Checked with mypy License: MIT

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-id escape 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 pluggable SecretResolver for 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.dev api.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 with ai-registry catalog diff|sync.
  • Observability built in: Resolution.otel_attributes() emits OpenTelemetry GenAI attributes plus which alias and account were selected.
  • Testable: ai_registry.testing ships 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)

Source distribution for ai-registry 0.3.1
File Size Uploaded
ai_registry-0.3.1.tar.gz 59.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ai-registry 0.3.1
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page