# How to Use the Rust ReviewStore Library API for Programmatic Review Access

> Learn to use the Rust ReviewStore API in agavra/tuicr for programmatic access to code review sessions. Create, query, and mutate data without the TUI.

- Repository: [Almog Gavra/tuicr](https://github.com/agavra/tuicr)
- Tags: api-reference
- Published: 2026-08-07

---

**The `tuicr` crate exposes a pure-Rust `ReviewStore` API in [`src/review_store.rs`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs) that enables programmatic creation, querying, and mutation of persisted code review sessions without launching the TUI.**

The `tuicr` repository provides a Rust library interface that allows developers to interact with review sessions directly from their applications. By using the **Rust ReviewStore library API**, you can list existing sessions, load full review data, and append comments atomically from automation tools, bots, or custom workflows. This guide covers the core types, main operations, and practical examples for integrating the library into your Rust projects.

## Core Types and Architecture

The API centers around several key types defined in [[`src/review_store.rs`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs)](https://github.com/agavra/tuicr/blob/main/src/review_store.rs) and the model modules:

- **`ReviewStore`** ([`src/review_store.rs#L10-L30`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs#L10-L30)): The facade that manages the directory where sessions are stored.
- **`SessionRef`** ([`src/review_store.rs#L27-L41`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs#L27-L41)): Opaque handle to a single session file (`PathBuf`).
- **`SessionSummary`** ([`src/review_store.rs#L59-L71`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs#L59-L71)): Light-weight metadata shown by `list_*` methods, including slug, kind, timestamps, and comment counts.
- **`AddCommentRequest`** ([`src/review_store.rs#L73-L88`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs#L73-L88)): Describes a new draft comment with target, content, type, author, and optional commit SHA.
- **`CommentTarget`** ([`src/review_store.rs#L90-L102`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs#L90-L102)): Enum defining where the comment attaches (review-wide, file, line, or line-range).
- **`ReviewSession`** ([`src/model/review.rs#L89-L124`](https://github.com/agavra/tuicr/blob/main/src/model/review.rs#L89-L124)): In-memory representation containing files, comments, and reviewed hunk state.
- **`Comment`** ([`src/model/comment.rs#L55-L78`](https://github.com/agavra/tuicr/blob/main/src/model/comment.rs#L55-L78)): Individual comment object with content, type, author, lifecycle, and commit scoping.

## Initializing the ReviewStore

Create a store instance using the platform-default reviews directory or a custom path.

**`ReviewStore::new()`** ([`src/review_store.rs#L16-L21`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs#L16-L21)) builds a store using the default location (`~/.local/share/tuicr/reviews` on Linux).

**`ReviewStore::with_reviews_dir(dir)`** ([`src/review_store.rs#L22-L28`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs#L22-L28)) overrides the storage location, useful for tests or isolated tooling.

```rust
use tuicr::review_store::ReviewStore;

// Use the default platform directory
let store = ReviewStore::new();

// Or use a temporary isolated directory (useful for tests)
let temp_dir = std::env::temp_dir().join("my_tuicr_reviews");
let store = ReviewStore::with_reviews_dir(temp_dir);

```

## Querying Sessions

Discover existing sessions using selector methods that return `Vec<SessionSummary>`.

**`list_sessions_for_repo(selector)`** ([`src/review_store.rs#L34-L45`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs#L34-L45)) returns all persisted sessions belonging to a checkout path or a forge coordinate (`owner/repo`).

**`list_all_sessions()`** ([`src/review_store.rs#L47-L55`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs#L47-L55)) retrieves every session (local and PR) ordered newest-first.

**`resolve_pr_session(slug)`** ([`src/review_store.rs#L59-L66`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs#L59-L66)) converts a PR slug (e.g., `gh:owner/repo/pr/<n>`) into a `SessionRef` if the session exists.

```rust
use std::path::Path;

// List sessions for a specific repository checkout
let repo_path = Path::new("/home/me/project");
let sessions = store
    .list_sessions_for_repo(repo_path)
    .expect("failed to list sessions");

// Resolve a PR session from its slug
let slug = "gh:agavra/tuicr/pr/42";
if let Some(session_ref) = store
    .resolve_pr_session(slug)
    .expect("failed to resolve PR")
{
    // Session found
}

```

## Loading and Mutating Sessions

Once you have a `SessionRef`, load the full session data and modify it.

**`get_review(&session_ref)`** ([`src/review_store.rs#L67-L71`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs#L67-L71)) loads the complete `ReviewSession` from disk.

**`add_comment(&session_ref, request)`** ([`src/review_store.rs#L72-L84`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs#L72-L84)) appends a local draft comment atomically. It validates content, creates a `Comment` via `Comment::new`, inserts it based on `CommentTarget`, and updates the session's `updated_at` timestamp.

**`save_review(&session)`** ([`src/review_store.rs#L86-L90`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs#L86-L90)) persists a brand-new session or overwrites an existing one, returning its `SessionRef`.

```rust
use tuicr::review_store::{AddCommentRequest, CommentTarget};

// Load the full session
let mut review = store
    .get_review(&session_ref)
    .expect("could not load review session");

// Add a line-specific comment
let req = AddCommentRequest {
    target: CommentTarget::Line {
        path: std::path::PathBuf::from("src/main.rs"),
        line: 42,
        side: tuicr::model::LineSide::New,
    },
    content: "Consider extracting this block into a helper function".into(),
    comment_type: tuicr::model::CommentType::from_id("suggestion"),
    author: "my-bot".into(),
    commit_id: None,
};

store
    .add_comment(&session_ref, req)
    .expect("failed to add comment");

```

## Persistence Mechanics and Thread Safety

All I/O delegates to `crate::persistence::storage`, which writes sessions under `$XDG_DATA_HOME/tuicr/reviews/` (or the custom directory) and maintains manifests for fast listing.

The **`reviews_dir()`** helper ([`src/review_store.rs#L92-L98`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs#L92-L98)) abstracts path resolution:

```rust
fn reviews_dir(&self) -> Result<PathBuf> {
    match &self.reviews_dir {
        Some(path) => Ok(path.clone()),
        None => storage::get_reviews_dir(),
    }
}

```

**Atomicity**: `add_comment` and `save_review` use `storage::update_session_in_dir` and `storage::save_session_in_dir`, which lock the session file, merge external changes, and rename temporary files atomically. This prevents corruption when concurrent CLI tools or scripts access the same session.

## Complete Workflow Example

The following example demonstrates initializing the store, listing sessions, loading a specific review, and adding a comment:

```rust
use tuicr::review_store::{ReviewStore, AddCommentRequest, CommentTarget};
use std::path::Path;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. Initialize store
    let store = ReviewStore::new();
    
    // 2. Discover sessions
    let repo_path = Path::new("/home/me/project");
    let sessions = store.list_sessions_for_repo(repo_path)?;
    
    if let Some(first) = sessions.first() {
        // 3. Load session
        let session_ref = &first.session_ref;
        let review = store.get_review(session_ref)?;
        
        println!("Loaded session with {} files", review.files.len());
        
        // 4. Add comment
        let req = AddCommentRequest {
            target: CommentTarget::Line {
                path: std::path::PathBuf::from("src/lib.rs"),
                line: 10,
                side: tuicr::model::LineSide::New,
            },
            content: "This needs better error handling".into(),
            comment_type: tuicr::model::CommentType::from_id("issue"),
            author: "ci-bot".into(),
            commit_id: None,
        };
        
        // 5. Persist (automatically handled by add_comment)
        store.add_comment(session_ref, req)?;
    }
    
    Ok(())
}

```

## Summary

- **ReviewStore** provides the main entry point via `new()` or `with_reviews_dir()` for custom paths.
- Use **list_sessions_for_repo()** or **list_all_sessions()** to discover existing sessions, and **resolve_pr_session()** for PR-specific lookups.
- **get_review()** loads the full `ReviewSession` into memory for inspection.
- **add_comment()** atomically appends draft comments with precise targeting via `CommentTarget` and validates through `AddCommentRequest`.
- **save_review()** persists modifications atomically using file locking and temporary file replacement to ensure thread safety.
- All operations return `Result<T, TuicrError>` for robust error handling in production code.

## Frequently Asked Questions

### How do I use a custom storage directory instead of the default XDG path?

Call **`ReviewStore::with_reviews_dir(path)`** instead of `ReviewStore::new()`. This method ([`src/review_store.rs#L22-L28`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs#L22-L28)) accepts a `PathBuf` and overrides the platform-default reviews directory, which is ideal for testing or isolated tooling environments.

### What is the difference between `add_comment` and `add_comment_to_session`?

**`add_comment`** is the high-level API method that accepts a `SessionRef` and `AddCommentRequest`, loads the session, delegates to `add_comment_to_session` for validation and insertion, and persists the result. **`add_comment_to_session`** ([`src/review_store.rs#L9-L65`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs#L9-L65)) is the lower-level helper that performs the actual mutation logic on an in-memory `ReviewSession` and is public for use by the TUI and library consumers.

### How does the library handle concurrent access to session files?

The library guarantees atomicity through `storage::update_session_in_dir` and `storage::save_session_in_dir`, which implement file locking and atomic rename operations. When `add_comment` or `save_review` executes, the system locks the session file, merges any external changes, and writes to a temporary file before renaming it into place, preventing data corruption from concurrent CLI tools or scripts.

### Can I programmatically create a new review session from scratch?

Yes. Construct a `ReviewSession` programmatically, populate its fields (such as `session_notes`, `files`, and initial comments), then call **`save_review(&session)`** ([`src/review_store.rs#L86-L90`](https://github.com/agavra/tuicr/blob/main/src/review_store.rs#L86-L90)). This method persists the session to disk and returns a `SessionRef` that you can use for subsequent operations.