Alternative LLM Providers (MiniMax, Kimi, GLM everywhere)
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.
Problem
jackin' already routes one alternative provider into one agent: Z.AI (GLM Coding Plan) 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
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 | 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 (Plus $20 / Max $50 / Ultra $120 per month; international endpoint only) | platform.minimax.io/console/plan → Plan Details → Subscription Key (sk-cp) | sk-cp-… | MiniMax-M3 (Token Plan), M2.x (Coding Plan) |
| Kimi Code | kimi.com/membership/pricing (shares Kimi membership quota; weekly + rate-limit windows, no carryover) | Kimi Code Console → API Keys (shown once; up to 5 keys) | sk-ki… | kimi-for-coding |
The MiniMax 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
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) 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: 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
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 (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
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
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 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 endpointANTHROPIC_AUTH_TOKEN— the provider key (Kimi's own docs useANTHROPIC_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 mappingAPI_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 crates/jackin-protocol/src/lib.rs and the allowlist in SESSION_ENV_PASSTHROUGH (crates/jackin-capsule/src/session.rs) already carry the ANTHROPIC_* keys.
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 crates/jackin-capsule/src/runtime_setup.rs), all inside the container — the host's ~/.codex/ is never touched (the host-side rule in AGENTS.md forbids it).
- The provider block, appended to
~/.codex/config.toml:
[model_providers.minimax]
name = "MiniMax"
base_url = "https://api.minimax.io/v1"
env_key = "MINIMAX_API_KEY"
wire_api = "responses"- The profile file
~/.codex/minimax.config.toml, loaded bycodex --profile minimax. It lives in its own file, not as a[profiles.minimax]table insideconfig.toml: Codex errors when--profileis passed alongside a legacy v1 profiles table. The context window is deliberately omitted here — a profile-scopedmodel_context_windowis clamped to the model's fallback cap, so it can never raise the window for a custom model.
model_provider = "minimax"
model = "MiniMax-M3"- The model catalog
~/.codex/minimax.models.json, derived at setup from the installed Codex's own catalog (codex debug models) and patched to aMiniMax-M3entry with a real 512k context window. Without it Codex has no metadata forMiniMax-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'sModelInfoschema 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, crates/jackin-capsule/src/session.rs); 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
jackin-capsule runtime-setup writes ~/.config/opencode/opencode.json (see write_opencode_config in crates/jackin-capsule/src/runtime_setup.rs) 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:
{
"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
One provider catalog, three renderers, plus the operator surface that already exists for Z.AI.
1. Generalize the provider catalog
In crates/jackin-protocol/src/lib.rs:
- Add
Provider::MinimaxandProvider::Kimivariants alongsideAnthropicandZai. (TheKimiprovider is distinct from thekimiagent 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_availableparameter onavailable_forwith 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
- Claude Code: keep
env_overridesas the Anthropic-surface renderer; extend it to the new variants. - Codex: add a renderer that emits the
[model_providers]+[profiles]TOML fragment, written byjackin-capsule runtime-setup. - OpenCode: add a renderer that emits a self-contained
providerblock per provider into~/.config/opencode/opencode.json.
3. Operator surface
- Host env keys
MINIMAX_API_KEYandKIMI_CODE_API_KEYalongside the shippedZAI_API_KEY, resolved in-container at spawn (same path asdaemon.rsresolvesZAI_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::Zairow. - 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
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
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
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)
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
Extend OPENCODE_CONFIG_CONTENT with the provider block and model selection.
Phase 4 — Operator surface + docs
Auth-tab rows, N-item picker generalization, per-provider tab labels, and the per-provider operator guides.
Open questions
- 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). 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, modelkimi-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 whetherchat-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. - Kimi Anthropic auth variable. Kimi's Claude Code docs use
ANTHROPIC_API_KEYrather thanANTHROPIC_AUTH_TOKEN. Confirm which variable theapi.kimi.com/codingendpoint 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. - 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 exposeskimi-for-coding. Confirm the intended tier maps, especially as MiniMax's Coding Plan model (M2.x) differs from its Token Plan model (M3). - Region. International endpoints only. MiniMax's separate China base URL (
api.minimaxi.com) is out of scope; the catalog hardcodes the internationalapi.minimax.iosurface and does not expose a region selector. - 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 account-state work.
Related files
crates/jackin-protocol/src/lib.rs—Providerenum,env_overrides,available_for,ZAI_*constantscrates/jackin-capsule/src/session.rs—SESSION_ENV_PASSTHROUGHallowlistcrates/jackin-capsule/src/daemon.rs— in-container key resolution (ZAI_API_KEY) and provider env applicationcrates/jackin-capsule/src/runtime_setup.rs— in-container agent setup (target for Codexconfig.tomlgeneration)docker/runtime/entrypoint.sh—OPENCODE_CONFIG_CONTENTexportcrates/jackin-core/src/manifest.rs— per-agentmodelfieldscrates/jackin-console/src/tui/state/manager.rs—zai_key_presentand the Auth tab
Cross-references
- Z.AI (GLM Coding Plan) — the shipped single-provider integration this item generalizes
- Multi-runtime support — the agent runtimes this routing targets
- AgentRuntime and Provider registry — each runtime's provider renderer belongs in its adapter rather than in shared dispatch
- Agent launch flags API — shares the
jackin-capsule runtime-setupdispatch surface Phase 2 writes into - Reliable Claude authentication strategy — the parallel work for Anthropic's own auth