Mimir is an embeddable routing oracle, pricing source, and decision vocabulary for LLM workloads. You consult it in-process: hand it a workload descriptor and an operational snapshot, and it hands back a placement (or a reasoned no-candidate answer) plus an auditable decision record. A gateway service built on top of Mimir is one possible embedder — not a requirement. A single application can link the library directly and route its own calls with no service in between.
The name is a nod to the consulted head: every carrier embeds the same oracle. The well it drinks from — metered access, minted keys, fleet state — is the embedder's business, not this library's.
Installation
Add mimir to your list of dependencies in mix.exs:
def deps do
[
{:mimir, "~> 0.1.0"}
]
endModule inventory
| Module | What it does |
|---|---|
Mimir.Descriptor | Validated workload descriptor — the contract a workflow step presents to the oracle. |
Mimir.Oracle | Pure filter-then-rank placement decision over catalog entries. |
Mimir.Catalog | Config-sourced routable entries, with an injectable model resolver seam. |
Mimir.Snapshot | Explicit-inputs operational snapshot the oracle ranks against (pricing, health, budget). |
Mimir.Health | Failure-streak table for router lanes, driven by telemetry. |
Mimir.DecisionRecord | Pure builder for a binary-keyed routing-decision audit record. |
Mimir.RouteLog | Typed route outcome plus a request-log meta builder. |
Mimir.Pricing | Token usage to integer microdollar cost, config-first over a vendored LiteLLM pricing DB. |
Mimir.TurnEvents | Per-request ordered gen_ai.* event buffer. |
Mimir.RouterClient | Behaviour for routing clients, with an HTTP (Req-based) implementation. |
Mimir.Redact | Secret masking and payload-capture gating helpers. |
Design rules
Mimir has no dependency on any agent-runtime or LLM client library. It does not call models, does not manage conversation state, and does not mint or verify auth. Governance — budget enforcement, key issuance, multi-tenant isolation — composes in the embedder, on top of the plain data Mimir returns.
Supervision
Mimir.Health and Mimir.TurnEvents are GenServers that own ETS tables.
Add the ones you use to your application's supervision tree:
children = [
Mimir.Health,
Mimir.TurnEvents
]Everything else in the library (Descriptor, Oracle, Catalog,
Snapshot, DecisionRecord, RouteLog, Pricing, RouterClient,
Redact) is stateless — no process, no supervision needed.
Configuration reference
All configuration lives under the :mimir application:
| Key | Used by | Meaning |
|---|---|---|
:catalog | Mimir.Catalog | List of routable entry configs (id, model, lane, runtime, ...). |
:pricing | Mimir.Pricing, Mimir.Snapshot | Config-table token rates, "provider:model" => %{input:, output:}. Wins over the vendored DB. |
:pricing_db_path | Mimir.Pricing | Override path to the vendored pricing DB (useful in tests). |
:health_threshold | Mimir.Health | Failure-streak count at which a lane is reported :degraded. Default 3. |
:completion_event | Mimir.Health | Telemetry event Health.attach/0 listens on. Default [:mimir, :completion]. |
:turn_events_tables | Mimir.TurnEvents | {seq_table, buf_table} ETS table names, for running more than one buffer instance. |
Examples
Runnable, heavily-commented examples ship with the package:
examples/gateway_less.exs— the headline pattern: consult the oracle in-process, no service required. Configures a catalog and pricing in-script, parses a descriptor, assembles the degenerate snapshot, and prints both a placement's decision record and a couple ofno_candidateoutcomes.examples/routed_grants.exs— the fleet shape: route through a live router service viaMimir.RouterClient.HTTP, print the placement and masked grant, and handleno_candidateand error responses. Prints friendly setup instructions and exits cleanly ifROUTER_URL/ROUTER_KEYaren't set.
Development
mix quality— format check,--warnings-as-errorscompile,credo --strict, dialyzer.mix mimir.smoke— a staged end-to-end smoke of the public API: descriptor, catalog, oracle, decision record, route log, pricing, health, turn events, router client, and redact. It runs 10 stages; the router-client (HTTP) stage exercises a real request against an in-process plug underMIX_ENV=test(or in CI), and reports[SKIP]honestly otherwise, since the Plug dependency it needs is test-only.mix test— the ExUnit suite.
Gateway-less mode
A single-app deployment embeds the library directly — no routing service, no minted keys, no fleet state:
# config/config.exs
config :mimir, :catalog, [
%{id: "local-qwen", model: "ollama:qwen3", lane: "local", runtime: "local", priority: 10},
%{id: "claude", model: "anthropic:claude-sonnet-4-6", lane: "anthropic", runtime: "managed"}
]
config :mimir, :pricing, %{
"anthropic:claude-sonnet-4-6" => %{input: 3_000_000, output: 15_000_000}
}
# at the call site
{:ok, descriptor} =
Mimir.Descriptor.parse(%{
task_class: "extraction",
budget_ceiling_microdollars: 50_000,
latency_tolerance_ms: 30_000
})
snapshot = Mimir.Snapshot.assemble([]) # degenerate: all lanes healthy, config pricing
case Mimir.Oracle.decide(descriptor, Mimir.Catalog.entries(), %Mimir.Oracle.Policy{}, snapshot) do
{:placement, placement} -> run_step_on(placement.entry)
{:no_candidate, reasons, _candidates} -> handle_no_candidate(reasons)
endSame descriptors, same decision records, no service required. Budget guards
without minted keys arrive with Mimir.Guard in 0.2.0.
Documentation
Full API docs are published on HexDocs once
released, and can be generated locally with mix docs.
License
Apache-2.0. See LICENSE.