# Alternative LLM Providers (MiniMax, Kimi, GLM everywhere) (https://jackin.tailrocks.com/reference/roadmap/alternative-llm-providers/)



**Status**: Partially implemented — Phases 1–4 shipped on `main` (catalog + Claude Code + Codex MiniMax + Codex OpenAI default + OpenCode + operator Auth-tab rows + provider picker that collapses the agent's native auth + per-provider model overrides in role manifests via `[<agent>.providers.<id>]`); Codex GLM and Kimi cells remain deferred pending upstream Responses-API endpoint.

> **Registry note.** Provider routing now lives behind the workspace crate registry. The durable design record for the runtime/provider adapter work lives in [Architecture](/reference/getting-oriented/architecture/#agentruntime-and-provider-registry).

## Problem [#problem]

jackin' already routes one alternative provider into one agent: [Z.AI (GLM Coding Plan)](/guides/authentication/zai/) is offered as an Anthropic-compatible backend for Claude Code sessions only. The scaffolding that makes this work — the `Provider` enum, `Provider::env_overrides`, `Provider::available_for`, the in-container token resolution keyed on `ZAI_API_KEY`, and the console provider picker — is hardcoded to exactly that one provider and that one agent surface.

Operators who hold a **MiniMax** or **Kimi** coding subscription, or who want to point **Codex** at a GLM/MiniMax/Kimi backend, have no path today. The three providers all sell coding-focused subscription plans that issue a plain API key usable against a coding base URL (no OAuth flow), so the shipped env-key pattern fits all three — but the catalog is closed at the `Provider::Zai` variant, `available_for` returns providers only for `agent == "claude"`, and there is no generation of the per-agent config that Codex and OpenCode require to route to an OpenAI-compatible endpoint.

This item generalizes the existing single-provider scaffolding into a small provider catalog covering **MiniMax**, **Kimi**, and **GLM/Z.AI**, across **Claude Code**, **Codex**, and **OpenCode**.

## Subscription landscape [#subscription-landscape]

All three providers sell a coding-oriented subscription whose activation surface is a **copyable API key**, not an OAuth session. This is the load-bearing fact for the design: the operator journey is identical in shape to the shipped Z.AI flow — subscribe, copy a key from a console page, paste it into the jackin' **Auth** tab, pick the provider at launch. jackin' stores the key in its own `[env]` map (never a host dotfile) and injects the redirect into the spawned agent process only.

| Provider                        | Subscribe                                                                                                                                        | Extract key                                                                                                                         | Key shape    | Models                                      |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | ------------ | ------------------------------------------- |
| **Z.AI / GLM Coding Plan**      | [z.ai/subscribe](https://z.ai/subscribe)                                                                                                         | [z.ai/manage-apikey/apikey-list](https://z.ai/manage-apikey/apikey-list)                                                            | Z.AI API key | GLM-5.1, GLM-5-Turbo, GLM-4.7, GLM-4.5-Air  |
| **MiniMax Coding / Token Plan** | [platform.minimax.io](https://platform.minimax.io/subscribe/token-plan) (Plus $20 / Max $50 / Ultra $120 per month; international endpoint only) | [platform.minimax.io/console/plan](https://platform.minimax.io/console/plan) → **Plan Details** → &#x2A;*Subscription Key (sk-cp)** | `sk-cp-…`    | MiniMax-M3 (Token Plan), M2.x (Coding Plan) |
| **Kimi Code**                   | [kimi.com/membership/pricing](https://www.kimi.com/membership/pricing) (shares Kimi membership quota; weekly + rate-limit windows, no carryover) | [Kimi Code Console](https://www.kimi.com/code/console) → **API Keys** (shown once; up to 5 keys)                                    | `sk-ki…`     | `kimi-for-coding`                           |

The MiniMax &#x2A;*Subscription Key (sk-cp)** is explicitly scoped to "Token Plan / credits calls" and "cannot be used for pay-as-you-go" — it is the subscription key, distinct from a pay-as-you-go platform key. Kimi Code's coding endpoint (`api.kimi.com/coding`) is likewise distinct from the general Moonshot platform endpoint (`api.moonshot.ai/v1`); the subscription benefit is the coding endpoint, and its key is managed in the Kimi Code Console, not the Moonshot platform.

## Authentication model — key-only [#authentication-model--key-only]

**The only credential mode for an alternative provider is "provide the API key."** There is no `sync` and no `oauth_token` mode for these providers, and that is deliberate, not a first-cut shortcut.

jackin's existing agent auth axis (documented in [Agent Authentication](/guides/authentication/agents/)) offers `sync` / `api_key` / `oauth_token` / `ignore` for an agent's **own** account — the host's Claude login, the host's Codex login — where there is a host-side session jackin' can forward. An alternative provider is a different axis: it is not the agent's own account but a redirect that points an agent at a third-party backend. For that axis there is nothing on the host to sync — these providers ship no first-class local CLI whose credentials jackin' could copy in. MiniMax has no "MiniMax Code" agent at all (which is exactly why an operator routes the MiniMax model *through* Claude Code or Codex); and the Kimi *provider* is distinct from the `kimi` *agent runtime*, so "syncing Kimi" already means the runtime, not the backend redirect. The single credential each provider hands a subscriber is the API key from the console pages above.

So the alternative-provider auth axis collapses to two states:

* **key provided** — the provider appears in the launch picker for every agent it can serve;
* **key absent** — the provider is ignored and never offered.

This is the same "provide the key" approach jackin' already implements for the `api_key` mode of supported agents, reused verbatim: the key is stored in the jackin' `config.toml` `[env]` map (literal value or `op://` reference), follows the standard per-(workspace × role) > per-workspace > global scope resolution, and is injected only into the selected agent process at spawn. The shipped Z.AI **Auth**-tab row (mode fixed to **API Key**) is the exact UI this item replicates for MiniMax and Kimi — one row per provider, one field, key in or `Ignore`.

The scope of this umbrella item is therefore: &#x2A;*add key-only authentication for all three subscriptions, wired into every supported client a given provider can actually serve.** Where a provider cannot serve a client (the deferred Codex cells below), that cell is simply omitted — the operator still gets that provider on Claude Code and OpenCode. No provider is dropped wholesale just because one client is out of reach.

## Endpoints [#endpoints]

Each provider exposes both an Anthropic-compatible surface (for Claude Code) and an OpenAI-compatible surface (for Codex and OpenCode):

| Provider       | Anthropic-compatible (Claude Code)                     | OpenAI-compatible (Codex / OpenCode)  |
| -------------- | ------------------------------------------------------ | ------------------------------------- |
| **Z.AI / GLM** | `https://api.z.ai/api/anthropic&#x60; &#x2A;(shipped)* | `https://api.z.ai/api/coding/paas/v4` |
| **MiniMax**    | `https://api.minimax.io/anthropic`                     | `https://api.minimax.io/v1`           |
| **Kimi**       | `https://api.kimi.com/coding`                          | `https://api.kimi.com/coding/v1`      |

## Deliverable scope [#deliverable-scope]

This item ships **only the cells that are clearly documented, testable, and work end-to-end**. Cells blocked by an upstream protocol gap are explicitly out of scope until that gap closes — jackin' does not half-build a routing path that cannot route.

| Provider               | Claude Code | Codex                                                        | OpenCode |
| ---------------------- | ----------- | ------------------------------------------------------------ | -------- |
| **Anthropic** (native) | ✅ ship      | n/a                                                          | ✅ ship   |
| **OpenAI** (native)    | n/a         | ✅ ship — Codex's default auth; no `wire_api` redirect needed | n/a      |
| **MiniMax**            | ✅ ship      | ✅ ship (`wire_api = "responses"`)                            | ✅ ship   |
| **Z.AI / GLM**         | ✅ shipped   | ✖ deferred — Chat-only, blocked on current Codex             | ✅ ship   |
| **Kimi**               | ✅ ship      | ✖ deferred — Chat-only, no Responses endpoint                | ✅ ship   |

The "native" rows cover each agent's own auth surface: Anthropic for Claude Code (subscription), OpenAI for Codex (`auth.json` sync or `OPENAI_API_KEY`). They are catalog entries even though no env redirect is emitted — the catalog drives the provider picker, and the picker skips these entries when no alt provider is configured (so Claude and Codex launch with no picker when only the native auth is available, mirroring each other).

The two deferred Codex cells are a protocol mismatch, not a missing-key problem (see Open Questions): GLM and Kimi expose only Chat Completions, and Codex no longer speaks it. They become deliverable only if upstream ships a Responses-compatible endpoint, at which point they reduce to catalog data. Treat them as known-blocked, not as work to attempt and discover broken.

## Per-agent injection mechanism [#per-agent-injection-mechanism]

The three target agents read provider configuration through three different mechanisms. The design keeps one provider catalog as the source of truth and gives each agent its own renderer off that catalog.

### Claude Code — environment variables (mechanism already shipped) [#claude-code--environment-variables-mechanism-already-shipped]

Claude Code routes to an Anthropic-compatible endpoint through process environment variables. This is exactly what `Provider::env_overrides` produces today for Z.AI:

* `ANTHROPIC_BASE_URL` — the provider's Anthropic-compatible endpoint
* `ANTHROPIC_AUTH_TOKEN` — the provider key (Kimi's own docs use `ANTHROPIC_API_KEY`; the implementation must confirm which variable Kimi's endpoint honors)
* `ANTHROPIC_DEFAULT_OPUS_MODEL` / `ANTHROPIC_DEFAULT_SONNET_MODEL` / `ANTHROPIC_DEFAULT_HAIKU_MODEL` — per-provider tier mapping
* `API_TIMEOUT_MS`, `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` — operational settings already injected for Z.AI

Extending Claude Code support to MiniMax and Kimi is purely catalog data: add the variants, their base URLs, and their model maps. The injection path in <RepoFile path="crates/jackin-protocol/src/lib.rs">crates/jackin-protocol/src/lib.rs</RepoFile> and the allowlist in `SESSION_ENV_PASSTHROUGH` (<RepoFile path="crates/jackin-capsule/src/session.rs">crates/jackin-capsule/src/session.rs</RepoFile>) already carry the `ANTHROPIC_*` keys.

### Codex — provider block + v2 profile file + model catalog (new mechanism) [#codex--provider-block--v2-profile-file--model-catalog-new-mechanism]

Codex routes to a custom backend through a `[model_providers.<id>]` table in `~/.codex/config.toml` plus a **v2 profile** that selects it. MiniMax is the deliverable Codex cell because it speaks the Responses API Codex now requires. jackin' writes three pieces during `jackin-capsule runtime-setup` (see <RepoFile path="crates/jackin-capsule/src/runtime_setup.rs">crates/jackin-capsule/src/runtime\_setup.rs</RepoFile>), all inside the container — the host's `~/.codex/` is never touched (the host-side rule in <RepoFile path="AGENTS.md">AGENTS.md</RepoFile> forbids it).

1. The provider block, appended to `~/.codex/config.toml`:

```toml
[model_providers.minimax]
name = "MiniMax"
base_url = "https://api.minimax.io/v1"
env_key = "MINIMAX_API_KEY"
wire_api = "responses"
```

2. The profile file `~/.codex/minimax.config.toml`, loaded by `codex --profile minimax`. It lives in its own file, **not** as a `[profiles.minimax]` table inside `config.toml`: Codex errors when `--profile` is passed alongside a legacy v1 profiles table. The context window is deliberately omitted here — a profile-scoped `model_context_window` is clamped to the model's fallback cap, so it can never raise the window for a custom model.

```toml
model_provider = "minimax"
model = "MiniMax-M3"
```

3. The model catalog `~/.codex/minimax.models.json`, derived at setup from the installed Codex's own catalog (`codex debug models`) and patched to a `MiniMax-M3` entry with a real 512k context window. Without it Codex has no metadata for `MiniMax-M3`, falls back to a \~272k window plus a per-turn "metadata not found, can degrade performance" warning, and clamps any window override to that fallback cap. Deriving the entry from the live catalog keeps it matching the installed Codex's `ModelInfo` schema rather than a snapshot that drifts as Codex evolves.

The capsule injects `JACKIN_CODEX_PROFILE=minimax` into the spawn env (allowlisted in `SESSION_ENV_PASSTHROUGH`, <RepoFile path="crates/jackin-capsule/src/session.rs">crates/jackin-capsule/src/session.rs</RepoFile>); the entrypoint turns it into `--profile minimax` plus `-c model_catalog_json=~/.codex/minimax.models.json` (the catalog is passed as a `-c` override because a profile-file `model_catalog_json` key trips a Codex config-parse bug).

GLM and Kimi would use the same provider shape with `wire_api = "chat"`, but Codex no longer accepts Chat Completions, so those two cells are deferred (see Deliverable scope and Open Questions) rather than generated.

### OpenCode — self-contained `provider` blocks in `~/.config/opencode/opencode.json` [#opencode--self-contained-provider-blocks-in-configopencodeopencodejson]

`jackin-capsule runtime-setup` writes `~/.config/opencode/opencode.json` (see `write_opencode_config` in <RepoFile path="crates/jackin-capsule/src/runtime_setup.rs">crates/jackin-capsule/src/runtime\_setup.rs</RepoFile>) with `"permission":"allow"` plus a `provider` block for each alt provider whose key is present in the container env. Each block is **self-contained** — it pins the SDK (`npm`), base URL, API key, and the one model id — rather than overriding only `baseURL` and leaving OpenCode to fill the rest from its bundled models.dev registry:

```json
{
  "permission": "allow",
  "provider": {
    "zai": {
      "name": "Z.AI",
      "npm": "@ai-sdk/openai-compatible",
      "options": { "baseURL": "https://api.z.ai/api/coding/paas/v4", "apiKey": "<ZAI_API_KEY>" },
      "models": { "glm-5.1": { "name": "glm-5.1" } }
    }
  }
}
```

The self-contained shape is load-bearing: the registry keys Z.AI's credential off `ZHIPU_API_KEY` (a name jackin' never sets) and has no `kimi` provider at all (its entry is `kimi-for-coding`), so a bare `{options:{baseURL}}` block would fail to authenticate or to resolve `-m kimi/kimi-for-coding`. MiniMax and Kimi hit the same Anthropic-compatible hosts as the verified Claude Code path via `@ai-sdk/anthropic`, but with a `/v1`-suffixed `baseURL` (`https://api.minimax.io/anthropic/v1`, `https://api.kimi.com/coding/v1`): that SDK appends only `/messages` to the configured `baseURL` (its default is `https://api.anthropic.com/v1`), whereas Claude Code's own SDK appends `/v1/messages` — so the OpenCode block must carry the `/v1` the Claude-path env var omits. Z.AI's coding-plan endpoint is OpenAI-compatible. At spawn the selected provider's `Provider::opencode_model()` supplies the `-m <provider>/<model>` flag (e.g. `-m zai/glm-5.1`).

## Proposal [#proposal]

One provider catalog, three renderers, plus the operator surface that already exists for Z.AI.

### 1. Generalize the provider catalog [#1-generalize-the-provider-catalog]

In <RepoFile path="crates/jackin-protocol/src/lib.rs">crates/jackin-protocol/src/lib.rs</RepoFile>:

* Add `Provider::Minimax` and `Provider::Kimi` variants alongside `Anthropic` and `Zai`. (The `Kimi` *provider* is distinct from the `kimi` *agent runtime* — naming in code and docs must keep that separation explicit so the two concepts do not blur.)
* Add a per-provider constant block (base URLs for both protocol surfaces, model-tier map, timeout) mirroring the existing `ZAI_*` constants.
* Replace the boolean `zai_key_available` parameter on `available_for` with a per-provider key-presence input, and return the providers available for a given `(agent, provider-keys)` pair from a single matrix.

### 2. Per-agent renderers off the catalog [#2-per-agent-renderers-off-the-catalog]

* **Claude Code**: keep `env_overrides` as the Anthropic-surface renderer; extend it to the new variants.
* **Codex**: add a renderer that emits the `[model_providers]` + `[profiles]` TOML fragment, written by `jackin-capsule runtime-setup`.
* **OpenCode**: add a renderer that emits a self-contained `provider` block per provider into `~/.config/opencode/opencode.json`.

### 3. Operator surface [#3-operator-surface]

* Host env keys `MINIMAX_API_KEY` and `KIMI_CODE_API_KEY` alongside the shipped `ZAI_API_KEY`, resolved in-container at spawn (same path as `daemon.rs` resolves `ZAI_API_KEY`). Per the operator decision, keys follow the existing env-key pattern — no new config table, no schema version bump.
* Auth-tab rows for MiniMax and Kimi mirroring the shipped `AuthKind::Zai` row.
* Generalize the two-item provider picker into an N-item picker driven by `available_for`, and the tab-label suffix (`Claude (Z.AI)`) into a per-provider suffix.

### 4. Documentation [#4-documentation]

Ship an operator guide per provider under `guides/authentication/` (mirroring the Z.AI guide), each documenting the subscribe → extract-key → paste-into-Auth-tab → pick-at-launch journey for subscription holders.

## Host-side effects [#host-side-effects]

None. Every artifact this feature generates — the Codex `config.toml` provider block, the OpenCode provider JSON, the Claude Code env overrides — is produced **inside the container** at spawn time. Provider keys live in jackin' `config.toml` `[env]` map (the operator's jackin' config, not a host dotfile) and are injected only into the selected agent process. The host's `~/.codex/`, `~/.claude/`, and OpenCode config stay untouched. This is the same contract the shipped Z.AI integration honors.

## Implementation phases [#implementation-phases]

### Phase 1 — Catalog + Claude Code for all three providers [#phase-1--catalog--claude-code-for-all-three-providers]

Add the `Minimax` and `Kimi` variants and their constants; extend `env_overrides`, `available_for`, and the picker/tab-label surfaces. This phase reuses the entire shipped Z.AI mechanism and delivers MiniMax + Kimi for Claude Code with the lowest risk.

### Phase 2 — Codex backend routing (MiniMax only) [#phase-2--codex-backend-routing-minimax-only]

Add the `[model_providers]` + `[profiles]` renderer and wire it into `jackin-capsule runtime-setup`. Scope this phase to **MiniMax**, the only provider whose Responses-API surface Codex accepts. GLM and Kimi Codex cells stay deferred until upstream ships a Responses endpoint; do not generate a `chat`-wire block that cannot route.

### Phase 3 — OpenCode backend routing [#phase-3--opencode-backend-routing]

Extend `OPENCODE_CONFIG_CONTENT` with the provider block and model selection.

### Phase 4 — Operator surface + docs [#phase-4--operator-surface--docs]

Auth-tab rows, N-item picker generalization, per-provider tab labels, and the per-provider operator guides.

## Open questions [#open-questions]

1. **Codex wire protocol — gates the Codex column.** Codex moved to the Responses API and is reported to have removed Chat Completions support in early 2026 ([openai/codex#9612](https://github.com/openai/codex/issues/9612)). This splits the Codex cells cleanly: **MiniMax** documents `wire_api = "responses"` and is deliverable; **GLM/Z.AI** and **Kimi** expose only Chat Completions (`wire_api = "chat"`) on their OpenAI-compatible endpoints, so on a current Codex they likely will not route at all. Kimi in particular has **no documented Responses-compatible endpoint** — its coding surface is Anthropic-compatible (`api.kimi.com/coding`, for Claude Code) plus Chat-Completions OpenAI-compatible (`api.kimi.com/coding/v1`, model `kimi-for-coding`, the surface Roo Code uses); there is no third surface for Codex. Phase 2 must verify against the pinned Codex version in the construct image whether `chat`-wire still routes, and if not, treat `(GLM, Codex)` and `(Kimi, Codex)` as **blocked until upstream ships a Responses endpoint** rather than as deliverable cells. Claude Code (Anthropic-compatible) and OpenCode (Chat-Completions OpenAI-compatible) are unaffected for all three providers.
2. **Kimi Anthropic auth variable.** Kimi's Claude Code docs use `ANTHROPIC_API_KEY` rather than `ANTHROPIC_AUTH_TOKEN`. Confirm which variable the `api.kimi.com/coding` endpoint honors, and whether Kimi's reported pre-launch "skip Anthropic login" step is needed inside the container or is already covered by jackin's launch flags.
3. **Model-tier mapping per provider.** Z.AI maps Opus/Sonnet/Haiku tiers to GLM-5.1 / GLM-5-Turbo / GLM-4.5-Air. MiniMax exposes a single `MiniMax-M3` (so all three tiers map to one model); Kimi exposes `kimi-for-coding`. Confirm the intended tier maps, especially as MiniMax's Coding Plan model (M2.x) differs from its Token Plan model (M3).
4. **Region.** International endpoints only. MiniMax's separate China base URL (`api.minimaxi.com`) is out of scope; the catalog hardcodes the international `api.minimax.io` surface and does not expose a region selector.
5. **Per-provider quota surfacing.** Subscriptions carry 5-hour / weekly / 7-day quota windows. Whether jackin' surfaces remaining quota is a separate concern, likely deferred to the [Desktop Agent Hub](/reference/roadmap/jackin-desktop-agent-hub/) account-state work.

## Related files [#related-files]

* <RepoFile path="crates/jackin-protocol/src/lib.rs">crates/jackin-protocol/src/lib.rs</RepoFile> — `Provider` enum, `env_overrides`, `available_for`, `ZAI_*` constants
* <RepoFile path="crates/jackin-capsule/src/session.rs">crates/jackin-capsule/src/session.rs</RepoFile> — `SESSION_ENV_PASSTHROUGH` allowlist
* <RepoFile path="crates/jackin-capsule/src/daemon.rs">crates/jackin-capsule/src/daemon.rs</RepoFile> — in-container key resolution (`ZAI_API_KEY`) and provider env application
* <RepoFile path="crates/jackin-capsule/src/runtime_setup.rs">crates/jackin-capsule/src/runtime\_setup.rs</RepoFile> — in-container agent setup (target for Codex `config.toml` generation)
* <RepoFile path="docker/runtime/entrypoint.sh">docker/runtime/entrypoint.sh</RepoFile> — `OPENCODE_CONFIG_CONTENT` export
* <RepoFile path="crates/jackin-core/src/manifest.rs">crates/jackin-core/src/manifest.rs</RepoFile> — per-agent `model` fields
* <RepoFile path="crates/jackin-console/src/tui/state/manager.rs">crates/jackin-console/src/tui/state/manager.rs</RepoFile> — `zai_key_present` and the Auth tab

## Cross-references [#cross-references]

* [Z.AI (GLM Coding Plan)](/guides/authentication/zai/) — the shipped single-provider integration this item generalizes
* [Multi-runtime support](/reference/roadmap/multi-runtime-support/) — the agent runtimes this routing targets
* [AgentRuntime and Provider registry](/reference/getting-oriented/architecture/#agentruntime-and-provider-registry) — each runtime's provider renderer belongs in its adapter rather than in shared dispatch
* [Agent launch flags API](/reference/roadmap/agent-launch-flags-api/) — shares the `jackin-capsule runtime-setup` dispatch surface Phase 2 writes into
* [Reliable Claude authentication strategy](/reference/roadmap/claude-auth-strategy/) — the parallel work for Anthropic's own auth
