Skip to main content
Working on multiple projects or tasks can be challenging, especially when each one has a different conversation context. ChatCLI solves this with a simple and powerful session management system. A session is essentially a complete β€œsave” of your conversation history, allowing you to resume exactly where you left off.
ChatCLI uses a unified history β€” a single message array shared across all modes (chat, agent, coder). When saving a session, the entire context is preserved regardless of the mode in which it was generated. Use /compact to reduce size and /rewind to go back to earlier points.

Session Commands

All session management commands start with /session.
1

/session save <name>

Saves the current conversation (the entire history of prompts and responses) with a name of your choice.
After saving, the session name will appear in your prompt (e.g., debug-api-pagamentos), indicating that you are working within that session.
2

/session load <name>

Loads a previously saved session. The current conversation is replaced by the loaded session’s history.
Loading also rotates the shared Conversation Hub thread, so the old cross-channel backlog is not spliced on top of the loaded session.
3

/session attach <name>

Binds the conversation to a named session β€” loads it when it exists, creates it when it doesn’t. While attached, every turn is written through to the session file and writes made by other surfaces are adopted before each turn β€” see Cross-surface continuity.
/session save and /session load also bind: after either one, the conversation is attached to that name. attach is the alias that works whether or not the session exists yet.
4

/session detach

Keeps the current conversation in memory but drops the binding: turns stop being written through to the named session file.
5

/session status

Shows whether the conversation is bound to a named session, and to which one.
6

/session list

Lists all sessions you have saved to disk.
7

/session delete <name>

Permanently removes a saved session from disk. This action cannot be undone.
If you delete the currently active session, your current history will be cleared and you will start a new conversation.
8

/session new (or /newsession)

Clears the current history and starts a completely new conversation. Perfect for starting a task from scratch without being tied to any named session. Same semantics as /newsession: it also drops any session binding and rotates the shared hub thread, so no backlog from the old conversation leaks into the new one.
9

/session fork <new-name>

Creates an independent copy of the current session with a new name. The original remains untouched and you automatically switch to working on the fork. The fork is its own timeline: it gets a fresh transcript journal seeded with the parent’s events (the two never append to one journal, so /rewind and undo stay per session) and keeps the attachments, the cost reference and the CCR archive keys. A session file written by a newer ChatCLI (higher schema version) is refused on load instead of being silently rewritten minus the fields this build does not know.Ideal for experimenting with different approaches without losing current progress, or branching a conversation in different directions.
Works with both saved and unsaved (in-memory) sessions. For unsaved sessions, the fork is created from the current history state.
10

/session export <md|jsonl> [path]

Exports the full transcript β€” the journal, not the compacted window β€” as a Markdown document (one section per message, tool calls and results in fenced blocks, system prompts collapsed) or as JSON Lines (one turn per line, the same format @trajectory uses). Falls back to the live history when the journal is off.
Without a path the file lands in the working directory as chatcli-<session>-<timestamp>.<ext>, mode 0600.
11

/session transcript <search|show|export|stats>

Works on the same full record:
  • search <query> ranks every journaled message with BM25 and prints the top hits with their position β€” #17 assistant …the deploy freeze ends on Friday….
  • show <from> [count] replays messages from a position (default 10), so a hit can be read in context.
  • export <md|jsonl> [path] is the same as /session export.
  • stats prints the message count, size, source (journal or live history) and journal id.

Automatic saving on exit

You don’t have to remember /session save: when the interactive REPL exits, the conversation is auto-saved under a reserved autosave-YYYYMMDD-HHMMSS name. Trivial sessions (fewer than 2 non-system messages) are skipped, and one-shot -p runs never autosave. Gated by CHATCLI_SESSION_AUTOSAVE (on by default, shown in /config session). Autosaved conversations are fully searchable and readable via @session. MCP sessions autosave too: the MCP/ACP server mirrors each live conversation to a rolling mcp-<session> file after every turn (both the full-pipeline and plain paths), and manage_session clear saves one last time before discarding. An explicit CHATCLI_MCP_SESSION_AUTOSAVE always wins; unset, it follows the global CHATCLI_SESSION_AUTOSAVE gate β€” on by default. Retention for both surfaces is covered under Automatic Cleanup below.

Cross-surface continuity

A named session is ChatCLI’s durable continuity layer across surfaces: the interactive REPL, the MCP server (chatcli mcp-server), the ACP server (chatcli acp) and the Chat Gateway all read and write the same session file. Start on the terminal, continue in the IDE, finish on WhatsApp β€” same conversation. While a named session is active (after /session save, /session load or /session attach), the binding works in both directions on every turn:
  • Write-through β€” each completed turn is written to the session file immediately (atomic write: temp file + rename, so there are never torn files).
  • Adoption β€” before each turn, writes made by other surfaces (MCP/ACP server, gateway daemon, another terminal) since the last sync are adopted: when the file is newer, it replaces the in-memory history wholesale (last-writer-wins).
Each surface has its own way in:
Machine-created sessions (autosave-, mcp- prefixes) are rolling mirrors owned by the autosave paths β€” they never become live bindings.
Last-writer-wins converges as long as surfaces alternate turns. Two surfaces answering the same turn simultaneously in real time remains the Conversation Hub’s job (ephemeral, cross-channel); the named session is the durable record.

Transcript journal

A saved session persists the conversation as it stands in memory β€” after a compaction the window holds a summary, and the original messages survive only as @recall keys in the CCR store (7-day TTL, size-capped). The transcript journal is the durable full record underneath that window:
  • ~/.chatcli/transcripts/<id>.jsonl, one file per session, append-only, every line fsynced.
  • Every message is appended once, the first time it appears at the tail of the live history β€” at each chat turn end, at the start of every agent/coder turn (so the previous turn’s tool results are on disk before any rewrite can stub them) and when an agent run exits, however it exits. A hard kill mid-run loses at most the tool batch in flight.
  • A history rewrite (auto-compact, /compact, microcompact, skill aging, repeated-read dedup) is recorded as a rewrite event carrying the ordered hashes of the history it replaced; only genuinely new messages (the summary) are appended, nothing is duplicated. Those hashes are what /rewind compact and persisted /rewind checkpoints resolve after a resume.
  • The journal is readable, not write-only: /session export and /session transcript search|show|stats work on it directly.
  • Every sync compares the whole history against the last journaled hashes, so a message changed in place (microcompact, read dedup, tool-result pairing repair, Level 1 trim) is recorded as a rewrite too β€” /rewind compact and persisted checkpoints keep resolving in agent sessions. Hashes cover native tool calls (id, name, arguments) and images, and repeated tail messages (β€œok”) are recorded as the separate messages they are.
  • The reader tolerates damage: a partial last line from a crash and any foreign line are skipped and counted, never fatal; the next append starts on a fresh line. A sealed line this process cannot open is still an error, because that is a key problem rather than corruption.
  • Saved sessions carry their transcript_id, so /session load and /session attach keep writing to the same journal across resumes.
  • Saved sessions also carry their /context attach records (attachments: context id, priority, selected chunks, retrieval mode). Attach state used to be process-local β€” a restart or a load on another surface lost every attached context; loading a session now re-attaches the same contexts, skipping any that no longer exist.
  • With CHATCLI_ENCRYPTION_KEY set, each line is sealed (same AES-256-GCM format as sessions) and the journal cannot be read without the key.
  • Journals follow the machine-session TTL (CHATCLI_SESSION_TTL, 90 days by default). CHATCLI_SESSION_TRANSCRIPT=false disables the journal; /config session shows the active id.

Where Sessions Are Stored

Sessions are saved as JSON files in a per-user store β€” the same store every surface (REPL, MCP/ACP server, gateway daemon) reads and writes:
For example, running /session save debug-api creates the file:
The SessionManager is the internal component responsible for all session file I/O. It handles read/write errors (permissions, full disk, malformed JSON) and displays clear messages if something fails.
Session files contain the complete conversation history at the time of saving β€” including user messages, AI responses, tool call results, and summaries generated by /compact.
Since the store is per-user (home directory), the same sessions are visible no matter which directory you launch ChatCLI from β€” and every surface (terminal, IDE, MCP client, gateway channel) sees the same list. Use /session list to see them all.

Data Format (v2)

Session files use the v2 format, defined by the SessionData struct in the models package. The JSON structure is:

Message Fields

Format Evolution

  • v1 (older versions): Maintained separate histories per mode β€” chat_history, agent_history, and coder_history each with their own messages.
  • v2 (current version): Uses a unified history. The chat_history field contains all messages from all modes. The agent_history and coder_history fields exist for compatibility but are empty in new sessions.
When loading a v1 session (with separate per-mode histories), ChatCLI automatically merges the messages in chronological order into the unified history. No manual intervention is required.

Unified History and Sessions

ChatCLI uses a single message array for all interaction modes. This means:
  • When saving a session, the entire unified history is serialized β€” including messages from chat, agent, and coder mode.
  • System messages, tool call results, and compacted summaries are all preserved in the file.
  • When loading a session, the current history is completely replaced by the loaded session’s history.
The active session name appears as a prefix in the interactive prompt:
This makes it easy to know which context you are working in at any time.
Loading a session replaces the entire current history. If you have an unsaved conversation, it will be lost. Save first with /session save if you want to preserve it.

Interaction with Other Systems

Sessions interact with several other ChatCLI subsystems. Here is how each one behaves:

Compaction (/compact)

The /compact command reduces history size by creating summaries of older messages. If you save a session after compacting, the resulting file will be significantly smaller, as it contains summaries instead of the original messages.

Rewind (/rewind)

The checkpoints used by /rewind are saved with the session as ordered message-hash lists (checkpoints) and rebuilt from the transcript journal on /session load; a checkpoint whose messages the journal no longer holds is dropped. /rewind compact (undo the latest compaction) is also journal-backed after a resume. With the journal disabled, checkpoints are process-local as before.

Bootstrap (SOUL.md, etc.)

Bootstrap files are not part of the session. They are loaded automatically on every ChatCLI startup, regardless of which session is active. This ensures that the AI’s base behavior is always consistent.

Memory (/memory)

Memory is global β€” it is not tied to any specific session. Data saved with /memory save is available across all sessions and survives ChatCLI restarts.

Context (/context attach)

Contexts attached via /context attach are not saved in the session file. When loading a session, you need to re-attach the necessary contexts manually.
Quick summary: Sessions only save the message history. Bootstrap, memory, contexts, and rewind checkpoints are managed separately.

Auto-Save and Persistence

Besides the explicit /session save, persistence has two automatic layers:
  • Bound named session β€” after /session save, /session load or /session attach, every turn is written through to the session file (see Cross-surface continuity; gated by CHATCLI_SESSION_WRITETHROUGH, on by default).
  • Exit autosave β€” an unbound conversation is still saved as autosave-YYYYMMDD-HHMMSS when the interactive REPL exits (see Automatic saving on exit; gated by CHATCLI_SESSION_AUTOSAVE, on by default).
Save under a name you chose whenever the conversation matters: user-named sessions never expire, while autosaves are subject to Automatic Cleanup.

The .chatcli_history File (Don’t Confuse)

ChatCLI maintains a separate file called .chatcli_history that stores the command input history (similar to ~/.bash_history). This file:
  • Contains only the text you typed at the prompt, not the AI’s responses
  • Is controlled by the HISTORY_FILE and HISTORY_MAX_SIZE environment variables
  • Has no relation to session files (~/.chatcli/sessions/*.json)

To get the most out of the session system, follow these practices:
1

Name sessions after the task

Use descriptive names that clearly identify the objective. Examples: fix-auth-bug, refactor-api, docs-v2, debug-memory-leak.
2

Compact before saving

Use /compact before /session save to reduce file size and keep only the essential information.
3

Start clean before switching sessions

Use /session new before loading another session. This ensures the previous context doesn’t interfere.
4

Switch between tasks freely

You can have multiple sessions saved for different tasks and switch between them as needed.

Session Encryption

Session files can be encrypted at rest using AES-256-GCM to protect sensitive conversation data: When configured, all session operations (save/load) use transparent encryption:
Key derivation uses HKDF (HMAC-based Key Derivation Function) to generate unique per-session keys from the master key. This ensures that compromising one session does not compromise others.
Transparent migration: Existing plaintext sessions are automatically encrypted when loaded and saved again. No manual action is needed to migrate old sessions.
Store the encryption key in a secure location. If the key is lost, encrypted sessions cannot be recovered.

Automatic Cleanup

ChatCLI applies a bounded lifecycle to machine-created sessions on startup (REPL and MCP/ACP server alike). The core rule: sessions you named are never deleted automatically β€” only the autosave- and mcp- prefixed files ChatCLI creates on its own are subject to retention. Time is the primary retention: machine sessions untouched for the TTL are removed in the background at startup. The keep-count is a generous backstop against pathological accumulation, not the working limit. And nothing distilled is ever lost: facts, episodes and rollups extracted from a session are permanent and survive its cleanup β€” pruning bounds disk and search cost, not knowledge.
Use CHATCLI_SESSION_TTL=0 to disable automatic cleanup and keep all sessions indefinitely. To make one conversation immortal regardless of policy, just save it under a name: /session save my-checkpoint.

Curating storage on demand

The startup pass is silent. /storage makes the same policies visible: one line per local store with its file count, size, the rule that governs it and what would be removed right now, plus the stores that are never pruned (distilled memory, skills, plugins, contexts, agents, commands, scheduler, tokenizers, logs). /storage prune lists what the rules would remove, grouped by reason β€” past TTL, orphaned, test burst, stray temp file β€” and only /storage prune --apply removes it; /storage prune costs --apply scopes it to one store. Two rules exist only on demand because a boot pass must not guess: cost snapshots started in a burst (four or more sessions in one minute with at most two requests each), and the CCR and hub sweeps, which open their own stores. Coder checkpoints joined the startup pass: a shadow repository whose workspace is a temp directory or no longer exists is removed at boot, the rest follow the session TTL. chatcli storage prune --apply is the same thing without a REPL, for cron β€” or schedule it from inside with /schedule, which runs slash commands.

Name Validation

Session names are validated with a strict regex to prevent path traversal and problematic characters:
  • Allowed characters: letters (a-z, A-Z), numbers (0-9), hyphens (-), underscores (_), and dots (.)
  • Length: 1 to 128 characters
  • Forbidden: spaces, slashes, special characters, .. sequences
Invalid names are rejected with a clear error message indicating the allowed characters.

Frequently Asked Questions

No. Session files are stored locally under ~/.chatcli/sessions. To transfer a session between machines, copy the ~/.chatcli/sessions/<name>.json file to the same location on the other machine.
Technically, the limit is defined by the HISTORY_MAX_SIZE variable (default: 100MB), but in practice sessions rarely exceed a few megabytes. If the history is too large, use /compact before saving to significantly reduce the size.
Yes, but with care. The file follows the v2 format described above. You can remove messages, edit content, or adjust metadata. Make sure to keep the JSON valid and the structure intact (especially the version field).
ChatCLI automatically detects sessions in the v1 format (with separate per-mode histories) and performs an automatic migration to v2, merging all messages in chronological order into the unified history. The process is transparent and requires no action from the user.
No β€” the store is per-user. Sessions live in ~/.chatcli/sessions, so the same names are visible from any directory and any surface (REPL, MCP/ACP server, gateway). That shared namespace is exactly what makes cross-surface continuity work; use task-specific names (projeto-a-debug, projeto-b-debug) to keep projects apart.

Next Steps

Conversation Control

Use /compact and /rewind to manage history size and state.

Persistent Context

Save, attach, and reuse project snapshots with the /context command.

Bootstrap and Memory

Customize the AI and maintain long-term context.

One-Shot Mode

Use ChatCLI in scripts, automations, and CI/CD pipelines.