{"id":"bb281726-685f-4356-a1ae-ecfa5b756806","entityType":"agent","slug":"clawhub-askegor-space-duck-kimi-relay","name":"space-duck-kimi-relay","canonicalUrl":"https://www.xpersona.co/agent/clawhub-askegor-space-duck-kimi-relay","canonicalPath":"/agent/clawhub-askegor-space-duck-kimi-relay","generatedAt":"2026-10-10T11:52:17.322Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T09:08:13.891Z","emptyReason":null},"description":"Optional Lane A / BYOB add-on for Space Duck — runs a local RFC 8628 device-code \"Sign in with Kimi\" flow (no password; browser-approved) so a self-hosted duck can use the owner's flat-rate Kimi membership for inference. Credentials (access + rotating refresh token) are stored locally at ~/.kimi-code/credentials/kimi.json (0600) and are NEVER sent to Spaceduckling. Contacts only auth.kimi.com and api.kimi.com; inference is processed by Moonshot AI in China (no Western data residency). Optional pay-per-token fallback to openrouter.ai when OPENROUTER_API_KEY is set (daily-capped). Runs a localhost-only proxy (127.0.0.1, default 8471) protected by an auto-generated 0600 bearer secret. Hosted (Lane B) ducks use the Mission Control card instead. Triggers on \"sign in with kimi\", \"kimi membership login\", \"clawhub space-duck kimi\", \"kimi relay login\".","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.5K downloads reported by the source. Last updated 10/10/2026.","installCommand":"clawhub skill install s17e5znj81e7w3zawrsxqg06hn85qbfq:space-duck-kimi-relay","sourceUrl":"https://clawhub.ai/askegor/space-duck-kimi-relay","homepage":"https://clawhub.ai/askegor/skills/space-duck-kimi-relay","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/askegor/space-duck-kimi-relay","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/askegor/skills/space-duck-kimi-relay","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":64,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"space-duck-kimi-relay technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-10T09:08:13.891Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T09:08:13.891Z","emptyReason":null},"stars":null,"forks":null,"downloads":1535,"packageName":null,"latestVersion":"0.9.8","tractionLabel":"1.5K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T09:08:13.890Z","emptyReason":null},"lastUpdatedAt":"2026-10-10T09:08:13.891Z","lastCrawledAt":"2026-10-10T09:08:13.890Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-11T09:08:13.890Z","lastVerifiedAt":null,"highlights":[{"version":"0.9.8","createdAt":"2026-09-26T05:18:21.991Z","changelog":"0.9.8: no-op lockstep bump with space-duck 0.9.8 (family version alignment).","fileCount":5,"zipByteSize":14864},{"version":"0.9.7","createdAt":"2026-09-14T17:36:30.989Z","changelog":"Lockstep no-op version bump to 0.9.7 (space-duck family alignment; no code changes).","fileCount":5,"zipByteSize":15196},{"version":"0.9.6","createdAt":"2026-09-14T17:08:55.895Z","changelog":"Lockstep no-op bump to 0.9.6 with space-duck (SKILL-095).","fileCount":5,"zipByteSize":14972},{"version":"0.9.5","createdAt":"2026-09-14T17:06:34.679Z","changelog":"Lockstep no-op bump to 0.9.5 with space-duck (SKILL-095). Also reconciles _meta.json version drift (was 0.9.2 on disk).","fileCount":5,"zipByteSize":15090},{"version":"0.9.4","createdAt":"2026-09-14T15:39:56.727Z","changelog":"Lockstep version alignment with space-duck 0.9.4 (SKILL-094 connections.py bond truth). No functional changes to the relay.","fileCount":5,"zipByteSize":14964},{"version":"0.9.3","createdAt":"2026-09-14T12:18:19.722Z","changelog":"0.9.3: no-op version bump — lockstep alignment with space-duck 0.9.3 (setup.py --validate truthful-verdict fix). No relay code changes.","fileCount":5,"zipByteSize":15109},{"version":"0.9.2","createdAt":"2026-09-14T08:11:45.583Z","changelog":"0.9.2: no-op lockstep version bump with space-duck 0.9.2 (family version alignment).","fileCount":5,"zipByteSize":14998},{"version":"0.9.1","createdAt":"2026-09-12T23:41:36.574Z","changelog":"0.9.1: lockstep version alignment with space-duck 0.9.1 (grant-expiry advisories in the core skill). No relay code changes.","fileCount":5,"zipByteSize":14965}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17e5znj81e7w3zawrsxqg06hn85qbfq:space-duck-kimi-relay","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s17e5znj81e7w3zawrsxqg06hn85qbfq:space-duck-kimi-relay` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/askegor/space-duck-kimi-relay before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-askegor-space-duck-kimi-relay/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-askegor-space-duck-kimi-relay/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-askegor-space-duck-kimi-relay/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-askegor-space-duck-kimi-relay/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-askegor-space-duck-kimi-relay/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-askegor-space-duck-kimi-relay/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-10T11:52:17.318Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-askegor-space-duck-kimi-relay/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-askegor-space-duck-kimi-relay/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-askegor-space-duck-kimi-relay/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-askegor-space-duck-kimi-relay/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T09:08:13.891Z","emptyReason":null},"readme":"Skill: space-duck-kimi-relay\n\nOwner: askegor\n\nSummary: Optional Lane A / BYOB add-on for Space Duck — runs a local RFC 8628 device-code \"Sign in with Kimi\" flow (no password; browser-approved) so a self-hosted duck can use the owner's flat-rate Kimi membership for inference. Credentials (access + rotating refresh token) are stored locally at ~/.kimi-code/credentials/kimi.json (0600) and are NEVER sent to Spaceduckling. Contacts only auth.kimi.com and api.kimi.com; inference is processed by Moonshot AI in China (no Western data residency). Optional pay-per-token fallback to openrouter.ai when OPENROUTER_API_KEY is set (daily-capped). Runs a localhost-only proxy (127.0.0.1, default 8471) protected by an auto-generated 0600 bearer secret. Hosted (Lane B) ducks use the Mission Control card instead. Triggers on \"sign in with kimi\", \"kimi membership login\", \"clawhub space-duck kimi\", \"kimi relay login\".\n\nTags: kimi:0.9.8, lane-a:0.9.8, latest:0.9.8, space-duck:0.9.8\n\nVersion history:\n\nv0.9.8 | 2026-09-26T05:18:21.991Z | user\n\n0.9.8: no-op lockstep bump with space-duck 0.9.8 (family version alignment).\n\nv0.9.7 | 2026-09-14T17:36:30.989Z | user\n\nLockstep no-op version bump to 0.9.7 (space-duck family alignment; no code changes).\n\nv0.9.6 | 2026-09-14T17:08:55.895Z | user\n\nLockstep no-op bump to 0.9.6 with space-duck (SKILL-095).\n\nv0.9.5 | 2026-09-14T17:06:34.679Z | user\n\nLockstep no-op bump to 0.9.5 with space-duck (SKILL-095). Also reconciles _meta.json version drift (was 0.9.2 on disk).\n\nv0.9.4 | 2026-09-14T15:39:56.727Z | user\n\nLockstep version alignment with space-duck 0.9.4 (SKILL-094 connections.py bond truth). No functional changes to the relay.\n\nv0.9.3 | 2026-09-14T12:18:19.722Z | user\n\n0.9.3: no-op version bump — lockstep alignment with space-duck 0.9.3 (setup.py --validate truthful-verdict fix). No relay code changes.\n\nv0.9.2 | 2026-09-14T08:11:45.583Z | user\n\n0.9.2: no-op lockstep version bump with space-duck 0.9.2 (family version alignment).\n\nv0.9.1 | 2026-09-12T23:41:36.574Z | user\n\n0.9.1: lockstep version alignment with space-duck 0.9.1 (grant-expiry advisories in the core skill). No relay code changes.\n\nv0.9.0 | 2026-09-10T13:31:36.381Z | user\n\nLockstep no-op bump to 0.9.0 (family version alignment; no code changes since 0.8.21-era content).\n\nv0.8.21 | 2026-09-02T15:01:49.089Z | user\n\nv0.8.21 - version lockstep with space-duck 0.8.21. No functional change to the Kimi relay itself; released together so a duck's core skill and relay never report divergent versions.\n\nv0.8.20 | 2026-09-02T13:46:28.398Z | user\n\nv0.8.20 - family lockstep with space-duck 0.8.20 (no functional change). Keeps the space-duck skill family on one version number per Josh's no-drift rule.\n\nv0.8.11 | 2026-08-30T01:15:01.927Z | user\n\n0.8.11: lockstep version alignment with space-duck 0.8.11. No functional change.\n\nv0.8.9 | 2026-08-29T05:20:39.411Z | user\n\n0.8.9 lockstep no-op bump to stay aligned with space-duck 0.8.9 [LANE-089]. No code or behaviour change in the relay.\n\nv0.8.8 | 2026-08-28T19:42:01.154Z | user\n\n0.8.8 lockstep no-op bump to stay aligned with space-duck 0.8.8 [LOOKUP-088]. No code or behaviour change in the relay.\n\nv0.8.7 | 2026-08-19T02:00:03.778Z | user\n\n0.8.7 — no-op lockstep bump with space-duck 0.8.7 (STATUS-087). No code changes.\n\nv0.8.6 | 2026-08-17T17:56:57.611Z | user\n\n0.8.6: lockstep family alignment with space-duck 0.8.6 (FIELD-086 fix wave). No relay code changes.\n\nv0.8.5 | 2026-08-16T10:57:54.025Z | user\n\nLockstep no-op bump to 0.8.5 with space-duck (family version alignment). No code changes.\n\nv0.8.4 | 2026-08-11T16:56:23.723Z | user\n\n0.8.4 lockstep family bump (aligns with space-duck 0.8.4 critic-hardening). No relay code/behavior change; manifest version aligned.\n\nv0.8.3 | 2026-08-11T11:32:24.232Z | user\n\n0.8.3 lockstep family bump (aligns with space-duck 0.8.3 security hardening). No relay code/behavior change; manifest version aligned.\n\nv0.8.2 | 2026-08-11T05:04:55.424Z | user\n\n0.8.2 (family-aligned release): removed publisher-infra note from shipped _meta.json (was leaking ClawHub token path + HOME override — SSD-3). Softened SKILL.md remote-token guidance toward local-login-first custody. Carries the 0.5.2 secrets-hardening (systemd EnvironmentFile) + byte-grounded SECURITY-MANIFEST.md. Version aligned to the space-duck family.\n\nv0.5.2 | 2026-08-11T04:09:00.772Z | user\n\n0.5.2: install-service no longer inlines OPENROUTER_API_KEY/KIMI_* secrets into the systemd unit — secrets now in a separate 0600 EnvironmentFile (relay.env), unit itself 0600; uninstall + drift-check updated to match. Byte-grounded SECURITY-MANIFEST.md added (file:line evidence for every egress/credential/exec claim). NO_AUTH left as-is by design: already localhost-bound + secret-by-default (disclosure, not a code change).\n\nv0.5.1 | 2026-08-08T03:09:59.197Z | user\n\n0.5.1: fallback SSE chunk now carries usage (spend metering); status warns on service-unit env drift (names only); credential lineage doctrine in SKILL.md (one-way moves, re-login on kept box); reboot-recovery proven (systemd container, system-unit; user-mode+linger still caveated)\n\nv0.5.0 | 2026-08-08T02:22:39.463Z | user\n\n0.5.0: proxy now requires a local bearer secret (auto-generated 0600 file; 401 without it) so other local processes cannot spend your membership quota; KIMI_RELAY_NO_AUTH=1 opt-out; 10MB request cap + 120s socket timeout; per-box fallback-cap note. BREAKING: set your runtime api key to the printed proxy secret.\n\nv0.4.0 | 2026-08-05T05:44:18.808Z | user\n\n0.4.0: streaming clients get SSE-wrapped fallback replies (no more JSON-where-SSE-expected); install-service captures OPENROUTER_API_KEY/KIMI_* env into the unit (0600) so fallback survives reboots.\n\nv0.3.0 | 2026-08-05T05:02:07.019Z | user\n\n0.3.0: SSE streaming passthrough, metered OR fallback (daily cap, 429 past cap), install-service/uninstall-service/status (systemd user + launchd), /health endpoint. All legs live-tested incl. cold install on stock Debian container.\n\nv0.2.0 | 2026-08-05T03:47:23.455Z | user\n\nLive-proven release: fcntl-locked refresh (rotation-race safe), 'serve' localhost proxy with per-request token injection + optional OpenRouter fallback (OPENROUTER_API_KEY), env-overridable client_id/hosts, atomic cred writes, probe fixed for k3 reasoning-token budget. login/probe/proxy/fallback all e2e-tested.\n\nv0.1.0 | 2026-08-05T03:35:21.076Z | user\n\nInitial release: local Kimi membership device-code sign-in for Lane A (BYOB) ducks — token stays on the owner's box; login/token/probe/logout; refresh-rotation safe.\n\nArchive index:\n\nArchive v0.9.8: 5 files, 14864 bytes\n\nFiles: _meta.json (140b), scripts/kimi_login.py (24355b), SECURITY-MANIFEST.md (3240b), skill-card.md (2593b), SKILL.md (8055b)\n\nFile v0.9.8:SKILL.md\n\n---\nname: space-duck-kimi-relay\ndescription: Optional Lane A / BYOB add-on for Space Duck — runs a local RFC 8628 device-code \"Sign in with Kimi\" flow (no password; browser-approved) so a self-hosted duck can use the owner's flat-rate Kimi membership for inference. Credentials (access + rotating refresh token) are stored locally at ~/.kimi-code/credentials/kimi.json (0600) and are NEVER sent to Spaceduckling. Contacts only auth.kimi.com and api.kimi.com; inference is processed by Moonshot AI in China (no Western data residency). Optional pay-per-token fallback to openrouter.ai when OPENROUTER_API_KEY is set (daily-capped). Runs a localhost-only proxy (127.0.0.1, default 8471) protected by an auto-generated 0600 bearer secret. Hosted (Lane B) ducks use the Mission Control card instead. Triggers on \"sign in with kimi\", \"kimi membership login\", \"clawhub space-duck kimi\", \"kimi relay login\".\ndisclosures:\n  network:\n    - auth.kimi.com          # OAuth device authorization + token/refresh\n    - api.kimi.com           # membership inference (Moonshot AI, China)\n    - openrouter.ai          # OPTIONAL pay-per-token fallback, only if OPENROUTER_API_KEY set\n  credentials:\n    - Kimi access + refresh token at ~/.kimi-code/credentials/kimi.json (0600, local only)\n    - auto-generated proxy bearer secret at ~/.kimi-code/credentials/proxy_secret (0600)\n    - reads OPENROUTER_API_KEY from env; forwarded only to openrouter.ai on fallback\n  data_residency: \"Kimi inference runs on Moonshot AI infrastructure in China.\"\n  overridable_endpoints:\n    - KIMI_AUTH_HOST, KIMI_CODING_BASE, KIMI_CLIENT_ID   # advanced; changing these re-points token traffic\n  spend: \"Fallback is metered, default cap KIMI_RELAY_FALLBACK_DAILY_CAP=200 calls/day; past cap returns 429.\"\n  auth_bypass: \"KIMI_RELAY_NO_AUTH=1 disables the localhost proxy's bearer check — single-user boxes only.\"\n  privilege: \"install-service writes a systemd-user/launchd unit; captured KIMI_*/OPENROUTER_API_KEY secrets go in a separate 0600 EnvironmentFile (~/.kimi-code/credentials/relay.env), never inlined into the unit.\"\n  sends_to_spaceduckling: none\n---\n\n# Space Duck Kimi Relay (optional add-on, Lane A)\n\nLets a duck that runs on **your own infrastructure** use your **Kimi\nmembership** (flat-rate subscription quota) for inference instead of\npay-per-token API keys.\n\n## Trust model — the whole point\n\n- The device-code sign-in runs **locally on your box**.\n- Tokens are stored at `~/.kimi-code/credentials/kimi.json` (0600), on\n  **your machine only**.\n- The only host this skill contacts is Kimi itself (`auth.kimi.com` and\n  `api.kimi.com`). **Spaceduckling never sees or holds the token.**\n- This is the Lane A mirror of Mission Control's hosted \"Sign in with\n  Kimi\" card: same protocol capability, different custody. (Cross-lane\n  parity doctrine — capability exists in both lanes, credentials follow\n  the lane's trust model.)\n\n## Commands\n\n```\nkimi_login.py login         # interactive device sign-in\nkimi_login.py token         # print fresh access token (auto-refresh, file-locked)\nkimi_login.py probe         # inference smoke on membership quota\nkimi_login.py serve [port]  # local proxy for your runtime (default 8471)\nkimi_login.py install-service [port]   # run proxy as a service (systemd user / launchd)\nkimi_login.py uninstall-service        # remove the service\nkimi_login.py status [port] # creds + proxy + fallback-meter health check\nkimi_login.py logout        # delete local credentials\n```\n\n`login` shows a kimi.com URL + user code; approve it in your browser and\nthe script stores the tokens. `token` transparently refreshes — Kimi\naccess tokens live ~15 minutes and **refresh tokens rotate on every\ngrant**, so always let this script (not ad-hoc curl) do the refreshing;\na stale refresh token is dead after one rotation.\n\n## Wiring the duck's brain — use the proxy\n\nKimi access tokens live ~15 minutes, so a static key in your runtime's\nconfig will not survive. Run the local proxy instead:\n\n```\nkimi_login.py serve            # http://127.0.0.1:8471/v1/chat/completions\n```\n\nPoint your runtime's OpenAI-compatible provider at\n`http://127.0.0.1:8471/v1`. As the api key, use the **proxy secret**\nthat `serve` / `status` prints (auto-generated at\n`~/.kimi-code/credentials/proxy_secret`, 0600) — without it the proxy\nanswers 401, so other local processes/users can't spend your quota.\n`KIMI_RELAY_NO_AUTH=1` disables the check (single-user boxes only).\nThe proxy injects a fresh membership token per request (refreshes under\na file lock — safe when several ducks on one box share the login; note\nthe fallback cap below is per-box, so ducks sharing a box share the\nbudget).\n\n- Models: `k3` (full), `kimi-for-coding` (budget)\n- k3 emits `reasoning_content` and spends completion budget on it —\n  give it roomy `max_tokens` (512+) or replies can arrive empty.\n\nStreaming (`\"stream\": true`) is passed through as SSE, so chat UIs get\ntoken-by-token output on the membership lane.\n\n**Automatic fallback:** export `OPENROUTER_API_KEY` before `serve` and\nany failed membership call (quota/auth/outage) is retried once on\nOpenRouter's kimi lane (`moonshotai/*`, pay-per-token) — same\ndegradation the hosted lane performs. Fallback is metered: capped at\n`KIMI_RELAY_FALLBACK_DAILY_CAP` calls/day (default 200) so a broken\nmembership can't silently run up a pay-per-token bill; past the cap the\nproxy returns 429. If the client asked for `stream: true`, the fallback\nreply is wrapped as a single SSE chunk + `[DONE]` so streaming clients\nstill get valid SSE. Without the env var, failures return the error so\nyour runtime's own ladder takes over.\n\nFor a proxy that survives reboots, `install-service` writes a systemd\nuser unit (Linux — enable lingering with\n`loginctl enable-linger $USER` so it runs while logged out) or a\nlaunchd agent (macOS). Any `OPENROUTER_API_KEY` / `KIMI_*` env vars set\nwhen you run `install-service` are written to a **separate 0600\n`EnvironmentFile`** (`~/.kimi-code/credentials/relay.env`) that the unit\nreferences — secrets are never inlined into the world-readable systemd\nunit itself — so the fallback survives reboots without leaking the key.\n`status` shows creds, proxy health, and the fallback meter.\n\nEnv overrides: `KIMI_CLIENT_ID` (if Moonshot rotates the public\nclient), `KIMI_AUTH_HOST`, `KIMI_CODING_BASE`,\n`KIMI_RELAY_FALLBACK_DAILY_CAP`.\n\n## Moving credentials between machines\n\nRefresh tokens **rotate on every grant**. That means:\n\n- Creds move **one-way only**. If you copy `~/.kimi-code/credentials/kimi.json`\n  to a second box and let that box run (`token`, `probe`, or `serve`), it\n  will refresh and rotate the shared refresh token — the box you copied\n  *from* will silently strand on the next refresh.\n- Rule: after running the creds on another box, **re-login on the box\n  you want to keep** with `kimi_login.py login`. Never copy `kimi.json`\n  back to the original box.\n- Prefer a local login on every box (`kimi_login.py login`) — that keeps\n  the token in local custody where the trust model expects it. Only if\n  you cannot log in on the remote box, a short-lived access token from\n  `kimi_login.py token` can be used for a brief test: it is valid ~15 min,\n  has no refresh capability, and cannot strand any lineage. Treat it like\n  any secret — do not paste it into logs, chat, or shared terminals, and\n  let it expire rather than storing it.\n- One lineage per runtime. Don't share a single `kimi.json` across two\n  long-running services; give each its own login.\n\n## Data residency\n\nKimi inference is processed by Moonshot AI on infrastructure in China.\nDon't route conversations through this lane if you require Western data\nresidency.\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `scripts/kimi_login.py` | Device sign-in, token refresh, probe, logout |\n\n## Important\n\n- Opt-in add-on; the core `space-duck` skill works without it.\n- Updates arrive via ClawHub with owner consent (Mission Control shows\n  \"update available\") — never force-pushed to your box.\n\nFile v0.9.8:_meta.json\n\n{\n  \"ownerId\": \"kn7cav8v08rpkp9w38xg3d9mp985q1e1\",\n  \"slug\": \"space-duck-kimi-relay\",\n  \"version\": \"0.9.8\",\n  \"publishedAt\": 1790399901991\n}\n\nFile v0.9.8:SECURITY-MANIFEST.md\n\n# space-duck-kimi-relay — Security Manifest (byte-grounded)\n\nVersion: 0.8.4 (aligned with the space-duck family — see MEMORY.md publish log) · Generated 2026-08-11 · Evidence = `scripts/kimi_login.py` line refs.\nRule: every claim below cites file:line. No claim rests on an LLM \"reading\".\n\n## Scope\nPackage is exactly 3 files: `SKILL.md`, `_meta.json`, `scripts/kimi_login.py`.\nNo `lib/`, no `bin/`, no `package.json`, no JS, no dependencies beyond Python stdlib\n(`fcntl, json, os, sys, time, urllib, http.server, secrets, subprocess`).\n\n## Credential custody\n- Store path: `~/.kimi-code/credentials/kimi.json` — `CRED_PATH` (kimi_login.py:41-42).\n- Written 0600 via `os.open(..., 0o600)` in `_save()` (kimi_login.py:73); dir 0700 (kimi_login.py:65).\n- Proxy bearer secret `proxy_secret` written 0600 (kimi_login.py:206).\n- Access token read only from local file in `_load()`/`fresh_token()` (kimi_login.py:80-154).\n\n## Outbound hosts (complete egress allowlist)\nEvery network call is a `urllib.request.urlopen` — there are exactly three call sites:\n- kimi_login.py:55  → `AUTH_HOST` = `https://auth.kimi.com` (OAuth device + token/refresh), :36\n- kimi_login.py:166 → `CODING_BASE` = `https://api.kimi.com/coding/v1` (inference), :40\n- kimi_login.py:353 → `CODING_BASE` (streaming inference)\n- kimi_login.py:333 → `https://openrouter.ai/api/v1` — ONLY when `OPENROUTER_API_KEY` set (:319)\nNo other socket/urlopen/requests calls exist. **Nothing is sent to Spaceduckling.**\n\n## Where the token can leave the process\n- Kimi token injected as `Authorization: Bearer` only to Kimi hosts: kimi_login.py:164, :350.\n- `OPENROUTER_API_KEY` sent only to openrouter.ai: kimi_login.py:333.\n- No logging of token/secret values (log_message prints request lines only, :278-279).\n\n## Proxy exposure\n- Binds localhost only: `ThreadingHTTPServer((\"127.0.0.1\", port), ...)` (kimi_login.py:387). No bind-address override exists.\n- Auth ON by default: bearer check at kimi_login.py:291-296; secret auto-generated (:203-209).\n- `KIMI_RELAY_NO_AUTH=1` is an explicit opt-OUT (:194) and prints a loud warning (:394).\n  Assessed NOT a defect: already localhost-bound + secret-by-default. Disclosure, not a patch.\n\n## Fallback spend\n- Metered, default cap 200/day (`FALLBACK_DAILY_CAP`, :210); returns 429 past cap (:322-324).\n\n## Service install (hardened in 0.5.2)\n- systemd: secrets written to a **separate 0600 EnvironmentFile** `~/.kimi-code/credentials/relay.env` (kimi_login.py:461), referenced via `EnvironmentFile=` (:465). Secrets are NOT inlined into the (world-readable) unit.\n- Deterministic test asserts: secret value absent from unit, `EnvironmentFile=` present, env file 0600. PASS (2026-08-11).\n- macOS launchd: plist written 0600 (:444); values embedded in plist (0600) — documented residual.\n\n## Overridable endpoints (disclosed)\n- `KIMI_AUTH_HOST` (:36), `KIMI_CODING_BASE` (:40), `KIMI_CLIENT_ID` (:38). Changing these re-points token traffic — advanced use, disclosed in frontmatter.\n\n## Not covered by this manifest\n- Runtime behavior of the remote Kimi/OpenRouter endpoints (out of package scope).\n- Signing / GitHub provenance: ClawHub v0.9.0 exposes no signing command — registry-feature gap, not a code defect.\n\nFile v0.9.8:skill-card.md\n\n## Description:\n\nEnables self-hosted Space Duck agents to sign in to Kimi through a browser-approved device flow and use a local inference proxy with optional metered fallback.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[askegor](https://clawhub.ai/user/askegor)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers running self-hosted Space Duck agents can use their Kimi membership for inference through a locally authenticated proxy instead of configuring a static access token. An optional OpenRouter fallback supports metered inference when membership calls fail.\n\n### Deployment Geography for Use:\n\nGlobal; Kimi inference is processed in China and is unsuitable where Western data residency is required.\n\n## Known Risks and Mitigations:\n\nRisk: Local Kimi tokens and an optional OpenRouter key grant access to accounts or metered usage.\n\nMitigation: Protect local credential files, prefer the authenticated localhost proxy, and avoid printing or sharing tokens.\n\nRisk: Disabling proxy authentication can expose membership quota to other users or processes on a shared machine.\n\nMitigation: Do not enable KIMI_RELAY_NO_AUTH on shared machines.\n\nRisk: Optional fallback can incur pay-per-token charges when membership requests fail.\n\nMitigation: Enable fallback only when needed and set an appropriate daily call cap.\n\nRisk: Endpoint overrides can redirect token traffic, and service installation can persist secrets in a macOS launchd plist.\n\nMitigation: Avoid endpoint overrides unless the destination is trusted; review service installation and protect the macOS plist.\n\nRisk: Kimi inference is processed in China rather than under Western data residency.\n\nMitigation: Do not route conversations requiring Western data residency through this relay.\n\n## Reference(s):\n\n- [Space Duck Kimi Relay on ClawHub](https://clawhub.ai/askegor/skills/space-duck-kimi-relay)\n- [Security manifest](SECURITY-MANIFEST.md)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Configuration instructions, Guidance]\n\n**Output Format:** [Markdown with command examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Supports local sign-in, token refresh, proxy setup, and optional paid fallback.]\n\n## Skill Version(s):\n\n0.9.8 (source: ClawHub release metadata and _meta.json)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.9.7: 5 files, 15196 bytes\n\nFiles: _meta.json (140b), scripts/kimi_login.py (24355b), SECURITY-MANIFEST.md (3240b), skill-card.md (3342b), SKILL.md (8055b)\n\nFile v0.9.7:SKILL.md\n\n---\nname: space-duck-kimi-relay\ndescription: Optional Lane A / BYOB add-on for Space Duck — runs a local RFC 8628 device-code \"Sign in with Kimi\" flow (no password; browser-approved) so a self-hosted duck can use the owner's flat-rate Kimi membership for inference. Credentials (access + rotating refresh token) are stored locally at ~/.kimi-code/credentials/kimi.json (0600) and are NEVER sent to Spaceduckling. Contacts only auth.kimi.com and api.kimi.com; inference is processed by Moonshot AI in China (no Western data residency). Optional pay-per-token fallback to openrouter.ai when OPENROUTER_API_KEY is set (daily-capped). Runs a localhost-only proxy (127.0.0.1, default 8471) protected by an auto-generated 0600 bearer secret. Hosted (Lane B) ducks use the Mission Control card instead. Triggers on \"sign in with kimi\", \"kimi membership login\", \"clawhub space-duck kimi\", \"kimi relay login\".\ndisclosures:\n  network:\n    - auth.kimi.com          # OAuth device authorization + token/refresh\n    - api.kimi.com           # membership inference (Moonshot AI, China)\n    - openrouter.ai          # OPTIONAL pay-per-token fallback, only if OPENROUTER_API_KEY set\n  credentials:\n    - Kimi access + refresh token at ~/.kimi-code/credentials/kimi.json (0600, local only)\n    - auto-generated proxy bearer secret at ~/.kimi-code/credentials/proxy_secret (0600)\n    - reads OPENROUTER_API_KEY from env; forwarded only to openrouter.ai on fallback\n  data_residency: \"Kimi inference runs on Moonshot AI infrastructure in China.\"\n  overridable_endpoints:\n    - KIMI_AUTH_HOST, KIMI_CODING_BASE, KIMI_CLIENT_ID   # advanced; changing these re-points token traffic\n  spend: \"Fallback is metered, default cap KIMI_RELAY_FALLBACK_DAILY_CAP=200 calls/day; past cap returns 429.\"\n  auth_bypass: \"KIMI_RELAY_NO_AUTH=1 disables the localhost proxy's bearer check — single-user boxes only.\"\n  privilege: \"install-service writes a systemd-user/launchd unit; captured KIMI_*/OPENROUTER_API_KEY secrets go in a separate 0600 EnvironmentFile (~/.kimi-code/credentials/relay.env), never inlined into the unit.\"\n  sends_to_spaceduckling: none\n---\n\n# Space Duck Kimi Relay (optional add-on, Lane A)\n\nLets a duck that runs on **your own infrastructure** use your **Kimi\nmembership** (flat-rate subscription quota) for inference instead of\npay-per-token API keys.\n\n## Trust model — the whole point\n\n- The device-code sign-in runs **locally on your box**.\n- Tokens are stored at `~/.kimi-code/credentials/kimi.json` (0600), on\n  **your machine only**.\n- The only host this skill contacts is Kimi itself (`auth.kimi.com` and\n  `api.kimi.com`). **Spaceduckling never sees or holds the token.**\n- This is the Lane A mirror of Mission Control's hosted \"Sign in with\n  Kimi\" card: same protocol capability, different custody. (Cross-lane\n  parity doctrine — capability exists in both lanes, credentials follow\n  the lane's trust model.)\n\n## Commands\n\n```\nkimi_login.py login         # interactive device sign-in\nkimi_login.py token         # print fresh access token (auto-refresh, file-locked)\nkimi_login.py probe         # inference smoke on membership quota\nkimi_login.py serve [port]  # local proxy for your runtime (default 8471)\nkimi_login.py install-service [port]   # run proxy as a service (systemd user / launchd)\nkimi_login.py uninstall-service        # remove the service\nkimi_login.py status [port] # creds + proxy + fallback-meter health check\nkimi_login.py logout        # delete local credentials\n```\n\n`login` shows a kimi.com URL + user code; approve it in your browser and\nthe script stores the tokens. `token` transparently refreshes — Kimi\naccess tokens live ~15 minutes and **refresh tokens rotate on every\ngrant**, so always let this script (not ad-hoc curl) do the refreshing;\na stale refresh token is dead after one rotation.\n\n## Wiring the duck's brain — use the proxy\n\nKimi access tokens live ~15 minutes, so a static key in your runtime's\nconfig will not survive. Run the local proxy instead:\n\n```\nkimi_login.py serve            # http://127.0.0.1:8471/v1/chat/completions\n```\n\nPoint your runtime's OpenAI-compatible provider at\n`http://127.0.0.1:8471/v1`. As the api key, use the **proxy secret**\nthat `serve` / `status` prints (auto-generated at\n`~/.kimi-code/credentials/proxy_secret`, 0600) — without it the proxy\nanswers 401, so other local processes/users can't spend your quota.\n`KIMI_RELAY_NO_AUTH=1` disables the check (single-user boxes only).\nThe proxy injects a fresh membership token per request (refreshes under\na file lock — safe when several ducks on one box share the login; note\nthe fallback cap below is per-box, so ducks sharing a box share the\nbudget).\n\n- Models: `k3` (full), `kimi-for-coding` (budget)\n- k3 emits `reasoning_content` and spends completion budget on it —\n  give it roomy `max_tokens` (512+) or replies can arrive empty.\n\nStreaming (`\"stream\": true`) is passed through as SSE, so chat UIs get\ntoken-by-token output on the membership lane.\n\n**Automatic fallback:** export `OPENROUTER_API_KEY` before `serve` and\nany failed membership call (quota/auth/outage) is retried once on\nOpenRouter's kimi lane (`moonshotai/*`, pay-per-token) — same\ndegradation the hosted lane performs. Fallback is metered: capped at\n`KIMI_RELAY_FALLBACK_DAILY_CAP` calls/day (default 200) so a broken\nmembership can't silently run up a pay-per-token bill; past the cap the\nproxy returns 429. If the client asked for `stream: true`, the fallback\nreply is wrapped as a single SSE chunk + `[DONE]` so streaming clients\nstill get valid SSE. Without the env var, failures return the error so\nyour runtime's own ladder takes over.\n\nFor a proxy that survives reboots, `install-service` writes a systemd\nuser unit (Linux — enable lingering with\n`loginctl enable-linger $USER` so it runs while logged out) or a\nlaunchd agent (macOS). Any `OPENROUTER_API_KEY` / `KIMI_*` env vars set\nwhen you run `install-service` are written to a **separate 0600\n`EnvironmentFile`** (`~/.kimi-code/credentials/relay.env`) that the unit\nreferences — secrets are never inlined into the world-readable systemd\nunit itself — so the fallback survives reboots without leaking the key.\n`status` shows creds, proxy health, and the fallback meter.\n\nEnv overrides: `KIMI_CLIENT_ID` (if Moonshot rotates the public\nclient), `KIMI_AUTH_HOST`, `KIMI_CODING_BASE`,\n`KIMI_RELAY_FALLBACK_DAILY_CAP`.\n\n## Moving credentials between machines\n\nRefresh tokens **rotate on every grant**. That means:\n\n- Creds move **one-way only**. If you copy `~/.kimi-code/credentials/kimi.json`\n  to a second box and let that box run (`token`, `probe`, or `serve`), it\n  will refresh and rotate the shared refresh token — the box you copied\n  *from* will silently strand on the next refresh.\n- Rule: after running the creds on another box, **re-login on the box\n  you want to keep** with `kimi_login.py login`. Never copy `kimi.json`\n  back to the original box.\n- Prefer a local login on every box (`kimi_login.py login`) — that keeps\n  the token in local custody where the trust model expects it. Only if\n  you cannot log in on the remote box, a short-lived access token from\n  `kimi_login.py token` can be used for a brief test: it is valid ~15 min,\n  has no refresh capability, and cannot strand any lineage. Treat it like\n  any secret — do not paste it into logs, chat, or shared terminals, and\n  let it expire rather than storing it.\n- One lineage per runtime. Don't share a single `kimi.json` across two\n  long-running services; give each its own login.\n\n## Data residency\n\nKimi inference is processed by Moonshot AI on infrastructure in China.\nDon't route conversations through this lane if you require Western data\nresidency.\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `scripts/kimi_login.py` | Device sign-in, token refresh, probe, logout |\n\n## Important\n\n- Opt-in add-on; the core `space-duck` skill works without it.\n- Updates arrive via ClawHub with owner consent (Mission Control shows\n  \"update available\") — never force-pushed to your box.\n\nFile v0.9.7:_meta.json\n\n{\n  \"ownerId\": \"kn7cav8v08rpkp9w38xg3d9mp985q1e1\",\n  \"slug\": \"space-duck-kimi-relay\",\n  \"version\": \"0.9.7\",\n  \"publishedAt\": 1789407390989\n}\n\nFile v0.9.7:SECURITY-MANIFEST.md\n\n# space-duck-kimi-relay — Security Manifest (byte-grounded)\n\nVersion: 0.8.4 (aligned with the space-duck family — see MEMORY.md publish log) · Generated 2026-08-11 · Evidence = `scripts/kimi_login.py` line refs.\nRule: every claim below cites file:line. No claim rests on an LLM \"reading\".\n\n## Scope\nPackage is exactly 3 files: `SKILL.md`, `_meta.json`, `scripts/kimi_login.py`.\nNo `lib/`, no `bin/`, no `package.json`, no JS, no dependencies beyond Python stdlib\n(`fcntl, json, os, sys, time, urllib, http.server, secrets, subprocess`).\n\n## Credential custody\n- Store path: `~/.kimi-code/credentials/kimi.json` — `CRED_PATH` (kimi_login.py:41-42).\n- Written 0600 via `os.open(..., 0o600)` in `_save()` (kimi_login.py:73); dir 0700 (kimi_login.py:65).\n- Proxy bearer secret `proxy_secret` written 0600 (kimi_login.py:206).\n- Access token read only from local file in `_load()`/`fresh_token()` (kimi_login.py:80-154).\n\n## Outbound hosts (complete egress allowlist)\nEvery network call is a `urllib.request.urlopen` — there are exactly three call sites:\n- kimi_login.py:55  → `AUTH_HOST` = `https://auth.kimi.com` (OAuth device + token/refresh), :36\n- kimi_login.py:166 → `CODING_BASE` = `https://api.kimi.com/coding/v1` (inference), :40\n- kimi_login.py:353 → `CODING_BASE` (streaming inference)\n- kimi_login.py:333 → `https://openrouter.ai/api/v1` — ONLY when `OPENROUTER_API_KEY` set (:319)\nNo other socket/urlopen/requests calls exist. **Nothing is sent to Spaceduckling.**\n\n## Where the token can leave the process\n- Kimi token injected as `Authorization: Bearer` only to Kimi hosts: kimi_login.py:164, :350.\n- `OPENROUTER_API_KEY` sent only to openrouter.ai: kimi_login.py:333.\n- No logging of token/secret values (log_message prints request lines only, :278-279).\n\n## Proxy exposure\n- Binds localhost only: `ThreadingHTTPServer((\"127.0.0.1\", port), ...)` (kimi_login.py:387). No bind-address override exists.\n- Auth ON by default: bearer check at kimi_login.py:291-296; secret auto-generated (:203-209).\n- `KIMI_RELAY_NO_AUTH=1` is an explicit opt-OUT (:194) and prints a loud warning (:394).\n  Assessed NOT a defect: already localhost-bound + secret-by-default. Disclosure, not a patch.\n\n## Fallback spend\n- Metered, default cap 200/day (`FALLBACK_DAILY_CAP`, :210); returns 429 past cap (:322-324).\n\n## Service install (hardened in 0.5.2)\n- systemd: secrets written to a **separate 0600 EnvironmentFile** `~/.kimi-code/credentials/relay.env` (kimi_login.py:461), referenced via `EnvironmentFile=` (:465). Secrets are NOT inlined into the (world-readable) unit.\n- Deterministic test asserts: secret value absent from unit, `EnvironmentFile=` present, env file 0600. PASS (2026-08-11).\n- macOS launchd: plist written 0600 (:444); values embedded in plist (0600) — documented residual.\n\n## Overridable endpoints (disclosed)\n- `KIMI_AUTH_HOST` (:36), `KIMI_CODING_BASE` (:40), `KIMI_CLIENT_ID` (:38). Changing these re-points token traffic — advanced use, disclosed in frontmatter.\n\n## Not covered by this manifest\n- Runtime behavior of the remote Kimi/OpenRouter endpoints (out of package scope).\n- Signing / GitHub provenance: ClawHub v0.9.0 exposes no signing command — registry-feature gap, not a code defect.\n\nFile v0.9.7:skill-card.md\n\n## Description:\n\nSpace Duck Kimi Relay lets self-hosted Space Duck users sign in with Kimi locally, store Kimi credentials on their machine, and run a localhost proxy for Kimi membership inference with an optional capped OpenRouter fallback.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[askegor](https://clawhub.ai/user/askegor)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and self-hosted Space Duck operators use this skill to set up local Kimi membership sign-in, token refresh, proxy serving, health checks, service installation, and logout flows while keeping Kimi credentials outside Spaceduckling.\n\n### Deployment Geography for Use:\n\nGlobal; do not use this lane where Moonshot AI inference processing in China conflicts with residency or compliance requirements.\n\n## Known Risks and Mitigations:\n\nRisk: Kimi access and refresh tokens are stored locally, and printed access tokens or proxy secrets can grant access if exposed.\n\nMitigation: Keep credential files private, treat printed tokens and proxy secrets as secrets, avoid sharing them in logs or chat, and use logout when local custody is no longer desired.\n\nRisk: Kimi inference is processed on Moonshot AI infrastructure in China.\n\nMitigation: Do not route conversations through this lane when Western data residency or another residency requirement applies.\n\nRisk: Disabling proxy authentication can let other local processes use the proxy on the same machine.\n\nMitigation: Leave bearer authentication enabled by default and use KIMI_RELAY_NO_AUTH=1 only on a trusted single-user machine.\n\nRisk: KIMI_* endpoint overrides can redirect token or inference traffic.\n\nMitigation: Review KIMI_AUTH_HOST, KIMI_CODING_BASE, and KIMI_CLIENT_ID before use and only set them intentionally.\n\nRisk: The optional OpenRouter fallback is pay-per-token and can create metered usage when membership calls fail.\n\nMitigation: Set OPENROUTER_API_KEY only when fallback is desired, keep the daily fallback cap in place, and monitor status output for fallback use.\n\nRisk: Persistent service installation keeps the local proxy available across restarts.\n\nMitigation: Install the service only when persistent proxy behavior is intended and protect the generated 0600 environment file containing captured secrets.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/askegor/skills/space-duck-kimi-relay)\n- [Security Manifest](SECURITY-MANIFEST.md)\n- [Kimi authentication endpoint](https://auth.kimi.com)\n- [Kimi coding API endpoint](https://api.kimi.com/coding/v1)\n- [OpenRouter API endpoint](https://openrouter.ai/api/v1)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Configuration, Guidance]\n\n**Output Format:** [Markdown with inline shell commands]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Includes local login and proxy setup, service commands, health-check guidance, and cautions for secrets, endpoint overrides, data residency, and fallback spend.]\n\n## Skill Version(s):\n\n0.9.7 (source: server release metadata and artifact _meta.json)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.9.6: 5 files, 14972 bytes\n\nFiles: _meta.json (140b), scripts/kimi_login.py (24355b), SECURITY-MANIFEST.md (3240b), skill-card.md (2707b), SKILL.md (8055b)\n\nFile v0.9.6:SKILL.md\n\n---\nname: space-duck-kimi-relay\ndescription: Optional Lane A / BYOB add-on for Space Duck — runs a local RFC 8628 device-code \"Sign in with Kimi\" flow (no password; browser-approved) so a self-hosted duck can use the owner's flat-rate Kimi membership for inference. Credentials (access + rotating refresh token) are stored locally at ~/.kimi-code/credentials/kimi.json (0600) and are NEVER sent to Spaceduckling. Contacts only auth.kimi.com and api.kimi.com; inference is processed by Moonshot AI in China (no Western data residency). Optional pay-per-token fallback to openrouter.ai when OPENROUTER_API_KEY is set (daily-capped). Runs a localhost-only proxy (127.0.0.1, default 8471) protected by an auto-generated 0600 bearer secret. Hosted (Lane B) ducks use the Mission Control card instead. Triggers on \"sign in with kimi\", \"kimi membership login\", \"clawhub space-duck kimi\", \"kimi relay login\".\ndisclosures:\n  network:\n    - auth.kimi.com          # OAuth device authorization + token/refresh\n    - api.kimi.com           # membership inference (Moonshot AI, China)\n    - openrouter.ai          # OPTIONAL pay-per-token fallback, only if OPENROUTER_API_KEY set\n  credentials:\n    - Kimi access + refresh token at ~/.kimi-code/credentials/kimi.json (0600, local only)\n    - auto-generated proxy bearer secret at ~/.kimi-code/credentials/proxy_secret (0600)\n    - reads OPENROUTER_API_KEY from env; forwarded only to openrouter.ai on fallback\n  data_residency: \"Kimi inference runs on Moonshot AI infrastructure in China.\"\n  overridable_endpoints:\n    - KIMI_AUTH_HOST, KIMI_CODING_BASE, KIMI_CLIENT_ID   # advanced; changing these re-points token traffic\n  spend: \"Fallback is metered, default cap KIMI_RELAY_FALLBACK_DAILY_CAP=200 calls/day; past cap returns 429.\"\n  auth_bypass: \"KIMI_RELAY_NO_AUTH=1 disables the localhost proxy's bearer check — single-user boxes only.\"\n  privilege: \"install-service writes a systemd-user/launchd unit; captured KIMI_*/OPENROUTER_API_KEY secrets go in a separate 0600 EnvironmentFile (~/.kimi-code/credentials/relay.env), never inlined into the unit.\"\n  sends_to_spaceduckling: none\n---\n\n# Space Duck Kimi Relay (optional add-on, Lane A)\n\nLets a duck that runs on **your own infrastructure** use your **Kimi\nmembership** (flat-rate subscription quota) for inference instead of\npay-per-token API keys.\n\n## Trust model — the whole point\n\n- The device-code sign-in runs **locally on your box**.\n- Tokens are stored at `~/.kimi-code/credentials/kimi.json` (0600), on\n  **your machine only**.\n- The only host this skill contacts is Kimi itself (`auth.kimi.com` and\n  `api.kimi.com`). **Spaceduckling never sees or holds the token.**\n- This is the Lane A mirror of Mission Control's hosted \"Sign in with\n  Kimi\" card: same protocol capability, different custody. (Cross-lane\n  parity doctrine — capability exists in both lanes, credentials follow\n  the lane's trust model.)\n\n## Commands\n\n```\nkimi_login.py login         # interactive device sign-in\nkimi_login.py token         # print fresh access token (auto-refresh, file-locked)\nkimi_login.py probe         # inference smoke on membership quota\nkimi_login.py serve [port]  # local proxy for your runtime (default 8471)\nkimi_login.py install-service [port]   # run proxy as a service (systemd user / launchd)\nkimi_login.py uninstall-service        # remove the service\nkimi_login.py status [port] # creds + proxy + fallback-meter health check\nkimi_login.py logout        # delete local credentials\n```\n\n`login` shows a kimi.com URL + user code; approve it in your browser and\nthe script stores the tokens. `token` transparently refreshes — Kimi\naccess tokens live ~15 minutes and **refresh tokens rotate on every\ngrant**, so always let this script (not ad-hoc curl) do the refreshing;\na stale refresh token is dead after one rotation.\n\n## Wiring the duck's brain — use the proxy\n\nKimi access tokens live ~15 minutes, so a static key in your runtime's\nconfig will not survive. Run the local proxy instead:\n\n```\nkimi_login.py serve            # http://127.0.0.1:8471/v1/chat/completions\n```\n\nPoint your runtime's OpenAI-compatible provider at\n`http://127.0.0.1:8471/v1`. As the api key, use the **proxy secret**\nthat `serve` / `status` prints (auto-generated at\n`~/.kimi-code/credentials/proxy_secret`, 0600) — without it the proxy\nanswers 401, so other local processes/users can't spend your quota.\n`KIMI_RELAY_NO_AUTH=1` disables the check (single-user boxes only).\nThe proxy injects a fresh membership token per request (refreshes under\na file lock — safe when several ducks on one box share the login; note\nthe fallback cap below is per-box, so ducks sharing a box share the\nbudget).\n\n- Models: `k3` (full), `kimi-for-coding` (budget)\n- k3 emits `reasoning_content` and spends completion budget on it —\n  give it roomy `max_tokens` (512+) or replies can arrive empty.\n\nStreaming (`\"stream\": true`) is passed through as SSE, so chat UIs get\ntoken-by-token output on the membership lane.\n\n**Automatic fallback:** export `OPENROUTER_API_KEY` before `serve` and\nany failed membership call (quota/auth/outage) is retried once on\nOpenRouter's kimi lane (`moonshotai/*`, pay-per-token) — same\ndegradation the hosted lane performs. Fallback is metered: capped at\n`KIMI_RELAY_FALLBACK_DAILY_CAP` calls/day (default 200) so a broken\nmembership can't silently run up a pay-per-token bill; past the cap the\nproxy returns 429. If the client asked for `stream: true`, the fallback\nreply is wrapped as a single SSE chunk + `[DONE]` so streaming clients\nstill get valid SSE. Without the env var, failures return the error so\nyour runtime's own ladder takes over.\n\nFor a proxy that survives reboots, `install-service` writes a systemd\nuser unit (Linux — enable lingering with\n`loginctl enable-linger $USER` so it runs while logged out) or a\nlaunchd agent (macOS). Any `OPENROUTER_API_KEY` / `KIMI_*` env vars set\nwhen you run `install-service` are written to a **separate 0600\n`EnvironmentFile`** (`~/.kimi-code/credentials/relay.env`) that the unit\nreferences — secrets are never inlined into the world-readable systemd\nunit itself — so the fallback survives reboots without leaking the key.\n`status` shows creds, proxy health, and the fallback meter.\n\nEnv overrides: `KIMI_CLIENT_ID` (if Moonshot rotates the public\nclient), `KIMI_AUTH_HOST`, `KIMI_CODING_BASE`,\n`KIMI_RELAY_FALLBACK_DAILY_CAP`.\n\n## Moving credentials between machines\n\nRefresh tokens **rotate on every grant**. That means:\n\n- Creds move **one-way only**. If you copy `~/.kimi-code/credentials/kimi.json`\n  to a second box and let that box run (`token`, `probe`, or `serve`), it\n  will refresh and rotate the shared refresh token — the box you copied\n  *from* will silently strand on the next refresh.\n- Rule: after running the creds on another box, **re-login on the box\n  you want to keep** with `kimi_login.py login`. Never copy `kimi.json`\n  back to the original box.\n- Prefer a local login on every box (`kimi_login.py login`) — that keeps\n  the token in local custody where the trust model expects it. Only if\n  you cannot log in on the remote box, a short-lived access token from\n  `kimi_login.py token` can be used for a brief test: it is valid ~15 min,\n  has no refresh capability, and cannot strand any lineage. Treat it like\n  any secret — do not paste it into logs, chat, or shared terminals, and\n  let it expire rather than storing it.\n- One lineage per runtime. Don't share a single `kimi.json` across two\n  long-running services; give each its own login.\n\n## Data residency\n\nKimi inference is processed by Moonshot AI on infrastructure in China.\nDon't route conversations through this lane if you require Western data\nresidency.\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `scripts/kimi_login.py` | Device sign-in, token refresh, probe, logout |\n\n## Important\n\n- Opt-in add-on; the core `space-duck` skill works without it.\n- Updates arrive via ClawHub with owner consent (Mission Control shows\n  \"update available\") — never force-pushed to your box.\n\nFile v0.9.6:_meta.json\n\n{\n  \"ownerId\": \"kn7cav8v08rpkp9w38xg3d9mp985q1e1\",\n  \"slug\": \"space-duck-kimi-relay\",\n  \"version\": \"0.9.6\",\n  \"publishedAt\": 1789405735895\n}\n\nFile v0.9.6:SECURITY-MANIFEST.md\n\n# space-duck-kimi-relay — Security Manifest (byte-grounded)\n\nVersion: 0.8.4 (aligned with the space-duck family — see MEMORY.md publish log) · Generated 2026-08-11 · Evidence = `scripts/kimi_login.py` line refs.\nRule: every claim below cites file:line. No claim rests on an LLM \"reading\".\n\n## Scope\nPackage is exactly 3 files: `SKILL.md`, `_meta.json`, `scripts/kimi_login.py`.\nNo `lib/`, no `bin/`, no `package.json`, no JS, no dependencies beyond Python stdlib\n(`fcntl, json, os, sys, time, urllib, http.server, secrets, subprocess`).\n\n## Credential custody\n- Store path: `~/.kimi-code/credentials/kimi.json` — `CRED_PATH` (kimi_login.py:41-42).\n- Written 0600 via `os.open(..., 0o600)` in `_save()` (kimi_login.py:73); dir 0700 (kimi_login.py:65).\n- Proxy bearer secret `proxy_secret` written 0600 (kimi_login.py:206).\n- Access token read only from local file in `_load()`/`fresh_token()` (kimi_login.py:80-154).\n\n## Outbound hosts (complete egress allowlist)\nEvery network call is a `urllib.request.urlopen` — there are exactly three call sites:\n- kimi_login.py:55  → `AUTH_HOST` = `https://auth.kimi.com` (OAuth device + token/refresh), :36\n- kimi_login.py:166 → `CODING_BASE` = `https://api.kimi.com/coding/v1` (inference), :40\n- kimi_login.py:353 → `CODING_BASE` (streaming inference)\n- kimi_login.py:333 → `https://openrouter.ai/api/v1` — ONLY when `OPENROUTER_API_KEY` set (:319)\nNo other socket/urlopen/requests calls exist. **Nothing is sent to Spaceduckling.**\n\n## Where the token can leave the process\n- Kimi token injected as `Authorization: Bearer` only to Kimi hosts: kimi_login.py:164, :350.\n- `OPENROUTER_API_KEY` sent only to openrouter.ai: kimi_login.py:333.\n- No logging of token/secret values (log_message prints request lines only, :278-279).\n\n## Proxy exposure\n- Binds localhost only: `ThreadingHTTPServer((\"127.0.0.1\", port), ...)` (kimi_login.py:387). No bind-address override exists.\n- Auth ON by default: bearer check at kimi_login.py:291-296; secret auto-generated (:203-209).\n- `KIMI_RELAY_NO_AUTH=1` is an explicit opt-OUT (:194) and prints a loud warning (:394).\n  Assessed NOT a defect: already localhost-bound + secret-by-default. Disclosure, not a patch.\n\n## Fallback spend\n- Metered, default cap 200/day (`FALLBACK_DAILY_CAP`, :210); returns 429 past cap (:322-324).\n\n## Service install (hardened in 0.5.2)\n- systemd: secrets written to a **separate 0600 EnvironmentFile** `~/.kimi-code/credentials/relay.env` (kimi_login.py:461), referenced via `EnvironmentFile=` (:465). Secrets are NOT inlined into the (world-readable) unit.\n- Deterministic test asserts: secret value absent from unit, `EnvironmentFile=` present, env file 0600. PASS (2026-08-11).\n- macOS launchd: plist written 0600 (:444); values embedded in plist (0600) — documented residual.\n\n## Overridable endpoints (disclosed)\n- `KIMI_AUTH_HOST` (:36), `KIMI_CODING_BASE` (:40), `KIMI_CLIENT_ID` (:38). Changing these re-points token traffic — advanced use, disclosed in frontmatter.\n\n## Not covered by this manifest\n- Runtime behavior of the remote Kimi/OpenRouter endpoints (out of package scope).\n- Signing / GitHub provenance: ClawHub v0.9.0 exposes no signing command — registry-feature gap, not a code defect.\n\nFile v0.9.6:skill-card.md\n\n## Description:\n\nOptional Lane A / BYOB add-on for Space Duck that runs a local RFC 8628 device-code \"Sign in with Kimi\" flow so a self-hosted duck can use the owner's Kimi membership for inference through a localhost OpenAI-compatible proxy.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[askegor](https://clawhub.ai/user/askegor)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and operators of self-hosted Space Duck deployments use this skill to sign in to Kimi locally, refresh Kimi membership tokens, run a localhost inference relay, and optionally configure an OpenRouter fallback.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Endpoint override variables can redirect token or prompt traffic away from the intended Kimi services.\n\nMitigation: Leave KIMI_AUTH_HOST and KIMI_CODING_BASE unset unless the destination is explicitly trusted and reviewed.\n\nRisk: The skill stores Kimi access and refresh credentials locally and can install a persistent local service.\n\nMitigation: Install and run it only on trusted machines, keep credential files private, and review service environment variables before using install-service.\n\nRisk: Prompts routed through the Kimi lane are processed by Moonshot AI infrastructure in China, and the optional fallback routes prompts to OpenRouter.\n\nMitigation: Do not use this relay for workloads that require Western data residency or prohibit those third-party inference providers.\n\nRisk: Optional OpenRouter fallback is pay-per-token and can create spend if membership calls fail.\n\nMitigation: Set OPENROUTER_API_KEY only when fallback is intended and keep KIMI_RELAY_FALLBACK_DAILY_CAP at an acceptable daily limit.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/askegor/skills/space-duck-kimi-relay)\n- [Publisher profile](https://clawhub.ai/user/askegor)\n- [Security Manifest](artifact/SECURITY-MANIFEST.md)\n- [Skill instructions](artifact/SKILL.md)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown with inline shell commands and configuration instructions]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May guide use of a local proxy, local credential files, environment variables, and service installation commands.]\n\n## Skill Version(s):\n\n0.9.6 (source: ClawHub release evidence and artifact/_meta.json)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.9.5: 5 files, 15090 bytes\n\nFiles: _meta.json (140b), scripts/kimi_login.py (24355b), SECURITY-MANIFEST.md (3240b), skill-card.md (3045b), SKILL.md (8055b)\n\nFile v0.9.5:SKILL.md\n\n---\nname: space-duck-kimi-relay\ndescription: Optional Lane A / BYOB add-on for Space Duck — runs a local RFC 8628 device-code \"Sign in with Kimi\" flow (no password; browser-approved) so a self-hosted duck can use the owner's flat-rate Kimi membership for inference. Credentials (access + rotating refresh token) are stored locally at ~/.kimi-code/credentials/kimi.json (0600) and are NEVER sent to Spaceduckling. Contacts only auth.kimi.com and api.kimi.com; inference is processed by Moonshot AI in China (no Western data residency). Optional pay-per-token fallback to openrouter.ai when OPENROUTER_API_KEY is set (daily-capped). Runs a localhost-only proxy (127.0.0.1, default 8471) protected by an auto-generated 0600 bearer secret. Hosted (Lane B) ducks use the Mission Control card instead. Triggers on \"sign in with kimi\", \"kimi membership login\", \"clawhub space-duck kimi\", \"kimi relay login\".\ndisclosures:\n  network:\n    - auth.kimi.com          # OAuth device authorization + token/refresh\n    - api.kimi.com           # membership inference (Moonshot AI, China)\n    - openrouter.ai          # OPTIONAL pay-per-token fallback, only if OPENROUTER_API_KEY set\n  credentials:\n    - Kimi access + refresh token at ~/.kimi-code/credentials/kimi.json (0600, local only)\n    - auto-generated proxy bearer secret at ~/.kimi-code/credentials/proxy_secret (0600)\n    - reads OPENROUTER_API_KEY from env; forwarded only to openrouter.ai on fallback\n  data_residency: \"Kimi inference runs on Moonshot AI infrastructure in China.\"\n  overridable_endpoints:\n    - KIMI_AUTH_HOST, KIMI_CODING_BASE, KIMI_CLIENT_ID   # advanced; changing these re-points token traffic\n  spend: \"Fallback is metered, default cap KIMI_RELAY_FALLBACK_DAILY_CAP=200 calls/day; past cap returns 429.\"\n  auth_bypass: \"KIMI_RELAY_NO_AUTH=1 disables the localhost proxy's bearer check — single-user boxes only.\"\n  privilege: \"install-service writes a systemd-user/launchd unit; captured KIMI_*/OPENROUTER_API_KEY secrets go in a separate 0600 EnvironmentFile (~/.kimi-code/credentials/relay.env), never inlined into the unit.\"\n  sends_to_spaceduckling: none\n---\n\n# Space Duck Kimi Relay (optional add-on, Lane A)\n\nLets a duck that runs on **your own infrastructure** use your **Kimi\nmembership** (flat-rate subscription quota) for inference instead of\npay-per-token API keys.\n\n## Trust model — the whole point\n\n- The device-code sign-in runs **locally on your box**.\n- Tokens are stored at `~/.kimi-code/credentials/kimi.json` (0600), on\n  **your machine only**.\n- The only host this skill contacts is Kimi itself (`auth.kimi.com` and\n  `api.kimi.com`). **Spaceduckling never sees or holds the token.**\n- This is the Lane A mirror of Mission Control's hosted \"Sign in with\n  Kimi\" card: same protocol capability, different custody. (Cross-lane\n  parity doctrine — capability exists in both lanes, credentials follow\n  the lane's trust model.)\n\n## Commands\n\n```\nkimi_login.py login         # interactive device sign-in\nkimi_login.py token         # print fresh access token (auto-refresh, file-locked)\nkimi_login.py probe         # inference smoke on membership quota\nkimi_login.py serve [port]  # local proxy for your runtime (default 8471)\nkimi_login.py install-service [port]   # run proxy as a service (systemd user / launchd)\nkimi_login.py uninstall-service        # remove the service\nkimi_login.py status [port] # creds + proxy + fallback-meter health check\nkimi_login.py logout        # delete local credentials\n```\n\n`login` shows a kimi.com URL + user code; approve it in your browser and\nthe script stores the tokens. `token` transparently refreshes — Kimi\naccess tokens live ~15 minutes and **refresh tokens rotate on every\ngrant**, so always let this script (not ad-hoc curl) do the refreshing;\na stale refresh token is dead after one rotation.\n\n## Wiring the duck's brain — use the proxy\n\nKimi access tokens live ~15 minutes, so a static key in your runtime's\nconfig will not survive. Run the local proxy instead:\n\n```\nkimi_login.py serve            # http://127.0.0.1:8471/v1/chat/completions\n```\n\nPoint your runtime's OpenAI-compatible provider at\n`http://127.0.0.1:8471/v1`. As the api key, use the **proxy secret**\nthat `serve` / `status` prints (auto-generated at\n`~/.kimi-code/credentials/proxy_secret`, 0600) — without it the proxy\nanswers 401, so other local processes/users can't spend your quota.\n`KIMI_RELAY_NO_AUTH=1` disables the check (single-user boxes only).\nThe proxy injects a fresh membership token per request (refreshes under\na file lock — safe when several ducks on one box share the login; note\nthe fallback cap below is per-box, so ducks sharing a box share the\nbudget).\n\n- Models: `k3` (full), `kimi-for-coding` (budget)\n- k3 emits `reasoning_content` and spends completion budget on it —\n  give it roomy `max_tokens` (512+) or replies can arrive empty.\n\nStreaming (`\"stream\": true`) is passed through as SSE, so chat UIs get\ntoken-by-token output on the membership lane.\n\n**Automatic fallback:** export `OPENROUTER_API_KEY` before `serve` and\nany failed membership call (quota/auth/outage) is retried once on\nOpenRouter's kimi lane (`moonshotai/*`, pay-per-token) — same\ndegradation the hosted lane performs. Fallback is metered: capped at\n`KIMI_RELAY_FALLBACK_DAILY_CAP` calls/day (default 200) so a broken\nmembership can't silently run up a pay-per-token bill; past the cap the\nproxy returns 429. If the client asked for `stream: true`, the fallback\nreply is wrapped as a single SSE chunk + `[DONE]` so streaming clients\nstill get valid SSE. Without the env var, failures return the error so\nyour runtime's own ladder takes over.\n\nFor a proxy that survives reboots, `install-service` writes a systemd\nuser unit (Linux — enable lingering with\n`loginctl enable-linger $USER` so it runs while logged out) or a\nlaunchd agent (macOS). Any `OPENROUTER_API_KEY` / `KIMI_*` env vars set\nwhen you run `install-service` are written to a **separate 0600\n`EnvironmentFile`** (`~/.kimi-code/credentials/relay.env`) that the unit\nreferences — secrets are never inlined into the world-readable systemd\nunit itself — so the fallback survives reboots without leaking the key.\n`status` shows creds, proxy health, and the fallback meter.\n\nEnv overrides: `KIMI_CLIENT_ID` (if Moonshot rotates the public\nclient), `KIMI_AUTH_HOST`, `KIMI_CODING_BASE`,\n`KIMI_RELAY_FALLBACK_DAILY_CAP`.\n\n## Moving credentials between machines\n\nRefresh tokens **rotate on every grant**. That means:\n\n- Creds move **one-way only**. If you copy `~/.kimi-code/credentials/kimi.json`\n  to a second box and let that box run (`token`, `probe`, or `serve`), it\n  will refresh and rotate the shared refresh token — the box you copied\n  *from* will silently strand on the next refresh.\n- Rule: after running the creds on another box, **re-login on the box\n  you want to keep** with `kimi_login.py login`. Never copy `kimi.json`\n  back to the original box.\n- Prefer a local login on every box (`kimi_login.py login`) — that keeps\n  the token in local custody where the trust model expects it. Only if\n  you cannot log in on the remote box, a short-lived access token from\n  `kimi_login.py token` can be used for a brief test: it is valid ~15 min,\n  has no refresh capability, and cannot strand any lineage. Treat it like\n  any secret — do not paste it into logs, chat, or shared terminals, and\n  let it expire rather than storing it.\n- One lineage per runtime. Don't share a single `kimi.json` across two\n  long-running services; give each its own login.\n\n## Data residency\n\nKimi inference is processed by Moonshot AI on infrastructure in China.\nDon't route conversations through this lane if you require Western data\nresidency.\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `scripts/kimi_login.py` | Device sign-in, token refresh, probe, logout |\n\n## Important\n\n- Opt-in add-on; the core `space-duck` skill works without it.\n- Updates arrive via ClawHub with owner consent (Mission Control shows\n  \"update available\") — never force-pushed to your box.\n\nFile v0.9.5:_meta.json\n\n{\n  \"ownerId\": \"kn7cav8v08rpkp9w38xg3d9mp985q1e1\",\n  \"slug\": \"space-duck-kimi-relay\",\n  \"version\": \"0.9.5\",\n  \"publishedAt\": 1789405594679\n}\n\nFile v0.9.5:SECURITY-MANIFEST.md\n\n# space-duck-kimi-relay — Security Manifest (byte-grounded)\n\nVersion: 0.8.4 (aligned with the space-duck family — see MEMORY.md publish log) · Generated 2026-08-11 · Evidence = `scripts/kimi_login.py` line refs.\nRule: every claim below cites file:line. No claim rests on an LLM \"reading\".\n\n## Scope\nPackage is exactly 3 files: `SKILL.md`, `_meta.json`, `scripts/kimi_login.py`.\nNo `lib/`, no `bin/`, no `package.json`, no JS, no dependencies beyond Python stdlib\n(`fcntl, json, os, sys, time, urllib, http.server, secrets, subprocess`).\n\n## Credential custody\n- Store path: `~/.kimi-code/credentials/kimi.json` — `CRED_PATH` (kimi_login.py:41-42).\n- Written 0600 via `os.open(..., 0o600)` in `_save()` (kimi_login.py:73); dir 0700 (kimi_login.py:65).\n- Proxy bearer secret `proxy_secret` written 0600 (kimi_login.py:206).\n- Access token read only from local file in `_load()`/`fresh_token()` (kimi_login.py:80-154).\n\n## Outbound hosts (complete egress allowlist)\nEvery network call is a `urllib.request.urlopen` — there are exactly three call sites:\n- kimi_login.py:55  → `AUTH_HOST` = `https://auth.kimi.com` (OAuth device + token/refresh), :36\n- kimi_login.py:166 → `CODING_BASE` = `https://api.kimi.com/coding/v1` (inference), :40\n- kimi_login.py:353 → `CODING_BASE` (streaming inference)\n- kimi_login.py:333 → `https://openrouter.ai/api/v1` — ONLY when `OPENROUTER_API_KEY` set (:319)\nNo other socket/urlopen/requests calls exist. **Nothing is sent to Spaceduckling.**\n\n## Where the token can leave the process\n- Kimi token injected as `Authorization: Bearer` only to Kimi hosts: kimi_login.py:164, :350.\n- `OPENROUTER_API_KEY` sent only to openrouter.ai: kimi_login.py:333.\n- No logging of token/secret values (log_message prints request lines only, :278-279).\n\n## Proxy exposure\n- Binds localhost only: `ThreadingHTTPServer((\"127.0.0.1\", port), ...)` (kimi_login.py:387). No bind-address override exists.\n- Auth ON by default: bearer check at kimi_login.py:291-296; secret auto-generated (:203-209).\n- `KIMI_RELAY_NO_AUTH=1` is an explicit opt-OUT (:194) and prints a loud warning (:394).\n  Assessed NOT a defect: already localhost-bound + secret-by-default. Disclosure, not a patch.\n\n## Fallback spend\n- Metered, default cap 200/day (`FALLBACK_DAILY_CAP`, :210); returns 429 past cap (:322-324).\n\n## Service install (hardened in 0.5.2)\n- systemd: secrets written to a **separate 0600 EnvironmentFile** `~/.kimi-code/credentials/relay.env` (kimi_login.py:461), referenced via `EnvironmentFile=` (:465). Secrets are NOT inlined into the (world-readable) unit.\n- Deterministic test asserts: secret value absent from unit, `EnvironmentFile=` present, env file 0600. PASS (2026-08-11).\n- macOS launchd: plist written 0600 (:444); values embedded in plist (0600) — documented residual.\n\n## Overridable endpoints (disclosed)\n- `KIMI_AUTH_HOST` (:36), `KIMI_CODING_BASE` (:40), `KIMI_CLIENT_ID` (:38). Changing these re-points token traffic — advanced use, disclosed in frontmatter.\n\n## Not covered by this manifest\n- Runtime behavior of the remote Kimi/OpenRouter endpoints (out of package scope).\n- Signing / GitHub provenance: ClawHub v0.9.0 exposes no signing command — registry-feature gap, not a code defect.\n\nFile v0.9.5:skill-card.md\n\n## Description:\n\nSpace Duck Kimi Relay helps self-hosted Space Duck users sign in to Kimi locally, store Kimi tokens on their machine, and run a localhost proxy that forwards inference to Kimi with an optional capped OpenRouter fallback.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[askegor](https://clawhub.ai/user/askegor)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal developers and self-hosted Space Duck operators use this skill to connect a local duck runtime to a personal Kimi membership without handing Kimi tokens to the hosted lane. It also provides local proxy, service, status, logout, and optional OpenRouter fallback commands.\n\n### Deployment Geography for Use:\n\nGlobal, with China-based Kimi inference data residency disclosed.\n\n## Known Risks and Mitigations:\n\nRisk: The skill handles Kimi access and refresh tokens, proxy bearer secrets, and an optional OpenRouter API key.\n\nMitigation: Install only when local token custody is acceptable, keep credential files at 0600 permissions, avoid pasting printed tokens or secrets into logs or shared terminals, and use logout to remove local credentials.\n\nRisk: Prompts and completions sent through the Kimi lane are processed by Moonshot AI infrastructure in China, and fallback requests can be sent to OpenRouter when OPENROUTER_API_KEY is set.\n\nMitigation: Do not use this lane for workloads requiring Western data residency; enable OpenRouter fallback only when that routing and metered spend are acceptable.\n\nRisk: KIMI_RELAY_NO_AUTH=1 disables the localhost proxy bearer check, and the proxy can be installed as a persistent background service.\n\nMitigation: Keep proxy authentication enabled except on tightly controlled single-user machines and review persistent service configuration before enabling autostart.\n\nRisk: The optional OpenRouter daily cap is not a hard financial limit under concurrent load.\n\nMitigation: Treat the cap as a guardrail, monitor OpenRouter usage externally, and set a conservative KIMI_RELAY_FALLBACK_DAILY_CAP.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/askegor/skills/space-duck-kimi-relay)\n- [Kimi authentication endpoint](https://auth.kimi.com)\n- [Kimi coding API endpoint](https://api.kimi.com/coding/v1)\n- [OpenRouter API endpoint](https://openrouter.ai/api/v1)\n\n## Skill Output:\n\n**Output Type(s):** [Guidance, Shell commands, Configuration]\n\n**Output Format:** [Markdown with inline shell commands and configuration values]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May include local file paths, environment variables, localhost proxy URLs, token-handling cautions, and service-management commands.]\n\n## Skill Version(s):\n\n0.9.5 (source: server release metadata and artifact/_meta.json)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.9.4: 5 files, 14964 bytes\n\nFiles: _meta.json (140b), scripts/kimi_login.py (24355b), SECURITY-MANIFEST.md (3240b), skill-card.md (2813b), SKILL.md (8055b)\n\nFile v0.9.4:SKILL.md\n\n---\nname: space-duck-kimi-relay\ndescription: Optional Lane A / BYOB add-on for Space Duck — runs a local RFC 8628 device-code \"Sign in with Kimi\" flow (no password; browser-approved) so a self-hosted duck can use the owner's flat-rate Kimi membership for inference. Credentials (access + rotating refresh token) are stored locally at ~/.kimi-code/credentials/kimi.json (0600) and are NEVER sent to Spaceduckling. Contacts only auth.kimi.com and api.kimi.com; inference is processed by Moonshot AI in China (no Western data residency). Optional pay-per-token fallback to openrouter.ai when OPENROUTER_API_KEY is set (daily-capped). Runs a localhost-only proxy (127.0.0.1, default 8471) protected by an auto-generated 0600 bearer secret. Hosted (Lane B) ducks use the Mission Control card instead. Triggers on \"sign in with kimi\", \"kimi membership login\", \"clawhub space-duck kimi\", \"kimi relay login\".\ndisclosures:\n  network:\n    - auth.kimi.com          # OAuth device authorization + token/refresh\n    - api.kimi.com           # membership inference (Moonshot AI, China)\n    - openrouter.ai          # OPTIONAL pay-per-token fallback, only if OPENROUTER_API_KEY set\n  credentials:\n    - Kimi access + refresh token at ~/.kimi-code/credentials/kimi.json (0600, local only)\n    - auto-generated proxy bearer secret at ~/.kimi-code/credentials/proxy_secret (0600)\n    - reads OPENROUTER_API_KEY from env; forwarded only to openrouter.ai on fallback\n  data_residency: \"Kimi inference runs on Moonshot AI infrastructure in China.\"\n  overridable_endpoints:\n    - KIMI_AUTH_HOST, KIMI_CODING_BASE, KIMI_CLIENT_ID   # advanced; changing these re-points token traffic\n  spend: \"Fallback is metered, default cap KIMI_RELAY_FALLBACK_DAILY_CAP=200 calls/day; past cap returns 429.\"\n  auth_bypass: \"KIMI_RELAY_NO_AUTH=1 disables the localhost proxy's bearer check — single-user boxes only.\"\n  privilege: \"install-service writes a systemd-user/launchd unit; captured KIMI_*/OPENROUTER_API_KEY secrets go in a separate 0600 EnvironmentFile (~/.kimi-code/credentials/relay.env), never inlined into the unit.\"\n  sends_to_spaceduckling: none\n---\n\n# Space Duck Kimi Relay (optional add-on, Lane A)\n\nLets a duck that runs on **your own infrastructure** use your **Kimi\nmembership** (flat-rate subscription quota) for inference instead of\npay-per-token API keys.\n\n## Trust model — the whole point\n\n- The device-code sign-in runs **locally on your box**.\n- Tokens are stored at `~/.kimi-code/credentials/kimi.json` (0600), on\n  **your machine only**.\n- The only host this skill contacts is Kimi itself (`auth.kimi.com` and\n  `api.kimi.com`). **Spaceduckling never sees or holds the token.**\n- This is the Lane A mirror of Mission Control's hosted \"Sign in with\n  Kimi\" card: same protocol capability, different custody. (Cross-lane\n  parity doctrine — capability exists in both lanes, credentials follow\n  the lane's trust model.)\n\n## Commands\n\n```\nkimi_login.py login         # interactive device sign-in\nkimi_login.py token         # print fresh access token (auto-refresh, file-locked)\nkimi_login.py probe         # inference smoke on membership quota\nkimi_login.py serve [port]  # local proxy for your runtime (default 8471)\nkimi_login.py install-service [port]   # run proxy as a service (systemd user / launchd)\nkimi_login.py uninstall-service        # remove the service\nkimi_login.py status [port] # creds + proxy + fallback-meter health check\nkimi_login.py logout        # delete local credentials\n```\n\n`login` shows a kimi.com URL + user code; approve it in your browser and\nthe script stores the tokens. `token` transparently refreshes — Kimi\naccess tokens live ~15 minutes and **refresh tokens rotate on every\ngrant**, so always let this script (not ad-hoc curl) do the refreshing;\na stale refresh token is dead after one rotation.\n\n## Wiring the duck's brain — use the proxy\n\nKimi access tokens live ~15 minutes, so a static key in your runtime's\nconfig will not survive. Run the local proxy instead:\n\n```\nkimi_login.py serve            # http://127.0.0.1:8471/v1/chat/completions\n```\n\nPoint your runtime's OpenAI-compatible provider at\n`http://127.0.0.1:8471/v1`. As the api key, use the **proxy secret**\nthat `serve` / `status` prints (auto-generated at\n`~/.kimi-code/credentials/proxy_secret`, 0600) — without it the proxy\nanswers 401, so other local processes/users can't spend your quota.\n`KIMI_RELAY_NO_AUTH=1` disables the check (single-user boxes only).\nThe proxy injects a fresh membership token per request (refreshes under\na file lock — safe when several ducks on one box share the login; note\nthe fallback cap below is per-box, so ducks sharing a box share the\nbudget).\n\n- Models: `k3` (full), `kimi-for-coding` (budget)\n- k3 emits `reasoning_content` and spends completion budget on it —\n  give it roomy `max_tokens` (512+) or replies can arrive empty.\n\nStreaming (`\"stream\": true`) is passed through as SSE, so chat UIs get\ntoken-by-token output on the membership lane.\n\n**Automatic fallback:** export `OPENROUTER_API_KEY` before `serve` and\nany failed membership call (quota/auth/outage) is retried once on\nOpenRouter's kimi lane (`moonshotai/*`, pay-per-token) — same\ndegradation the hosted lane performs. Fallback is metered: capped at\n`KIMI_RELAY_FALLBACK_DAILY_CAP` calls/day (default 200) so a broken\nmembership can't silently run up a pay-per-token bill; past the cap the\nproxy returns 429. If the client asked for `stream: true`, the fallback\nreply is wrapped as a single SSE chunk + `[DONE]` so streaming clients\nstill get valid SSE. Without the env var, failures return the error so\nyour runtime's own ladder takes over.\n\nFor a proxy that survives reboots, `install-service` writes a systemd\nuser unit (Linux — enable lingering with\n`loginctl enable-linger $USER` so it runs while logged out) or a\nlaunchd agent (macOS). Any `OPENROUTER_API_KEY` / `KIMI_*` env vars set\nwhen you run `install-service` are written to a **separate 0600\n`EnvironmentFile`** (`~/.kimi-code/credentials/relay.env`) that the unit\nreferences — secrets are never inlined into the world-readable systemd\nunit itself — so the fallback survives reboots without leaking the key.\n`status` shows creds, proxy health, and the fallback meter.\n\nEnv overrides: `KIMI_CLIENT_ID` (if Moonshot rotates the public\nclient), `KIMI_AUTH_HOST`, `KIMI_CODING_BASE`,\n`KIMI_RELAY_FALLBACK_DAILY_CAP`.\n\n## Moving credentials between machines\n\nRefresh tokens **rotate on every grant**. That means:\n\n- Creds move **one-way only**. If you copy `~/.kimi-code/credentials/kimi.json`\n  to a second box and let that box run (`token`, `probe`, or `serve`), it\n  will refresh and rotate the shared refresh token — the box you copied\n  *from* will silently strand on the next refresh.\n- Rule: after running the creds on another box, **re-login on the box\n  you want to keep** with `kimi_login.py login`. Never copy `kimi.json`\n  back to the original box.\n- Prefer a local login on every box (`kimi_login.py login`) — that keeps\n  the token in local custody where the trust model expects it. Only if\n  you cannot log in on the remote box, a short-lived access token from\n  `kimi_login.py token` can be used for a brief test: it is valid ~15 min,\n  has no refresh capability, and cannot strand any lineage. Treat it like\n  any secret — do not paste it into logs, chat, or shared terminals, and\n  let it expire rather than storing it.\n- One lineage per runtime. Don't share a single `kimi.json` across two\n  long-running services; give each its own login.\n\n## Data residency\n\nKimi inference is processed by Moonshot AI on infrastructure in China.\nDon't route conversations through this lane if you require Western data\nresidency.\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `scripts/kimi_login.py` | Device sign-in, token refresh, probe, logout |\n\n## Important\n\n- Opt-in add-on; the core `space-duck` skill works without it.\n- Updates arrive via ClawHub with owner consent (Mission Control shows\n  \"update available\") — never force-pushed to your box.\n\nFile v0.9.4:_meta.json\n\n{\n  \"ownerId\": \"kn7cav8v08rpkp9w38xg3d9mp985q1e1\",\n  \"slug\": \"space-duck-kimi-relay\",\n  \"version\": \"0.9.4\",\n  \"publishedAt\": 1789400396727\n}\n\nFile v0.9.4:SECURITY-MANIFEST.md\n\n# space-duck-kimi-relay — Security Manifest (byte-grounded)\n\nVersion: 0.8.4 (aligned with the space-duck family — see MEMORY.md publish log) · Generated 2026-08-11 · Evidence = `scripts/kimi_login.py` line refs.\nRule: every claim below cites file:line. No claim rests on an LLM \"reading\".\n\n## Scope\nPackage is exactly 3 files: `SKILL.md`, `_meta.json`, `scripts/kimi_login.py`.\nNo `lib/`, no `bin/`, no `package.json`, no JS, no dependencies beyond Python stdlib\n(`fcntl, json, os, sys, time, urllib, http.server, secrets, subprocess`).\n\n## Credential custody\n- Store path: `~/.kimi-code/credentials/kimi.json` — `CRED_PATH` (kimi_login.py:41-42).\n- Written 0600 via `os.open(..., 0o600)` in `_save()` (kimi_login.py:73); dir 0700 (kimi_login.py:65).\n- Proxy bearer secret `proxy_secret` written 0600 (kimi_login.py:206).\n- Access token read only from local file in `_load()`/`fresh_token()` (kimi_login.py:80-154).\n\n## Outbound hosts (complete egress allowlist)\nEvery network call is a `urllib.request.urlopen` — there are exactly three call sites:\n- kimi_login.py:55  → `AUTH_HOST` = `https://auth.kimi.com` (OAuth device + token/refresh), :36\n- kimi_login.py:166 → `CODING_BASE` = `https://api.kimi.com/coding/v1` (inference), :40\n- kimi_login.py:353 → `CODING_BASE` (streaming inference)\n- kimi_login.py:333 → `https://openrouter.ai/api/v1` — ONLY when `OPENROUTER_API_KEY` set (:319)\nNo other socket/urlopen/requests calls exist. **Nothing is sent to Spaceduckling.**\n\n## Where the token can leave the process\n- Kimi token injected as `Authorization: Bearer` only to Kimi hosts: kimi_login.py:164, :350.\n- `OPENROUTER_API_KEY` sent only to openrouter.ai: kimi_login.py:333.\n- No logging of token/secret values (log_message prints request lines only, :278-279).\n\n## Proxy exposure\n- Binds localhost only: `ThreadingHTTPServer((\"127.0.0.1\", port), ...)` (kimi_login.py:387). No bind-address override exists.\n- Auth ON by default: bearer check at kimi_login.py:291-296; secret auto-generated (:203-209).\n- `KIMI_RELAY_NO_AUTH=1` is an explicit opt-OUT (:194) and prints a loud warning (:394).\n  Assessed NOT a defect: already localhost-bound + secret-by-default. Disclosure, not a patch.\n\n## Fallback spend\n- Metered, default cap 200/day (`FALLBACK_DAILY_CAP`, :210); returns 429 past cap (:322-324).\n\n## Service install (hardened in 0.5.2)\n- systemd: secrets written to a **separate 0600 EnvironmentFile** `~/.kimi-code/credentials/relay.env` (kimi_login.py:461), referenced via `EnvironmentFile=` (:465). Secrets are NOT inlined into the (world-readable) unit.\n- Deterministic test asserts: secret value absent from unit, `EnvironmentFile=` present, env file 0600. PASS (2026-08-11).\n- macOS launchd: plist written 0600 (:444); values embedded in plist (0600) — documented residual.\n\n## Overridable endpoints (disclosed)\n- `KIMI_AUTH_HOST` (:36), `KIMI_CODING_BASE` (:40), `KIMI_CLIENT_ID` (:38). Changing these re-points token traffic — advanced use, disclosed in frontmatter.\n\n## Not covered by this manifest\n- Runtime behavior of the remote Kimi/OpenRouter endpoints (out of package scope).\n- Signing / GitHub provenance: ClawHub v0.9.0 exposes no signing command — registry-feature gap, not a code defect.\n\nFile v0.9.4:skill-card.md\n\n## Description:\n\nspace-duck-kimi-relay helps a self-hosted Space Duck use a local Kimi membership by guiding device-code sign-in, token refresh, and a localhost OpenAI-compatible proxy with optional OpenRouter fallback.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[askegor](https://clawhub.ai/user/askegor)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and operators use this skill when running Space Duck on their own infrastructure and want inference routed through their local Kimi membership instead of a static API key. It is intended for users who accept local credential custody, Kimi service dependency, and the documented data-residency and fallback-spend constraints.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill brokers Kimi account tokens and local proxy secrets.\n\nMitigation: Install it only on machines that should broker the Kimi account, and treat printed tokens and proxy secrets as credentials.\n\nRisk: Environment overrides can redirect token or inference traffic.\n\nMitigation: Set KIMI_AUTH_HOST or KIMI_CODING_BASE only when the destination is fully trusted.\n\nRisk: Disabling local proxy authentication can expose Kimi quota to other local processes or users.\n\nMitigation: Avoid KIMI_RELAY_NO_AUTH except on a tightly controlled single-user host.\n\nRisk: The optional OpenRouter fallback can incur metered usage and its daily cap may not be a hard financial limit under concurrent traffic.\n\nMitigation: Enable fallback intentionally, monitor usage, and do not rely on the cap as the only spend control.\n\nRisk: Kimi inference is processed by Moonshot AI infrastructure in China.\n\nMitigation: Do not route workloads through this lane when Western data residency is required.\n\nRisk: Service installation creates a persistent local proxy.\n\nMitigation: Review service files and stored environment values before relying on install-service.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/askegor/skills/space-duck-kimi-relay)\n- [ClawHub publisher profile](https://clawhub.ai/user/askegor)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Code, Shell commands, Configuration, Guidance]\n\n**Output Format:** [Markdown with inline shell commands and configuration guidance]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Guidance may cover local credential handling, proxy configuration, service installation, and optional fallback setup.]\n\n## Skill Version(s):\n\n0.9.4 (source: server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.9.3: 5 files, 15109 bytes\n\nFiles: _meta.json (140b), scripts/kimi_login.py (24355b), SECURITY-MANIFEST.md (3240b), skill-card.md (3152b), SKILL.md (8055b)\n\nFile v0.9.3:SKILL.md\n\n---\nname: space-duck-kimi-relay\ndescription: Optional Lane A / BYOB add-on for Space Duck — runs a local RFC 8628 device-code \"Sign in with Kimi\" flow (no password; browser-approved) so a self-hosted duck can use the owner's flat-rate Kimi membership for inference. Credentials (access + rotating refresh token) are stored locally at ~/.kimi-code/credentials/kimi.json (0600) and are NEVER sent to Spaceduckling. Contacts only auth.kimi.com and api.kimi.com; inference is processed by Moonshot AI in China (no Western data residency). Optional pay-per-token fallback to openrouter.ai when OPENROUTER_API_KEY is set (daily-capped). Runs a localhost-only proxy (127.0.0.1, default 8471) protected by an auto-generated 0600 bearer secret. Hosted (Lane B) ducks use the Mission Control card instead. Triggers on \"sign in with kimi\", \"kimi membership login\", \"clawhub space-duck kimi\", \"kimi relay login\".\ndisclosures:\n  network:\n    - auth.kimi.com          # OAuth device authorization + token/refresh\n    - api.kimi.com           # membership inference (Moonshot AI, China)\n    - openrouter.ai          # OPTIONAL pay-per-token fallback, only if OPENROUTER_API_KEY set\n  credentials:\n    - Kimi access + refresh token at ~/.kimi-code/credentials/kimi.json (0600, local only)\n    - auto-generated proxy bearer secret at ~/.kimi-code/credentials/proxy_secret (0600)\n    - reads OPENROUTER_API_KEY from env; forwarded only to openrouter.ai on fallback\n  data_residency: \"Kimi inference runs on Moonshot AI infrastructure in China.\"\n  overridable_endpoints:\n    - KIMI_AUTH_HOST, KIMI_CODING_BASE, KIMI_CLIENT_ID   # advanced; changing these re-points token traffic\n  spend: \"Fallback is metered, default cap KIMI_RELAY_FALLBACK_DAILY_CAP=200 calls/day; past cap returns 429.\"\n  auth_bypass: \"KIMI_RELAY_NO_AUTH=1 disables the localhost proxy's bearer check — single-user boxes only.\"\n  privilege: \"install-service writes a systemd-user/launchd unit; captured KIMI_*/OPENROUTER_API_KEY secrets go in a separate 0600 EnvironmentFile (~/.kimi-code/credentials/relay.env), never inlined into the unit.\"\n  sends_to_spaceduckling: none\n---\n\n# Space Duck Kimi Relay (optional add-on, Lane A)\n\nLets a duck that runs on **your own infrastructure** use your **Kimi\nmembership** (flat-rate subscription quota) for inference instead of\npay-per-token API keys.\n\n## Trust model — the whole point\n\n- The device-code sign-in runs **locally on your box**.\n- Tokens are stored at `~/.kimi-code/credentials/kimi.json` (0600), on\n  **your machine only**.\n- The only host this skill contacts is Kimi itself (`auth.kimi.com` and\n  `api.kimi.com`). **Spaceduckling never sees or holds the token.**\n- This is the Lane A mirror of Mission Control's hosted \"Sign in with\n  Kimi\" card: same protocol capability, different custody. (Cross-lane\n  parity doctrine — capability exists in both lanes, credentials follow\n  the lane's trust model.)\n\n## Commands\n\n```\nkimi_login.py login         # interactive device sign-in\nkimi_login.py token         # print fresh access token (auto-refresh, file-locked)\nkimi_login.py probe         # inference smoke on membership quota\nkimi_login.py serve [port]  # local proxy for your runtime (default 8471)\nkimi_login.py install-service [port]   # run proxy as a service (systemd user / launchd)\nkimi_login.py uninstall-service        # remove the service\nkimi_login.py status [port] # creds + proxy + fallback-meter health check\nkimi_login.py logout        # delete local credentials\n```\n\n`login` shows a kimi.com URL + user code; approve it in your browser and\nthe script stores the tokens. `token` transparently refreshes — Kimi\naccess tokens live ~15 minutes and **refresh tokens rotate on every\ngrant**, so always let this script (not ad-hoc curl) do the refreshing;\na stale refresh token is dead after one rotation.\n\n## Wiring the duck's brain — use the proxy\n\nKimi access tokens live ~15 minutes, so a static key in your runtime's\nconfig will not survive. Run the local proxy instead:\n\n```\nkimi_login.py serve            # http://127.0.0.1:8471/v1/chat/completions\n```\n\nPoint your runtime's OpenAI-compatible provider at\n`http://127.0.0.1:8471/v1`. As the api key, use the **proxy secret**\nthat `serve` / `status` prints (auto-generated at\n`~/.kimi-code/credentials/proxy_secret`, 0600) — without it the proxy\nanswers 401, so other local processes/users can't spend your quota.\n`KIMI_RELAY_NO_AUTH=1` disables the check (single-user boxes only).\nThe proxy injects a fresh membership token per request (refreshes under\na file lock — safe when several ducks on one box share the login; note\nthe fallback cap below is per-box, so ducks sharing a box share the\nbudget).\n\n- Models: `k3` (full), `kimi-for-coding` (budget)\n- k3 emits `reasoning_content` and spends completion budget on it —\n  give it roomy `max_tokens` (512+) or replies can arrive empty.\n\nStreaming (`\"stream\": true`) is passed through as SSE, so chat UIs get\ntoken-by-token output on the membership lane.\n\n**Automatic fallback:** export `OPENROUTER_API_KEY` before `serve` and\nany failed membership call (quota/auth/outage) is retried once on\nOpenRouter's kimi lane (`moonshotai/*`, pay-per-token) — same\ndegradation the hosted lane performs. Fallback is metered: capped at\n`KIMI_RELAY_FALLBACK_DAILY_CAP` calls/day (default 200) so a broken\nmembership can't silently run up a pay-per-token bill; past the cap the\nproxy returns 429. If the client asked for `stream: true`, the fallback\nreply is wrapped as a single SSE chunk + `[DONE]` so streaming clients\nstill get valid SSE. Without the env var, failures return the error so\nyour runtime's own ladder takes over.\n\nFor a proxy that survives reboots, `install-service` writes a systemd\nuser unit (Linux — enable lingering with\n`loginctl enable-linger $USER` so it runs while logged out) or a\nlaunchd agent (macOS). Any `OPENROUTER_API_KEY` / `KIMI_*` env vars set\nwhen you run `install-service` are written to a **separate 0600\n`EnvironmentFile`** (`~/.kimi-code/credentials/relay.env`) that the unit\nreferences — secrets are never inlined into the world-readable systemd\nunit itself — so the fallback survives reboots without leaking the key.\n`status` shows creds, proxy health, and the fallback meter.\n\nEnv overrides: `KIMI_CLIENT_ID` (if Moonshot rotates the public\nclient), `KIMI_AUTH_HOST`, `KIMI_CODING_BASE`,\n`KIMI_RELAY_FALLBACK_DAILY_CAP`.\n\n## Moving credentials between machines\n\nRefresh tokens **rotate on every grant**. That means:\n\n- Creds move **one-way only**. If you copy `~/.kimi-code/credentials/kimi.json`\n  to a second box and let that box run (`token`, `probe`, or `serve`), it\n  will refresh and rotate the shared refresh token — the box you copied\n  *from* will silently strand on the next refresh.\n- Rule: after running the creds on another box, **re-login on the box\n  you want to keep** with `kimi_login.py login`. Never copy `kimi.json`\n  back to the original box.\n- Prefer a local login on every box (`kimi_login.py login`) — that keeps\n  the token in local custody where the trust model expects it. Only if\n  you cannot log in on the remote box, a short-lived access token from\n  `kimi_login.py token` can be used for a brief test: it is valid ~15 min,\n  has no refresh capability, and cannot strand any lineage. Treat it like\n  any secret — do not paste it into logs, chat, or shared terminals, and\n  let it expire rather than storing it.\n- One lineage per runtime. Don't share a single `kimi.json` across two\n  long-running services; give each its own login.\n\n## Data residency\n\nKimi inference is processed by Moonshot AI on infrastructure in China.\nDon't route conversations through this lane if you require Western data\nresidency.\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `scripts/kimi_login.py` | Device sign-in, token refresh, probe, logout |\n\n## Important\n\n- Opt-in add-on; the core `space-duck` skill works without it.\n- Updates arrive via ClawHub with owner consent (Mission Control shows\n  \"update available\") — never force-pushed to your box.\n\nFile v0.9.3:_meta.json\n\n{\n  \"ownerId\": \"kn7cav8v08rpkp9w38xg3d9mp985q1e1\",\n  \"slug\": \"space-duck-kimi-relay\",\n  \"version\": \"0.9.3\",\n  \"publishedAt\": 1789388299722\n}\n\nFile v0.9.3:SECURITY-MANIFEST.md\n\n# space-duck-kimi-relay — Security Manifest (byte-grounded)\n\nVersion: 0.8.4 (aligned with the space-duck family — see MEMORY.md publish log) · Generated 2026-08-11 · Evidence = `scripts/kimi_login.py` line refs.\nRule: every claim below cites file:line. No claim rests on an LLM \"reading\".\n\n## Scope\nPackage is exactly 3 files: `SKILL.md`, `_meta.json`, `scripts/kimi_login.py`.\nNo `lib/`, no `bin/`, no `package.json`, no JS, no dependencies beyond Python stdlib\n(`fcntl, json, os, sys, time, urllib, http.server, secrets, subprocess`).\n\n## Credential custody\n- Store path: `~/.kimi-code/credentials/kimi.json` — `CRED_PATH` (kimi_login.py:41-42).\n- Written 0600 via `os.open(..., 0o600)` in `_save()` (kimi_login.py:73); dir 0700 (kimi_login.py:65).\n- Proxy bearer secret `proxy_secret` written 0600 (kimi_login.py:206).\n- Access token read only from local file in `_load()`/`fresh_token()` (kimi_login.py:80-154).\n\n## Outbound hosts (complete egress allowlist)\nEvery network call is a `urllib.request.urlopen` — there are exactly three call sites:\n- kimi_login.py:55  → `AUTH_HOST` = `https://auth.kimi.com` (OAuth device + token/refresh), :36\n- kimi_login.py:166 → `CODING_BASE` = `https://api.kimi.com/coding/v1` (inference), :40\n- kimi_login.py:353 → `CODING_BASE` (streaming inference)\n- kimi_login.py:333 → `https://openrouter.ai/api/v1` — ONLY when `OPENROUTER_API_KEY` set (:319)\nNo other socket/urlopen/requests calls exist. **Nothing is sent to Spaceduckling.**\n\n## Where the token can leave the process\n- Kimi token injected as `Authorization: Bearer` only to Kimi hosts: kimi_login.py:164, :350.\n- `OPENROUTER_API_KEY` sent only to openrouter.ai: kimi_login.py:333.\n- No logging of token/secret values (log_message prints request lines only, :278-279).\n\n## Proxy exposure\n- Binds localhost only: `ThreadingHTTPServer((\"127.0.0.1\", port), ...)` (kimi_login.py:387). No bind-address override exists.\n- Auth ON by default: bearer check at kimi_login.py:291-296; secret auto-generated (:203-209).\n- `KIMI_RELAY_NO_AUTH=1` is an explicit opt-OUT (:194) and prints a loud warning (:394).\n  Assessed NOT a defect: already localhost-bound + secret-by-default. Disclosure, not a patch.\n\n## Fallback spend\n- Metered, default cap 200/day (`FALLBACK_DAILY_CAP`, :210); returns 429 past cap (:322-324).\n\n## Service install (hardened in 0.5.2)\n- systemd: secrets written to a **separate 0600 EnvironmentFile** `~/.kimi-code/credentials/relay.env` (kimi_login.py:461), referenced via `EnvironmentFile=` (:465). Secrets are NOT inlined into the (world-readable) unit.\n- Deterministic test asserts: secret value absent from unit, `EnvironmentFile=` present, env file 0600. PASS (2026-08-11).\n- macOS launchd: plist written 0600 (:444); values embedded in plist (0600) — documented residual.\n\n## Overridable endpoints (disclosed)\n- `KIMI_AUTH_HOST` (:36), `KIMI_CODING_BASE` (:40), `KIMI_CLIENT_ID` (:38). Changing these re-points token traffic — advanced use, disclosed in frontmatter.\n\n## Not covered by this manifest\n- Runtime behavior of the remote Kimi/OpenRouter endpoints (out of package scope).\n- Signing / GitHub provenance: ClawHub v0.9.0 exposes no signing command — registry-feature gap, not a code defect.\n\nFile v0.9.3:skill-card.md\n\n## Description:\n\nOptional Lane A / BYOB add-on for Space Duck that runs a local RFC 8628 device-code sign-in flow for Kimi, stores Kimi credentials locally, and exposes a localhost OpenAI-compatible proxy with optional OpenRouter fallback.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[askegor](https://clawhub.ai/user/askegor)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and operators use this skill when running Space Duck on their own infrastructure and want a local Kimi membership relay instead of static pay-per-token API keys. It helps configure login, token refresh, proxy service management, health checks, and optional capped fallback behavior.\n\n### Deployment Geography for Use:\n\nGlobal; Kimi inference is processed on Moonshot AI infrastructure in China, so users with Western data residency requirements should avoid this lane.\n\n## Known Risks and Mitigations:\n\nRisk: Environment overrides can redirect authentication, token refresh, prompts, and persistent service configuration away from the intended Kimi endpoints.\n\nMitigation: Before login, serve, or install-service, confirm KIMI_AUTH_HOST and KIMI_CODING_BASE are unset or set only to the intended Kimi HTTPS endpoints.\n\nRisk: The local machine holds and refreshes Kimi access and refresh credentials for the relay.\n\nMitigation: Install and run the relay only on machines where persistent local credential custody is acceptable; avoid printing tokens except for brief manual tests and never paste them into logs, chats, or shared terminals.\n\nRisk: Optional OpenRouter fallback can create pay-per-token spend if OPENROUTER_API_KEY is configured.\n\nMitigation: Use the documented daily cap and monitor fallback status; leave OPENROUTER_API_KEY unset if paid fallback is not intended.\n\nRisk: Disabling proxy bearer authentication allows any local process to spend the user's Kimi quota through the localhost proxy.\n\nMitigation: Keep proxy authentication enabled by default and use KIMI_RELAY_NO_AUTH=1 only on single-user machines where that local exposure is acceptable.\n\nRisk: Kimi inference is processed on Moonshot AI infrastructure in China.\n\nMitigation: Do not route conversations through this lane when Western data residency or other incompatible residency controls are required.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/askegor/skills/space-duck-kimi-relay)\n- [Publisher profile](https://clawhub.ai/user/askegor)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown guidance with inline shell commands and configuration values]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Guides local credential setup, localhost proxy use, service installation, status checks, and fallback limits.]\n\n## Skill Version(s):\n\n0.9.3 (source: server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.9.2: 5 files, 14998 bytes\n\nFiles: _meta.json (140b), scripts/kimi_login.py (24355b), SECURITY-MANIFEST.md (3240b), skill-card.md (2762b), SKILL.md (8055b)\n\nFile v0.9.2:SKILL.md\n\n---\nname: space-duck-kimi-relay\ndescription: Optional Lane A / BYOB add-on for Space Duck — runs a local RFC 8628 device-code \"Sign in with Kimi\" flow (no password; browser-approved) so a self-hosted duck can use the owner's flat-rate Kimi membership for inference. Credentials (access + rotating refresh token) are stored locally at ~/.kimi-code/credentials/kimi.json (0600) and are NEVER sent to Spaceduckling. Contacts only auth.kimi.com and api.kimi.com; inference is processed by Moonshot AI in China (no Western data residency). Optional pay-per-token fallback to openrouter.ai when OPENROUTER_API_KEY is set (daily-capped). Runs a localhost-only proxy (127.0.0.1, default 8471) protected by an auto-generated 0600 bearer secret. Hosted (Lane B) ducks use the Mission Control card instead. Triggers on \"sign in with kimi\", \"kimi membership login\", \"clawhub space-duck kimi\", \"kimi relay login\".\ndisclosures:\n  network:\n    - auth.kimi.com          # OAuth device authorization + token/refresh\n    - api.kimi.com           # membership inference (Moonshot AI, China)\n    - openrouter.ai          # OPTIONAL pay-per-token fallback, only if OPENROUTER_API_KEY set\n  credentials:\n    - Kimi access + refresh token at ~/.kimi-code/credentials/kimi.json (0600, local only)\n    - auto-generated proxy bearer secret at ~/.kimi-code/credentials/proxy_secret (0600)\n    - reads OPENROUTER_API_KEY from env; forwarded only to openrouter.ai on fallback\n  data_residency: \"Kimi inference runs on Moonshot AI infrastructure in China.\"\n  overridable_endpoints:\n    - KIMI_AUTH_HOST, KIMI_CODING_BASE, KIMI_CLIENT_ID   # advanced; changing these re-points token traffic\n  spend: \"Fallback is metered, default cap KIMI_RELAY_FALLBACK_DAILY_CAP=200 calls/day; past cap returns 429.\"\n  auth_bypass: \"KIMI_RELAY_NO_AUTH=1 disables the localhost proxy's bearer check — single-user boxes only.\"\n  privilege: \"install-service writes a systemd-user/launchd unit; captured KIMI_*/OPENROUTER_API_KEY secrets go in a separate 0600 EnvironmentFile (~/.kimi-code/credentials/relay.env), never inlined into the unit.\"\n  sends_to_spaceduckling: none\n---\n\n# Space Duck Kimi Relay (optional add-on, Lane A)\n\nLets a duck that runs on **your own infrastructure** use your **Kimi\nmembership** (flat-rate subscription quota) for inference instead of\npay-per-token API keys.\n\n## Trust model — the whole point\n\n- The device-code sign-in runs **locally on your box**.\n- Tokens are stored at `~/.kimi-code/credentials/kimi.json` (0600), on\n  **your machine only**.\n- The only host this skill contacts is Kimi itself (`auth.kimi.com` and\n  `api.kimi.com`). **Spaceduckling never sees or holds the token.**\n- This is the Lane A mirror of Mission Control's hosted \"Sign in with\n  Kimi\" card: same protocol capability, different custody. (Cross-lane\n  parity doctrine — capability exists in both lanes, credentials follow\n  the lane's trust model.)\n\n## Commands\n\n```\nkimi_login.py login         # interactive device sign-in\nkimi_login.py token         # print fresh access token (auto-refresh, file-locked)\nkimi_login.py probe         # inference smoke on membership quota\nkimi_login.py serve [port]  # local proxy for your runtime (default 8471)\nkimi_login.py install-service [port]   # run proxy as a service (systemd user / launchd)\nkimi_login.py uninstall-service        # remove the service\nkimi_login.py status [port] # creds + proxy + fallback-meter health check\nkimi_login.py logout        # delete local credentials\n```\n\n`login` shows a kimi.com URL + user code; approve it in your browser and\nthe script stores the tokens. `token` transparently refreshes — Kimi\naccess tokens live ~15 minutes and **refresh tokens rotate on every\ngrant**, so always let this script (not ad-hoc curl) do the refreshing;\na stale refresh token is dead after one rotation.\n\n## Wiring the duck's brain — use the proxy\n\nKimi access tokens live ~15 minutes, so a static key in your runtime's\nconfig will not survive. Run the local proxy instead:\n\n```\nkimi_login.py serve            # http://127.0.0.1:8471/v1/chat/completions\n```\n\nPoint your runtime's OpenAI-compatible provider at\n`http://127.0.0.1:8471/v1`. As the api key, use the **proxy secret**\nthat `serve` / `status` prints (auto-generated at\n`~/.kimi-code/credentials/proxy_secret`, 0600) — without it the proxy\nanswers 401, so other local processes/users can't spend your quota.\n`KIMI_RELAY_NO_AUTH=1` disables the check (single-user boxes only).\nThe proxy injects a fresh membership token per request (refreshes under\na file lock — safe when several ducks on one box share the login; note\nthe fallback cap below is per-box, so ducks sharing a box share the\nbudget).\n\n- Models: `k3` (full), `kimi-for-coding` (budget)\n- k3 emits `reasoning_content` and spends completion budget on it —\n  give it roomy `max_tokens` (512+) or replies can arrive empty.\n\nStreaming (`\"stream\": true`) is passed through as SSE, so chat UIs get\ntoken-by-token output on the membership lane.\n\n**Automatic fallback:** export `OPENROUTER_API_KEY` before `serve` and\nany failed membership call (quota/auth/outage) is retried once on\nOpenRouter's kimi lane (`moonshotai/*`, pay-per-token) — same\ndegradation the hosted lane performs. Fallback is metered: capped at\n`KIMI_RELAY_FALLBACK_DAILY_CAP` calls/day (default 200) so a broken\nmembership can't silently run up a pay-per-token bill; past the cap the\nproxy returns 429. If the client asked for `stream: true`, the fallback\nreply is wrapped as a single SSE chunk + `[DONE]` so streaming clients\nstill get valid SSE. Without the env var, failures return the error so\nyour runtime's own ladder takes over.\n\nFor a proxy that survives reboots, `install-service` writes a systemd\nuser unit (Linux — enable lingering with\n`loginctl enable-linger $USER` so it runs while logged out) or a\nlaunchd agent (macOS). Any `OPENROUTER_API_KEY` / `KIMI_*` env vars set\nwhen you run `install-service` are written to a **separate 0600\n`EnvironmentFile`** (`~/.kimi-code/credentials/relay.env`) that the unit\nreferences — secrets are never inlined into the world-readable systemd\nunit itself — so the fallback survives reboots without leaking the key.\n`status` shows creds, proxy health, and the fallback meter.\n\nEnv overrides: `KIMI_CLIENT_ID` (if Moonshot rotates the public\nclient), `KIMI_AUTH_HOST`, `KIMI_CODING_BASE`,\n`KIMI_RELAY_FALLBACK_DAILY_CAP`.\n\n## Moving credentials between machines\n\nRefresh tokens **rotate on every grant**. That means:\n\n- Creds move **one-way only**. If you copy `~/.kimi-code/credentials/kimi.json`\n  to a second box and let that box run (`token`, `probe`, or `serve`), it\n  will refresh and rotate the shared refresh token — the box you copied\n  *from* will silently strand on the next refresh.\n- Rule: after running the creds on another box, **re-login on the box\n  you want to keep** with `kimi_login.py login`. Never copy `kimi.json`\n  back to the original box.\n- Prefer a local login on every box (`kimi_login.py login`) — that keeps\n  the token in local custody where the trust model expects it. Only if\n  you cannot log in on the remote box, a short-lived access token from\n  `kimi_login.py token` can be used for a brief test: it is valid ~15 min,\n  has no refresh capability, and cannot strand any lineage. Treat it like\n  any secret — do not paste it into logs, chat, or shared terminals, and\n  let it expire rather than storing it.\n- One lineage per runtime. Don't share a single `kimi.json` across two\n  long-running services; give each its own login.\n\n## Data residency\n\nKimi inference is processed by Moonshot AI on infrastructure in China.\nDon't route conversations through this lane if you require Western data\nresidency.\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `scripts/kimi_login.py` | Device sign-in, token refresh, probe, logout |\n\n## Important\n\n- Opt-in add-on; the core `space-duck` skill works without it.\n- Updates arrive via ClawHub with owner consent (Mission Control shows\n  \"update available\") — never force-pushed to your box.\n\nFile v0.9.2:_meta.json\n\n{\n  \"ownerId\": \"kn7cav8v08rpkp9w38xg3d9mp985q1e1\",\n  \"slug\": \"space-duck-kimi-relay\",\n  \"version\": \"0.9.2\",\n  \"publishedAt\": 1789373505583\n}\n\nFile v0.9.2:SECURITY-MANIFEST.md\n\n# space-duck-kimi-relay — Security Manifest (byte-grounded)\n\nVersion: 0.8.4 (aligned with the space-duck family — see MEMORY.md publish log) · Generated 2026-08-11 · Evidence = `scripts/kimi_login.py` line refs.\nRule: every claim below cites file:line. No claim rests on an LLM \"reading\".\n\n## Scope\nPackage is exactly 3 files: `SKILL.md`, `_meta.json`, `scripts/kimi_login.py`.\nNo `lib/`, no `bin/`, no `package.json`, no JS, no dependencies beyond Python stdlib\n(`fcntl, json, os, sys, time, urllib, http.server, secrets, subprocess`).\n\n## Credential custody\n- Store path: `~/.kimi-code/credentials/kimi.json` — `CRED_PATH` (kimi_login.py:41-42).\n- Written 0600 via `os.open(..., 0o600)` in `_save()` (kimi_login.py:73); dir 0700 (kimi_login.py:65).\n- Proxy bearer secret `proxy_secret` written 0600 (kimi_login.py:206).\n- Access token read only from local file in `_load()`/`fresh_token()` (kimi_login.py:80-154).\n\n## Outbound hosts (complete egress allowlist)\nEvery network call is a `urllib.request.urlopen` — there are exactly three call sites:\n- kimi_login.py:55  → `AUTH_HOST` = `https://auth.kimi.com` (OAuth device + token/refresh), :36\n- kimi_login.py:166 → `CODING_BASE` = `https://api.kimi.com/coding/v1` (inference), :40\n- kimi_login.py:353 → `CODING_BASE` (streaming inference)\n- kimi_login.py:333 → `https://openrouter.ai/api/v1` — ONLY when `OPENROUTER_API_KEY` set (:319)\nNo other socket/urlopen/requests calls exist. **Nothing is sent to Spaceduckling.**\n\n## Where the token can leave the process\n- Kimi token injected as `Authorization: Bearer` only to Kimi hosts: kimi_login.py:164, :350.\n- `OPENROUTER_API_KEY` sent only to openrouter.ai: kimi_login.py:333.\n- No logging of token/secret values (log_message prints request lines only, :278-279).\n\n## Proxy exposure\n- Binds localhost only: `ThreadingHTTPServer((\"127.0.0.1\", port), ...)` (kimi_login.py:387). No bind-address override exists.\n- Auth ON by default: bearer check at kimi_login.py:291-296; secret auto-generated (:203-209).\n- `KIMI_RELAY_NO_AUTH=1` is an explicit opt-OUT (:194) and prints a loud warning (:394).\n  Assessed NOT a defect: already localhost-bound + secret-by-default. Disclosure, not a patch.\n\n## Fallback spend\n- Metered, default cap 200/day (`FALLBACK_DAILY_CAP`, :210); returns 429 past cap (:322-324).\n\n## Service install (hardened in 0.5.2)\n- systemd: secrets written to a **separate 0600 EnvironmentFile** `~/.kimi-code/credentials/relay.env` (kimi_login.py:461), referenced via `EnvironmentFile=` (:465). Secrets are NOT inlined into the (world-readable) unit.\n- Deterministic test asserts: secret value absent from unit, `EnvironmentFile=` present, env file 0600. PASS (2026-08-11).\n- macOS launchd: plist written 0600 (:444); values embedded in plist (0600) — documented residual.\n\n## Overridable endpoints (disclosed)\n- `KIMI_AUTH_HOST` (:36), `KIMI_CODING_BASE` (:40), `KIMI_CLIENT_ID` (:38). Changing these re-points token traffic — advanced use, disclosed in frontmatter.\n\n## Not covered by this manifest\n- Runtime behavior of the remote Kimi/OpenRouter endpoints (out of package scope).\n- Signing / GitHub provenance: ClawHub v0.9.0 exposes no signing command — registry-feature gap, not a code defect.\n\nFile v0.9.2:skill-card.md\n\n## Description:\n\nOptional BYOB add-on for self-hosted Space Duck users that signs in to Kimi locally, stores Kimi credentials on the user's machine, and runs a localhost OpenAI-compatible proxy for Kimi membership inference with optional OpenRouter fallback.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[askegor](https://clawhub.ai/user/askegor)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and operators use this skill to connect a self-hosted Space Duck runtime to a user's Kimi membership through a local device-code login and localhost proxy. It is intended for users who want local custody of Kimi credentials and understand the external Kimi, Moonshot AI, and optional OpenRouter data paths.\n\n### Deployment Geography for Use:\n\nGlobal, with Kimi inference processed by Moonshot AI infrastructure in China.\n\n## Known Risks and Mitigations:\n\nRisk: Kimi account tokens and proxy secrets are handled locally and could be misused on an untrusted or compromised machine.\n\nMitigation: Install and run the service only on machines you control, keep credential files local with restrictive permissions, and prefer the localhost proxy over printing tokens.\n\nRisk: Environment overrides such as KIMI_AUTH_HOST and KIMI_CODING_BASE can redirect token or chat traffic.\n\nMitigation: Use the default Kimi endpoints unless the alternate destination is fully trusted and intentionally configured.\n\nRisk: Optional OpenRouter fallback can send prompts to OpenRouter and consume metered pay-per-token capacity.\n\nMitigation: Set OPENROUTER_API_KEY only when fallback is desired, keep the daily fallback cap enabled, and monitor relay status.\n\nRisk: Kimi inference is processed by Moonshot AI infrastructure in China.\n\nMitigation: Do not use this lane for conversations or workloads that require Western data residency.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/askegor/skills/space-duck-kimi-relay)\n- [Security Manifest](artifact/SECURITY-MANIFEST.md)\n\n## Skill Output:\n\n**Output Type(s):** [Guidance, Shell commands, Configuration, Code]\n\n**Output Format:** [Markdown with shell command examples and executable Python script behavior]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Outputs local login, token, status, service, and proxy usage guidance; the included script can print short-lived tokens and serve a localhost API proxy.]\n\n## Skill Version(s):\n\n0.9.2 (source: server release metadata and artifact _meta.json)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.9.1: 5 files, 14965 bytes\n\nFiles: _meta.json (140b), scripts/kimi_login.py (24355b), SECURITY-MANIFEST.md (3240b), skill-card.md (2704b), SKILL.md (8055b)\n\nFile v0.9.1:SKILL.md\n\n---\nname: space-duck-kimi-relay\ndescription: Optional Lane A / BYOB add-on for Space Duck — runs a local RFC 8628 device-code \"Sign in with Kimi\" flow (no password; browser-approved) so a self-hosted duck can use the owner's flat-rate Kimi membership for inference. Credentials (access + rotating refresh token) are stored locally at ~/.kimi-code/credentials/kimi.json (0600) and are NEVER sent to Spaceduckling. Contacts only auth.kimi.com and api.kimi.com; inference is processed by Moonshot AI in China (no Western data residency). Optional pay-per-token fallback to openrouter.ai when OPENROUTER_API_KEY is set (daily-capped). Runs a localhost-only proxy (127.0.0.1, default 8471) protected by an auto-generated 0600 bearer secret. Hosted (Lane B) ducks use the Mission Control card instead. Triggers on \"sign in with kimi\", \"kimi membership login\", \"clawhub space-duck kimi\", \"kimi relay login\".\ndisclosures:\n  network:\n    - auth.kimi.com          # OAuth device authorization + token/refresh\n    - api.kimi.com           # membership inference (Moonshot AI, China)\n    - openrouter.ai          # OPTIONAL pay-per-token fallback, only if OPENROUTER_API_KEY set\n  credentials:\n    - Kimi access + refresh token at ~/.kimi-code/credentials/kimi.json (0600, local only)\n    - auto-generated proxy bearer secret at ~/.kimi-code/credentials/proxy_secret (0600)\n    - reads OPENROUTER_API_KEY from env; forwarded only to openrouter.ai on fallback\n  data_residency: \"Kimi inference runs on Moonshot AI infrastructure in China.\"\n  overridable_endpoints:\n    - KIMI_AUTH_HOST, KIMI_CODING_BASE, KIMI_CLIENT_ID   # advanced; changing these re-points token traffic\n  spend: \"Fallback is metered, default cap KIMI_RELAY_FALLBACK_DAILY_CAP=200 calls/day; past cap returns 429.\"\n  auth_bypass: \"KIMI_RELAY_NO_AUTH=1 disables the localhost proxy's bearer check — single-user boxes only.\"\n  privilege: \"install-service writes a systemd-user/launchd unit; captured KIMI_*/OPENROUTER_API_KEY secrets go in a separate 0600 EnvironmentFile (~/.kimi-code/credentials/relay.env), never inlined into the unit.\"\n  sends_to_spaceduckling: none\n---\n\n# Space Duck Kimi Relay (optional add-on, Lane A)\n\nLets a duck that runs on **your own infrastructure** use your **Kimi\nmembership** (flat-rate subscription quota) for inference instead of\npay-per-token API keys.\n\n## Trust model — the whole point\n\n- The device-code sign-in runs **locally on your box**.\n- Tokens are stored at `~/.kimi-code/credentials/kimi.json` (0600), on\n  **your machine only**.\n- The only host this skill contacts is Kimi itself (`auth.kimi.com` and\n  `api.kimi.com`). **Spaceduckling never sees or holds the token.**\n- This is the Lane A mirror of Mission Control's hosted \"Sign in with\n  Kimi\" card: same protocol capability, different custody. (Cross-lane\n  parity doctrine — capability exists in both lanes, credentials follow\n  the lane's trust model.)\n\n## Commands\n\n```\nkimi_login.py login         # interactive device sign-in\nkimi_login.py token         # print fresh access token (auto-refresh, file-locked)\nkimi_login.py probe         # inference smoke on membership quota\nkimi_login.py serve [port]  # local proxy for your runtime (default 8471)\nkimi_login.py install-service [port]   # run proxy as a service (systemd user / launchd)\nkimi_login.py uninstall-service        # remove the service\nkimi_login.py status [port] # creds + proxy + fallback-meter health check\nkimi_login.py logout        # delete local credentials\n```\n\n`login` shows a kimi.com URL + user code; approve it in your browser and\nthe script stores the tokens. `token` transparently refreshes — Kimi\naccess tokens live ~15 minutes and **refresh tokens rotate on every\ngrant**, so always let this script (not ad-hoc curl) do the refreshing;\na stale refresh token is dead after one rotation.\n\n## Wiring the duck's brain — use the proxy\n\nKimi access tokens live ~15 minutes, so a static key in your runtime's\nconfig will not survive. Run the local proxy instead:\n\n```\nkimi_login.py serve            # http://127.0.0.1:8471/v1/chat/completions\n```\n\nPoint your runtime's OpenAI-compatible provider at\n`http://127.0.0.1:8471/v1`. As the api key, use the **proxy secret**\nthat `serve` / `status` prints (auto-generated at\n`~/.kimi-code/credentials/proxy_secret`, 0600) — without it the proxy\nanswers 401, so other local processes/users can't spend your quota.\n`KIMI_RELAY_NO_AUTH=1` disables the check (single-user boxes only).\nThe proxy injects a fresh membership token per request (refreshes under\na file lock — safe when several ducks on one box share the login; note\nthe fallback cap below is per-box, so ducks sharing a box share the\nbudget).\n\n- Models: `k3` (full), `kimi-for-coding` (budget)\n- k3 emits `reasoning_content` and spends completion budget on it —\n  give it roomy `max_tokens` (512+) or replies can arrive empty.\n\nStreaming (`\"stream\": true`) is passed through as SSE, so chat UIs get\ntoken-by-token output on the membership lane.\n\n**Automatic fallback:** export `OPENROUTER_API_KEY` before `serve` and\nany failed membership call (quota/auth/outage) is retried once on\nOpenRouter's kimi lane (`moonshotai/*`, pay-per-token) — same\ndegradation the hosted lane performs. Fallback is metered: capped at\n`KIMI_RELAY_FALLBACK_DAILY_CAP` calls/day (default 200) so a broken\nmembership can't silently run up a pay-per-token bill; past the cap the\nproxy returns 429. If the client asked for `stream: true`, the fallback\nreply is wrapped as a single SSE chunk + `[DONE]` so streaming clients\nstill get valid SSE. Without the env var, failures return the error so\nyour runtime's own ladder takes over.\n\nFor a proxy that survives reboots, `install-service` writes a systemd\nuser unit (Linux — enable lingering with\n`loginctl enable-linger $USER` so it runs while logged out) or a\nlaunchd agent (macOS). Any `OPENROUTER_API_KEY` / `KIMI_*` env vars set\nwhen you run `install-service` are written to a **separate 0600\n`EnvironmentFile`** (`~/.kimi-code/credentials/relay.env`) that the unit\nreferences — secrets are never inlined into the world-readable systemd\nunit itself — so the fallback survives reboots without leaking the key.\n`status` shows creds, proxy health, and the fallback meter.\n\nEnv overrides: `KIMI_CLIENT_ID` (if Moonshot rotates the public\nclient), `KIMI_AUTH_HOST`, `KIMI_CODING_BASE`,\n`KIMI_RELAY_FALLBACK_DAILY_CAP`.\n\n## Moving credentials between machines\n\nRefresh tokens **rotate on every grant**. That means:\n\n- Creds move **one-way only**. If you copy `~/.kimi-code/credentials/kimi.json`\n  to a second box and let that box run (`token`, `probe`, or `serve`), it\n  will refresh and rotate the shared refresh token — the box you copied\n  *from* will silently strand on the next refresh.\n- Rule: after running the creds on another box, **re-login on the box\n  you want to keep** with `kimi_login.py login`. Never copy `kimi.json`\n  back to the original box.\n- Prefer a local login on every box (`kimi_login.py login`) — that keeps\n  the token in local custody where the trust model expects it. Only if\n  you cannot log in on the remote box, a short-lived access token from\n  `kimi_login.py token` can be used for a brief test: it is valid ~15 min,\n  has no refresh capability, and cannot strand any lineage. Treat it like\n  any secret — do not paste it into logs, chat, or shared terminals, and\n  let it expire rather than storing it.\n- One lineage per runtime. Don't share a single `kimi.json` across two\n  long-running services; give each its own login.\n\n## Data residency\n\nKimi inference is processed by Moonshot AI on infrastructure in China.\nDon't route conversations through this lane if you require Western data\nresidency.\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `scripts/kimi_login.py` | Device sign-in, token refresh, probe, logout |\n\n## Important\n\n- Opt-in add-on; the core `space-duck` skill works without it.\n- Updates arrive via ClawHub with owner consent (Mission Control shows\n  \"update available\") — never force-pushed to your box.\n\nFile v0.9.1:_meta.json\n\n{\n  \"ownerId\": \"kn7cav8v08rpkp9w38xg3d9mp985q1e1\",\n  \"slug\": \"space-duck-kimi-relay\",\n  \"version\": \"0.9.1\",\n  \"publishedAt\": 1789256496574\n}\n\nFile v0.9.1:SECURITY-MANIFEST.md\n\n# space-duck-kimi-relay — Security Manifest (byte-grounded)\n\nVersion: 0.8.4 (aligned with the space-duck family — see MEMORY.md publish log) · Generated 2026-08-11 · Evidence = `scripts/kimi_login.py` line refs.\nRule: every claim below cites file:line. No claim rests on an LLM \"reading\".\n\n## Scope\nPackage is exactly 3 files: `SKILL.md`, `_meta.json`, `scripts/kimi_login.py`.\nNo `lib/`, no `bin/`, no `package.json`, no JS, no dependencies beyond Python stdlib\n(`fcntl, json, os, sys, time, urllib, http.server, secrets, subprocess`).\n\n## Credential custody\n- Store path: `~/.kimi-code/credentials/kimi.json` — `CRED_PATH` (kimi_login.py:41-42).\n- Written 0600 via `os.open(..., 0o600)` in `_save()` (kimi_login.py:73); dir 0700 (kimi_login.py:65).\n- Proxy bearer secret `proxy_secret` written 0600 (kimi_login.py:206).\n- Access token read only from local file in `_load()`/`fresh_token()` (kimi_login.py:80-154).\n\n## Outbound hosts (complete egress allowlist)\nEvery network call is a `urllib.request.urlopen` — there are exactly three call sites:\n- kimi_login.py:55  → `AUTH_HOST` = `https://auth.kimi.com` (OAuth device + token/refresh), :36\n- kimi_login.py:166 → `CODING_BASE` = `https://api.kimi.com/coding/v1` (inference), :40\n- kimi_login.py:353 → `CODING_BASE` (streaming inference)\n- kimi_login.py:333 → `https://openrouter.ai/api/v1` — ONLY when `OPENROUTER_API_KEY` set (:319)\nNo other socket/urlopen/requests calls exist. **Nothing is sent to Spaceduckling.**\n\n## Where the token can leave the process\n- Kimi token injected as `Authorization: Bearer` only to Kimi hosts: kimi_login.py:164, :350.\n- `OPENROUTER_API_KEY` sent only to openrouter.ai: kimi_login.py:333.\n- No logging of token/secret values (log_message prints request lines only, :278-279).\n\n## Proxy exposure\n- Binds localhost only: `ThreadingHTTPServer((\"127.0.0.1\", port), ...)` (kimi_login.py:387). No bind-address override exists.\n- Auth ON by default: bearer check at kimi_login.py:291-296; secret auto-generated (:203-209).\n- `KIMI_RELAY_NO_AUTH=1` is an explicit opt-OUT (:194) and prints a loud warning (:394).\n  Assessed NOT a defect: already localhost-bound + secret-by-default. Disclosure, not a patch.\n\n## Fallback spend\n- Metered, default cap 200/day (`FALLBACK_DAILY_CAP`, :210); returns 429 past cap (:322-324).\n\n## Service install (hardened in 0.5.2)\n- systemd: secrets written to a **separate 0600 EnvironmentFile** `~/.kimi-code/credentials/relay.env` (kimi_login.py:461), referenced via `EnvironmentFile=` (:465). Secrets are NOT inlined into the (world-readable) unit.\n- Deterministic test asserts: secret value absent from unit, `EnvironmentFile=` present, env file 0600. PASS (2026-08-11).\n- macOS launchd: plist written 0600 (:444); values embedded in plist (0600) — documented residual.\n\n## Overridable endpoints (disclosed)\n- `KIMI_AUTH_HOST` (:36), `KIMI_CODING_BASE` (:40), `KIMI_CLIENT_ID` (:38). Changing these re-points token traffic — advanced use, disclosed in frontmatter.\n\n## Not covered by this manifest\n- Runtime behavior of the remote Kimi/OpenRouter endpoints (out of package scope).\n- Signing / GitHub provenance: ClawHub v0.9.0 exposes no signing command — registry-feature gap, not a code defect.\n\nFile v0.9.1:skill-card.md\n\n## Description:\n\nspace-duck-kimi-relay helps a self-hosted Space Duck deployment sign in to Kimi locally, store credentials on the user's machine, and run a localhost OpenAI-compatible proxy with an optional capped OpenRouter fallback.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[askegor](https://clawhub.ai/user/askegor)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and operators running Space Duck on their own infrastructure use this skill to configure local Kimi membership authentication, token refresh, proxy serving, service installation, status checks, fallback behavior, and logout workflows.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill stores Kimi access and refresh tokens locally and can print a fresh access token.\n\nMitigation: Keep credential files private, avoid pasting tokens into logs or shared terminals, use the proxy for normal operation, and run logout when local custody is no longer needed.\n\nRisk: Endpoint override variables can repoint token or inference traffic.\n\nMitigation: Use KIMI_AUTH_HOST, KIMI_CODING_BASE, and KIMI_CLIENT_ID only for trusted destinations and review environment variables before starting or installing the service.\n\nRisk: The install-service workflow can persist captured configuration and secrets across sessions.\n\nMitigation: Review the persisted service environment before enabling autostart and uninstall or refresh the service when secrets or endpoints change.\n\nRisk: Inference through the Kimi lane is processed by Moonshot AI infrastructure in China.\n\nMitigation: Do not route workloads through this lane when Western data residency or a different processing region is required.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/askegor/skills/space-duck-kimi-relay)\n- [Security manifest](artifact/SECURITY-MANIFEST.md)\n- [Skill source](artifact/SKILL.md)\n\n## Skill Output:\n\n**Output Type(s):** [text, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown guidance with command examples and local Python script usage]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Produces setup and operational guidance for a local proxy; the included script can emit access tokens, health/status text, and OpenAI-compatible proxy responses when run by the user.]\n\n## Skill Version(s):\n\n0.9.1 (source: server release evidence and artifact metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.9.0: 5 files, 14966 bytes\n\nFiles: _meta.json (140b), scripts/kimi_login.py (24355b), SECURITY-MANIFEST.md (3240b), skill-card.md (2732b), SKILL.md (8055b)\n\nFile v0.9.0:SKILL.md\n\n---\nname: space-duck-kimi-relay\ndescription: Optional Lane A / BYOB add-on for Space Duck — runs a local RFC 8628 device-code \"Sign in with Kimi\" flow (no password; browser-approved) so a self-hosted duck can use the owner's flat-rate Kimi membership for inference. Credentials (access + rotating refresh token) are stored locally at ~/.kimi-code/credentials/kimi.json (0600) and are NEVER sent to Spaceduckling. Contacts only auth.kimi.com and api.kimi.com; inference is processed by Moonshot AI in China (no Western data residency). Optional pay-per-token fallback to openrouter.ai when OPENROUTER_API_KEY is set (daily-capped). Runs a localhost-only proxy (127.0.0.1, default 8471) protected by an auto-generated 0600 bearer secret. Hosted (Lane B) ducks use the Mission Control card instead. Triggers on \"sign in with kimi\", \"kimi membership login\", \"clawhub space-duck kimi\", \"kimi relay login\".\ndisclosures:\n  network:\n    - auth.kimi.com          # OAuth device authorization + token/refresh\n    - api.kimi.com           # membership inference (Moonshot AI, China)\n    - openrouter.ai          # OPTIONAL pay-per-token fallback, only if OPENROUTER_API_KEY set\n  credentials:\n    - Kimi access + refresh token at ~/.kimi-code/credentials/kimi.json (0600, local only)\n    - auto-generated proxy bearer secret at ~/.kimi-code/credentials/proxy_secret (0600)\n    - reads OPENROUTER_API_KEY from env; forwarded only to openrouter.ai on fallback\n  data_residency: \"Kimi inference runs on Moonshot AI infrastructure in China.\"\n  overridable_endpoints:\n    - KIMI_AUTH_HOST, KIMI_CODING_BASE, KIMI_CLIENT_ID   # advanced; changing these re-points token traffic\n  spend: \"Fallback is metered, default cap KIMI_RELAY_FALLBACK_DAILY_CAP=200 calls/day; past cap returns 429.\"\n  auth_bypass: \"KIMI_RELAY_NO_AUTH=1 disables the localhost proxy's bearer check — single-user boxes only.\"\n  privilege: \"install-service writes a systemd-user/launchd unit; captured KIMI_*/OPENROUTER_API_KEY secrets go in a separate 0600 EnvironmentFile (~/.kimi-code/credentials/relay.env), never inlined into the unit.\"\n  sends_to_spaceduckling: none\n---\n\n# Space Duck Kimi Relay (optional add-on, Lane A)\n\nLets a duck that runs on **your own infrastructure** use your **Kimi\nmembership** (flat-rate subscription quota) for inference instead of\npay-per-token API keys.\n\n## Trust model — the whole point\n\n- The device-code sign-in runs **locally on your box**.\n- Tokens are stored at `~/.kimi-code/credentials/kimi.json` (0600), on\n  **your machine only**.\n- The only host this skill contacts is Kimi itself (`auth.kimi.com` and\n  `api.kimi.com`). **Spaceduckling never sees or holds the token.**\n- This is the Lane A mirror of Mission Control's hosted \"Sign in with\n  Kimi\" card: same protocol capability, different custody. (Cross-lane\n  parity doctrine — capability exists in both lanes, credentials follow\n  the lane's trust model.)\n\n## Commands\n\n```\nkimi_login.py login         # interactive device sign-in\nkimi_login.py token         # print fresh access token (auto-refresh, file-locked)\nkimi_login.py probe         # inference smoke on membership quota\nkimi_login.py serve [port]  # local proxy for your runtime (default 8471)\nkimi_login.py install-service [port]   # run proxy as a service (systemd user / launchd)\nkimi_login.py uninstall-service        # remove the service\nkimi_login.py status [port] # creds + proxy + fallback-meter health check\nkimi_login.py logout        # delete local credentials\n```\n\n`login` shows a kimi.com URL + user code; approve it in your browser and\nthe script stores the tokens. `token` transparently refreshes — Kimi\naccess tokens live ~15 minutes and **refresh tokens rotate on every\ngrant**, so always let this script (not ad-hoc curl) do the refreshing;\na stale refresh token is dead after one rotation.\n\n## Wiring the duck's brain — use the proxy\n\nKimi access tokens live ~15 minutes, so a static key in your runtime's\nconfig will not survive. Run the local proxy instead:\n\n```\nkimi_login.py serve            # http://127.0.0.1:8471/v1/chat/completions\n```\n\nPoint your runtime's OpenAI-compatible provider at\n`http://127.0.0.1:8471/v1`. As the api key, use the **proxy secret**\nthat `serve` / `status` prints (auto-generated at\n`~/.kimi-code/credentials/proxy_secret`, 0600) — without it the proxy\nanswers 401, so other local processes/users can't spend your quota.\n`KIMI_RELAY_NO_AUTH=1` disables the check (single-user boxes only).\nThe proxy injects a fresh membership token per request (refreshes under\na file lock — safe when several ducks on one box share the login; note\nthe fallback cap below is per-box, so ducks sharing a box share the\nbudget).\n\n- Models: `k3` (full), `kimi-for-coding` (budget)\n- k3 emits `reasoning_content` and spends completion budget on it —\n  give it roomy `max_tokens` (512+) or replies can arrive empty.\n\nStreaming (`\"stream\": true`) is passed through as SSE, so chat UIs get\ntoken-by-token output on the membership lane.\n\n**Automatic fallback:** export `OPENROUTER_API_KEY` before `serve` and\nany failed membership call (quota/auth/outage) is retried once on\nOpenRouter's kimi lane (`moonshotai/*`, pay-per-token) — same\ndegradation the hosted lane performs. Fallback is metered: capped at\n`KIMI_RELAY_FALLBACK_DAILY_CAP` calls/day (default 200) so a broken\nmembership can't silently run up a pay-per-token bill; past the cap the\nproxy returns 429. If the client asked for `stream: true`, the fallback\nreply is wrapped as a single SSE chunk + `[DONE]` so streaming clients\nstill get valid SSE. Without the env var, failures return the error so\nyour runtime's own ladder takes over.\n\nFor a proxy that survives reboots, `install-service` writes a systemd\nuser unit (Linux — enable lingering with\n`loginctl enable-linger $USER` so it runs while logged out) or a\nlaunchd agent (macOS). Any `OPENROUTER_API_KEY` / `KIMI_*` env vars set\nwhen you run `install-service` are written to a **separate 0600\n`EnvironmentFile`** (`~/.kimi-code/credentials/relay.env`) that the unit\nreferences — secrets are never inlined into the world-readable systemd\nunit itself — so the fallback survives reboots without leaking the key.\n`status` shows creds, proxy health, and the fallback meter.\n\nEnv overrides: `KIMI_CLIENT_ID` (if Moonshot rotates the public\nclient), `KIMI_AUTH_HOST`, `KIMI_CODING_BASE`,\n`KIMI_RELAY_FALLBACK_DAILY_CAP`.\n\n## Moving credentials between machines\n\nRefresh tokens **rotate on every grant**. That means:\n\n- Creds move **one-way only**. If you copy `~/.kimi-code/credentials/kimi.json`\n  to a second box and let that box run (`token`, `probe`, or `serve`), it\n  will refresh and rotate the shared refresh token — the box you copied\n  *from* will silently strand on the next refresh.\n- Rule: after running the creds on another box, **re-login on the box\n  you want to keep** with `kimi_login.py login`. Never copy `kimi.json`\n  back to the original box.\n- Prefer a local login on every box (`kimi_login.py login`) — that keeps\n  the token in local custody where the trust model expects it. Only if\n  you cannot log in on the remote box, a short-lived access token from\n  `kimi_login.py token` can be used for a brief test: it is valid ~15 min,\n  has no refresh capability, and cannot strand any lineage. Treat it like\n  any secret — do not paste it into logs, chat, or shared terminals, and\n  let it expire rather than storing it.\n- One lineage per runtime. Don't share a single `kimi.json` across two\n  long-running services; give each its own login.\n\n## Data residency\n\nKimi inference is processed by Moonshot AI on infrastructure in China.\nDon't route conversations through this lane if you require Western data\nresidency.\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `scripts/kimi_login.py` | Device sign-in, token refresh, probe, logout |\n\n## Important\n\n- Opt-in add-on; the core `space-duck` skill works without it.\n- Updates arrive via ClawHub with owner consent (Mission Control shows\n  \"update available\") — never force-pushed to your box.\n\nFile v0.9.0:_meta.json\n\n{\n  \"ownerId\": \"kn7cav8v08rpkp9w38xg3d9mp985q1e1\",\n  \"slug\": \"space-duck-kimi-relay\",\n  \"version\": \"0.9.0\",\n  \"publishedAt\": 1789047096381\n}\n\nFile v0.9.0:SECURITY-MANIFEST.md\n\n# space-duck-kimi-relay — Security Manifest (byte-grounded)\n\nVersion: 0.8.4 (aligned with the space-duck family — see MEMORY.md publish log) · Generated 2026-08-11 · Evidence = `scripts/kimi_login.py` line refs.\nRule: every claim below cites file:line. No claim rests on an LLM \"reading\".\n\n## Scope\nPackage is exactly 3 files: `SKILL.md`, `_meta.json`, `scripts/kimi_login.py`.\nNo `lib/`, no `bin/`, no `package.json`, no JS, no dependencies beyond Python stdlib\n(`fcntl, json, os, sys, time, urllib, http.server, secrets, subprocess`).\n\n## Credential custody\n- Store path: `~/.kimi-code/credentials/kimi.json` — `CRED_PATH` (kimi_login.py:41-42).\n- Written 0600 via `os.open(..., 0o600)` in `_save()` (kimi_login.py:73); dir 0700 (kimi_login.py:65).\n- Proxy bearer secret `proxy_secret` written 0600 (kimi_login.py:206).\n- Access token read only from local file in `_load()`/`fresh_token()` (kimi_login.py:80-154).\n\n## Outbound hosts (complete egress allowlist)\nEvery network call is a `urllib.request.urlopen` — there are exactly three call sites:\n- kimi_login.py:55  → `AUTH_HOST` = `https://auth.kimi.com` (OAuth device + token/refresh), :36\n- kimi_login.py:166 → `CODING_BASE` = `https://api.kimi.com/coding/v1` (inference), :40\n- kimi_login.py:353 → `CODING_BASE` (streaming inference)\n- kimi_login.py:333 → `https://openrouter.ai/api/v1` — ONLY when `OPENROUTER_API_KEY` set (:319)\nNo other socket/urlopen/requests calls exist. **Nothing is sent to Spaceduckling.**\n\n## Where the token can leave the process\n- Kimi token injected as `Authorization: Bearer` only to Kimi hosts: kimi_login.py:164, :350.\n- `OPENROUTER_API_KEY` sent only to openrouter.ai: kimi_login.py:333.\n- No logging of token/secret values (log_message prints request lines only, :278-279).\n\n## Proxy exposure\n- Binds localhost only: `ThreadingHTTPServer((\"127.0.0.1\", port), ...)` (kimi_login.py:387). No bind-address override exists.\n- Auth ON by default: bearer check at kimi_login.py:291-296; secret auto-generated (:203-209).\n- `KIMI_RELAY_NO_AUTH=1` is an explicit opt-OUT (:194) and prints a loud warning (:394).\n  Assessed NOT a defect: already localhost-bound + secret-by-default. Disclosure, not a patch.\n\n## Fallback spend\n- Metered, default cap 200/day (`FALLBACK_DAILY_CAP`, :210); returns 429 past cap (:322-324).\n\n## Service install (hardened in 0.5.2)\n- systemd: secrets written to a **separate 0600 EnvironmentFile** `~/.kimi-code/credentials/relay.env` (kimi_login.py:461), referenced via `EnvironmentFile=` (:465). Secrets are NOT inlined into the (world-readable) unit.\n- Deterministic test asserts: secret value absent from unit, `EnvironmentFile=` present, env file 0600. PASS (2026-08-11).\n- macOS launchd: plist written 0600 (:444); values embedded in plist (0600) — documented residual.\n\n## Overridable endpoints (disclosed)\n- `KIMI_AUTH_HOST` (:36), `KIMI_CODING_BASE` (:40), `KIMI_CLIENT_ID` (:38). Changing these re-points token traffic — advanced use, disclosed in frontmatter.\n\n## Not covered by this manifest\n- Runtime behavior of the remote Kimi/OpenRouter endpoints (out of package scope).\n- Signing / GitHub provenance: ClawHub v0.9.0 exposes no signing command — registry-feature gap, not a code defect.\n\nFile v0.9.0:skill-card.md\n\n## Description:\n\nSpace Duck Kimi Relay lets self-hosted Space Duck users sign in to Kimi locally and run a localhost proxy that injects fresh Kimi membership tokens for inference, with an optional daily-capped OpenRouter fallback.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[askegor](https://clawhub.ai/user/askegor)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and self-hosted Space Duck operators use this skill to connect a local agent runtime to a Kimi membership without handing credentials to Spaceduckling. It supports local sign-in, token refresh, proxy service setup, health checks, fallback configuration, and logout.\n\n### Deployment Geography for Use:\n\nGlobal; Kimi inference is processed by Moonshot AI infrastructure in China, so users with Western data residency requirements should avoid this lane.\n\n## Known Risks and Mitigations:\n\nRisk: The relay stores Kimi access and refresh credentials plus a local proxy bearer secret on the user's machine.\n\nMitigation: Install only on trusted local machines, keep the default 0600 credential files, and remove credentials or the service when the relay is no longer needed.\n\nRisk: Overridable Kimi endpoints can redirect credential-bearing traffic if set to untrusted hosts.\n\nMitigation: Avoid KIMI_AUTH_HOST and KIMI_CODING_BASE unless the target endpoint is fully trusted.\n\nRisk: KIMI_RELAY_NO_AUTH disables the localhost proxy bearer check.\n\nMitigation: Leave proxy authentication enabled except on explicitly single-user systems.\n\nRisk: Kimi inference is processed in China, and the optional OpenRouter fallback sends prompts to third-party infrastructure and can incur metered spend.\n\nMitigation: Do not use this lane for workloads requiring Western data residency, and configure the OpenRouter fallback only intentionally with an appropriate daily cap.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/askegor/skills/space-duck-kimi-relay)\n- [Security Manifest](artifact/SECURITY-MANIFEST.md)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown guidance with inline shell commands and configuration values]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Includes local service commands, credential handling guidance, endpoint disclosures, and fallback limits.]\n\n## Skill Version(s):\n\n0.9.0 (source: server release metadata and artifact/_meta.json)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.8.21: 5 files, 15037 bytes\n\nFiles: _meta.json (141b), scripts/kimi_login.py (24355b), SECURITY-MANIFEST.md (3240b), skill-card.md (3003b), SKILL.md (8055b)\n\nFile v0.8.21:SKILL.md\n\n---\nname: space-duck-kimi-relay\ndescription: Optional Lane A / BYOB add-on for Space Duck — runs a local RFC 8628 device-code \"Sign in with Kimi\" flow (no password; browser-approved) so a self-hosted duck can use the owner's flat-rate Kimi membership for inference. Credentials (access + rotating refresh token) are stored locally at ~/.kimi-code/credentials/kimi.json (0600) and are NEVER sent to Spaceduckling. Contacts only auth.kimi.com and api.kimi.com; inference is processed by Moonshot AI in China (no Western data residency). Optional pay-per-token fallback to openrouter.ai when OPENROUTER_API_KEY is set (daily-capped). Runs a localhost-only proxy (127.0.0.1, default 8471) protected by an auto-generated 0600 bearer secret. Hosted (Lane B) ducks use the Mission Control card instead. Triggers on \"sign in with kimi\", \"kimi membership login\", \"clawhub space-duck kimi\", \"kimi relay login\".\ndisclosures:\n  network:\n    - auth.kimi.com          # OAuth device authorization + token/refresh\n    - api.kimi.com           # membership inference (Moonshot AI, China)\n    - openrouter.ai          # OPTIONAL pay-per-token fallback, only if OPENROUTER_API_KEY set\n  credentials:\n    - Kimi access + refresh token at ~/.kimi-code/credentials/kimi.json (0600, local only)\n    - auto-generated proxy bearer secret at ~/.kimi-code/credentials/proxy_secret (0600)\n    - reads OPENROUTER_API_KEY from env; forwarded only to openrouter.ai on fallback\n  data_residency: \"Kimi inference runs on Moonshot AI infrastructure in China.\"\n  overridable_endpoints:\n    - KIMI_AUTH_HOST, KIMI_CODING_BASE, KIMI_CLIENT_ID   # advanced; changing these re-points token traffic\n  spend: \"Fallback is metered, default cap KIMI_RELAY_FALLBACK_DAILY_CAP=200 calls/day; past cap returns 429.\"\n  auth_bypass: \"KIMI_RELAY_NO_AUTH=1 disables the localhost proxy's bearer check — single-user boxes only.\"\n  privilege: \"install-service writes a systemd-user/launchd unit; captured KIMI_*/OPENROUTER_API_KEY secrets go in a separate 0600 EnvironmentFile (~/.kimi-code/credentials/relay.env), never inlined into the unit.\"\n  sends_to_spaceduckling: none\n---\n\n# Space Duck Kimi Relay (optional add-on, Lane A)\n\nLets a duck that runs on **your own infrastructure** use your **Kimi\nmembership** (flat-rate subscription quota) for inference instead of\npay-per-token API keys.\n\n## Trust model — the whole point\n\n- The device-code sign-in runs **locally on your box**.\n- Tokens are stored at `~/.kimi-code/credentials/kimi.json` (0600), on\n  **your machine only**.\n- The only host this skill contacts is Kimi itself (`auth.kimi.com` and\n  `api.kimi.com`). **Spaceduckling never sees or holds the token.**\n- This is the Lane A mirror of Mission Control's hosted \"Sign in with\n  Kimi\" card: same protocol capability, different custody. (Cross-lane\n  parity doctrine — capability exists in both lanes, credentials follow\n  the lane's trust model.)\n\n## Commands\n\n```\nkimi_login.py login         # interactive device sign-in\nkimi_login.py token         # print fresh access token (auto-refresh, file-locked)\nkimi_login.py probe         # inference smoke on membership quota\nkimi_login.py serve [port]  # local proxy for your runtime (default 8471)\nkimi_login.py install-service [port]   # run proxy as a service (systemd user / launchd)\nkimi_login.py uninstall-service        # remove the service\nkimi_login.py status [port] # creds + proxy + fallback-meter health check\nkimi_login.py logout        # delete local credentials\n```\n\n`login` shows a kimi.com URL + user code; approve it in your browser and\nthe script stores the tokens. `token` transparently refreshes — Kimi\naccess tokens live ~15 minutes and **refresh tokens rotate on every\ngrant**, so always let this script (not ad-hoc curl) do the refreshing;\na stale refresh token is dead after one rotation.\n\n## Wiring the duck's brain — use the proxy\n\nKimi access tokens live ~15 minutes, so a static key in your runtime's\nconfig will not survive. Run the local proxy instead:\n\n```\nkimi_login.py serve            # http://127.0.0.1:8471/v1/chat/completions\n```\n\nPoint your runtime's OpenAI-compatible provider at\n`http://127.0.0.1:8471/v1`. As the api key, use the **proxy secret**\nthat `serve` / `status` prints (auto-generated at\n`~/.kimi-code/credentials/proxy_secret`, 0600) — without it the proxy\nanswers 401, so other local processes/users can't spend your quota.\n`KIMI_RELAY_NO_AUTH=1` disables the check (single-user boxes only).\nThe proxy injects a fresh membership token per request (refreshes under\na file lock — safe when several ducks on one box share the login; note\nthe fallback cap below is per-box, so ducks sharing a box share the\nbudget).\n\n- Models: `k3` (full), `kimi-for-coding` (budget)\n- k3 emits `reasoning_content` and spends completion budget on it —\n  give it roomy `max_tokens` (512+) or replies can arrive empty.\n\nStreaming (`\"stream\": true`) is passed through as SSE, so chat UIs get\ntoken-by-token output on the membership lane.\n\n**Automatic fallback:** export `OPENROUTER_API_KEY` before `serve` and\nany failed membership call (quota/auth/outage) is retried once on\nOpenRouter's kimi lane (`moonshotai/*`, pay-per-token) — same\ndegradation the hosted lane performs. Fallback is metered: capped at\n`KIMI_RELAY_FALLBACK_DAILY_CAP` calls/day (default 200) so a broken\nmembership can't silently run up a pay-per-token bill; past the cap the\nproxy returns 429. If the client asked for `stream: true`, the fallback\nreply is wrapped as a single SSE chunk + `[DONE]` so streaming clients\nstill get valid SSE. Without the env var, failures return the error so\nyour runtime's own ladder takes over.\n\nFor a proxy that survives reboots, `install-service` writes a systemd\nuser unit (Linux — enable lingering with\n`loginctl enable-linger $USER` so it runs while logged out) or a\nlaunchd agent (macOS). Any `OPENROUTER_API_KEY` / `KIMI_*` env vars set\nwhen you run `install-service` are written to a **separate 0600\n`EnvironmentFile`** (`~/.kimi-code/credentials/relay.env`) that the unit\nreferences — secrets are never inlined into the world-readable systemd\nunit itself — so the fallback survives reboots without leaking the key.\n`status` shows creds, proxy health, and the fallback meter.\n\nEnv overrides: `KIMI_CLIENT_ID` (if Moonshot rotates the public\nclient), `KIMI_AUTH_HOST`, `KIMI_CODING_BASE`,\n`KIMI_RELAY_FALLBACK_DAILY_CAP`.\n\n## Moving credentials between machines\n\nRefresh tokens **rotate on every grant**. That means:\n\n- Creds move **one-way only**. If you copy `~/.kimi-code/credentials/kimi.json`\n  to a second box and let that box run (`token`, `probe`, or `serve`), it\n  will refresh and rotate the shared refresh token — the box you copied\n  *from* will silently strand on the next refresh.\n- Rule: after running the creds on another box, **re-login on the box\n  you want to keep** with `kimi_login.py login`. Never copy `kimi.json`\n  back to the original box.\n- Prefer a local login on every box (`kimi_login.py login`) — that keeps\n  the token in local custody where the trust model expects it. Only if\n  you cannot log in on the remote box, a short-lived access token from\n  `kimi_login.py token` can be used for a brief test: it is valid ~15 min,\n  has no refresh capability, and cannot strand any lineage. Treat it like\n  any secret — do not paste it into logs, chat, or shared terminals, and\n  let it expire rather than storing it.\n- One lineage per runtime. Don't share a single `kimi.json` across two\n  long-running services; give each its own login.\n\n## Data residency\n\nKimi inference is processed by Moonshot AI on infrastructure in China.\nDon't route conversations through this lane if you require Western data\nresidency.\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `scripts/kimi_login.py` | Device sign-in, token refresh, probe, logout |\n\n## Important\n\n- Opt-in add-on; the core `space-duck` skill works without it.\n- Updates arrive via ClawHub with owner consent (Mission Control shows\n  \"update available\") — never force-pushed to your box.\n\nFile v0.8.21:_meta.json\n\n{\n  \"ownerId\": \"kn7cav8v08rpkp9w38xg3d9mp985q1e1\",\n  \"slug\": \"space-duck-kimi-relay\",\n  \"version\": \"0.8.21\",\n  \"publishedAt\": 1788361309089\n}\n\nFile v0.8.21:SECURITY-MANIFEST.md\n\n# space-duck-kimi-relay — Security Manifest (byte-grounded)\n\nVersion: 0.8.4 (aligned with the space-duck family — see MEMORY.md publish log) · Generated 2026-08-11 · Evidence = `scripts/kimi_login.py` line refs.\nRule: every claim below cites file:line. No claim rests on an LLM \"reading\".\n\n## Scope\nPackage is exactly 3 files: `SKILL.md`, `_meta.json`, `scripts/kimi_login.py`.\nNo `lib/`, no `bin/`, no `package.json`, no JS, no dependencies beyond Python stdlib\n(`fcntl, json, os, sys, time, urllib, http.server, secrets, subprocess`).\n\n## Credential custody\n- Store path: `~/.kimi-code/credentials/kimi.json` — `CRED_PATH` (kimi_login.py:41-42).\n- Written 0600 via `os.open(..., 0o600)` in `_save()` (kimi_login.py:73); dir 0700 (kimi_login.py:65).\n- Proxy bearer secret `proxy_secret` written 0600 (kimi_login.py:206).\n- Access token read only from local file in `_load()`/`fresh_token()` (kimi_login.py:80-154).\n\n## Outbound hosts (complete egress allowlist)\nEvery network call is a `urllib.request.urlopen` — there are exactly three call sites:\n- kimi_login.py:55  → `AUTH_HOST` = `https://auth.kimi.com` (OAuth device + token/refresh), :36\n- kimi_login.py:166 → `CODING_BASE` = `https://api.kimi.com/coding/v1` (inference), :40\n- kimi_login.py:353 → `CODING_BASE` (streaming inference)\n- kimi_login.py:333 → `https://openrouter.ai/api/v1` — ONLY when `OPENROUTER_API_KEY` set (:319)\nNo other socket/urlopen/requests calls exist. **Nothing is sent to Spaceduckling.**\n\n## Where the token can leave the process\n- Kimi token injected as `Authorization: Bearer` only to Kimi hosts: kimi_login.py:164, :350.\n- `OPENROUTER_API_KEY` sent only to openrouter.ai: kimi_login.py:333.\n- No logging of token/secret values (log_message prints request lines only, :278-279).\n\n## Proxy exposure\n- Binds localhost only: `ThreadingHTTPServer((\"127.0.0.1\", port), ...)` (kimi_login.py:387). No bind-address override exists.\n- Auth ON by default: bearer check at kimi_login.py:291-296; secret auto-generated (:203-209).\n- `KIMI_RELAY_NO_AUTH=1` is an explicit opt-OUT (:194) and prints a loud warning (:394).\n  Assessed NOT a defect: already localhost-bound + secret-by-default. Disclosure, not a patch.\n\n## Fallback spend\n- Metered, default cap 200/day (`FALLBACK_DAILY_CAP`, :210); returns 429 past cap (:322-324).\n\n## Service install (hardened in 0.5.2)\n- systemd: secrets written to a **separate 0600 EnvironmentFile** `~/.kimi-code/credentials/relay.env` (kimi_login.py:461), referenced via `EnvironmentFile=` (:465). Secrets are NOT inlined into the (world-readable) unit.\n- Deterministic test asserts: secret value absent from unit, `EnvironmentFile=` present, env file 0600. PASS (2026-08-11).\n- macOS launchd: plist written 0600 (:444); values embedded in plist (0600) — documented residual.\n\n## Overridable endpoints (disclosed)\n- `KIMI_AUTH_HOST` (:36), `KIMI_CODING_BASE` (:40), `KIMI_CLIENT_ID` (:38). Changing these re-points token traffic — advanced use, disclosed in frontmatter.\n\n## Not covered by this manifest\n- Runtime behavior of the remote Kimi/OpenRouter endpoints (out of package scope).\n- Signing / GitHub provenance: ClawHub v0.9.0 exposes no signing command — registry-feature gap, not a code defect.\n\nFile v0.8.21:skill-card.md\n\n## Description:\n\nSpace Duck Kimi Relay lets self-hosted Space Duck users sign in to Kimi locally and run a localhost OpenAI-compatible proxy for Kimi inference, with an optional metered OpenRouter fallback.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[askegor](https://clawhub.ai/user/askegor)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and operators running Space Duck on their own","readmeExcerpt":"Skill: space-duck-kimi-relay Owner: askegor Summary: Optional Lane A / BYOB add-on for Space Duck — runs a local RFC 8628 device-code \"Sign in with Kimi\" flow (no password; browser-approved) so a self-hosted duck can use the owner's flat-rate Kimi membership for inference. Credentials (access + rotating refresh token) are stored locally at ~/.kimi-code/credentials/kimi.json (0600) and are NEVER sent to Spaceduckling.","codeSnippets":[],"executableExamples":[{"language":"text","snippet":"kimi_login.py login         # interactive device sign-in\nkimi_login.py token         # print fresh access token (auto-refresh, file-locked)\nkimi_login.py probe         # inference smoke on membership quota\nkimi_login.py serve [port]  # local proxy for your runtime (default 8471)\nkimi_login.py install-service [port]   # run proxy as a service (systemd user / launchd)\nkimi_login.py uninstall-service        # remove the service\nkimi_login.py status [port] # creds + proxy + fallback-meter health check\nkimi_login.py logout        # delete local credentials"},{"language":"text","snippet":"kimi_login.py serve            # http://127.0.0.1:8471/v1/chat/completions"},{"language":"text","snippet":"kimi_login.py login         # interactive device sign-in\nkimi_login.py token         # print fresh access token (auto-refresh, file-locked)\nkimi_login.py probe         # inference smoke on membership quota\nkimi_login.py serve [port]  # local proxy for your runtime (default 8471)\nkimi_login.py install-service [port]   # run proxy as a service (systemd user / launchd)\nkimi_login.py uninstall-service        # remove the service\nkimi_login.py status [port] # creds + proxy + fallback-meter health check\nkimi_login.py logout        # delete local credentials"},{"language":"text","snippet":"kimi_login.py serve            # http://127.0.0.1:8471/v1/chat/completions"},{"language":"text","snippet":"kimi_login.py login         # interactive device sign-in\nkimi_login.py token         # print fresh access token (auto-refresh, file-locked)\nkimi_login.py probe         # inference smoke on membership quota\nkimi_login.py serve [port]  # local proxy for your runtime (default 8471)\nkimi_login.py install-service [port]   # run proxy as a service (systemd user / launchd)\nkimi_login.py uninstall-service        # remove the service\nkimi_login.py status [port] # creds + proxy + fallback-meter health check\nkimi_login.py logout        # delete local credentials"},{"language":"text","snippet":"kimi_login.py serve            # http://127.0.0.1:8471/v1/chat/completions"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: space-duck-kimi-relay\ndescription: Optional Lane A / BYOB add-on for Space Duck — runs a local RFC 8628 device-code \"Sign in with Kimi\" flow (no password; browser-approved) so a self-hosted duck can use the owner's flat-rate Kimi membership for inference. Credentials (access + rotating refresh token) are stored locally at ~/.kimi-code/credentials/kimi.json (0600) and are NEVER sent to Spaceduckling. Contacts only auth.kimi.com and api.kimi.com; inference is processed by Moonshot AI in China (no Western data residency). Optional pay-per-token fallback to openrouter.ai when OPENROUTER_API_KEY is set (daily-capped). Runs a localhost-only proxy (127.0.0.1, default 8471) protected by an auto-generated 0600 bearer secret. Hosted (Lane B) ducks use the Mission Control card instead. Triggers on \"sign in with kimi\", \"kimi membership login\", \"clawhub space-duck kimi\", \"kimi relay login\".\ndisclosures:\n  network:\n    - auth.kimi.com          # OAuth device authorization + token/refresh\n    - api.kimi.com           # membership inference (Moonshot AI, China)\n    - openrouter.ai          # OPTIONAL pay-per-token fallback, only if OPENROUTER_API_KEY set\n  credentials:\n    - Kimi access + refresh token at ~/.kimi-code/credentials/kimi.json (0600, local only)\n    - auto-generated proxy bearer secret at ~/.kimi-code/credentials/proxy_secret (0600)\n    - reads OPENROUTER_API_KEY from env; forwarded only to openrouter.ai on fallback\n  data_residency: \"Kimi inference runs on Moonshot AI infrastructure in China.\"\n  overridable_endpoints:\n    - KIMI_AUTH_HOST, KIMI_CODING_BASE, KIMI_CLIENT_ID   # advanced; changing these re-points token traffic\n  spend: \"Fallback is metered, default cap KIMI_RELAY_FALLBACK_DAILY_CAP=200 calls/day; past cap returns 429.\"\n  auth_bypass: \"KIMI_RELAY_NO_AUTH=1 disables the localhost proxy's bearer check — single-user boxes only.\"\n  privilege: \"install-service writes a systemd-user/launchd unit; captured KIMI_*/OPENROUTER_API_KEY secrets go in a separate 0600 EnvironmentFile (~/.kimi-code/credentials/relay.env), never inlined into the unit.\"\n  sends_to_spaceduckling: none\n---\n\n# Space Duck Kimi Relay (optional add-on, Lane A)\n\nLets a duck that runs on **your own infrastructure** use your **Kimi\nmembership** (flat-rate subscription quota) for inference instead of\npay-per-token API keys.\n\n## Trust model — the whole point\n\n- The device-code sign-in runs **locally on your box**.\n- Tokens are stored at `~/.kimi-code/credentials/kimi.json` (0600), on\n  **your machine only**.\n- The only host this skill contacts is Kimi itself (`auth.kimi.com` and\n  `api.kimi.com`). **Spaceduckling never sees or holds the token.**\n- This is the Lane A mirror of Mission Control's hosted \"Sign in with\n  Kimi\" card: same protocol capability, different custody. (Cross-lane\n  parity doctrine — capability exists in both lanes, credentials follow\n  the lane's trust model.)\n\n## Commands\n\n```\nkimi_login.py login         # interactive device sign-in\nkimi_login.py t"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7cav8v08rpkp9w38xg3d9mp985q1e1\",\n  \"slug\": \"space-duck-kimi-relay\",\n  \"version\": \"0.9.8\",\n  \"publishedAt\": 1790399901991\n}"},{"path":"SECURITY-MANIFEST.md","content":"# space-duck-kimi-relay — Security Manifest (byte-grounded)\n\nVersion: 0.8.4 (aligned with the space-duck family — see MEMORY.md publish log) · Generated 2026-08-11 · Evidence = `scripts/kimi_login.py` line refs.\nRule: every claim below cites file:line. No claim rests on an LLM \"reading\".\n\n## Scope\nPackage is exactly 3 files: `SKILL.md`, `_meta.json`, `scripts/kimi_login.py`.\nNo `lib/`, no `bin/`, no `package.json`, no JS, no dependencies beyond Python stdlib\n(`fcntl, json, os, sys, time, urllib, http.server, secrets, subprocess`).\n\n## Credential custody\n- Store path: `~/.kimi-code/credentials/kimi.json` — `CRED_PATH` (kimi_login.py:41-42).\n- Written 0600 via `os.open(..., 0o600)` in `_save()` (kimi_login.py:73); dir 0700 (kimi_login.py:65).\n- Proxy bearer secret `proxy_secret` written 0600 (kimi_login.py:206).\n- Access token read only from local file in `_load()`/`fresh_token()` (kimi_login.py:80-154).\n\n## Outbound hosts (complete egress allowlist)\nEvery network call is a `urllib.request.urlopen` — there are exactly three call sites:\n- kimi_login.py:55  → `AUTH_HOST` = `https://auth.kimi.com` (OAuth device + token/refresh), :36\n- kimi_login.py:166 → `CODING_BASE` = `https://api.kimi.com/coding/v1` (inference), :40\n- kimi_login.py:353 → `CODING_BASE` (streaming inference)\n- kimi_login.py:333 → `https://openrouter.ai/api/v1` — ONLY when `OPENROUTER_API_KEY` set (:319)\nNo other socket/urlopen/requests calls exist. **Nothing is sent to Spaceduckling.**\n\n## Where the token can leave the process\n- Kimi token injected as `Authorization: Bearer` only to Kimi hosts: kimi_login.py:164, :350.\n- `OPENROUTER_API_KEY` sent only to openrouter.ai: kimi_login.py:333.\n- No logging of token/secret values (log_message prints request lines only, :278-279).\n\n## Proxy exposure\n- Binds localhost only: `ThreadingHTTPServer((\"127.0.0.1\", port), ...)` (kimi_login.py:387). No bind-address override exists.\n- Auth ON by default: bearer check at kimi_login.py:291-296; secret auto-generated (:203-209).\n- `KIMI_RELAY_NO_AUTH=1` is an explicit opt-OUT (:194) and prints a loud warning (:394).\n  Assessed NOT a defect: already localhost-bound + secret-by-default. Disclosure, not a patch.\n\n## Fallback spend\n- Metered, default cap 200/day (`FALLBACK_DAILY_CAP`, :210); returns 429 past cap (:322-324).\n\n## Service install (hardened in 0.5.2)\n- systemd: secrets written to a **separate 0600 EnvironmentFile** `~/.kimi-code/credentials/relay.env` (kimi_login.py:461), referenced via `EnvironmentFile=` (:465). Secrets are NOT inlined into the (world-readable) unit.\n- Deterministic test asserts: secret value absent from unit, `EnvironmentFile=` present, env file 0600. PASS (2026-08-11).\n- macOS launchd: plist written 0600 (:444); values embedded in plist (0600) — documented residual.\n\n## Overridable endpoints (disclosed)\n- `KIMI_AUTH_HOST` (:36), `KIMI_CODING_BASE` (:40), `KIMI_CLIENT_ID` (:38). Changing these re-points token traffic — advanced use, disclosed in frontmatter.\n\n## Not covered by"},{"path":"skill-card.md","content":"## Description:\n\nEnables self-hosted Space Duck agents to sign in to Kimi through a browser-approved device flow and use a local inference proxy with optional metered fallback.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[askegor](https://clawhub.ai/user/askegor)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers running self-hosted Space Duck agents can use their Kimi membership for inference through a locally authenticated proxy instead of configuring a static access token. An optional OpenRouter fallback supports metered inference when membership calls fail.\n\n### Deployment Geography for Use:\n\nGlobal; Kimi inference is processed in China and is unsuitable where Western data residency is required.\n\n## Known Risks and Mitigations:\n\nRisk: Local Kimi tokens and an optional OpenRouter key grant access to accounts or metered usage.\n\nMitigation: Protect local credential files, prefer the authenticated localhost proxy, and avoid printing or sharing tokens.\n\nRisk: Disabling proxy authentication can expose membership quota to other users or processes on a shared machine.\n\nMitigation: Do not enable KIMI_RELAY_NO_AUTH on shared machines.\n\nRisk: Optional fallback can incur pay-per-token charges when membership requests fail.\n\nMitigation: Enable fallback only when needed and set an appropriate daily call cap.\n\nRisk: Endpoint overrides can redirect token traffic, and service installation can persist secrets in a macOS launchd plist.\n\nMitigation: Avoid endpoint overrides unless the destination is trusted; review service installation and protect the macOS plist.\n\nRisk: Kimi inference is processed in China rather than under Western data residency.\n\nMitigation: Do not route conversations requiring Western data residency through this relay.\n\n## Reference(s):\n\n- [Space Duck Kimi Relay on ClawHub](https://clawhub.ai/askegor/skills/space-duck-kimi-relay)\n- [Security manifest](SECURITY-MANIFEST.md)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Configuration instructions, Guidance]\n\n**Output Format:** [Markdown with command examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Supports local sign-in, token refresh, proxy setup, and optional paid fallback.]\n\n## Skill Version(s):\n\n0.9.8 (source: ClawHub release metadata and _meta.json)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":1878,"uniquenessScore":38,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-10T09:08:13.891Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-10T09:08:13.891Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-10T11:52:17.322Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}