How to Use the Rust ReviewStore Library API for Programmatic Review Access
The tuicr crate exposes a pure-Rust ReviewStore API in 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) and the model modules:
ReviewStore(src/review_store.rs#L10-L30): The facade that manages the directory where sessions are stored.SessionRef(src/review_store.rs#L27-L41): Opaque handle to a single session file (PathBuf).SessionSummary(src/review_store.rs#L59-L71): Light-weight metadata shown bylist_*methods, including slug, kind, timestamps, and comment counts.AddCommentRequest(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): Enum defining where the comment attaches (review-wide, file, line, or line-range).ReviewSession(src/model/review.rs#L89-L124): In-memory representation containing files, comments, and reviewed hunk state.Comment(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) builds a store using the default location (~/.local/share/tuicr/reviews on Linux).
ReviewStore::with_reviews_dir(dir) (src/review_store.rs#L22-L28) overrides the storage location, useful for tests or isolated tooling.
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) returns all persisted sessions belonging to a checkout path or a forge coordinate (owner/repo).
list_all_sessions() (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) converts a PR slug (e.g., gh:owner/repo/pr/<n>) into a SessionRef if the session exists.
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) loads the complete ReviewSession from disk.
add_comment(&session_ref, request) (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) persists a brand-new session or overwrites an existing one, returning its SessionRef.
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) abstracts path resolution:
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:
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()orwith_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
ReviewSessioninto memory for inspection. - add_comment() atomically appends draft comments with precise targeting via
CommentTargetand validates throughAddCommentRequest. - 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) 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) 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). This method persists the session to disk and returns a SessionRef that you can use for subsequent operations.
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 →