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

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 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. 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. 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): 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 (lines 29‑80) 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.
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) and the ACP API (src/kimi_cli/ui/acp/__init__.py), both of which delegate to Session.continue_. This method, located at lines 88‑106, 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) 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.

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) 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, which tracks the last_session_id pointer for each work directory.
  • Session.create (lines 29‑80) generates UUIDs, builds the physical directory structure (.kimi/sessions/<id>/), and initializes context.jsonl and WireFile storage.
  • Session.continue_ (lines 88‑106) implements the resume logic by querying metadata and delegating to Session.find (lines 85‑124) to validate and reconstruct the session object.
  • Title derivation happens lazily in Session.refresh (lines 106‑124) 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, 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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →