How Tuicr Handles Session Persistence: Architecture and Implementation

Tuicr persists review sessions by serializing the in-memory ReviewSession to JSON files under a user-specific data directory, using atomic writes with file locking to ensure crash safety and concurrent access between the TUI and CLI.

The agavra/tuicr repository implements a robust session persistence mechanism that allows code review state—including comments, file-level flags, and diff views—to survive application restarts. By combining JSON serialization with atomic file operations and a manifest-based index, Tuicr ensures that both interactive TUI sessions and non-interactive CLI commands can safely read and write review data without corruption.

Core Persistence Architecture

ReviewSession and Data Models

The foundation of how Tuicr handles session persistence lies in the ReviewSession struct defined in src/model/review.rs. This type holds the complete review state, including per-file FileReview instances, line-level comments, and reviewed hunks. When the application serializes state to disk, it converts this in-memory representation into JSON format for human-readable storage and easy debugging.

ReviewStore Public API

src/review_store.rs exposes the ReviewStore facade, which serves as the primary interface for listing, loading, and saving sessions. The store abstracts the underlying file operations, providing methods like get_review(repo_or_slug) to retrieve existing sessions and add_comment() to merge new data. This layer ensures that both the TUI application and CLI utilities interact with persistence through a consistent, type-safe API.

Storage Layer with Atomic Writes

Low-level I/O operations reside in src/persistence/storage.rs, which implements save_session() using atomic write patterns. The implementation writes to a temporary file first, acquires an exclusive lock using flock, then renames the temporary file to the final destination. This approach prevents data corruption if the process crashes mid-write and handles concurrent modification attempts from multiple Tuicr instances.

Manifest and Index Management

The src/persistence/manifest.rs module maintains an index.json file that maps repository paths and PR slugs to their corresponding session file names. This manifest tracks active TUI sessions via PID and timestamp metadata, enabling fast lookups and automatic cleanup of stale entries. The index allows Tuicr to locate session files quickly without scanning the entire data directory.

Session Persistence Workflow

Initializing a New Session

When the TUI initializes via App::new() in src/app/session.rs, the application checks for an existing session file in the user data directory—$XDG_DATA_HOME/tuicr/reviews/ on Unix or %APPDATA%\tuicr\reviews\ on Windows. If no session exists for the current repository and PR combination, ReviewStore creates a new empty JSON file that will store subsequent review activity.

Autosave and Atomic Write Mechanics

Tuicr implements a background autosave mechanism driven by the review_watch_interval_ms configuration parameter, defaulting to 1000 milliseconds. At each interval, the system serializes the current ReviewSession to JSON and invokes storage::save_session() to perform an atomic write. The file locking mechanism ensures that if a CLI command modifies the session simultaneously, the TUI waits for the lock before writing, preventing race conditions.

Merging External Changes

Before each autosave operation, Tuicr reloads the session file from disk using load_session(). This step detects modifications made by external processes, such as tuicr review add CLI invocations, and merges them into the in-memory state via ReviewStore::add_comment(). This three-way merge strategy ensures that comments added from the command line appear immediately in the TUI without overwriting existing in-memory changes.

Session Retrieval and Cleanup

CLI commands like tuicr review list and tuicr review comments call ReviewStore::get_review() to access persisted data. The store consults the manifest to locate the correct JSON file, then deserializes it using serde_json. On normal TUI exit, the application removes its active session entry from the manifest and deletes empty session files that contain no comments or reviewed flags, preventing disk pollution.

Code Examples

Saving Comments from the TUI

When users add comments through the interface, src/app/comments.rs delegates to the persistence layer:

// Inside App::save_comment()
let req = AddCommentRequest {
    file: path.clone(),
    line: Some(line_no),
    body: comment_body.clone(),
    // … other fields …
};
add_comment_to_session(&mut self.session, req);

The add_comment_to_session() function updates the in-memory ReviewSession, which the background autosave thread then persists to disk via storage::save_session().

Adding Comments via CLI

External tools can append comments to active sessions without launching the TUI:


# Add a comment to an existing session

tuicr review add --repo . --input '{"file":"src/main.rs","line":42,"body":"Consider refactoring"}'

Behind the scenes, ReviewStore::add_comment() loads the existing session JSON, merges the new comment, and triggers an atomic write to ensure the TUI sees the change on its next autosave cycle.

Loading Sessions Programmatically

Scripts and integrations can access review data directly through the Rust API:

use tuicr::ReviewStore;

fn main() -> Result<()> {
    // Load the active session for the current repo
    let store = ReviewStore::new()?;
    let session = store.get_review(".")?;
    println!("Loaded {} comments", session.total_comment_count());
    Ok(())
}

This approach leverages the same ReviewStore facade used internally, ensuring consistent path resolution and file locking behavior.

Cleaning Up Empty Sessions

For maintenance operations, the manifest API provides cleanup utilities:

use tuicr::persistence::manifest::Manifest;

fn purge_empty() -> Result<()> {
    let mut manifest = Manifest::load()?;
    manifest.remove_empty_sessions()?; // walks the data dir and deletes files with no content
    Ok(())
}

This function removes stale session files that lack comments or review markers, reclaiming disk space while maintaining the integrity of the index.json manifest.

Summary

  • Tuicr stores review sessions as JSON files in platform-specific data directories ($XDG_DATA_HOME/tuicr/reviews/ or %APPDATA%\tuicr\reviews\).
  • The ReviewSession struct in src/model/review.rs defines the persistence schema, while ReviewStore in src/review_store.rs provides the public API.
  • Atomic writes in src/persistence/storage.rs use temporary files and flock locking to prevent corruption during concurrent access.
  • The manifest system in src/persistence/manifest.rs maintains an index.json index for fast session lookups and tracks active TUI processes.
  • Autosave intervals (default 1000ms) coupled with pre-write reloading ensure that CLI and TUI modifications merge without data loss.

Frequently Asked Questions

Where does Tuicr store session persistence files?

Tuicr stores session data in JSON format under the user data directory, specifically $XDG_DATA_HOME/tuicr/reviews/ on Unix systems or %APPDATA%\tuicr\reviews\ on Windows. Each session file corresponds to a specific repository and PR combination, with an index.json manifest tracking active sessions.

How does Tuicr prevent data corruption when multiple processes access the same session?

The persistence layer implements atomic writes using temporary files and POSIX flock advisory locks in src/persistence/storage.rs. Before writing, Tuicr acquires an exclusive lock on the session file, writes to a temporary location, then renames the file into place, ensuring that concurrent CLI and TUI processes cannot corrupt the JSON structure.

Can I access Tuicr review sessions from external scripts?

Yes, the ReviewStore API exposed in src/review_store.rs allows programmatic access to persisted sessions. You can instantiate ReviewStore::new() and call get_review(repo_path) to load the current session state, enabling integration with CI pipelines or custom review tooling that reads comment data from the JSON files.

What happens to session files when the TUI crashes?

Tuicr's storage layer detects orphaned lock files left by crashed processes and removes them before attempting new writes. Empty session files containing no comments or reviewed flags are automatically cleaned up on the next normal exit, while sessions with content persist indefinitely until explicitly deleted or the review is completed.

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 →