# How tuicr Syncs and Displays Remote PR Review Threads: Architecture and Implementation

> Learn how tuicr syncs and displays remote PR review threads from GitHub GitLab and Bitbucket. Explore its architecture and implementation for efficient code review.

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

---

**tuicr synchronizes remote pull request review threads from GitHub, GitLab, or Bitbucket by fetching them through forge-specific backends, caching them in a unified model, and rendering them inline with diffs using a visibility-controlled filtering system.**

The `agavra/tuicr` repository implements a terminal-based code review workflow that aggregates discussions from multiple forges into a unified interface. Understanding how tuicr syncs and displays remote PR review threads requires examining its three-stage pipeline that bridges remote APIs with local terminal rendering while maintaining cursor-accurate layouts.

## Fetching Remote Threads via the ForgeBackend Trait

When a user executes `tuicr pr open`, the application initiates synchronization through the `App::load_pr` flow. This delegates to platform-specific backends that implement the `ForgeBackend` trait defined in [`src/forge/traits.rs`](https://github.com/agavra/tuicr/blob/main/src/forge/traits.rs) (lines 470-484).

Each forge provides its own backend implementation:

- **GitHub**: `GhBackend` in [`src/forge/github/gh.rs`](https://github.com/agavra/tuicr/blob/main/src/forge/github/gh.rs) (lines 350-360)
- **GitLab**: `GlabBackend` in [`src/forge/gitlab/glab.rs`](https://github.com/agavra/tuicr/blob/main/src/forge/gitlab/glab.rs) (lines 470-480)
- **Bitbucket**: `BktBackend` in [`src/forge/bitbucket/bkt.rs`](https://github.com/agavra/tuicr/blob/main/src/forge/bitbucket/bkt.rs) (lines 485-496)

These implementations override the `list_review_threads` method to execute platform-specific API calls, returning deserialized thread data for uniform processing.

```rust
// In the main event loop (simplified)
let pr = app.open_pr(target).await?;               // fetches PR details
let threads = backend.list_review_threads(&pr)?;   // remote fetch
app.forge_review_threads = remote_comments::dedupe_threads(threads);
app.session.remote_comments_visibility = PrCommentsVisibility::default(); // Unresolved

```

## Normalizing Data in the Remote Comments Model

After fetching, tuicr converts platform-specific responses into vendor-agnostic structures defined in [`src/forge/remote_comments.rs`](https://github.com/agavra/tuicr/blob/main/src/forge/remote_comments.rs). The central types include:

- `RemoteReviewThread`: Represents a complete discussion thread with metadata
- `RemoteReviewComment`: Individual comments containing author, body, and timestamp
- `RemoteReviewSummary`: PR-level review summaries from maintainers
- `PrCommentsVisibility`: Enum at lines 145-155 controlling display state (Unresolved, All, Hide)

The session stores fetched data in `App::forge_review_threads` and `App::forge_review_summaries`. Before storage, tuicr removes duplicates using `dedupe_threads` (lines 46-57), preventing redundant entries when refreshing PR data.

## Rendering Threads with Cursor-Aware Layout

The display logic integrates with diff rendering in [`src/ui/diff_unified.rs`](https://github.com/agavra/tuicr/blob/main/src/ui/diff_unified.rs) (lines 13-20) and [`src/ui/diff_side_by_side.rs`](https://github.com/agavra/tuicr/blob/main/src/ui/diff_side_by_side.rs). During the render phase, the UI consults `app.session.remote_comments_visibility` (lines 182-190) to determine thread eligibility.

The rendering pipeline executes three critical steps:

1. **Filtering**: `filter_threads` (lines 90-110) applies the visibility enum to include or exclude resolved discussions
2. **Layout Calculation**: `thread_display_lines` or `summary_display_lines` (lines 196-210) compute vertical space requirements, ensuring cursor arithmetic remains accurate for terminal navigation
3. **Side Anchoring**: `RemoteCommentSide::Right` or `Left` positions comments on the added or base side of the diff hunk

This architecture allows remote review threads to appear inline with code changes without disrupting the terminal's coordinate system.

## Controlling Visibility with the :comments Command

Users manipulate thread visibility at runtime through the `:comments` command, which accepts `Unresolved`, `All`, or `Hide` arguments. The handler updates session state via `set_remote_comments_visibility`, immediately triggering a re-render with the new filter applied.

```rust
// Handler for the `:comments` command
match args[0] {
    "unresolved" => app.set_remote_comments_visibility(PrCommentsVisibility::Unresolved),
    "all"        => app.set_remote_comments_visibility(PrCommentsVisibility::All),
    "hide"       => app.set_remote_comments_visibility(PrCommentsVisibility::Hide),
    _ => {}
}

```

## Exporting Remote Threads to Markdown

When users execute `:clip` or `:export`, the [`src/output/markdown.rs`](https://github.com/agavra/tuicr/blob/main/src/output/markdown.rs) module (lines 11-20) processes both local and remote comments through the same pipeline. The exporter inserts a configurable header (default: "## Upstream") at lines 470-500, then converts `RemoteReviewThread` structures into markdown format alongside local review notes.

```rust
let export = Export::new(&app.session);
let markdown = export.to_markdown(); // injects remote_comments_header and threads
println!("{}", markdown);

```

## Summary

- **tuicr** fetches remote PR review threads through the `ForgeBackend` trait implemented by GitHub, GitLab, and Bitbucket backends in `src/forge/`
- Raw API responses normalize into `RemoteReviewThread` and `RemoteReviewComment` structures in [`src/forge/remote_comments.rs`](https://github.com/agavra/tuicr/blob/main/src/forge/remote_comments.rs), with deduplication handled by `dedupe_threads`
- The `PrCommentsVisibility` enum controls display states (Unresolved, All, Hide) and persists across the review session in `app.session`
- Diff renderers in [`src/ui/diff_unified.rs`](https://github.com/agavra/tuicr/blob/main/src/ui/diff_unified.rs) use `filter_threads` and `thread_display_lines` to calculate cursor-accurate layouts that anchor to `RemoteCommentSide` values
- Remote threads export seamlessly via [`src/output/markdown.rs`](https://github.com/agavra/tuicr/blob/main/src/output/markdown.rs) using the `remote_comments_header` configuration, ensuring upstream discussions appear in final review documents

## Frequently Asked Questions

### How does tuicr handle duplicate remote comments when reloading a PR?

tuicr removes duplicate entries using the `dedupe_threads` function in [`src/forge/remote_comments.rs`](https://github.com/agavra/tuicr/blob/main/src/forge/remote_comments.rs) (lines 46-57) before storing fetched data in `App::forge_review_threads`. This ensures that refreshing a pull request doesn't create redundant thread entries in the session cache.

### Can tuicr display resolved review threads or only unresolved ones?

Users control visibility through the `:comments` command with three options: `Unresolved` (default), `All`, or `Hide`. The `PrCommentsVisibility` enum in [`src/forge/remote_comments.rs`](https://github.com/agavra/tuicr/blob/main/src/forge/remote_comments.rs) (lines 145-155) drives the `filter_threads` logic that determines which threads render in the diff view.

### Which files handle the actual API calls to GitHub, GitLab, and Bitbucket?

Platform-specific implementations reside in [`src/forge/github/gh.rs`](https://github.com/agavra/tuicr/blob/main/src/forge/github/gh.rs) (lines 350-360), [`src/forge/gitlab/glab.rs`](https://github.com/agavra/tuicr/blob/main/src/forge/gitlab/glab.rs) (lines 470-480), and [`src/forge/bitbucket/bkt.rs`](https://github.com/agavra/tuicr/blob/main/src/forge/bitbucket/bkt.rs) (lines 485-496). Each implements the `list_review_threads` method from the `ForgeBackend` trait defined in [`src/forge/traits.rs`](https://github.com/agavra/tuicr/blob/main/src/forge/traits.rs) (lines 470-484).

### How are remote threads positioned correctly in side-by-side diffs?

The renderer uses `RemoteCommentSide::Right` or `Left` to anchor comments to the appropriate diff side, while `thread_display_lines` in [`src/forge/remote_comments.rs`](https://github.com/agavra/tuicr/blob/main/src/forge/remote_comments.rs) (lines 196-210) calculates exact line heights. This ensures cursor arithmetic remains accurate in both unified and side-by-side modes defined in [`src/ui/diff_unified.rs`](https://github.com/agavra/tuicr/blob/main/src/ui/diff_unified.rs) and [`src/ui/diff_side_by_side.rs`](https://github.com/agavra/tuicr/blob/main/src/ui/diff_side_by_side.rs).