# How Session Save, Resume, and History Retrieval Work in DeepSeek-Reasonix

> Learn how DeepSeek-Reasonix saves, resumes, and retrieves conversation history via atomic JSON-L files. Access sessions using CLI or programmatically with crash-safe guarantees.

- Repository: [YHH/DeepSeek-Reasonix](https://github.com/esengine/DeepSeek-Reasonix)
- Tags: internals
- Published: 2026-06-22

---

**DeepSeek-Reasonix persists every conversation as an atomic JSON-L file and provides both CLI and programmatic interfaces for resuming sessions and retrieving history with crash-safe guarantees.**

The session management system in the [DeepSeek-Reasonix](https://github.com/esengine/DeepSeek-Reasonix) repository handles conversation lifecycle through a combination of atomic file operations, in-memory snapshots, and specialized tools for AI agents. Understanding these mechanisms is essential for building reliable integrations or debugging conversation state issues.

## Session Persistence: Atomic JSON-L Serialization

Every conversation turn triggers an automatic save to a `*.jsonl` file containing a sequence of `provider.Message` structs. The `Session.Save` method in [`internal/agent/save.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/agent/save.go) implements crash-safe persistence using atomic file replacement.

The save process works as follows:

- **Temporary File Creation**: The full transcript writes to a temporary file first
- **Atomic Rename**: `fileutil.ReplaceFile` renames the temporary file to the final destination, ensuring that a system crash cannot leave a partially-written session file
- **Path Generation**: `NewSessionPath` generates unique filenames for new sessions, while `ContinueSessionPath` creates continuation paths when model switches occur

```go
func (c *Controller) snapshot(markActivity bool) error {
    // ...
    if err := s.Save(path); err != nil {        // <-- writes JSONL
        return err
    }
    preview, turns := agent.SessionPreviewFromMessages(s.Snapshot())
    return agent.UpdateSessionMeta(path, modelRef, preview, turns, markActivity)
}

```

The controller stores the active path in its `sessionPath` field, which is used for subsequent autosaves.

## Loading and Normalizing Sessions

When resuming a conversation, `LoadSession` in [`internal/agent/save.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/agent/save.go) handles deserialization and data integrity checks.

**The loading sequence**:
1. Open the JSON-L file and decode each message using a streaming `json.Decoder`
2. Run `NormalizeSession` to repair any legacy format inconsistencies or missing fields
3. Return a populated `*agent.Session` struct ready for the controller

This normalization step ensures backward compatibility with older session formats without manual migration.

## Resuming Sessions in the Controller

The `Controller.Resume` method in [`internal/control/controller.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/control/controller.go) (lines 53-66) binds a loaded session to the active runtime environment.

**Resume operations include**:
- Pinning the session file path to `c.sessionPath` for future autosaves
- Re-binding checkpoint metadata from the previous conversation
- Clearing the planner's internal state to prevent stale context contamination
- Executing `maybeColdResumePrune` to remove stale tool results if the session exceeded the provider cache duration

After resuming, the controller's `History()` method immediately returns the restored transcript, making the conversation available to the UI layer.

## Retrieving Conversation History

Front-end interfaces access conversation history through `Controller.History()` in [`internal/control/controller.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/control/controller.go) (lines 87-94). This method returns a defensive copy of the executor's `Session().Snapshot()`—a slice of `provider.Message` structs that represents the current conversation state.

The `chatTUI` layer consumes this snapshot to render scroll-back buffers, while the underlying `Session` struct in [`internal/agent/session.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/agent/session.go) manages the in-memory representation through methods like `Snapshot()` and `HasContent()`.

## Listing and Selecting Sessions

The `/resume` command leverages `ListSessions` in [`internal/agent/save.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/agent/save.go) to display available conversations without loading full message histories.

**Performance optimization through side-cars**:
- `ListSessions` builds lightweight `SessionOrderInfo` metadata for each `.jsonl` file
- Reads cached previews from side-car files rather than parsing entire JSON-L documents
- Returns `SessionInfo` structs containing timestamp, turn count, preview text, and file path

The CLI implementation in [`internal/cli/resume.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/cli/resume.go) provides two interaction modes:

```bash

# Interactive mode: shows numbered list with metadata

reasonix /resume

# Direct mode: resume specific session by index

reasonix /resume 3

```

When invoked without arguments, `showSessions` renders the picker interface; with an index argument, it loads the selected file via `agent.LoadSession` and invokes `Controller.Resume`.

## AI-Accessible Session Tools

The `sessiontool` package in [`internal/tool/sessiontool/sessiontool.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/tool/sessiontool/sessiontool.go) exposes session data to AI agents through two registered tools:

**`list_sessions`**: Returns available sessions with metadata (equivalent to the CLI picker data)

**`read_session`**: Validates filenames, checks for cleanup-pending markers, and returns a privacy-safe view of messages truncated to 2000 runes per message:

```json
{
  "session": "20231101-120000.000000000-gpt-4.jsonl"
}

```

By default, `read_session` omits system messages and tool results unless `show_tool_results` is set to `true`, preventing context window pollution while allowing optional deep inspection.

## Summary

- **DeepSeek-Reasonix** uses atomic file replacement (`fileutil.ReplaceFile`) in [`internal/agent/save.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/agent/save.go) to prevent corruption during session saves
- **Resume operations** bind loaded sessions to the controller, clear stale planner state, and optionally prune old tool results via `maybeColdResumePrune`
- **History retrieval** returns defensive copies of `provider.Message` slices through `Controller.History()` and `Session.Snapshot()`
- **Session listing** uses lightweight side-car metadata (`SessionOrderInfo`) to avoid parsing large JSON-L files during UI rendering
- **AI tools** provide controlled access via `list_sessions` and `read_session`, with content truncation at 2000 runes for privacy protection

## Frequently Asked Questions

### How does DeepSeek-Reasonix prevent data loss when saving sessions?

The system writes to a temporary file first, then uses `fileutil.ReplaceFile` for an atomic rename operation in [`internal/agent/save.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/agent/save.go). This ensures that the original session file remains intact until the new content is fully written to disk, eliminating the risk of partial writes during crashes or power failures.

### What is the difference between NewSessionPath and ContinueSessionPath?

`NewSessionPath` generates unique filenames for fresh conversations using timestamps and model identifiers, while `ContinueSessionPath` creates paths for model-switched continuations that maintain conversation lineage. The controller stores the active path in `sessionPath` and uses it for all subsequent autosave operations.

### How does the read_session tool protect sensitive information?

The tool truncates each message to 2000 runes and filters out system messages and tool results by default. Only when `show_tool_results` is explicitly set to `true` does it return full tool execution data, preventing accidental exposure of intermediate computation or private API responses to the AI context.

### Can sessions be resumed programmatically without the CLI?

Yes, developers can load sessions directly using `agent.LoadSession` and pass the result to `Controller.Resume`. This pattern is useful for testing, custom UI implementations, or automated workflows that need to restore conversation state without invoking the `/resume` slash command:

```go
sess, err := agent.LoadSession("/home/user/.reasonix/sessions/20231101-120000.000000000-gpt-4.jsonl")
if err != nil { log.Fatal(err) }
ctrl.Resume(sess, "/home/user/.reasonix/sessions/20231101-120000.000000000-gpt-4.jsonl")

```