jackin'
RoadmapAgent runtimes & authentication

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.

ProviderSubscribeExtract keyKey shapeModels
Z.AI / GLM Coding Planz.ai/subscribez.ai/manage-apikey/apikey-listZ.AI API keyGLM-5.1, GLM-5-Turbo, GLM-4.7, GLM-4.5-Air
MiniMax Coding / Token Planplatform.minimax.io (Plus $20 / Max $50 / Ultra $120 per month; international endpoint only)platform.minimax.io/console/planPlan DetailsSubscription Key (sk-cp)sk-cp-…MiniMax-M3 (Token Plan), M2.x (Coding Plan)
Kimi Codekimi.com/membership/pricing (shares Kimi membership quota; weekly + rate-limit windows, no carryover)Kimi Code ConsoleAPI 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):

ProviderAnthropic-compatible (Claude Code)OpenAI-compatible (Codex / OpenCode)
Z.AI / GLMhttps://api.z.ai/api/anthropic (shipped)https://api.z.ai/api/coding/paas/v4
MiniMaxhttps://api.minimax.io/anthropichttps://api.minimax.io/v1
Kimihttps://api.kimi.com/codinghttps://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.

ProviderClaude CodeCodexOpenCode
Anthropic (native)✅ shipn/a✅ ship
OpenAI (native)n/a✅ ship — Codex's default auth; no wire_api redirect neededn/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 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 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).

  1. 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"
  1. 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.
model_provider = "minimax"
model = "MiniMax-M3"
  1. 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, 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::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

  • 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

  • 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

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

  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). 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 account-state work.

Cross-references

On this page