---
title: Review changes (diff viewer)
---

# Review changes (diff viewer)

## What it is

The **Review-Changes** surface is Omniscio's built-in **git diff viewer** — a code-review pane for looking at exactly what changed in a project's files and accepting or rejecting those changes hunk-by-hunk or file-by-file, without leaving the app. It is how you review the work an agent did before you keep it.

It has two halves:

- **The Changes panel** — a sidebar list of every changed file in the project (or just the files a single session touched), grouped into a folder tree, with per-file +/− line counts, a status filter (Modified / Added / Deleted / Renamed / Untracked), a sort control, a review-progress summary bar, and (in Project mode) a **commit box** for writing a commit and pushing it.
- **The Diff viewer** — the main pane that opens when you click a file. It renders the actual diff (added lines green, removed lines red) with a dense, IDE-style layout, and overlays a full review toolbar: unified vs. split view, accept/reject for the whole file _and_ for each individual hunk, in-diff search, git blame, inline annotations, a whitespace toggle, font-size controls, file-to-file navigation, and a minimap.

It is built on **Monaco** — the same editor engine that powers VSCode — so it looks and behaves like VSCode's own diff view: side-by-side or inline, with long runs of unchanged code collapsed, built-in find, and a minimap. It renders from the file's full original and modified text (not an HTML patch), so the syntax highlighting and navigation match the real editor.

**There are two of these — a desktop one and a phone one.** Everything above describes the desktop surface, which lives in the **File Explorer** sidebar pane and is hidden at phone width. On a phone you get a separate, purpose-built screen instead — see **[On your phone](#on-your-phone)** below. Neither has a CLI control route; reviewing changes is an in-app action. On both, files that are binary or larger than the viewer's size cap can't be shown — you'll see a "Can't show this file inline" placeholder instead of an empty diff.

## Where to find it

### On your phone

The desktop viewer is built on Monaco — VSCode's editor engine — which needs a mouse for its
scrolling, its hover controls and its per-hunk buttons. So the phone gets its own screen rather
than a shrunken copy of that one. It is **off by default** while it is in development; turn it on
under Settings → Lab ("Review changes on your phone").

**How to open it:** open a session, tap the **⋯** menu in its header, and tap **View Diffs**.
(That menu item has always been there on a phone — before this screen existed, tapping it did
nothing when the session had changes to show.)

**What you get:**

- A list of the changed files, each with its status letter and its +/− line counts. If the
  project holds several git repos, the list is split into a section per repo.
- Tap a file to see its diff as a stack of blocks — one per changed region, added lines green
  with a `+`, removed lines red with a `−`, and a few lines of surrounding context. Long lines
  scroll sideways on their own row rather than wrapping.
- **Keep** and **Revert** buttons on every block, sized for a thumb. Revert asks first, because
  it rewrites the file on disk and can't be undone. After either one the diff reloads, so a
  second tap always acts on the block you actually pressed.
- **Keep file** and **Discard file** for the whole file, and a reviewed-of-total count in the
  header.
- In **Whole project** mode, a commit box per repo — write a message (or have the AI draft one),
  then **Commit**, or **Commit & Push**. Pushing asks you to confirm first and names the branch
  it is about to send.
- **Discard ALL changes**, which throws away every uncommitted change in the project. It makes
  you type the word "discard" first, and it tells you how many repos it is about to wipe.
- Pull down on the file list to refresh it — useful when an agent is still working while you read.

**What it deliberately does not have:** split view, in-diff search, git blame, inline
annotations, the minimap, and the whitespace and font-size controls. Those are desktop
affordances that would crowd a phone screen without earning the space. Use the desktop viewer
when you need them.

**A note on safety.** Accepting, reverting, discarding and pushing from a phone all reach the
same git commands the desktop uses. On a paired phone those commands travel over your Omniscio
web-access link, and anyone holding that link can run them — including discarding uncommitted
work and pushing to your remote. That was a deliberate decision (2026-09-08) to make the phone
screen genuinely useful rather than read-only. If that trade is not one you want, turn the
feature off in Settings → Lab and the phone goes back to having no diff screen at all.

On the desktop, the diff review surface is part of the **File Explorer** on the right side of a project's workspace. Its **Changes** tab lists changed files; clicking one opens the diff in the main area. On a phone, you get there from a session instead — open the session, tap the **⋯** menu, and tap **View Diffs**.

You choose what to review with the **Project / Session** toggle at the top of the Changes panel:

- **Project** — every uncommitted change in the project's git working tree. If the folder contains **more than one git repo** — sibling repos side by side, or a repo nested inside another — Omniscio discovers them all (recursively, within a bounded depth) and shows each repo as its own collapsible section, headed by the repo name, its branch, and its file count. A single-repo project looks exactly as before (one flat list). This means a folder that isn't itself a git repo but holds repos underneath still shows their changes.
- **Session** — only the files the currently-open session changed (disabled when no session is active). Session mode reviews the project's root repo only.

The panel refreshes itself whenever an agent in the project finishes a message — for example when its turn ends — even while other agents are still busy typing, so edits show up without you doing anything. Text an agent is still typing never triggers a refresh, the file list stays on screen while it updates, and a refresh that finds nothing new leaves the list exactly as you left it (folders you collapsed stay collapsed). There is also a manual **Refresh** button. A **commit picker** lets you diff against a chosen base commit instead of the working tree's default base. If the folder isn't a git repository **and** no repos are found underneath it, the panel just says "Not a git repository".

### How to use it

1. **Open the Changes panel** and pick **Project** or **Session**. The changed files appear as a folder tree (toggle to a flat list with the tree/list button). Each row shows its status letter and how many lines were added/removed.
2. **Filter and sort if needed.** Click a status chip (All / M / A / D / R / ?) to show only that kind of change; use the sort dropdown to order by Name, Status, or amount of Changes.
3. **Click a file** to open its diff in the main pane.
4. **Read the diff.** Added lines are green, removed lines red, with word-level highlights inside changed lines. Long runs of unchanged context auto-collapse (Monaco's hide-unchanged-regions) so you focus on what changed; click a collapsed region to expand it.
5. **Accept or reject — at two granularities:**
   - **Per hunk:** a small **✓ / ✗** control floats beside each changed block — click the green **✓** (Accept this hunk — keeps it and applies it) or the red **✗** (Reject this hunk — reverts just that block). Acted-on hunks show "Accepted" / "Reverted".
   - **Per file:** use the toolbar **✓ Accept (Y)** to mark the whole file reviewed/kept, or **✗ Reject (X)** to discard _all_ changes to that file (this is a destructive discard and asks for confirmation first — it cannot be undone).
   - **In bulk:** the review-summary bar offers **Accept all remaining** and **Reject all unreviewed** (the latter confirms, since it permanently discards).
6. **Move through files** with the **‹ / ›** toolbar arrows (or **J** / **K**). A `position/total` counter and a `reviewed/total` counter track your progress through the changeset.
7. **Open in your editor** with the toolbar **Open (O)** button to jump to the file in your external editor when you'd rather edit than review inline.

### Toolbar tools

- **Unified / Split view** — toggle between a single-column diff and a side-by-side (old vs. new) layout. Split view scrolls the two panes in sync.
- **Whitespace toggle** — hide or show whitespace-only changes (re-fetches the diff ignoring whitespace).
- **Font size −/+** — shrink or grow the diff text (10–20 px), remembered as a setting.
- **Search (F / Ctrl+F)** — opens Monaco's built-in find widget to search and step through matches inside the current file's diff.
- **Blame (B)** — marks each line; hover a line to see the commit author, date, short-SHA, and summary that last touched it.
- **Annotations** — click a line's left margin to attach a private note to that line; annotated lines get an amber dot you can hover to read the note. Notes are yours, for review — they don't change the code.
- **Minimap** — Monaco's built-in thumbnail of the file down the right edge for fast scrolling on large files (toggle via Settings → Code Review → Diff Minimap).

### Keyboard shortcuts (Diff Review)

When the diff viewer is focused, single-key shortcuts drive review (all rebindable under Settings → Keyboard Shortcuts → **Diff Review**):

| Key           | Action                                        |
| ------------- | --------------------------------------------- |
| **J** / **↓** | Next changed file                             |
| **K** / **↑** | Previous changed file                         |
| **Y**         | Accept (keep) the selected file               |
| **Shift+Y**   | Accept all remaining files                    |
| **X**         | Reject (discard) the selected file            |
| **Shift+X**   | Reject all remaining files                    |
| **V**         | Toggle unified / split view                   |
| **W**         | Toggle whitespace visibility                  |
| **F**         | Open Monaco's in-diff find widget             |
| **B**         | Toggle git blame                              |
| **O**         | Open the file in an external editor           |
| **R**         | Refresh the diff                              |
| **Esc**       | Deselect the file and return to the file list |

## How it behaves

### Commit and push (Project mode)

When you're in **Project** mode, each repo with changes shows a **commit box** under its header (a single box for a single-repo project; one box per repo for a multi-repo project). It is a guided [Conventional Commits](https://www.conventionalcommits.org/) composer, like VSCode's Conventional Commits extension:

1. **Fill in the fields.** Pick a **type** (`feat`, `fix`, `docs`, …), optionally a **scope**, and write a **subject**. A live **preview** shows the exact message git will receive (`feat(auth): add token refresh`). A counter warns past 72 characters, and a **Breaking change** toggle adds the `!` marker plus a `BREAKING CHANGE:` footer. The type list and the one-click **scope suggestions** are mined from the repo's own history, so a project that already uses its own types and scopes gets them offered back.
2. **Or let AI fill them in.** Click **✨ Generate** to have AI read that repo's diff and populate every field. It is steered toward the scopes your repo already uses. Review and edit before committing. Generating needs an AI API-key account and uses a small, cheap model; it's disabled when there are no changes.
3. **Need something the fields can't express?** Click **Edit as text** for a plain textarea (co-authors, trailers, custom footers). **Use fields** switches back and re-reads your text into the fields.
4. **Commit.** Click **Commit** to stage **every** change in that repo (`git add -A`) and commit it locally. Click **Commit & Push** to commit and then push the current branch to its remote (GitHub) in one step. Both buttons stay disabled until the repo has changes and the draft has at least a type and a subject (in raw mode: any message).
5. **What you'll see.** A success toast ("Committed." or "Committed and pushed."), the fields clear, and the file list refreshes (the committed files drop off). If a push fails after the commit, Omniscio tells you the commit was saved locally and why the push didn't go through — your work is never lost.

Notes: the push **never** pops a terminal/login prompt — Omniscio uses your already-connected GitHub credentials, and fails with a clear message if it can't authenticate or your branch is behind the remote (pull first, then push). If git doesn't yet know your name/email, Omniscio tells you the one-time `git config` command to set them. Committing always includes all changes — the per-file Accept/Reject above is for reviewing/discarding, not for choosing what goes into a commit.

### What "accept" and "reject" actually do

- **Accept a hunk** applies that specific change to your working file (it reconstructs a patch for just that hunk and applies it), then marks the hunk done.
- **Reject a hunk** reverts that specific block in your working file.
- **Accept a file** marks the whole file as reviewed/kept — you're signing off on it.
- **Reject a file** (or **Reject all unreviewed**) **discards** the changes to that file in the working tree. This is a real, irreversible git discard, which is why it always asks for confirmation. A successful accept/reject shows a toast; a failure shows an error toast and leaves your file untouched.

### AI features and the off-switch (D16)

Two spots in this surface can call an AI model — the **✨ AI Summary** strip above the diff ("Summarize File" / "Summarize All Changes"), and the **✨ Generate** button in the commit box that drafts a commit message from the diff.

- **They are per-click opt-in.** Neither one runs on its own — each only fires when you click it.
- **They are inert without an AI account.** Both need an AI API-key account connected to Omniscio; with none connected, clicking reports an error and nothing is sent anywhere.
- **That is the declared off-switch.** The sanctioned way to disable these features is to not connect an AI API-key account (or simply not click them). There is deliberately **no separate Settings toggle** — the features are cheap, opt-in, and dead without an account, so a toggle would be redundant surface area.

## For agents

### Where things live (for agents with repo access)

- Diff pane (Monaco `DiffEditor`) + toolbar + per-hunk Accept/Reject overlay + blame/annotation decorations + view modes: [/src/renderer/src/features/file-explorer/DiffViewer.tsx](/src/renderer/src/features/file-explorer/DiffViewer.tsx). Shared Monaco bootstrap (worker, language map, theme): [/src/renderer/src/lib/monaco/](/src/renderer/src/lib/monaco/). The contract is [monaco-viewers-contract.md](/.claude/memory/contracts/monaco-viewers-contract.md).
- Changes list (file tree, Project/Session toggle, status filter, sort, commit picker, review summary, auto-refresh on session output): [/src/renderer/src/features/file-explorer/ChangesPanel.tsx](/src/renderer/src/features/file-explorer/ChangesPanel.tsx), with [CommitPicker.tsx](/src/renderer/src/features/file-explorer/CommitPicker.tsx), [DiffReviewSummary.tsx](/src/renderer/src/features/file-explorer/DiffReviewSummary.tsx), and [DiffAnnotation.tsx](/src/renderer/src/features/file-explorer/DiffAnnotation.tsx).
- Commit box (per-repo message + Generate + Commit / Commit & Push): [CommitBox.tsx](/src/renderer/src/features/file-explorer/CommitBox.tsx); message generation + `stageAllAndCommit` / `pushCurrentBranch` in [git-service.ts](/src/main/services/git-service.ts) over the `git:generate-commit-message` + `git:commit` channels. The contract is [commit-push-contract.md](/.claude/memory/contracts/commit-push-contract.md).
- Nested/sibling-repo discovery + per-repo grouping (the multi-repo `git:multi-repo-changes` channel, `discoverRepos` / `getMultiRepoChanges` in [git-service.ts](/src/main/services/git-service.ts), and the `repoSubpath` routing on per-file git ops): the contract is [nested-repo-changes-contract.md](/.claude/memory/contracts/nested-repo-changes-contract.md).
- The pane is gated desktop-only via the File Explorer sidebar ([FileExplorerSidebar.tsx](/src/renderer/src/features/file-explorer/FileExplorerSidebar.tsx), `hidden md:flex`).
- All diff state (selected file, hunk states, reviewed set, view mode, blame, annotations, accept/reject/discard actions) lives in the git store: [/src/renderer/src/stores/git-store.ts](/src/renderer/src/stores/git-store.ts).
- Diff-review keybindings (category `diff-review`): [/src/shared/keybindings.ts](/src/shared/keybindings.ts).

## Related

- [pull-requests.md](pull-requests.md) — review changes that already landed on a branch / in a PR, rather than the working tree
- [peek-viewer.md](peek-viewer.md) — quick read-only preview of a single file's contents (no diff / no accept-reject)
- [keyboard-shortcuts.md](keyboard-shortcuts.md) — the full keybinding panel, including the Diff Review group
