Skip to content

Instantly share code, notes, and snippets.

@Evan-Kim2028
Created May 19, 2026 17:44
Show Gist options
  • Select an option

  • Save Evan-Kim2028/35e1008d469bc1a519f5d1ce53bd471f to your computer and use it in GitHub Desktop.

Select an option

Save Evan-Kim2028/35e1008d469bc1a519f5d1ce53bd471f to your computer and use it in GitHub Desktop.
Using a Kimi Code subscription (Kimi K2.6) with Factory's Droid CLI via BYOK + local User-Agent proxy

Using a Kimi Code subscription (Kimi K2.6) with Factory's Droid CLI (BYOK, no Droid subscription)

This guide sets up Kimi K2.6 as a custom BYOK model in the Droid CLI using a Kimi Code subscription key (the coding-plan key, sk-kimi-...), so you don't need a paid Droid subscription. Inference bills to your Kimi Code subscription.

Works the same whether you run droid directly or inside a terminal multiplexer like herdr (herdr just hosts the droid process in a pane — no special integration needed).


TL;DR — why it's not just a config file

The Kimi Code endpoint (https://api.kimi.com/coding/v1, OpenAI-compatible) gates requests by User-Agent. Only recognized coding agents (Claude Code, Kimi CLI, Roo Code, Kilo Code, …) are allowed; anything else returns:

403 Kimi For Coding is currently only available for Coding Agents such as
Kimi CLI, Claude Code, Roo Code, Kilo Code, etc.

Droid uses the OpenAI Node SDK, which sets its own User-Agent and ignores droid's extraHeaders override for that header. So a config-only UA spoof fails — you need a tiny local proxy that rewrites the header before forwarding to Kimi.


1. Prerequisites

  • A Kimi Code subscription and its API key (sk-kimi-...) — from the Kimi Code dashboard.
  • droid installed: curl -fsSL https://app.factory.ai/cli | sh
  • Node.js available (any recent version).
  • A free Factory account (you log in once with droid; BYOK = your key, your bill).

2. Local User-Agent rewrite proxy

Create ~/.factory/kimi-proxy.js:

#!/usr/bin/env node
// Minimal reverse proxy: forces a recognized User-Agent so a Kimi Code
// subscription key works with droid (OpenAI Node SDK overrides UA itself).
// Listen:  http://127.0.0.1:8788/v1/...  ->  https://api.kimi.com/coding/v1/...
const http = require("node:http");
const https = require("node:https");

const PORT = 8788;
const UPSTREAM_HOST = "api.kimi.com";
const PATH_PREFIX = "/coding"; // incoming /v1/... -> /coding/v1/...
const FORCED_UA = "claude-cli/1.0.119 (external, cli)";

const server = http.createServer((req, res) => {
  const headers = { ...req.headers };
  headers["host"] = UPSTREAM_HOST;
  headers["user-agent"] = FORCED_UA;
  delete headers["accept-encoding"];

  const upstream = https.request(
    { host: UPSTREAM_HOST, port: 443, method: req.method,
      path: PATH_PREFIX + req.url, headers },
    (uRes) => { res.writeHead(uRes.statusCode || 502, uRes.headers); uRes.pipe(res); }
  );
  upstream.on("error", (e) => {
    res.writeHead(502, { "content-type": "application/json" });
    res.end(JSON.stringify({ error: { message: "proxy: " + e.message } }));
  });
  req.pipe(upstream);
});

server.listen(PORT, "127.0.0.1", () =>
  console.log(`kimi-proxy on http://127.0.0.1:${PORT} -> https://${UPSTREAM_HOST}${PATH_PREFIX}`)
);

The proxy binds 127.0.0.1 only and passes your API key through untouched (it never stores or modifies the key — only the User-Agent).

3. Run the proxy as a persistent service (Linux / systemd)

~/.config/systemd/user/kimi-proxy.service:

[Unit]
Description=Kimi Code -> droid User-Agent rewrite proxy
After=network-online.target

[Service]
ExecStart=/usr/bin/env node %h/.factory/kimi-proxy.js
Restart=always
RestartSec=2

[Install]
WantedBy=default.target

Enable it:

systemctl --user daemon-reload
systemctl --user enable --now kimi-proxy.service
loginctl enable-linger "$USER"   # survive logout/reboot

(macOS: use a launchd plist, or just run node ~/.factory/kimi-proxy.js &.)

4. Configure the model in Droid

Edit ~/.factory/settings.json and add a customModels array (merge with existing settings — don't overwrite the file):

{
  "customModels": [
    {
      "model": "kimi-k2.6",
      "displayName": "Kimi K2.6 (Kimi Code)",
      "baseUrl": "http://127.0.0.1:8788/v1",
      "apiKey": "sk-kimi-YOUR_KIMI_CODE_KEY",
      "provider": "generic-chat-completion-api",
      "maxOutputTokens": 16384
    }
  ]
}

Note baseUrl points at the local proxy, not api.kimi.com directly.

5. Verify

curl -s http://127.0.0.1:8788/v1/chat/completions \
  -H "Authorization: Bearer sk-kimi-YOUR_KIMI_CODE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"kimi-k2.6","messages":[{"role":"user","content":"say ok"}],"max_tokens":8}'

A JSON completion with "model":"kimi-for-coding" means it works. A 403 means the proxy isn't running or the UA string is no longer accepted.

6. Use it

droid          # then: /model  ->  pick "Kimi K2.6 (Kimi Code)"

Or inside herdr:

herdr          # press n -> new workspace, then run `droid` in a pane

Maintenance

  • Rotate the key: edit apiKey in ~/.factory/settings.json only. The proxy passes the key through, so no proxy change needed.
  • Kimi changes its accepted-client list: bump FORCED_UA in kimi-proxy.js to a current Claude Code / Kimi CLI UA, then systemctl --user restart kimi-proxy.
  • Service control: systemctl --user status|restart|stop kimi-proxy.

Caveat

Routing a Kimi Code subscription through a client it doesn't officially list (via UA rewrite) may be against Kimi's terms of service. You're using your own key and your own subscription, but do this at your own discretion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment