This tutorial will show you how to configure and use Kimi CLI As a non-interactive AI coder. The CLI is installed through uv, with an isolated Python 3 environment. We configure Moonshot API Authentication through a TOML based provider and Model Definition, and create a Python wrapper that can be reused to run non-interactive CLI Commands. Kimi will be applied in a realistic workflow, whereby we analyze a source code base, determine implementation risks, modify the files autonomously, run unit tests and validation commands. The project is iterated until its test suite passes. In addition, we explore JSONL structured event streams, multi-turn persistent sessions, plan mode and Ralph loops. We also examine MCP Integrations, web-based access and session export.
Install Kimi CLI and Set Up Environment
import os, subprocess, textwrap, json, getpass, pathlib, shutil
Home = pathlib.Path.home()
def sh(cmd, check=True, env=None, cwd=None):
"""Run a shell command, stream its output, return CompletedProcess."""
print(f"n$ {cmd}")
e = {**os.environ, **(env or {})}
r = subprocess.run(cmd, shell=True, env=e, cwd=cwd,
capture_output=True, text=True)
If r.stdout, then print(r.stdout).
If R.Stderr is present: Print(R.Stderr[-2000:])
If check and returncode == 0, then:
raise RuntimeError(f"Command failed ({r.returncode}): {cmd}")
Return r
print("=" * 70, "nPART 1: Installing uv + Kimi CLIn", "=" * 70)
sh("curl -LsSf https://astral.sh/uv/install.sh | sh")
UV_BIN = str(HOME / ".local" / "bin")
os.environ["PATH"] I = F"{UV_BIN}:{os.environ['PATH']}"
sh("uv tool install --python 3.13 kimi-cli")
sh("kimi --version")
To begin, we import all the necessary Python modules. We then define a shell-command assister to control subprocess execution. We then install uv. Add its binary directory into the environment path and configure Kimi with an isolated Python runtime 3.13. We verify the installation using the Kimi version installed.
Moonshot API Model Access and Authentication Configuration
print("=" * 70, "nPART 2: Configuring API accessn", "=" * 70)
try:
Import userdata from Google.colab
API_KEY = userdata.get("MOONSHOT_API_KEY")
print("Loaded key from Colab Secrets.")
The exception:
API_KEY = getpass.getpass("Paste your Moonshot API key (hidden): ")
BASE_URL = "https://api.moonshot.ai/v1"
MODEL_NAME = "kimi-k2-0711-preview"
Home = kimi_dir ".kimi"
kimi_dir.mkdir(exist_ok=True)
(kimi_dir / "config.toml").write_text(textwrap.dedent(f"""
default_model = "kimi-k2"
[providers.moonshot]
Type = "kimi"
base_url = "{BASE_URL}"
api_key = "{API_KEY}"
[models.kimi-k2]
Provider "moonshot"
model = "{MODEL_NAME}"
max_context_size = 131072
"""))
print("Wrote ~/.kimi/config.toml")
The Moonshot API Key can be securely retrieved from Google Colab Secrets, or requested via an input prompt hidden. Create the.kimi file configuration directory after defining the Moonshot API target model and endpoint. We add the model, provider, context window and default settings for the model to config.toml.
How to Create a Kimi Wrapper that is Non-Interactive and Reusable
Def kimi (prompt, Work_dir=".", yolo=False, cont=False, quiet=True,
stream_json=False, extra="", timeout=600):
"""Run one headless Kimi CLI turn and return its stdout."""
Flags []
if stream_json
flags.append("--print --output-format stream-json")
elif quiet:
flags.append("--quiet")
else:
flags.append("--print")
If flags.append: yolo("--yolo")
if flags.append ("--continue")
flags.append(f'-w "{work_dir}"')
If extra: flags.append (extra)Cmd = f’kimi
cmd = f'kimi {" ".join(flags)} -p "{prompt}"'
print(f"n$ {cmd}n" + "-" * 60)
Subprocess.run() (cmd) with shell=True. Capture output is enabled.
text=True, timeout=timeout)
Strip = out()
If out, print a message else press r.stderr[-1500:])
Return out
A Python wrapper allows Kimi CLI commands to be run programmatically and without a terminal. The flags are dynamically assembled for silent output, JSON streaming, tool autonomy, continuation of session, working-directory separation, and step limit. The command output is captured, the error or response details are displayed, and the result returned for further processing.
Making and Analyzing Realistic Samples
print("=" * 70, "nPART 4: Demo A — codebase Q&An", "=" * 70)
Pathlib.Path = proj"/content/demo_project")
If the proj. exists(): shutil.rmtree(proj)
(proj / "app").mkdir(parents=True)
(proj / "app" / "inventory.py").write_text(textwrap.dedent("""
class Inventory:
def __init__(self):
self.items = {}
Def Add(self, Name, Qty)
self.items[name] = self.items.get(name, 0) + qty
def remove(self, name, qty):
# BUG: Allows negative stock and keyError to be displayed on missing items
self.items[name] = self.items[name] - qty
Def Total (self)
return sum(self.items.values())
"""))
(proj / "app" / "main.py").write_text(textwrap.dedent("""
Import Inventory
inv = Inventory()
inv.add("widget", 10)
inv.remove("widget", 3)
print("Total stock:", inv.total())
"""))
(proj / "README.md").write_text("# Demo: a tiny inventory servicen")
kimi("Summarize this project's structure and purpose in under 120 words, "
"then list any bugs or design risks you can spot in inventory.py.",
work_dir=str(proj))
The project includes an executable, a Python module and a Readme file. Kimi will be able to identify design and functional risks by inspecting the repository’s structure. We include intentional implementation bugs. After that, we ask for a short technical evaluation by running a project analysis read-only in the directory.
Automating code repair, testing, and independent validation
print("=" * 70, "nPART 5: Demo B — Kimi fixes the bug & adds testsn", "=" * 70)
kimi("Fix the bugs in app/inventory.py: remove() must raise KeyError->ValueError "
"for unknown items and never allow negative stock. Then create tests.py at "
"the project root using unittest covering add/remove/total and edge cases, "
"run it with 'python -m unittest tests -v', and iterate until all tests pass. "
"Finally print the test results.",
work_dir=str(proj), yolo=True, extra="--max-steps-per-turn 30")
print("n--- Files after Kimi's edits ---")
For f in the sorted(proj.rglob"*.py")):
print(f"n### {f.relative_to(proj)} ###n{f.read_text()}")
sh("python -m unittest tests -v", cwd=str(proj), check=False)
Kimi can modify the project independently, fix the inventory logic and generate unit test. Then, the entire suite of tests is executed. Configure a maximum number of agent steps so that the model is able to iteratively detect failures, and then refine implementations until successful validation. We examine the Python files generated and run the tests independently again to ensure that the changes are working correctly.
Discovering Structured JSONL Sessions and Advanced Features
print("=" * 70, "nPART 6: Demo C — machine-readable JSONL eventsn", "=" * 70)
raw = kimi("In one sentence, what does app/main.py print when run?",
work_dir=str(proj), stream_json=True, quiet=False)
print("nParsed event types:")
Line in Raw. Splitlines():
try:
evt = line.loads.json
print(" •", evt.get("type", "?"), "-",
str(evt)[:100].replace("n", " "))
except json.JSONDecodeError:
pass
print("=" * 70, "nPART 7: Demo D — conversational memoryn", "=" * 70)
kimi("Remember this: our release codename is BLUE-FALCON.", work_dir=str(proj))
kimi("What is our release codename? Answer with just the codename.",
work_dir=str(proj), cont=True)
print("=" * 70, "nPART 8: Power-user referencen", "=" * 70)
print(textwrap.dedent("""
# Plan mode — read-only exploration, produces an implementation plan:
kimi --quiet --plan -w /content/demo_project -p "Plan adding SQLite persistence"
# Choose a different model (must be in config.toml).
kimi --quiet -m kimi-k2 -p "hello"
# Think mode (if model supports)
"kimi - quiet -- thinking -p" "Prove sqrt(2) is irrational"
# Ralph loop — feed the same prompt repeatedly for one big task
# until you see the Agent outputs STOP Or the limit is hit:
kimi --print --yolo --max-ralph-iterations 5 -w /content/demo_project
-p "Keep improving test coverage; STOP when everything is covered."
# MCP tools — give Kimi extra capabilities via an MCP config file:
# /content/mcp.json -> {"mcpServers": {"context7":
# {"url": "https://mcp.context7.com/mcp",
# "headers": {"CONTEXT7_API_KEY": "YOUR_KEY"}}}}
kimi --quiet --mcp-config-file /content/mcp.json -p "Use context7 to ..."
# Debug a session by exporting a context.jsonl (wire.jsonl), state.jsonl and context.jsonl.
Kimi export --yes
# Web UI. (Needs tunnel in Colab. Since it's cloudflared/ngrok
# Binds local): kimi Web --noopen --port 549
"""))
print("Tutorial complete ✔ — Kimi CLI is installed, authenticated, and has "
"explored, fixed, tested, and remembered a real project headlessly.")
Kimi is executed with JSONL events and we parse them to determine the machine-readable types of response. In order to demonstrate persistent multi-turn memories, we store a release codename in a working directory and retrieve it at arbitrary times during the session. In conclusion, we review advanced commands in planning, Ralph loops and MCP, as well as model switching, Ralph mode, the thinking mode.
As a conclusion, we created an end-toend Kimi CLI work flow that doesn’t rely at all on an interactive terminal session. The workflow moved from the provisioning of environments and configurations to projects analysis, code generation and repair by autonomous means, testing, output structure parsing and continuation. Independently verifying the changes made by the agent helps distinguish the generated outputs from the actual results of execution and increases the reliability. We can extend this architecture, using the reusable wrapper commands and reference command, to other AI-assisted workflows.
Take a look at the Full Code here. Also, feel free to follow us on Twitter Don’t forget about our 150k+ML SubReddit Subscribe Now our Newsletter. Wait! Are you using Telegram? now you can join us on telegram as well.
You can partner with us to promote your GitHub Repository OR Hugging Page OR New Product Launch OR Webinar, etc.? Connect with us

