kimi-code/docs/en/reference/kimi-command.md
liruifengv 8c865f4817
feat(kimi-code): support automatic updates for native installations via staged swap (#2994)
* feat(kimi-code): support automatic updates for native installations via staged swap

Native (SEA) installs previously could not self-update on Windows and
relied on 'curl | bash' re-install on Unix. Replace both with a staged
swap updater:

- startup swaps in a staged binary (verified against the release
  manifest sha256, smoke-checked via --version) and re-execs it, so the
  running process never replaces itself (Windows-safe)
- downloads run in a self-spawned hidden sub-command, in the background
  from the update preflight or in the foreground from 'kimi upgrade'
- rollback from .bak on any swap failure; install failures keep the
  existing retry/prompt thresholds

* fix(kimi-code): fully clean staged artifacts on swap discard paths

Real-binary smoke testing on macOS surfaced two cleanup gaps in the
discard path: the claimed metadata file was unlinked after the staging
dir rmdir (so the empty dir survived), and the staged exe was
rediscovered via the already-claimed staged.json (so it leaked on the
downgrade-guard path). Pass the known metadata through and order the
unlink before the rmdir.

* fix(kimi-code): restore staged metadata on swap failure and sweep update leftovers at startup

* fix(kimi-code): address codex review on lock contention and swap crash window

- The background native install no longer takes the outer install lock:
  the self-spawned downloader holds it for the whole download, and the
  parent's spawn-time lock raced the child into a false lastSuccess.
- Smoke-check the staged exe before moving anything, so a bad staged
  binary is discarded with the install path never left empty; the
  remaining crash window is two adjacent atomic renames (documented,
  recoverable via the .bak or by re-running the install script).

* test(kimi-code): align swap test expectation with smoke-before-rename order

The restore-on-failure case now observes the early smoke check's
--version spawn; only the re-exec spawn must be absent.

* fix(kimi-code): stage the bare CDN binary instead of unzipping

The published per-release artifacts are the bare platform binaries
(kimi-code-<target>[.exe]), not zip archives — the staging flow now
streams the download straight to the staged exe after the manifest
sha256 check, and the zip reader is dropped. Verified end-to-end on
macOS against the live CDN: download -> sha256 match -> swap ->
re-exec into the real released binary.

* fix(kimi-code): address second codex review round

- re-exec: forward 128 + signo when the swapped-in child dies by signal
  instead of reporting exit 0
- __update_download: only exit 0 without staging when the lock holder is
  staging the SAME version; a different in-flight version (or a vanished
  lock) no longer surfaces as a successful foreground upgrade
- staging: sweep orphaned .part downloads and unreferenced staged exes
  before downloading, preserving live swap claims and their payloads

* feat(kimi-code): show download progress for native updates

The foreground 'kimi upgrade' path streamed 180 MB with a single static
'Downloading…' line. Render progress instead: a throttled in-place
percentage line on a TTY, one line per 32 MB when piped, and plain MB
counts when Content-Length is unknown.

* fix(kimi-code): bound native update downloads with an idle timeout

Codex review: the manifest fetch cleared its timer once headers arrived,
so a stalled response body hung the worker forever, and the binary
download had no abort at all. The manifest timeout now covers body
consumption, and the binary stream aborts after 30 s without a chunk
(total duration stays unbounded for slow networks). The idle timeout is
injectable for tests.

* fix(kimi-code): retry native updates blocked by an orphaned active record

Windows real-machine verification surfaced that a parent exiting before
the downloader's exit event leaves a fresh-looking 'active' record that
silently blocks every background retry for the 6 h TTL. For native
installs, lock liveness is the truth past a 60 s spawn grace window:
a held lock means a download is running, a free lock means the record
is an orphan and a new attempt may start. Package-manager sources keep
the TTL behavior (no lock to prove liveness).

* fix: skip staged swap while another instance holds a fresh claim

sweepStaleNativeUpdateArtifacts already detected an in-progress swap in
a concurrent instance, but the result stayed inside the cleanup helper:
startup still claimed a newly published staged.json and ran a second
swap, so the two launchers could rename the install path and delete each
other's rollback backup. Propagate the in-progress signal and skip
claiming until the existing claim is released or goes stale.

* fix: keep the install lock while its holder process is alive

The install lock went stale purely by age (30 min), but the native
downloader is idle-bounded, not duration-bounded: a slow link can
legitimately take longer. Another startup would then sweep the lock and
spawn a second downloader, and both would write and clean the same
.staging paths. Past the age threshold, fall back to a pid liveness
probe (signal 0) — the lock is stale only when the holder is gone.

* fix: keep recovery artifacts on rollback failure and wait out same-version downloads

Two robustness fixes from review:

- native-swap: when moving the staged exe into place fails AND the
  rollback rename fails too (transient lock, AV), the install path is
  left absent and no next launch can start. Discarding the staged
  payload and claim on top of that removes the second recovery copy.
  rollback() now reports its result; on a double failure the swap keeps
  the .bak (which IS the old exe), the staged exe and the claim so
  manual recovery or a re-install still works.
- update-download: a foreground `kimi upgrade` racing a background
  downloader of the same version exited 0 immediately, so the CLI
  printed a success message for a download that could still fail. The
  worker now waits while the same-version holder is in flight, adopts
  the verified staged result (staged.json lands before the lock is
  released), and takes over the download when the holder finished
  without staging.

* fix: stamp the swap claim with a fresh mtime when claiming

rename() preserves the staged metadata's mtime, which can be arbitrarily
old — the background download often finishes hours before the next
launch claims it. A concurrent launch's sweep would then classify the
live claim as crash residue (older than the 5-minute window) and delete
the claim, the staged exe, and eventually the first swap's rollback
backup. Stamp the claim file with the claim time so the staleness check
measures the swap's liveness, not the download's age.

* fix: stamp the claim before the rename so it is born fresh

Stamping after the rename left a window: a concurrent launch could
inspect the claim between the two syscalls, see the staged metadata's
old mtime, and delete the staged executable mid-swap. utimes the state
file first so the claim carries a fresh timestamp from the instant it is
published — no fresh-looking-later intermediate state exists.

* fix: chmod the staged download before publishing it at its final name

A swap claims only the staged METADATA; the staged exe stays in
.staging/. A concurrent same-version downloader (possible because swaps
do not hold the install lock) then re-downloads and renames its .part
over that path. If the swap moves the file into the install path between
the downloader's rename and its post-publish chmod, the chmod lands on a
path that is already gone and the installation is left non-executable —
every future launch fails. Apply the executable mode to the private
.part file before the publishing rename so the staged exe is executable
from the instant it appears.

* fix: publish the install lock atomically via hard link

The 'wx' open exposed a momentarily empty lock file before its contents
were written. A concurrent acquirer reading in that window got a
SyntaxError, treated the lock as stale, swept it and also won — two
"holders" then ran stageNativeUpdate against the same .staging paths.
Write the lock contents to a unique temp file and hard-link it into
place: link() fails when the destination exists (same exclusivity as
'wx') and the lock path only ever appears fully written.

* fix: serialize stale-lock takeover through a secondary lock

A pathname-level delete can never be conditioned on the file still being
the inspected stale instance, so a plain compare-and-delete still loses
exclusivity: two workers classifying the same stale lock could interleave
unlink and publish such that both won (proven by a 20-way contention
test). Takeovers now go through a secondary create-if-absent lock
(install.lock.takeover): the delete+publish section only ever runs in
one process, staleness is re-validated inside it, and a fast-path creator
that wins the briefly-free path simply beats the takeover. The takeover
lock itself is age-swept (a live section lasts microseconds), and handles
only release the lock instance they own.

* fix: verify lock ownership after publish and preserve freshly staged exes

Two more race fixes from review:

- install-lock: the stale-marker sweep repeats the inspect-then-delete
  race one level up — two contenders sweeping the same aged takeover
  marker could both win and enter the main-lock section together.
  Pathname APIs offer no conditional delete, so both the takeover marker
  and the main lock now verify ownership after publishing (unique marker
  content, read-back compare): a racing sweep converts to a single
  survivor instead of two holders. The irreducible residual (a delete
  landing in the microsecond link-to-verify window) degrades to a wasted
  download cycle, never a corrupt install — swap claims guard the exe
  independently.
- native-swap: sweeping a stale swap claim deleted the exe it referenced
  even when a FRESH staged.json referenced the same version-derived name
  (a downloader re-staged the version after the swap crashed), throwing
  away a verified ~180 MB stage. The sweep now preserves any exe the
  current staged metadata still references.

* fix: reject mismatched manifests, take over from dead holders, unique .part names

Three robustness fixes from review:

- native-manifest: the per-release endpoint can answer with ANOTHER
  release's manifest (stale cache, mispublish); its checksums would then
  be applied to this version's binary and fail verification on every
  attempt. Compare the parsed manifest version with the requested one.
- install-lock/update-download: a killed lock holder skips its finally
  and never releases, stranding a waiting foreground `kimi upgrade`
  forever. A lock whose recorded pid is dead is now stale at any age
  (the atomic publish guarantees the pid was alive when written), and
  the same-version wait loop polls the acquisition itself, so a dead
  holder's lock is taken over within one poll instead of never.
  Package-manager spawns are unaffected: they hold the lock only around
  the spawn, and the active-record bookkeeping guards that layer.
- native-stage: the download intermediate is now unique per worker
  (`.part` carries pid + counter), so overlapping same-version workers
  can no longer interleave writes into the same file.

* fix: restrict staging cleanup to updater-owned names and retry short writes

- cleanupStagingOrphans recursively deleted anything it did not
  recognize; the staging dir sits next to the exe and can contain files
  belonging to the user or another tool. Deletion now requires a
  positive match on updater-owned artifact names (staged exes and .part
  intermediates) and only ever unlinks files.
- FileHandle.write may persist fewer bytes than requested (short write,
  e.g. near disk exhaustion) while the running hash and size already
  accounted for the whole chunk — publishing a truncated binary under a
  valid checksum. The chunk write now loops until fully persisted.

* fix: scope failure cleanup, recognize all semvers, reverify staged checksums

Three fixes from review:

- native-stage failure cleanup deleted whatever staged update was
  currently published — including a concurrent worker's valid result
  that its caller had already reported as success. The catch path now
  removes only this attempt's own artifacts: its unique .part file and
  its staged exe name when the current metadata does not reference it.
- The orphan-cleanup ownership check only matched stable x.y.z names;
  prerelease/build-metadata versions (1.2.3-rc.1, 1.2.3+build) would
  never be cleaned and accumulate ~180 MB each. Ownership now derives
  from the semver contract via the semver package's valid().
- The swap path trusted a staged exe whose size matched, though the
  metadata records the release checksum; post-download on-disk damage
  could pass the --version smoke check with corrupted bytes.
  claimStagedUpdate now re-verifies the staged exe's sha256 before
  claiming and discards the stage (for a later re-download) on mismatch
  — paid only when an update is actually pending.

* fix: validate versions before path derivation and honor the update opt-out in the swap

- native-stage: stageNativeUpdate derived staging paths (including the
  cleanup rm targets) from the version before fetchNativeReleaseManifest
  rejected it; a traversal string like `x/../../kimi` would resolve the
  staged-exe cleanup onto the running installation. The semver check now
  happens before any path is derived, and the staged-metadata schema
  constrains exeFileName to a plain file name.
- native-swap: the startup swap ran before the update preflight, so
  KIMI_CODE_NO_AUTO_UPDATE / KIMI_CLI_NO_AUTO_UPDATE stopped gating
  update behavior once a payload was pending. The swap now honors the
  same opt-out: the staged payload stays in place for a later launch
  without the variable, and the current exe starts.

* fix: restrict backup cleanup to updater-owned .bak names

cleanupBackups treated every <exe>.*.bak sibling as swap residue, so a
user's own backup like kimi.config.bak in a shared bin directory was
silently deleted on startup. Only the exact <exe>.bak and the numeric
PID fallback <exe>.<pid>.bak are updater-created — cleanup now
positively matches those two formats.

* fix: claim staged metadata before validating it and let manual upgrades bypass the opt-out

- native-swap: claimStagedUpdate validated the metadata and hashed the
  staged exe BEFORE the atomic rename, so a concurrent downloader
  superseding staged.json in between could get its fresh metadata
  claimed under the older object — the smoke check then failed and
  discard() deleted the newly published stage, recording a failure for
  the wrong version. The claim (utimes + rename) now happens first and
  validation acts on exactly the claimed file; discards use a new
  discardClaimedUpdate that never removes anything a meanwhile-published
  stage references.
- The auto-update env opt-out gated the startup swap unconditionally,
  so an explicit `kimi upgrade` with the variable set staged the
  version but no launch ever applied it. Stages now record
  `manual: true` when they answer a user-initiated install
  (`__update_download --manual`, threaded from installUpdate through
  the hidden sub-command), and the swap applies manual stages even when
  automatic updates are opted out.

* fix: promote adopted stages to manual and preserve claim-referenced payloads

Three follow-up fixes from review:

- An explicit `kimi upgrade` adopting an auto-staged payload (already
  on disk, or still downloading via the wait path) returned before the
  manual marker applied, so under the env opt-out the swap still skipped
  it despite the success message. Both adoption paths now promote the
  staged metadata to manual: true via a new promoteStagedUpdateToManual.
- The download-failure cleanup checked only the current staged metadata,
  but a live swap holds the metadata renamed aside as its claim — a
  failing same-version downloader could delete the exe an active swap
  was about to move into place. The catch path now also preserves names
  referenced by any live swap claim.
- Restoring a claimed stage after a failed exe move used rename, which
  on POSIX replaces a newer staged.json a downloader published during
  the smoke check. The restore is now a create-if-absent hard link: it
  only lands when the state-file path is still free, and the older claim
  is discarded when a newer stage has taken it.

* fix: drop exe deletion from stale-claim cleanup

The stale-claim sweep deleted the referenced exe based on a metadata
snapshot taken before the loop; a downloader republishing the same
version between the read and the unlink would have its fresh payload
deleted after reporting success. Publication can never be synchronized
with a pathname-level snapshot, so the sweep now removes only the claim
files themselves — genuinely unreferenced exes are reaped by the
downloader's own orphan cleanup (keep-set aware) before its next stage.

* fix: never delete the staged exe when discarding a claim

The same publication race existed one level down: a same-version
downloader can rename its fresh payload onto the shared exe path after
the discard's metadata snapshot but before the unlink (payloads publish
before their metadata), and the discard would delete a download whose
caller then reports success with nothing behind it. discardClaimedUpdate
now removes only the claimed metadata file; unreferenced exes are reaped
by the downloader's own orphan cleanup before its next stage.

* fix: only reap staging orphans old enough to be abandoned

The orphan sweep could delete a concurrent worker's freshly renamed
staged exe in the gap before its staged.json lands (payloads publish
before their metadata), turning the admitted duplicate-worker race into
a successful stage with no payload behind it. Unreferenced artifacts are
now only deleted once older than a one-hour grace period — publication
takes milliseconds, so unreferenced AND old means definitively
abandoned.

* fix: honor the persisted auto-update preference in the swap and drop claim-unsafe deletions

- The startup swap gated only on the env opt-out, so a payload staged
  automatically still installed after the user disabled automatic
  updates via [upgrade] auto_install = false. The swap now loads the
  persisted preference (only when an automatic stage is actually
  pending) and skips it, exactly like the env opt-out; manual stages
  still always apply.
- Superseding a staged version deleted its exe through an uncoordinated
  read-then-remove that could pull the payload from a live swap. The
  supersede now removes only the old metadata record — the metadata
  write atomically replaces it, and an unreferenced exe is reaped by a
  later orphan cleanup. removeStagedNativeUpdate, left with no callers,
  is removed.
- docs: the kimi upgrade reference (en + zh) no longer claims Windows
  native installations cannot upgrade automatically; native installs
  download and verify in the foreground and swap on the next start.

* fix: gate on claimed metadata, stop shared-path deletes on failure, exact smoke match

- The opt-out gate evaluated a pre-claim snapshot of the staged
  metadata, but the claim could pick up a different (automatic) stage a
  downloader published in between — smuggling it past the gate. The
  env/preference check now runs on the CLAIMED metadata; when disabled,
  the claim is restored via create-if-absent link so a newer stage is
  never overwritten and a later launch can still apply it. The checksum
  re-verify moves after the gates so opted-out launches stop paying for
  the hash.
- The download-failure cleanup still deleted the shared staged-exe path
  based on snapshot reference checks — the same publication race as the
  paths already fixed. It now removes only the attempt's privately owned
  .part file; the shared exe is left for the age-gated orphan cleanup.
- The smoke check accepted the staged version as a substring of the
  --version output, so a mispublished 1.2.30 binary would satisfy a
  1.2.3 target with a matching manifest checksum. It now requires the
  trimmed output to equal the staged version exactly.

* fix: confirm the manual marker before reporting stage adoption

promoteStagedUpdateToManual silently no-oped when a startup swap had
claimed the state file, while the adoption paths still reported success
with manual: true synthesized — under the env opt-out the restored
automatic metadata would then be skipped on every later launch despite
the upgrade's success message. The helper now verifies the marker with a
confirming read (one retry) and returns whether it persisted; the
already-staged branch falls through to a fresh stage when it does not,
and the same-version wait loop only adopts after a confirmed promotion.

* fix(cli): verify the staged payload digest before adopting it as already-staged

readStagedNativeUpdate checks only the recorded size, so a same-size
corruption after the download was adopted and reported as success, only
for the startup swap's claim-time re-verify to reject and discard it.
Compare the actual sha256 before returning already-staged; a mismatch
falls through and re-stages from the CDN.

* fix(cli): keep staged metadata until its replacement is ready

Two related races around staged.json, both reported against the
duplicate-downloader residual:

- stageNativeUpdate deleted the previous record before downloading its
  replacement; a pathname-only delete can remove a concurrent worker's
  freshly published record, orphaning a payload whose worker already
  reported success. The old record now stays until the final atomic
  metadata write replaces it.
- promoteStagedUpdateToManual wrote the marker unconditionally onto
  whichever generation owned staged.json. It now takes the adopted record
  and promotes only while the on-disk metadata still matches it, and the
  post-write confirmation requires the promoted candidate itself.

* fix(cli): preserve the exe referenced by the current staged record during orphan cleanup

Since the supersede path now keeps the previous staged.json until the
final atomic write replaces it, an aged staged exe is still the
applicable update while its replacement downloads — but
cleanupStagingOrphans only pinned exes referenced by swap claim files,
so a payload older than the grace period was unlinked out from under
its own record. Read staged.json itself in the pinning pass so the
current record's exe is preserved like any live claim's.

* chore(kimi-code): reword the native auto-update changeset

* chore(kimi-code): trim the native auto-update changeset

* fix(cli): support update locking on filesystems without hard links

link() fails with ENOTSUP/ENOSYS/EPERM on FAT/exFAT and some network
mounts, which aborted every native update before the download. Add a
shared createFileIfAbsent primitive (hard-link a fully written temp
file, falling back to an exclusive create + write) and use it for the
install lock, its takeover marker, and the swap's claim restore. The
fallback's create->write gap is observable, so the lock inspection now
grants young unparseable content a publish grace before sweeping it as
crash residue.

* fix(cli): publish staged exes under unique names and recover orphaned claims

Two related robustness fixes in the staged swap flow:

- A staged executable is now published under a unique per-worker name
  (kimi-<version>.<pid>.<epoch-ms>.<n>[.exe]) and never replaced; the
  atomic metadata write retargets the pointer. The pathname a swap
  validates at claim time can no longer be exchanged by a concurrent
  same-version publisher between validation and install.
- restoreClaimedUpdate only drops the claim when the restore landed or a
  newer stage holds the state-file path; transient failures retain it.
  The stale-claim sweep now restores aged claims (create-if-absent)
  instead of deleting them, so a stage orphaned by a dead swap or a
  transient restore failure is retried on a later launch.

* fix(cli): verify the staged payload digest in the lock-wait adoption path

waitForStagedUpdate relied on readStagedNativeUpdate, which checks only
the recorded size: while a holder re-stages a same-size-corrupted
payload (its metadata is replaced only when the repaired generation
publishes), a waiter could promote and report the corrupt stage as
downloaded, and startup would later reject its checksum. Apply the same
integrity bar as stageNativeUpdate's already-staged path — adopt only a
payload that hashes to its recorded checksum; a mismatch falls through
to the lock poll, which takes over once the holder finishes without
repairing it.

* fix(cli): serialize swap critical sections and preserve in-flight publishes

- The fresh-claim sweep is only a directory snapshot: two processes could
  both pass it before either claimed, then rename the same installed exe
  concurrently and delete each other's rollback backup. A create-if-absent
  swap mutex (swap.lock, age-gated like the takeover marker) now serializes
  the executable-renaming section; the loser restores its claim and defers.
  The mutex is released as soon as the new exe is in place, before the
  re-exec, so it is never held for the child session's lifetime.
- claimStagedUpdate no longer destroys a claimed record that is unparseable
  but was young at claim time: on filesystems without hard links the
  exclusive-create publish is observable mid-write, and discarding it would
  orphan the staged exe while the writer reports success. Such a record is
  put back with the same inode so the writer completes it; aged corrupt
  residue and well-formed records with a missing/changed exe are still
  discarded.

* fix(cli): keep backup cleanup inside the swap mutex

The early release let a subsequent swap rename the just-installed exe to
the shared .bak path while the previous swap's cleanup was still about to
unlink that same path, destroying the second swap's rollback source. The
mutex now covers the backup cleanup; the cosmetic staging-dir rmdir and
the re-exec stay outside it.
2026-08-18 17:17:18 +08:00

20 KiB

kimi Command

kimi is the main command for Kimi Code CLI, used to start an interactive session in the terminal. Running it without any arguments opens a new session in the current working directory; combined with different flags, you can resume a previous session, skip approvals, start in Plan mode, or load Skills from a custom directory.

kimi [options]
kimi <subcommand> [options]

Main Command Options

All flags are optional — run kimi directly to enter an interactive session:

Option Short Description
--version -V Print the version number and exit
--help -h Show help information and exit
--session [id] -S Resume a session. With an ID, opens that session directly; without an ID, enters an interactive selector
--continue -c Continue the most recent session in the current working directory, without specifying an ID manually
--model <model> -m Specify a model alias for this launch. When omitted, new sessions use default_model from the config file
--prompt <prompt> -p Run a single prompt non-interactively and stream the Assistant output to stdout. This mode does not open the TUI
--output-format <format> Set the non-interactive output format; supports text and stream-json. Can only be used with --prompt; defaults to text
--yolo -y Auto-approve regular tool calls, skipping approval requests
--auto Start with auto permission mode; tool approvals are handled automatically and the Agent will not ask the user questions
--plan Start a new session in Plan mode — the AI will prioritize read-only tools for exploration and planning
--skills-dir <dir> Load Skills from the specified directory, replacing the automatically discovered user and project directories. Can be repeated
--agent <name> Start a new session with the specified agent as the main Agent. Cannot be combined with --session/--continue
--agent-file <path> Load a custom agent from a Markdown file for the new session and select it. Cannot be repeated or combined with --agent, --session, or --continue
--add-dir <dir> Add an extra workspace directory for this session. Relative paths resolve against the current working directory. Can be repeated

-r / --resume is a hidden alias for --session; --yes and --auto-approve are hidden aliases for --yolo and are not shown in help output.

::: warning --yolo skips human approval for regular tool calls, including file writes and shell command execution. Use it only in trusted working directories. Plan mode exit approval is not bypassed by --yolo; Bash inside Plan mode is handled under the regular allow rules. :::

Flag Conflict Rules

The following combinations are rejected at startup:

  • --continue and --session are mutually exclusive — both mean "resume a previous session"
  • --yolo and --auto are mutually exclusive — the two permission modes cannot be combined
  • --prompt cannot be used with --yolo, --auto, or --plan — non-interactive mode uses auto permission by default
  • --output-format can only be used together with --prompt

When resuming a session, you can override its saved permission or plan mode by adding --auto, --yolo, or --plan. For example, kimi --continue --auto resumes the latest session and switches it to auto permission mode.

Common Usage

Start a new session directly:

kimi

Pick up where you left off (automatically finds the most recent session in the current directory):

kimi --continue

Choose from the session history list, or specify a known ID directly:

kimi --session
kimi --session 01HZ...XYZ

Skip approval prompts — suitable for batch tasks that are known to be safe:

kimi --yolo

Let the Agent handle everything autonomously, without asking the user questions:

kimi --auto

Read the code and produce an implementation plan before making any file changes:

kimi --plan

Custom Skills Directories

There are two ways to specify Skills directories, with different semantics:

  • --skills-dir <dir> (CLI flag): Replaces the automatically discovered user and project directories for this launch only. Can be repeated to stack multiple directories:

    kimi --skills-dir /path/to/team-skills --skills-dir ./local-skills
    
  • extra_skill_dirs (config.toml): Adds directories on top of the automatically discovered ones, taking effect permanently. Suitable for configuring team-shared Skills. See Agent Skills.

Custom Agents

--agent and --agent-file select which agent drives a new session, in both print mode (kimi -p) and the interactive TUI:

kimi --agent reviewer
kimi -p --agent reviewer "Review the changes on this branch"

--agent-file registers a single agent file at the highest priority for this launch only and selects it; the flag cannot be repeated, and --agent and --agent-file are mutually exclusive. Both flags only apply when starting a new session — neither can be combined with --session/--continue, because the agent is bound at session creation and resuming restores the bound agent automatically. The selection is fixed at the session's first bind and cannot be switched later; in the TUI the flags bind only the startup session, and a session created later in the same process (for example via /new) starts with the default agent. See Agents and Sub-Agents for the agent file format and discovery directories.

Non-Interactive Execution

When running a single prompt in a script or CI environment, use -p:

kimi -p "Summarize the current repository status"

Output uses a transcript style: thinking content and Assistant text are both prefixed with , and wrapped lines are indented by two spaces. Assistant text goes to stdout; thinking, tool progress, and "resuming session" notices go to stderr. In -p mode, no human approval is requested — regular tool calls are handled under the auto permission policy, while static deny rules remain in effect.

Temporarily switch the model:

kimi -m kimi-code/kimi-for-coding -p "Explain the latest diff"

When you need to parse output programmatically, use the stream-json format — each line on stdout is a JSON object:

kimi -p "List changed files" --output-format stream-json

In stream-json mode, regular replies produce an Assistant message; when the model calls a tool, an Assistant message with tool_calls is emitted first, followed by the corresponding Tool message, then subsequent Assistant messages. Thinking content is not written to JSONL; tool progress and "resuming session" notices are still written to stderr.

Subcommands

kimi provides the following subcommands: login (non-interactive login), acp (ACP IDE mode), web (run the local REST/WebSocket/web service in the foreground and open the web UI), doctor (validate configuration files), export (export a session), migrate (migrate legacy data), upgrade (check for updates), and provider (manage providers).

kimi login

Log in to Kimi Code OAuth via the RFC 8628 device-code flow, without entering the TUI. The command issues a device authorization request, prints the verification URL and user code to stderr, then polls until the browser-side authorization is complete. The generated token is written to the same local location as TUI /login and is loaded automatically the next time kimi starts.

kimi login

This subcommand has no flags. Press Ctrl-C at any time during polling to cancel; the exit code is 1 on cancellation or failure, and 0 on success.

kimi acp

Switch Kimi Code CLI to ACP (Agent Client Protocol) mode, communicating with an IDE via JSON-RPC over stdin/stdout so the editor can directly drive kimi's sessions and tool calls. You typically do not need to run this manually — the IDE starts it as a subprocess entry point. For configuration, see Using in IDEs; for technical details, see the kimi acp reference.

kimi acp

kimi web

Run the local Kimi server in the foreground of the current terminal — a single process that exposes the REST + WebSocket API and serves the web UI from the same origin — and open the web UI in the default browser once it is ready. The command stays attached to the terminal and shuts down cleanly on SIGINT / SIGTERM (e.g. Ctrl-C).

When the server is running, GET /openapi.json returns the REST OpenAPI document and GET /asyncapi.json returns the local WebSocket AsyncAPI document. For an end-to-end walkthrough of driving sessions over the API, see Local server and API; for the protocol details, see the Server API reference.

kimi web                 # run the server in the foreground and open the browser
kimi web --no-open       # don't open the browser
kimi web --port 58628    # pick a specific bind port

Multiple instances can share one home directory: each registers itself under ~/.kimi-code/server/instances/, and a busy port is retried with port + 1 (58628, 58629, …).

Option Description
--port <port> Bind port; defaults to 58627; a busy port is retried with +1
--host [host] Bind host; omit for 127.0.0.1 (this machine only), pass a bare --host for 0.0.0.0 (all interfaces)
--allowed-host <host...> Extra Host header values allowed through the DNS-rebinding check; repeatable or comma-separated
--log-level <level> Enable server logs at the selected level; omitted by default
--debug-endpoints Mount /api/v1/debug/* routes (off by default)
--dangerous-bypass-auth Disable bearer-token auth on all REST and WebSocket routes so the web UI connects without a token; only for trusted networks or behind an authenticating proxy
--no-open Do not open the browser once the server is ready

kimi web binds to local loopback only by default and prints the bearer token in the startup banner; the web UI authenticates automatically via the #token= URL fragment.

::: info The kimi server command tree is deprecated: any kimi server … invocation (including all legacy subcommands) only prints a deprecation notice and exits with code 1 — use kimi web instead. The one exception is kimi server kill, which stays functional for stopping servers started by a version before 0.28.0. The notice will be removed in the next major version of Kimi Code. :::

::: danger --dangerous-bypass-auth disables authentication entirely. Anyone who can reach the port gets full access to your sessions, filesystem, and shell. Only use it on a trusted network or behind your own authenticating reverse proxy, and stop the server with Ctrl+C when you are done. :::

kimi server kill

Deprecated — only stops a server started by a version before 0.28.0. Those versions could leave a background server behind, recorded in the legacy single-instance lock at ~/.kimi-code/server/lock; the command first tries POST /api/v1/shutdown for a graceful exit, then signals the recorded pid with SIGTERM, escalating to SIGKILL when needed, and removes the lock file once the process is confirmed dead. Servers started by kimi web run in the foreground — stop them with Ctrl+C instead.

kimi web rotate-token

Generate a new persistent bearer token (written to ~/.kimi-code/server.token); the previous token stops working immediately. The token is shared by the whole home directory, so every running instance picks the new one up on its next auth check — no restart needed.

kimi doctor

Validate config.toml and tui.toml without starting the TUI or modifying either file. By default, the command checks the files under KIMI_CODE_HOME (or ~/.kimi-code when the environment variable is unset). Missing default files are reported as skipped because built-in defaults can apply.

kimi doctor
Command Description
kimi doctor Validate the default config.toml and tui.toml
kimi doctor config [path] Validate only config.toml, using path instead of the default file when provided
kimi doctor tui [path] Validate only tui.toml, using path instead of the default file when provided

When an explicit path is passed, the file must exist. The command exits with 0 when all checked files are valid or skipped, and 1 when any requested file is missing or invalid.

# Check the default config files
kimi doctor

# Check only the default runtime config
kimi doctor config

# Check a candidate TUI config before replacing the live config
kimi doctor tui ./tui.toml

kimi export

Package a session into a ZIP file for sharing, archiving, or submitting bug reports.

kimi export [sessionId] [options]
Parameter / Option Short Description
sessionId The ID of the session to export. When omitted, the most recent session in the current working directory is automatically selected and requires confirmation
--output <path> -o Output ZIP file path. When omitted, writes to a default filename in the current directory
--yes -y Skip the confirmation prompt for the default session and export directly
--no-include-global-log Do not include the global diagnostic log. Included by default

The export contains all files in the target session directory. The global diagnostic log (~/.kimi-code/logs/kimi-code.log) is included by default because it may contain events from other sessions or projects; add --no-include-global-log if you do not want to share it.

# Export the most recent session in the current directory, skipping confirmation
kimi export -y

# Export a specific session to a custom path
kimi export 01HZ...XYZ -o ./bug-report.zip

# Exclude the global diagnostic log
kimi export 01HZ...XYZ -o ./bug-report.zip --no-include-global-log

kimi migrate

Migrate local data from a legacy kimi-cli installation to kimi-code, including session history and configuration files. Runs entirely interactively, guiding you through the full process.

kimi migrate

For full migration instructions, see Migrating from kimi-cli.

kimi upgrade

Immediately check for the latest version and display an update prompt; exits after you make a selection. kimi update is an alias for this command.

kimi upgrade

For global npm, pnpm, yarn, and bun installations, kimi upgrade shows update options; selecting Install update now runs the corresponding foreground install command. For native installations (including Windows), it downloads and verifies the new binary in the foreground and swaps it in on the next start. When the current installation method cannot be upgraded automatically, the manual update command is printed instead.

kimi vis

Launch the session visualizer in your browser to inspect a session as it unfolds. The command starts an in-process server pointed at your local sessions, prints the URL, opens your browser, and keeps running until you press Ctrl-C.

kimi vis [sessionId] [options]
Parameter / Option Description
sessionId Open the visualizer directly to this session. When omitted, it opens the home view listing your sessions
--port <number> Port to bind. By default an available port is picked automatically
--host <host> Host to bind. Default: 127.0.0.1
--no-open Do not open the browser automatically; just print the URL
# Start the visualizer and open the browser at the home view
kimi vis

# Open directly to a specific session
kimi vis 01HZ...XYZ

# Bind a fixed port and host without opening a browser (e.g. on a remote host)
kimi vis --host 0.0.0.0 --port 8123 --no-open

kimi provider

Manage providers in the shell — the non-interactive equivalent of /provider in the TUI. Suitable for scripted deployments, CI initialization, and one-line setup on a new machine.

kimi provider <action> [options]

Five actions are available:

kimi provider add <url>

Bulk-import all providers from a custom registry (api.json). The command fetches the registry, creates a [providers.<id>] and [models.<alias>] entry for each item, and writes source metadata so the TUI refreshes providers and models from the same registry URL automatically on next startup.

Parameter / Option Description
<url> Registry URL
--api-key <key> Bearer token for accessing the registry. Falls back to the KIMI_REGISTRY_API_KEY environment variable if not provided; required
kimi provider add https://registry.example.com/v1/models/api.json --api-key YOUR_KEY

# Or via environment variable (suitable for CI / .envrc)
KIMI_REGISTRY_API_KEY=YOUR_KEY kimi provider add https://registry.example.com/v1/models/api.json

If a provider ID already exists, it is removed and re-created. The default model is not set automatically; you can select one later with -m or /model in the TUI.

kimi provider remove <providerId>

Remove the specified provider and all its model aliases. If the removed provider is the one referenced by default_model, default_model is also cleared.

kimi provider remove kohub

kimi provider list

Print each configured provider on a separate line, including type, model count, and source. Add --json to output the raw providers and models tables for programmatic processing.

kimi provider list
kimi provider list --json | jq '.providers | keys'

kimi provider catalog list [providerId]

Browse the public models.dev model catalog without modifying any configuration. Without an argument, lists all providers along with their protocol type and model count; with a providerId, lists all models under that provider along with their context window and capabilities. If the catalog URL cannot be reached, a built-in snapshot of the catalog is used instead.

Parameter / Option Description
[providerId] Optional — the provider ID to inspect
--filter <substring> Case-insensitive substring filter on ID or name
--url <url> Override the catalog URL; defaults to https://models.dev/api.json
--json Output matching entries as JSON
kimi provider catalog list
kimi provider catalog list --filter anthropic
kimi provider catalog list anthropic

kimi provider catalog add <providerId>

Import a known provider directly from the catalog by ID. The protocol type, base URL, and model information are all supplied by the catalog — only an API key is required. Vendors whose protocol the catalog does not declare (e.g. xai, openrouter, and other vendor-specific SDKs) are imported as OpenAI-compatible and the output notes the guess; when the catalog provides no usable endpoint, --base-url is required. Proprietary protocols (e.g. Amazon Bedrock) cannot be imported. When the public catalog is unreachable, the import uses the built-in snapshot, so it still works offline or in blocked networks.

Parameter / Option Description
<providerId> Provider ID in the catalog, e.g., anthropic, openai
--api-key <key> Provider API key. Falls back to KIMI_REGISTRY_API_KEY if not provided; required
--default-model <modelId> Optional — set default_model to <providerId>/<modelId> after import
--base-url <url> Override the catalog endpoint; required when the catalog declares none (or only an env placeholder)
--url <url> Override the catalog URL; defaults to https://models.dev/api.json
kimi provider catalog list anthropic          # Browse available models first
kimi provider catalog add anthropic --api-key sk-ant-... --default-model claude-opus-4-7

Next steps

  • Slash Commands — Quick reference for control commands in the interactive TUI
  • Configuration Files — Persistent configuration for default_model, permission mode, and other startup parameters
  • Agent Skills — Skill file format for directories loaded via --skills-dir
  • Agents and Sub-Agents — Built-in sub-agents, custom agent files, and main Agent selection via --agent