> ## Documentation Index
> Fetch the complete documentation index at: https://docs.e2b.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Kimi Code CLI

> Run Moonshot AI's Kimi Code CLI in a secure E2B sandbox with full filesystem, terminal, and git access.

[Kimi Code CLI](https://github.com/MoonshotAI/kimi-code) is Moonshot AI's coding agent and CLI. E2B provides a pre-built `kimi` template with Kimi Code CLI already installed.

## CLI

Create a sandbox with the [E2B CLI](https://docs.e2b.dev/cli.md).

```bash theme={"theme":"css-variables"}
e2b sbx create kimi
```

Once inside the sandbox, start Kimi Code CLI.

```bash theme={"theme":"css-variables"}
kimi
```

On first launch, Kimi Code CLI asks you to trust the current folder. Then run `/login` to sign in with Kimi Code OAuth or a Moonshot AI API key.

## Run headless

Use `-p` to run a single prompt non-interactively. In this mode Kimi Code CLI never asks for approval and runs tool calls automatically. The sandbox isolates the agent from your host machine, but sandboxes can reach the open internet by default — restrict outbound traffic with [network rules](https://docs.e2b.dev/network/internet-access.md).

Kimi Code CLI authenticates with an API key from the [Moonshot AI Open Platform](https://platform.moonshot.ai). Pass the key as `KIMI_MODEL_API_KEY` and the model as `KIMI_MODEL_NAME`. Kimi Code CLI does not read `KIMI_API_KEY` from the environment.

> [!NOTE]
>
> Auto-approving tool calls is contained by the sandbox: the agent cannot touch your host machine, local files, or credentials. It can still make outbound network requests — internet access is enabled by default. To limit where an auto-approved agent can connect, configure [outbound network rules](https://docs.e2b.dev/network/internet-access.md) (`allowInternetAccess`, plus allow/deny lists by CIDR or hostname). Hostname rules apply to HTTP(S) traffic only; use CIDR rules for other protocols.

```typescript JavaScript & TypeScript theme={"theme":"css-variables"}
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('kimi', {
  envs: {
    KIMI_MODEL_NAME: 'kimi-k3',
    KIMI_MODEL_API_KEY: process.env.MOONSHOT_API_KEY,
  },
})

const result = await sandbox.commands.run(
  `kimi -p "Create a hello world HTTP server in Go"`,
  { timeoutMs: 0 }
)

console.log(result.stdout)
await sandbox.kill()
```

```python Python theme={"theme":"css-variables"}
import os
from e2b import Sandbox

sandbox = Sandbox.create("kimi", envs={
    "KIMI_MODEL_NAME": "kimi-k3",
    "KIMI_MODEL_API_KEY": os.environ["MOONSHOT_API_KEY"],
})

result = sandbox.commands.run(
    'kimi -p "Create a hello world HTTP server in Go"',
    timeout=0,
)

print(result.stdout)
sandbox.kill()
```

The assistant's reply goes to stdout; thinking and tool progress go to stderr. If the key is missing or invalid, `kimi` exits with code `1` and prints the error to stderr. To use an OpenAI or Anthropic model instead, set `KIMI_MODEL_PROVIDER_TYPE` to `openai` or `anthropic`, set `KIMI_MODEL_NAME` to a model from that provider, and pass that provider's key as `KIMI_MODEL_API_KEY`.

### Example: work on a cloned repository

```typescript JavaScript & TypeScript theme={"theme":"css-variables"}
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('kimi', {
  envs: {
    KIMI_MODEL_NAME: 'kimi-k3',
    KIMI_MODEL_API_KEY: process.env.MOONSHOT_API_KEY,
  },
  timeoutMs: 600_000,
})

await sandbox.commands.run(
  'git clone --depth 1 https://x-access-token:$GITHUB_TOKEN@github.com/your-org/your-repo.git /home/user/repo',
  { envs: { GITHUB_TOKEN: process.env.GITHUB_TOKEN } }
)

const result = await sandbox.commands.run(
  `cd /home/user/repo && kimi -p "Add error handling to all API endpoints"`,
  { onStdout: (data) => { process.stdout.write(data) }, timeoutMs: 0 }
)

const diff = await sandbox.commands.run('cd /home/user/repo && git diff')
console.log(diff.stdout)

await sandbox.kill()
```

```python Python theme={"theme":"css-variables"}
import os
from e2b import Sandbox

sandbox = Sandbox.create("kimi", envs={
    "KIMI_MODEL_NAME": "kimi-k3",
    "KIMI_MODEL_API_KEY": os.environ["MOONSHOT_API_KEY"],
}, timeout=600)

sandbox.commands.run(
    "git clone --depth 1 https://x-access-token:$GITHUB_TOKEN@github.com/your-org/your-repo.git /home/user/repo",
    envs={"GITHUB_TOKEN": os.environ["GITHUB_TOKEN"]},
)

result = sandbox.commands.run(
    'cd /home/user/repo && kimi -p "Add error handling to all API endpoints"',
    on_stdout=lambda data: print(data, end=""),
    timeout=0,
)

diff = sandbox.commands.run("cd /home/user/repo && git diff")
print(diff.stdout)

sandbox.kill()
```

## Streaming events

Add `--output-format stream-json` to get a JSONL event stream on stdout. Each line is a JSON object with a `role`: `assistant` for model replies (including `tool_calls`), `tool` for tool results, and `meta` for run metadata, such as the CLI version. The last event is `session.resume_hint`, which carries the session ID. See [Resume a session](#resume-a-session).

```typescript JavaScript & TypeScript theme={"theme":"css-variables"}
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('kimi', {
  envs: {
    KIMI_MODEL_NAME: 'kimi-k3',
    KIMI_MODEL_API_KEY: process.env.MOONSHOT_API_KEY,
  },
})

let buffer = ''
const result = await sandbox.commands.run(
  `kimi -p "Create hello.py that prints hello, then run it" --output-format stream-json`,
  {
    timeoutMs: 0,
    onStdout: (data) => {
      buffer += data
      const lines = buffer.split('\n')
      buffer = lines.pop() ?? ''
      for (const line of lines.filter(Boolean)) {
        const event = JSON.parse(line)
        console.log(`[${event.role}]`, event)
      }
    },
  }
)

await sandbox.kill()
```

```python Python theme={"theme":"css-variables"}
import os
import json
from e2b import Sandbox

sandbox = Sandbox.create("kimi", envs={
    "KIMI_MODEL_NAME": "kimi-k3",
    "KIMI_MODEL_API_KEY": os.environ["MOONSHOT_API_KEY"],
})

buffer = ""

def handle_event(data):
    global buffer
    buffer += data
    *lines, buffer = buffer.split("\n")
    for line in filter(None, lines):
        event = json.loads(line)
        print(f"[{event['role']}]", event)

result = sandbox.commands.run(
    'kimi -p "Create hello.py that prints hello, then run it" --output-format stream-json',
    on_stdout=handle_event,
    timeout=0,
)

sandbox.kill()
```

## Resume a session

Kimi Code CLI stores each session under `~/.kimi-code/sessions` in the sandbox. Run the first task with `--output-format stream-json`, read the session ID from the last event (`session.resume_hint`), and pass it to `kimi -r <id>` to continue the same session.

```typescript JavaScript & TypeScript theme={"theme":"css-variables"}
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('kimi', {
  envs: {
    KIMI_MODEL_NAME: 'kimi-k3',
    KIMI_MODEL_API_KEY: process.env.MOONSHOT_API_KEY,
  },
  timeoutMs: 600_000,
})

// Start a new session
const initial = await sandbox.commands.run(
  `kimi -p "Create todo.py, a CLI that adds items to todo.txt" --output-format stream-json`,
  { timeoutMs: 0 }
)

// The last event is session.resume_hint
const lines = initial.stdout.trim().split('\n')
const sessionId = JSON.parse(lines[lines.length - 1]).session_id

// Continue in the same session
await sandbox.commands.run(
  `kimi -r ${sessionId} -p "Add a list command to todo.py"`,
  { onStdout: (data) => { process.stdout.write(data) }, timeoutMs: 0 }
)

const code = await sandbox.commands.run('cat /home/user/todo.py')
console.log(code.stdout)

await sandbox.kill()
```

```python Python theme={"theme":"css-variables"}
import os
import json
from e2b import Sandbox

sandbox = Sandbox.create("kimi", envs={
    "KIMI_MODEL_NAME": "kimi-k3",
    "KIMI_MODEL_API_KEY": os.environ["MOONSHOT_API_KEY"],
}, timeout=600)

# Start a new session
initial = sandbox.commands.run(
    'kimi -p "Create todo.py, a CLI that adds items to todo.txt" --output-format stream-json',
    timeout=0,
)

# The last event is session.resume_hint
session_id = json.loads(initial.stdout.strip().splitlines()[-1])["session_id"]

# Continue in the same session
sandbox.commands.run(
    f'kimi -r {session_id} -p "Add a list command to todo.py"',
    on_stdout=lambda data: print(data, end=""),
    timeout=0,
)

code = sandbox.commands.run("cat /home/user/todo.py")
print(code.stdout)

sandbox.kill()
```

To continue the most recent session in the working directory without an ID, use `kimi -c -p "follow-up task"`.

## Build a custom template

If you need to customize the environment (e.g. pre-install dependencies, add config files), build your own [custom template](https://docs.e2b.dev/template/quickstart.md) on top of the pre-built `kimi` template.

```typescript JavaScript & TypeScript theme={"theme":"css-variables"}
// template.ts
import { Template } from 'e2b'

export const template = Template()
  .fromTemplate('kimi')
```

```python Python theme={"theme":"css-variables"}
# template.py
from e2b import Template

template = (
    Template()
    .from_template("kimi")
)
```

```typescript JavaScript & TypeScript theme={"theme":"css-variables"}
// build.ts
import { Template, defaultBuildLogger } from 'e2b'
import { template as kimiTemplate } from './template'

await Template.build(kimiTemplate, 'my-kimi', {
  cpuCount: 2,
  memoryMB: 2048,
  onBuildLogs: defaultBuildLogger(),
})
```

```python Python theme={"theme":"css-variables"}
# build.py
from e2b import Template, default_build_logger
from template import template as kimi_template

Template.build(kimi_template, "my-kimi",
    cpu_count=2,
    memory_mb=2048,
    on_build_logs=default_build_logger(),
)
```

Run the build script to create the template.

```bash JavaScript & TypeScript theme={"theme":"css-variables"}
npx tsx build.ts
```

```bash Python theme={"theme":"css-variables"}
python build.py
```

## Related guides

> [card] [Sandbox persistence](https://docs.e2b.dev/sandbox/persistence.md)
>
> Auto-pause, resume, and manage sandbox lifecycle

> [card] [SSH access](https://docs.e2b.dev/sandbox/ssh-access.md)
>
> Connect to the sandbox via SSH for interactive sessions
