How Session Management and Resumption Work in Kimi CLI
Kimi CLI persists chat history and configuration in per-directory session folders using WorkDirMeta for global tracking and SessionState for local state, enabling resumption via the last_session_id reference and Session.continue_() method.
MoonshotAI/kimi-cli implements a layered session architecture that treats every interaction with a work directory as a resumable conversation. The system stores wire messages, approval settings, and custom titles in isolated session directories, allowing developers to pause AI-assisted workflows and return to them later. Understanding session management and resumption in Kimi CLI requires examining three core components that handle metadata, persistence, and runtime orchestration.
Core Components of the Session Architecture
WorkDirMeta: Global Directory Tracking
The WorkDirMeta class in src/kimi_cli/metadata.py maintains the global registry of all work directories known to the CLI. It stores the last_session_id for each directory and provides the sessions_dir path where individual session folders reside. When you initiate a conversation, load_metadata() reads the global metadata file at ~/.kimi/kimi.json to locate or create a WorkDirMeta entry for your current directory.
SessionState: Persistent Configuration Storage
Per-session persistence is handled by the SessionState model defined in src/kimi_cli/session_state.py. This JSON-serialized object contains approval flags, custom titles, archive status, and todo lists. The helper functions save_session_state() (line 31) and load_session_state() (lines 99‑127) manage atomic writes to state.json within each session directory, including automatic migration of legacy metadata.json files via _migrate_legacy_metadata.
Session: Runtime Orchestration
The Session class in src/kimi_cli/session.py serves as the runtime container, binding together the work directory, context files, and state. It provides static factory methods including create(), find(), list(), and continue_() that abstract the complexity of directory hashing, UUID generation, and file I/O.
Creating a New Session
When initializing a conversation via Session.create() (lines 30‑80 in session.py), the system executes a four-step persistence workflow:
- Directory Registration –
load_metadata()verifies the work directory exists in the global registry, creating a newWorkDirMetaentry if necessary. - Session ID Generation – A UUID is generated (or supplied by the caller) to identify the session uniquely.
- Directory Structure Creation – The system creates
sessions/<hash>/<session_id>/under the work directory's metadata root. - Initial File Population – Empty
context.jsonlandwire.jsonlfiles are created for message storage, and a defaultSessionState()instance is serialized tostate.jsonviaatomic_json_write.
from kimi_cli.session import Session
from kaos.path import KaosPath
from pathlib import Path
work_dir = KaosPath.unsafe_from_local_path(Path("/home/alice/project"))
session = await Session.create(work_dir)
print(session.id, session.title)
Storing and Loading Session State
Each session directory contains the critical state.json file produced by save_session_state(state, session_dir). When resuming work, load_session_state(session_dir) reads this file, applying default values if corruption is detected and automatically migrating legacy metadata.json data when present.
The system maintains two distinct log files:
wire.jsonl– Stores raw LLM-tool messages for history replaycontext.jsonl– Contains line-delimited JSON messages representing the conversation context
Deriving Session Titles
The Session.refresh method rebuilds human-readable titles by inspecting the wire.jsonl log. If state.custom_title is set, it uses that value; otherwise, it extracts the first user utterance from the initial TurnBegin message and truncates it via the shorten function (lines 14‑23 in session.py). The resulting title is cached in Session.title and synchronized to WorkDirMeta.last_session_id.
# Update session state with a custom title
session.state.custom_title = "My Feature Development"
session.save_state()
Resuming Previous Sessions
Session resumption relies on the Session.continue_() method (lines 88‑107), which implements the kimi continue command logic:
session = await Session.continue_(work_dir)
if session:
print("Resuming:", session.id, session.title)
This method retrieves the last_session_id from the work directory's metadata and invokes Session.find() to reconstruct the full runtime object, reloading state.json and preparing the wire log for append operations.
Session Enumeration and Cleanup
The CLI provides utilities for managing session lifecycles beyond simple resumption:
Session.list(work_dir)– Enumerates subdirectories in the session store, filters empty sessions, and returns results sorted byupdated_atSession.list_all()– Aggregates sessions across every known work directory viaload_metadata().work_dirsSession.delete()– Performs async removal of the entire session directory including both JSON state files
# List all sessions for a work directory
sessions = await Session.list(work_dir)
for s in sessions:
print(f"{s.id[:8]} – {s.title} (updated: {s.updated_at})")
Summary
Kimi CLI's session management system combines global metadata tracking with per-directory isolation to create a robust persistence layer:
- Global tracking via
WorkDirMetainsrc/kimi_cli/metadata.pymaintains thelast_session_idreference for quick resumption - State persistence through
SessionStateinsrc/kimi_cli/session_state.pyhandles atomic saves and legacy migrations - Runtime management via the
Sessionclass insrc/kimi_cli/session.pyprovides factory methods for creation, lookup, and continuation - History storage uses
wire.jsonlfor raw messages andcontext.jsonlfor conversation context - Resumption workflow leverages
Session.continue_()to reload the most recent session using stored metadata references
Frequently Asked Questions
How does Kimi CLI determine which session to resume when using kimi continue?
The CLI queries the WorkDirMeta entry for the current directory to retrieve the last_session_id field. This UUID is passed to Session.find(), which locates the corresponding session directory and reconstructs the runtime object by loading state.json and preparing the wire log for the next interaction.
Where are session states physically stored on disk?
Session data resides in ~/.kimi/kimi.json for global metadata and in sessions/<hash>/<session_id>/ subdirectories within each work directory's metadata folder. Each session contains state.json for configuration, wire.jsonl for message history, and context.jsonl for conversation context.
How does Kimi CLI derive the display title for a session?
If the user has set a custom_title in the SessionState object, that value is used. Otherwise, Session.refresh parses the first TurnBegin message from wire.jsonl, extracts the initial user utterance, and applies the shorten function to generate a concise display title automatically.
What happens if the state.json file becomes corrupted?
When load_session_state() encounters a corrupted or unreadable state.json file, it falls back to default values for all session parameters. Additionally, if a legacy metadata.json file exists from older CLI versions, the system automatically migrates its contents into the new state.json format before loading.
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 →