> ## Documentation Index
> Fetch the complete documentation index at: https://docs.knoxcall.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrating from LiteLLM

> Point knoxcall ai import at your existing LiteLLM config.yaml and get a dry-run plan: one agent per model_name, load-balanced deployments collapsed into weighted routes, retries and budgets carried across, and your model names preserved as gateway aliases.

# Migrating from LiteLLM

LiteLLM's proxy and KnoxCall's AI Gateway sit in the same place in your stack and
solve overlapping problems, so most of a `config.yaml` maps across mechanically.
There is a command for that.

```bash theme={"dark"}
knoxcall ai import --from litellm ./config.yaml
```

That is a **dry run**. It reads the file, prints exactly what it would create,
and writes nothing. `--apply` is the deliberate second step.

## What maps onto what

| LiteLLM                                           | KnoxCall                                                                          |
| ------------------------------------------------- | --------------------------------------------------------------------------------- |
| `model_list[].model_name`                         | one agent, slugified — and a gateway **model alias** so your clients keep working |
| `litellm_params.model` (`openai/gpt-4o`)          | the agent's `provider` + `default_model`                                          |
| `litellm_params.api_base`                         | the agent's `upstream` (SSRF-checked at create)                                   |
| several entries sharing one `model_name`          | **one** agent with weighted routes                                                |
| `litellm_params.weight` / `rpm`                   | that route's weight                                                               |
| `router_settings.num_retries`                     | `routing_policy.max_attempts` (+1 — we count attempts, they count retries)        |
| `litellm_settings.max_budget` + `budget_duration` | `budget_daily_usd` or `budget_monthly_usd`                                        |

### Load balancing collapses into one agent

This is the mapping worth understanding, because it changes your topology for the
better. In LiteLLM, listing the same `model_name` twice **is** the load balancer:

```yaml theme={"dark"}
model_list:
  - model_name: fast
    litellm_params: { model: groq/openai/gpt-oss-120b, weight: 3 }
  - model_name: fast
    litellm_params: { model: together_ai/openai/gpt-oss-120b, weight: 1 }
```

KnoxCall expresses that as one agent with two weighted routes, so it needs **one**
capability token rather than two, and one budget rather than two that have to be
kept in step. See [Routing, Retries & Fail-over](/ai-gateway/routing-and-failover).

### Your model names survive

Existing callers ask for `"model": "fast"`. Rather than make you edit every call
site on day one, the importer writes a gateway-level **model alias** mapping
`fast` → the real upstream id. Aliases resolve *before* the per-agent model
policy, so an alias target still has to pass that agent's allow/deny list.

## What it will not do: your keys

The importer **never reads an API key out of your config**, and never transmits
one. It records how each entry referenced its credential and leaves you to create
the KnoxCall secret:

```
credential (yours to create): os.environ/OPENAI_API_KEY
```

If an entry carries a **literal** key rather than an `os.environ/` reference, the
importer says so and does not read it — and tells you to treat that key as
exposed, because it is sitting in a file. Rotate it at the provider when you
create the KnoxCall secret.

That is not squeamishness. A migration tool that quietly ingests a plaintext key
from a checked-in config has copied that key into a second system, which is an odd
thing for a credential-custody product to do to you on your first day.

## What it will not do: guess

Two refusals you may hit, both deliberate:

**An unprefixed model.** LiteLLM treats `model: gpt-4o` with no provider prefix as
OpenAI. The importer will not inherit that default for you — pointing an agent at
the wrong provider with the wrong key is a worse outcome than a warning. Prefix it
(`openai/gpt-4o`) or set the provider after import.

**A budget duration we do not have.** KnoxCall has a daily cap and a monthly cap.
`budget_duration: 7d` is neither, so the budget is **not** imported and the report
says so. Dividing by seven to fake a daily rate would put a number in front of you
that you never chose.

## The YAML it can read

The importer parses a YAML subset — nested maps, lists of maps, scalars, simple
inline lists — which covers the LiteLLM configs people actually have. It has no
third-party YAML dependency, because `knoxcall` ships with **zero** runtime
dependencies and a credential-handling CLI is the wrong place to grow a
transitive tree.

Anything outside that subset — anchors, aliases, merge keys, block scalars,
multi-document files — is a hard error naming the line:

```
config.yaml: line 14: block scalars (| and >) are not supported
```

It refuses rather than skips, on purpose. An importer that silently dropped a
`model_list` entry would hand you a plan that looks complete and is not; you would
migrate, believe you were done, and find the missing model in production. Being
told about line 14 costs a minute.

## Applying it

```bash theme={"dark"}
knoxcall ai import --from litellm ./config.yaml --apply
```

Creates the gateway, the agents and the model aliases. Exit codes: `0` success,
`1` something failed while applying (partial creation is possible, and every
failure is named so you can retry just those), `2` the input was unusable and
nothing was written.

Then, for each agent: create a secret holding the provider key and attach it. At
that point you have what LiteLLM gave you, plus per-agent capability tokens,
mid-stream PII redaction, a prompt firewall, and per-call attribution.

## What you gain that has no LiteLLM equivalent

Worth knowing before you plan the cutover, because these are the reasons to do it
rather than the mechanics:

* **Your app never holds a provider key.** It holds a KnoxCall capability token
  scoped to a provider, a model set, a spend cap and a time window. The real key
  is injected at the egress hop. See [Capability keys](/ai-gateway/tokens-and-dpop).
* **[Mid-stream PII redaction](/ai-gateway/streaming-guarantees)** — entities are
  removed inside the SSE stream, including ones split across two frames, without
  buffering the response.
* **[A prompt firewall](/ai-gateway/firewall)** that can refuse a request, and
  [your own scanner](/ai-gateway/guardrail-webhook) if you already have one.
* **Per-call attribution and audit** — which token, which user, which team, what
  it cost.

<Note>
  One thing to check before you cut over: LiteLLM supports more providers than
  KnoxCall's fourteen. Run the dry run first and read the warnings — anything that
  could not be mapped is named there, and an entry with an `api_base` will usually
  map as `openai-compatible` even when its prefix is unknown to us.
</Note>
