Review Hub
Stage, commit, push, and resolve conflicts for any worktree, with a merge-readiness rail and a push destination git itself resolved.
Overview
Review Hub is the review-first workspace for one worktree's Git state. You stage files, read a merge-readiness summary, write a commit message, push, and resolve conflicts without switching to a terminal or another app. It exists mainly to review and ship what an agent produced, but it handles any changes in the worktree.
The commit composer is the focal point. The file list starts collapsed, so you land on the message and expand the files when you want to look at them. Conflicts, divergence, readiness, and PR status all surface in the same place.
A panel, not a modal
Review Hub is a review panel: the same kind of object as a terminal, a file viewer, or a diff. Most entry points present it as a dialog, which is a presentation of a panel rather than a separate component: the panel renders unmodified inside the dialog frame, and the dialog owns the surface, the focus trap, Escape, and focus restore.
Two consequences follow, and both matter in practice.
- Dialogs layer. Opening a file's diff from Review Hub pushes a second dialog on top of the hub rather than replacing it. Every frame in the stack stays mounted, so the hub keeps its scroll position, its selection, and your half-written commit message while you read the diff. Only the topmost frame takes focus.
- You can promote it into the grid. The dialog header carries an Open as panel button. Click it and the panel moves into the panel grid alongside your terminals, where it stays put while an agent works. Promotion always targets the topmost dialog, so it is only offered there.
You can also add Review directly to the grid from the panel launcher, which skips the dialog entirely. See Terminals & Panels for how panels are arranged. When the panel has no worktree to work on, it reads "Worktree unavailable: Open a worktree to review and commit changes."
Opening Review Hub
Every route below dispatches the same worktree.openReviewHub action, so they all land on the same surface.
- The worktree card's inline button. A small commit icon on the card's details bar (see Worktree Cards). Its tooltip reads Review & Commit normally, and Review & Push on a clean worktree that still has unpushed commits: there is a next step there too, so the opener stays visible and only the label shifts.
- The worktree menu. The three-dot menu and the right-click context menu both carry Review & Commit. Open changes sits directly above it and goes to the diff workspace instead.
- The agent completion banner. When an agent finishes a run that touched files, a banner appears at the bottom of its pane reading "N files changed, review when ready." Click Review. Any review surface opening for that worktree dismisses the banner: you are already looking at what it was pointing at.
- The notification center. The "Agent finished with changes" inbox entry carries an Open review hub action. Repeated runs on one worktree supersede each other rather than stacking. See Notifications & Sound.
- The panel launcher. Search for "Review": it also matches on
diff,commit,stage, andgit. See Palettes & Menus. - The command palette. "Open Review Hub" opens it directly. The palette's Commit row also redirects here rather than committing: Daintree never derives a commit message for you, so the palette sends you to the surface that shows the staged files and asks you to type one.
Auto-staging on open
Opening Review Hub as a dialog stages every unstaged file when nothing is staged yet, so you land on a ready-to-commit view. If you already have a partial staging set, it is left alone.
This is deliberately scoped to the dialog entry point. A panel you promoted into the grid, or one restored on restart, does not replay the stage when it remounts: a surface that has been sitting open should not silently change your index behind you.
The merge-readiness rail
A compact strip sits directly under the header and answers one question: is this worktree ready to ship, and if not, what is in the way. It is derived, not configured: nothing to turn on.
The rail leads with a level chip:
| Level | Meaning |
|---|---|
| Ready | No blockers and no warnings. |
| Needs attention | No blockers, but at least one warning. |
| Blocked | At least one blocker. |
Beside the chip sit the three highest-priority items from a closed vocabulary of twenty, ordered blockers first, then warnings, then infos. Each carries a severity dot, a short label, an optional detail, and sometimes a call to action. Anything past the first three collapses into a +N more hover.
The blockers are the states that make a commit impossible: a merge, rebase, cherry-pick or revert in progress; conflicted files; detached HEAD; a failed push. Warnings cover things worth a second look: behind the remote, CI failing on the PR, changes requested, only generated files changed, nothing staged, a closed PR, forge auth or rate-limit trouble. Infos are context: CI pending, review required, draft PR, merged PR, no PR for this branch, committing to a protected branch, no remote configured, unpushed commits.
Only four calls to action exist, and every one of them routes to a path Review Hub already has: Show conflicts, Show files, Pull and rebase (through its own confirmation), and Open PR. The readiness layer never commits, pushes, or merges anything itself.
Reading readiness from an agent
The same derivation is exposed as worktree.reviewReadiness, a read-only query action. It returns the level, three booleans (commitReady, pushReady, prReady), the full blocker/warning/info lists, staged and unstaged counts, ahead and behind counts, and the PR summary. It is annotated read-only and idempotent, and it performs no git or forge mutation.
Two design choices are worth knowing if you consume the result. Signals that depend on forge data report unknown rather than passing when that data has not arrived: an unknown is genuinely unknown and must not be read as a green light. And pushReady requires the behind count to be affirmatively zero, so an unresolved divergence state never reads as pushable. Its suggested next actions are restricted to the same closed safe set the rail uses, so a read-only result can never advertise a mutating follow-up.
Working tree vs base branch
Working tree mode
The default. You get a Staged section, a Changes (unstaged) section, and the commit composer. The refresh button is visible.
On a clean tree you see "Working tree clean: No changes to commit." If the tree is clean but the branch is ahead of its remote, that second line becomes a count ("3 commits not pushed") and a Push button appears beneath it, so you do not have to stage something just to reach a push control. The button appears only when readiness says the push can actually land.
Comparing against the main branch
Toggle to vs the main branch to see every file that differs from it, listed flat under "Changed vs (N files)". This view is read-only: no staging, no composer. Click a file to open its diff against the base. The toggle is disabled when you are already on the main branch.
When a pull request has unresolved review comments, matching rows carry an amber count badge. Click it to open that file's conversation in the PR in your browser.
The review loop
Four steps, each with its own page. You will not always need all four: a clean push is steps two and three, and step four only exists because remotes move under you.
- Read the diff. Walk the change file by file, mark each one viewed, and compare images side by side.
- Stage what you want. The file list, its filters, staging and unstaging, and the header controls the whole surface shares.
- Commit and push. Writing the message, committing, setting an upstream, and what each result state means.
- Handle divergence. Pull and rebase, force-with-lease, resolving conflicts, detached HEAD, and the errors that come with them.
What happens after the push, and where the pull request lives, is Code Forge.
Keyboard shortcuts
Inside Review Hub, with the file list expanded:
| Key | Action |
|---|---|
| ↑ / ↓ | Move focus between file rows |
| Enter | Open the focused file's diff |
| Space | Stage or unstage the focused file |
| v | Toggle the focused file's viewed marker |
| Shift+F10 / Menu | Open the focused row's context menu |
| Command Control Control +click | Toggle multi-select on a row |
| Shift+click | Range-select from the anchor |
Every one of those is suppressed while you are typing in a filter or the composer, while a menu is open, while a diff is layered above, or while the file list is collapsed: a key that acts on rows you cannot see is a key that acts by surprise.
In the composer:
| Key | Action |
|---|---|
| Command-Enter Control-Enter Control-Enter | Commit & Push (or Commit with no remote) |
| Shift-Command-Enter Control-Shift-Enter Control-Shift-Enter | Commit only |
| ↑ / ↓ (caret at start) | Recall previous / next commit message |
Escape works in priority order, one step per press: close an open diff, then clear a base-branch file selection, then clear a multi-selection, then close Review Hub.
Global Git chords
These act on the active worktree whether or not Review Hub is open.
| Action | Shortcut |
|---|---|
| Stage all changes | Command-K, then Command-G Control-K, then Control-G Control-K, then Control-G |
| Commit staged changes | Command-K, then Command-C Control-K, then Control-C Control-K, then Control-C |
| Push to remote (opens the commit-preview confirmation) | Command-K, then Command-P Control-K, then Control-P Control-K, then Control-P |
| Open changes for the focused worktree | Shift-Command-D Control-Shift-D Control-Shift-D |
Open changes lands in the diff workspace rather than in Review Hub.
Chords are two key combinations pressed in sequence, within about a second. For the full reference, see Keyboard Shortcuts.
What persists, what resets
Seven things survive a restart. Six of them are diff preferences shared with the diff workspace; the seventh is the push opt-out.
| Setting | Default | Scope |
|---|---|---|
| Diff layout (Split / Unified) | Split | Persisted, global |
| Wrap long lines | Off | Persisted, global |
| Ignore whitespace | Off | Persisted, global |
| Show the diff file sidebar | On | Persisted, global |
| Diff content scope (Changes / Full file) | Changes | Persisted, global |
| Diff text size (S / M / L) | M | Persisted, global |
| "Don't ask again" push confirmation | Off | Persisted, per worktree |
| File list expanded / collapsed | Collapsed | Session only, per worktree |
| Filter, sort, density, show-generated | None | Session only, reset on close |
| Viewed markers | None | Session only, cleared on commit |
The file sidebar's visibility and the full-file scope are sticky preferences, not per-panel state: set them once and every diff you open afterwards, from any surface, honors the choice.