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 aroundwire.jsonlthat records low-level wire events, includingTurnBeginmarkers 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:
- Canonicalize the supplied
KaosPathusingwork_dir.canonical()to ensure absolute, normalized paths. - Load global metadata via
load_metadata()and fetch theWorkDirMetarecord for the directory, creating it if absent. - Generate a UUID for the session if the caller did not supply a specific
session_id. - Create the physical directory at
<work_dir>/.kimi/sessions/<session_id>/. - Initialize
context.jsonlas an empty line-delimited JSON file for future message appends. - Initialize
wire.jsonlby instantiating aWireFileobject to begin event logging. - Persist an empty
SessionStateto the session directory to reserve storage for future mutable settings. - Refresh metadata by calling
session.refresh()to derive the initial title andupdated_attimestamp 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:
- Canonicalize the target work directory.
- Load global metadata and read the
last_session_idfield fromWorkDirMeta. - Delegate to
Session.findif a last-session ID exists; otherwise returnNone.
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
WorkDirMetainsrc/kimi_cli/metadata.py, which tracks thelast_session_idpointer for each work directory. Session.create(lines 29‑80) generates UUIDs, builds the physical directory structure (.kimi/sessions/<id>/), and initializescontext.jsonlandWireFilestorage.Session.continue_(lines 88‑106) implements the resume logic by querying metadata and delegating toSession.find(lines 85‑124) to validate and reconstruct the session object.- Title derivation happens lazily in
Session.refresh(lines 106‑124) by scanningwire.jsonlforTurnBeginevents, 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →