# Kimi CLI Session Management Architecture: How `Session.create` and `Session.resume` Operate

> Explore Kimi CLI session management architecture. Learn how Session create initializes new sessions and Session resume reloads existing conversations from disk, persisting your chat state.

- Repository: [Moonshot AI/kimi-cli](https://github.com/MoonshotAI/kimi-cli)
- Tags: architecture
- Published: 2026-07-22

---

**Kimi CLI persists conversation state through filesystem-bound sessions where `Session.create` initializes new storage structures in a work directory, while `Session.resume` (implemented internally as `Session.continue_`) reloads the last active session by reading global metadata and reconstructing the session state from disk.**

The MoonshotAI/kimi-cli repository implements a durable session management subsystem that binds conversational state to specific work directories on disk. The architecture leverages the `Session` class in [`src/kimi_cli/session.py`](https://github.com/MoonshotAI/kimi-cli/blob/main/src/kimi_cli/session.py) to provide atomic entry points for spinning up fresh contexts via `Session.create` and retrieving existing ones through resume operations, ensuring continuity across shell invocations and ACP API calls.

## Core Components of the Session Stack

### WorkDirMeta and Global Metadata

The foundation of session anchoring is the **`WorkDirMeta`** class defined in [`src/kimi_cli/metadata.py`](https://github.com/MoonshotAI/kimi-cli/blob/main/src/kimi_cli/metadata.py). This structure stores work-directory-specific information, including the path to the sessions folder (`.kimi/sessions`) and the **`last_session_id`** pointer that tracks which session was most recently active. The module exposes **`load_metadata()`** and **`save_metadata()`** functions that hydrate or persist this global state from a JSON file located in the work directory’s metadata path.

### SessionState, WireFile, and Context Storage

Per-session mutable data—such as custom titles, archive flags, and plan mode settings—is managed by the **`SessionState`** class in [`src/kimi_cli/session_state.py`](https://github.com/MoonshotAI/kimi-cli/blob/main/src/kimi_cli/session_state.py). The actual conversation history is recorded in two separate persistence layers:

- **`context.jsonl`**: A line-delimited JSON file storing high-level user-assistant message pairs.
- **`WireFile`** ([`src/kimi_cli/wire/file.py`](https://github.com/MoonshotAI/kimi-cli/blob/main/src/kimi_cli/wire/file.py)): A wrapper around `wire.jsonl` that records low-level wire events, including `TurnBegin` markers and tool call telemetry.

These files reside inside each session’s dedicated subdirectory, allowing the system to reconstruct full conversation context without parsing the entire UI layer.

## Creating New Sessions with `Session.create`

The static method **`Session.create`** in [`src/kimi_cli/session.py`](https://github.com/MoonshotAI/kimi-cli/blob/main/src/kimi_cli/session.py) ([lines 29‑80](https://github.com/MoonshotAI/kimi-cli/blob/main/src/kimi_cli/session.py#L29-L80)) handles the atomic initialization of a new session. The operation executes the following steps:

1. **Canonicalize** the supplied `KaosPath` using `work_dir.canonical()` to ensure absolute, normalized paths.
2. **Load global metadata** via `load_metadata()` and fetch the `WorkDirMeta` record for the directory, creating it if absent.
3. **Generate a UUID** for the session if the caller did not supply a specific `session_id`.
4. **Create the physical directory** at `<work_dir>/.kimi/sessions/<session_id>/`.
5. **Initialize `context.jsonl`** as an empty line-delimited JSON file for future message appends.
6. **Initialize `wire.jsonl`** by instantiating a `WireFile` object to begin event logging.
7. **Persist an empty `SessionState`** to the session directory to reserve storage for future mutable settings.
8. **Refresh metadata** by calling `session.refresh()` to derive the initial title and `updated_at` timestamp from the file system.

```python
from kaos.path import KaosPath
from kimi_cli.session import Session

async def spawn_session():
    work_dir = KaosPath.from_str("/home/user/project")
    # Returns a fully populated Session instance

    new_session = await Session.create(work_dir)
    print(f"Created session {new_session.id} with title: {new_session.title}")

```

## Resuming Existing Sessions with `Session.continue_` (`Session.resume`)

The CLI surface exposes "resume" functionality through shell commands (e.g., `/resume` in [`src/kimi_cli/ui/shell/keyboard.py`](https://github.com/MoonshotAI/kimi-cli/blob/main/src/kimi_cli/ui/shell/keyboard.py)) and the ACP API ([`src/kimi_cli/ui/acp/__init__.py`](https://github.com/MoonshotAI/kimi-cli/blob/main/src/kimi_cli/ui/acp/__init__.py)), both of which delegate to **`Session.continue_`**. This method, located at [lines 88‑106](https://github.com/MoonshotAI/kimi-cli/blob/main/src/kimi_cli/session.py#L88-L106), implements the resume logic:

1. **Canonicalize** the target work directory.
2. **Load global metadata** and read the `last_session_id` field from `WorkDirMeta`.
3. **Delegate to `Session.find`** if a last-session ID exists; otherwise return `None`.

**`Session.find`** ([lines 85‑124](https://github.com/MoonshotAI/kimi-cli/blob/main/src/kimi_cli/session.py#L85-L124)) validates the session’s existence by checking for the session directory and its `context.jsonl` file, performs any necessary legacy-file migrations, instantiates the `Session` object, and invokes `refresh()` before returning the reconstructed instance.

```python
async def resume_work():
    work_dir = KaosPath.from_str("/home/user/project")
    # Returns the last active Session or None if no metadata exists

    session = await Session.continue_(work_dir)
    if session:
        print(f"Resumed {session.id}: {session.title}")
    else:
        print("No previous session found in metadata.")

```

## Session Title Resolution and Metadata Refresh

After creation or retrieval, **`Session.refresh()`** ([lines 106‑124](https://github.com/MoonshotAI/kimi-cli/blob/main/src/kimi_cli/session.py#L106-L124)) populates human-readable metadata by inspecting `wire.jsonl` for the first `TurnBegin` event. If found, the method extracts the user’s initial prompt, truncates it to 50 characters, and assigns it as the session title. The `updated_at` field is populated from the modification time of `context.jsonl`, ensuring that listing operations (such as `Session.list`) can sort sessions by recency without parsing JSON content.

## Summary

- **Global anchoring** occurs through `WorkDirMeta` in [`src/kimi_cli/metadata.py`](https://github.com/MoonshotAI/kimi-cli/blob/main/src/kimi_cli/metadata.py), which tracks the `last_session_id` pointer for each work directory.
- **`Session.create`** ([lines 29‑80](https://github.com/MoonshotAI/kimi-cli/blob/main/src/kimi_cli/session.py#L29-L80)) generates UUIDs, builds the physical directory structure (`.kimi/sessions/<id>/`), and initializes `context.jsonl` and `WireFile` storage.
- **`Session.continue_`** ([lines 88‑106](https://github.com/MoonshotAI/kimi-cli/blob/main/src/kimi_cli/session.py#L88-L106)) implements the resume logic by querying metadata and delegating to `Session.find` ([lines 85‑124](https://github.com/MoonshotAI/kimi-cli/blob/main/src/kimi_cli/session.py#L85-L124)) to validate and reconstruct the session object.
- **Title derivation** happens lazily in `Session.refresh` ([lines 106‑124](https://github.com/MoonshotAI/kimi-cli/blob/main/src/kimi_cli/session.py#L106-L124)) by scanning `wire.jsonl` for `TurnBegin` events, decoupling display metadata from conversation content.

## Frequently Asked Questions

### What is the relationship between `Session.resume` and `Session.continue_`?

The user-facing "resume" command exposed in the shell UI and ACP layer maps directly to the **`Session.continue_`** static method. While the CLI documentation and interactive help refer to this action as "resume," the Python API uses `continue_` to avoid naming conflicts with Python keywords, making `Session.continue_` the programmatic entry point for reloading the last active session identified in `WorkDirMeta`.

### How does Kimi CLI determine the human-readable title for a session?

According to the implementation in [`src/kimi_cli/session.py`](https://github.com/MoonshotAI/kimi-cli/blob/main/src/kimi_cli/session.py), **`Session.refresh()`** scans the `wire.jsonl` file for the first `TurnBegin` event. Upon locating this event, it extracts the user’s initial prompt text, truncates the string to 50 characters, and stores the result as the session title. This approach ensures that titles reflect the actual intent of the conversation rather than generic identifiers or timestamps.

### Where does `Session.create` store the physical session data?

`Session.create` establishes a subdirectory under `<work_dir>/.kimi/sessions/<session_id>/` within the canonicalized work directory. This folder contains three primary artifacts: **`context.jsonl`** for high-level message history, **`wire.jsonl`** managed by the `WireFile` class for low-level event telemetry, and **[`session_state.json`](https://github.com/MoonshotAI/kimi-cli/blob/main/session_state.json)** for persisting mutable per-session flags managed by the `SessionState` object.

### What happens if `Session.find` cannot locate the session files?

`Session.find` validates the existence of both the session directory and its `context.jsonl` file before attempting to construct a `Session` instance. If the filesystem check fails—indicating corruption, deletion, or an invalid `last_session_id` in the metadata—the method will raise an appropriate exception or return `None`, which causes `Session.continue_` to propagate the failure and prevents the UI from loading a corrupted or non-existent session context.