review: TUI-based patch review workflow (alpha)

Warning

b4 review is a technology preview (alpha). Commands, keybindings, configuration options, and on-disk formats may change in incompatible ways between releases. Bug reports and feedback are welcome at tools@kernel.org.

The b4 review command provides a TUI-based workflow for maintainers who receive patches on mailing lists. It lets you track incoming patch series, review diffs with inline commenting, add code-review trailers, send review emails, and accept (apply) patches — all from a single terminal interface.

The workflow is built around a lightweight SQLite tracking database that records every series you are interested in, together with a per-series review branch in your git repository where comments, trailers, and review state are persisted between sessions.

Getting started

Enrolling a repository

Before you can track series, you need to enroll the repository:

b4 review enroll [path] [-i identifier]

This creates metadata under .git/b4-review/ and a SQLite database in $XDG_DATA_HOME/b4/review/. The -i flag sets the project identifier (defaults to the repository directory name). You only need to do this once per repository.

The -i flag lets you work with multiple checkouts of the same git repository, for example if you manage multiple subsystems. This way you can have ~/work/linux-subsystemA with identifier “subsystemA” and ~/work/linux-subsystemB with identifier “subsystemB”.

Tracking a series

Once enrolled, add a series to the tracking database:

b4 review track <msgid|url|change-id> [-i identifier]

You can also pipe a message on stdin:

cat message.eml | b4 review track

This makes it easy to integrate with mail clients. For example, to track a series directly from mutt with a single keypress, add the following to your ~/.muttrc:

macro index 8 "<pipe-message>~/bin/b4 review track -i linux-subsystemA<return>"

Pressing 8 on any message in the series will pipe it to b4 and start tracking.

B4 fetches the series from lore, discovers all available revisions (older and newer), and stores everything in the tracking database.

Tracking unthreaded series

When a submitter sends patches without proper threading (each patch as a separate, unrelated message), you can use --rethread to stitch them together. Pass any single patch from the series and b4 auto-discovers the rest:

b4 review track --rethread <msgid>

B4 searches lore for other patches from the same author sent within a 1-hour window, matches them by [PATCH n/m] counters and version, and assembles the full series. You can also provide all message IDs explicitly:

b4 review track --rethread <msgid1> <msgid2> [<msgid3> ...]

Or read them from stdin:

b4 review track --rethread - < msgids.txt

The --rethread flag cannot be combined with a positional series identifier.

New in version v0.16.

Using the TUI

Launch the TUI inside the repository with:

b4 review tui [-i identifier]

If you are already on a review branch (b4/review/<change-id>), the TUI opens the review interface directly and shows a notification suggesting you switch to your target branch (configured via b4.review-target-branch, or master/main by default) if you want to see the full tracking list instead. Otherwise it starts in the tracking list.

You can leave the tui running. Any series added in another terminal will be automatically recognized and displayed.

Tracking list

The tracking list shows all series you are following, with their current status.

Series lifecycle

Every tracked series passes through these statuses:

Status

Meaning

new

Freshly tracked, not yet reviewed

reviewing

Review branch created, review in progress

replied

Review comments sent to the mailing list

waiting

Waiting for a new revision from the submitter

snoozed

Deferred until a date, duration, or git tag

accepted

Patches applied to the target branch

thanked

Thank-you note sent to the contributor

archived

Review completed and archived

gone

Review branch deleted or missing (e.g. after a sync)

Series are grouped by lifecycle stage — Active (reviewing/replied/ accepted/thanked), New, Waiting, Snoozed, and Gone — and sorted within each group by the most recent activity, whether that is a new mailing list reply or a local status change.

Listing columns

Each row in the tracking list shows:

  • Submitter — patch author name (truncated if necessary)

  • A — attestation indicator: when all signatures verify, blank otherwise (details shown in the bottom panel)

  • A·R·T — Acked-by · Reviewed-by · Tested-by trailer counts collected from the review branch

  • Msgs — total message count for the thread, with any unseen messages shown as +N in yellow (populated after pressing u)

  • S — single-character status symbol; * suffix means the tracking data needs a refresh

  • Subject — compact [subsystem,vN,0/M] prefix followed by the series subject

Status symbols

Symbol

Status

new

reviewing

replied

waiting

snoozed

accepted

thanked

gone

Keybindings

Key

Action

Enter

Enter series (reviewing) or open action menu (other states)

r

Review — create or re-enter the review branch

t

Target branch — set or clear the per-series target branch

c

CI checks — run configured check commands and show results (see CI check integration)

e

Thread — open the lite thread viewer (see below)

a

Action menu — context-sensitive actions (see below)

d

Range-diff between revisions

u

Update — fetch latest trailers and check for newer revisions for the selected series

U

Update all — same as u but for all tracked series (skipping snoozed)

l

Limit — filter the list of displayed series

s

Shell — suspend to an interactive sub-shell

p

Patchwork — switch to the Patchwork browser (if configured)

Q

Queue — view and deliver queued thank-you messages (visible only when the queue is non-empty; see thanks_queue)

j/k

Move cursor down/up

?

Help — show keybinding reference

q

Quit

Press t to open the target branch dialog. Type a branch name (recently used branches are suggested) and press Enter to run an applicability check — b4 will test-apply the series patches against the chosen branch and report whether they apply cleanly. Press Ctrl-y to confirm without checking, Ctrl-d to clear the per-series target and fall back to the configured default, or Escape to cancel without changes.

The a key opens a context-sensitive action menu. Each action has a single-keypress shortcut shown in square brackets so you can act quickly — for example, a then T to take a series. Available actions depend on the series status:

Reviewing / replied:

  • [T] Take — apply patches to the target branch

  • [R] Rebase — rebase review branch onto HEAD

  • [w] Mark as waiting — waiting on new revision

  • [s] Snooze — defer until a date, duration, or git tag

  • [U] Upgrade — switch to a newer revision (when available)

  • [A] Abandon / [x] Archive

New / gone:

  • [r] Review — create or re-enter the review branch

  • [s] Snooze — defer until later (new only)

  • [A] Abandon

Waiting:

  • [r] Review — return to reviewing

  • [A] Abandon / [x] Archive

Snoozed:

  • [u] Unsnooze — wake up and restore previous status

  • [A] Abandon / [x] Archive

Accepted:

  • [t] Thank — send a thank-you note

  • [A] Abandon / [x] Archive

The details panel at the bottom shows the full original subject, sender, attestation status, send date, status, change-ID, lore link, known revisions, and the review branch name for active and snoozed series.

Attestation display

The attestation row shows the DKIM and patatt signature verification results for the series. Possible states:

  • pending — not yet checked; press u to update

  • no signatures — checked, but no DKIM or patatt signatures found

  • ✔ identity (green) — signature verified successfully

  • ? identity (no key) (orange) — signed, but the verifying key is not available locally

  • ✘ identity (signature failed) (red) — key is available but verification failed

Attestation is checked automatically when a series is updated (u or U) and when a review branch is checked out. Results are stored in the tracking database and displayed without re-checking on subsequent views. The attestation check honours the b4.attestation-policy and b4.attestation-staleness-days configuration options.

Lite thread viewer

Pressing e on any series opens a mutt-style thread viewer that fetches the full mailing list thread from lore and displays it in two levels:

Thread index — a flat list of all messages (patches and follow-ups) with a flag column, date, author, mutt-style threading tree art, and subject. Each message has one of four visual states:

  • Unseen (N) — not yet opened in the message viewer. Shown in the warning colour.

  • Flagged () — marked as important by the maintainer. Shown in bold accent colour for the entire row. Toggle with F in the message viewer.

  • Answered () — the maintainer has replied to the parent of this message (either from b4 or detected from their own email client). Shown with a dim accent.

  • Seen — previously opened. The row is dimmed.

Flag state is stored in a cross-project messages.sqlite3 database (under $XDG_DATA_HOME/b4/review/) keyed by message-id, so flags persist across sessions and work from both the tracking list and the Patchwork browser. When a review branch is checked out, all patches in the series are automatically marked as seen. Replies sent by the maintainer from an external email client are detected when the thread is loaded, and the parent messages are marked as answered.

Message view — full headers (Date, From, To, Cc, Subject, Link, Attestation) and message body with diff syntax highlighting and quoted-line dimming. Addresses are packed horizontally to make good use of available terminal width.

The thread viewer is available from both the tracking list and the Patchwork browser, providing a quick way to read a thread and fire off a reply without creating a review branch.

Thread index keybindings

Key

Action

Enter

Open the selected message in the message viewer

j/k

Move cursor down/up

q

Close the thread viewer

Message view keybindings

Key

Action

j/k

Next/previous message in thread

Enter

Scroll down one line

Backspace

Scroll up one line

Space

Page down

-

Page up

S

Skip past the next block of quoted text

^

Jump to top of message

$

Jump to bottom of message

r

Reply to the current message

F

Toggle flagged (important) state

q/Escape

Return to the thread index

The S key works like mutt’s skip-quoted: it scans forward from the current scroll position, finds the next block of quoted lines (> prefixed), skips past it, and scrolls to the first non-quoted line with a couple of trailing quote lines visible for context.

Review interface

The review interface presents a split-pane view: the left pane lists patches in the series, and the right pane shows the diff for the selected patch.

Review mode keybindings

Key

Action

[/]

Previous/next patch

j/k

Scroll down/up

h/l

Scroll left/right

Space/Backspace

Page down/up

./,

Jump to next/previous review comment

Tab

Switch focus between panels

t

Trailers — quickly add Reviewed-by, Acked-by, etc.

r

Reply — open $EDITOR to reply

n

Notes — view or edit review notes

f

Followups — toggle follow-up messages and external inline comments from lore

a

Agent — run review LLM agent (if configured)

d

Done — toggle “done” state on the current patch

x

Skip — toggle “skip” state on the current patch

H

Hide skipped — toggle visibility of skipped patches

c

CI checks — run check commands and show results (see CI check integration)

e

Toggle email mode

s

Shell — suspend to an interactive sub-shell

?

Help — show keybinding reference

q

Quit

Email preview mode keybindings

Key

Action

T

Edit To/Cc/Bcc recipients

S

Send review emails

e

Toggle email mode

Inline diff comments

Press r on a patch to open $EDITOR with the quoted commit message and diff. The content uses the standard mailing-list reply format: original content is quoted with ``> `` and your comments go on unquoted lines between quoted sections.

To leave a comment, write it on a new line below the quoted diff line you want to comment on:

> @@ -10,3 +10,4 @@
>  context line
> +new_function();

Needs a NULL check here.

> +return result;

You can also comment on the commit message — it appears quoted at the top of the editor, before the diff content. Comments before the first quoted line are stored as general comments on the patch.

On save, b4 parses your reply and extracts each comment, associating it with the nearest preceding quoted line (file path and line number, or commit message line). Any trailers you added (e.g. Reviewed-by) are extracted and stored separately. Your comments are displayed in the diff view as coloured bordered panels with your name shown in the bottom-right corner. Use . and , to jump between comments.

Press r again to re-open the editor with your existing comments interleaved into the quoted content for further editing.

When you send review emails, b4 automatically builds a standard quoted-reply for each patch: only hunks that contain comments are included, diff lines are quoted with >, and your comments appear unquoted after the relevant line — matching the format expected on mailing lists. To keep replies concise, b4 shows at most 5 lines of diff context above each comment and collapses larger gaps with a > [...] marker.

The left pane summarises the review state per reviewer using a trailer overlay. This overlay always shows all reviewers — both your own review and any external reviewers — so you can see at a glance who has commented on the current patch.

External inline comments

B4 can display inline comments from external sources alongside your own in the diff view. These sources include:

  • Follow-up messages — replies to patches on the mailing list that quote diff lines and add comments. These use the standard mailing-list review format: diff lines quoted with > and unquoted reviewer comments.

  • Sashiko — the sashiko.dev AI code review service (when b4.sashiko-url is configured).

  • Review agents — AI review agents invoked with a.

External inline comments are only displayed when follow-ups are active — press f to toggle them on. Your own comments are always visible regardless of the f state. When external comments are hidden, the diff view shows a gutter marker in the left margin on lines that have external comments, so you can see at a glance where reviewers have commented without loading the full panels.

Each reviewer’s comments are displayed in a distinct colour (green is excluded from the palette to avoid blending with diff additions). The reviewer’s full name is shown in the bottom-right corner of each comment panel; your own comments show “You” instead of your name.

Adopting external comments

When you open the reply editor (r), external reviewer comments are shown with a | prefix:

> +new_function();

| Pat Reviewer <pat@example.com>:
|
| Is it possible for this code to trigger an exception
| on heterogeneous systems?
|
| via: https://lore.kernel.org/...

> +return result;

Lines starting with | are read-only — they are shown in the editor for context but are not saved as your own comments.

To adopt an external comment as your own (for example, to endorse an agent suggestion or incorporate a reviewer’s point), delete the | prefix from the comment lines:

> +new_function();

Is it possible for this code to trigger an exception
on heterogeneous systems?

> +return result;

The comment is now treated as yours and will be included when you send review emails. You can also edit the text before saving. The original reviewer’s copy remains in the tracking data.

Editor syntax highlighting

B4 ships syntax highlighting files for Vim and Emacs in the misc/ directory. These provide diff-aware colouring for the reply editor format: quoted additions in green, removals in red, hunk headers in cyan, external | comments visually bracketed, and your own comments in the default foreground. Spell checking is limited to your own comment lines.

Vim

Copy or symlink the files into your Vim configuration:

mkdir -p ~/.vim/syntax ~/.vim/ftdetect
ln -s /path/to/b4/misc/vim/syntax/b4review.vim ~/.vim/syntax/
ln -s /path/to/b4/misc/vim/ftdetect/b4review.vim ~/.vim/ftdetect/

If ftdetect does not work with your plugin manager, add this to your ~/.vimrc instead:

augroup filetypedetect
  autocmd BufNewFile,BufRead *.b4-review.eml set filetype=b4review
augroup END

Emacs

Add this to your ~/.emacs.d/init.el or ~/.emacs:

(load "/path/to/b4/misc/emacs/b4-review-mode.el")

The mode is automatically activated for *.b4-review.eml files.

Per-patch states

Each patch in the series can be marked with a state to help you track your review progress:

State

Marker

Key

Meaning

(none)

Not yet reviewed

Unchanged

Patch identical to prior revision (auto, on upgrade)

External

±

External reviewers have inline comments (auto)

Draft

You have comments, a reply, or a nack trailer (auto)

Done

d

Review complete, include in outgoing emails

Skip

x

Intentionally skipped, exclude from outgoing emails

The marker column shows the highest-priority state that applies. For example, if external reviewers have commented but you have not yet reviewed, the marker shows ±; once you add your own comments it changes to . The marker is set automatically when upgrading a series to a newer revision — it indicates that the patch content has not changed, giving you a visual cue to focus on patches that did. Any review action (adding a trailer, reply, or comment) supersedes it.

Pressing d or x toggles the state for the current patch. The patch list on the left shows the state visually: done patches appear in bold, skipped and unchanged patches appear dimmed. Press H to hide skipped patches from the list entirely — useful for large series where many patches are irrelevant to your review.

Skipped patches are automatically excluded when sending review emails. When taking patches via cherry-pick, skipped patches are pre-deselected in the patch selection dialog.

Follow-up messages

Press f to load and display follow-up messages for the series being reviewed. B4 first checks the locally cached thread (stored as a git blob in the review branch); if no local copy exists, it fetches from lore in the background. The f key is a toggle — pressing it again hides the follow-up display.

Follow-up messages appear as coloured panels below the diff, showing threading depth (replies indented visually), along with From, Date, and Message-ID headers for easy cross-referencing with your mail client. Each panel shows the reviewer’s full name in the title.

When follow-ups contain inline diff review comments (quoted diff lines with unquoted reviewer comments), b4 extracts and resolves them against the real diff so they display at the correct position inline, alongside your own comments. This works for any follow-up that uses the standard mailing-list code review format.

You can click a follow-up panel header (marked with ↩) to compose a quick reply directly from the review interface. B4 opens $EDITOR with the quoted message and constructs a proper reply-to-all email with correct threading headers.

Patchwork integration

If your project uses a Patchwork server (see Patchwork integration settings), press p in the tracking list to open the Patchwork browser. From there you can:

  • Browse series from your Patchwork project

  • View a series thread (Enter)

  • View CI check details for a series (c)

  • Track a series directly from the Patchwork list (t)

  • Set or change the Patchwork state for a series (s)

  • Hide and unhide series (h/u)

  • Toggle display of hidden series (H)

  • Refresh the series list from Patchwork (r)

  • Filter the list with a mutt-style pattern (l)

  • Show keybinding help (?)

Each series in the listing shows a coloured CI status indicator when Patchwork has check results: green for pass, red for fail or warning, and dim for pending. Press c to open a detailed view of all CI checks grouped by patch, showing the check context, description, and a link to the full CI results.

Taking action

Upgrading to a newer revision

When a submitter sends a new revision of a series you are reviewing, the Revisions line in the details panel is highlighted to let you know. Press u to update the selected series (or U for all series) and discover new revisions, then use the action menu (a) and select Upgrade to switch the review branch. B4 will:

  1. Save your review comments on each patch, keyed by stable patch-id.

  2. Archive the current revision (creating a .tar.gz backup).

  3. Fetch and check out the new revision.

  4. Restore your comments onto patches whose content did not change.

Comments on patches that were modified between revisions are not carried over, since those patches need fresh review. Cover letter reviews are also not carried over, as they are specific to the previous revision.

Applying patches (take)

Open the action menu (a) and select Take to apply a reviewed series. The take flow has three steps:

Step 1 — Choose method and options. B4 offers three take methods:

  • Merge — creates a merge commit using the cover letter as the commit message template. Per-commit Signed-off-by and Link: trailers are applied to each patch individually.

  • Linear (git-am) — applies patches linearly with git am.

  • Cherry-pick — cherry-picks individual patches (you can select which ones in the next step). Skipped patches are pre-deselected.

The dialog suggests recently used target branches, with the configured b4.review-target-branch always included. You can also type a branch name directly. Toggle the Signed-off-by and Link: checkboxes to add those trailers to each commit. Press Ctrl-y to continue, or Escape to cancel.

Step 2 — Select patches (cherry-pick only). When cherry-pick is selected, a patch selection dialog lets you choose which patches to apply. Skipped patches are pre-deselected. Press Ctrl-y to continue.

Step 3 — Confirm. A confirmation screen runs a test apply in the background (using a temporary sparse worktree) and shows the result: green for clean, red with details if it fails. The screen also shows the series subject, method, and target branch as a final sanity check. Toggle Mark as accepted to update the series status after the take. Press Ctrl-y to proceed with the actual take, or Escape to back out without making any changes.

Conflict resolution

Several TUI operations apply patches and can encounter conflicts:

  • Checking out a series for review (r from the tracking list)

  • Upgrading to a newer revision (Upgrade from the action menu)

  • Taking patches (Take from the action menu)

  • Rebasing (Rebase from the action menu)

The first three use git am with three-way merge (git am -3), which resolves many conflicts automatically. When the patches come from lore and the referenced blobs are not already in your repository, b4 creates a temporary fake commit range so the three-way merge can find them. If the blobs are already present in your tree, this step is skipped.

When a conflict does occur, b4 suspends the TUI and drops you into an interactive shell so you can resolve it. The workflow depends on the operation:

For checkout, upgrade, and take (merge) — the shell opens inside the worktree where the conflict happened:

  • Inspect the conflict with git diff or git status

  • Edit the affected files to resolve the conflict

  • Stage your fixes with git add

  • Run git am --continue to finish applying

  • Type exit to return to the TUI

If you can’t resolve the conflict, run git am --abort and then exit. B4 cleans up the worktree and returns you to the TUI without making any changes to your branch.

For take (linear) — patches are applied directly to your target branch, so the shell opens in your repository directory. The same workflow applies: resolve, git am --continue, and exit.

For rebase — the shell opens in your repository directory with a git rebase in progress:

  • Inspect the conflict with git diff or git status

  • Edit the affected files to resolve the conflict

  • Stage your fixes with git add

  • Run git rebase --continue to move to the next patch

  • Repeat if further patches conflict

  • Type exit to return to the TUI

If you can’t resolve the conflict, run git rebase --abort and then exit. B4 returns you to the TUI without making any changes.

Rebasing

Open the action menu (a) and select Rebase to rebase the review branch onto a target branch. The dialog suggests recently used branches (same as the Take dialog). Press Ctrl-y to confirm, or Escape to cancel. B4 first tests applicability in a temporary worktree before performing the actual rebase.

Range-diff

Press d to compare two revisions of the series using git range-diff. B4 fetches the comparison revision from lore if needed.

Thank-you

Open the action menu (a) on an accepted series and select Thank to compose and send a thank-you note to the contributor. A preview screen shows the generated message with keybindings to Send (S), Edit (e), or Cancel (Escape).

Queuing thanks for delayed delivery

When b4.thanks-commit-url-mask is configured, the thank-you preview also offers a Queue option (W). Queuing writes the message as an RFC 2822 file in .git/b4-review/queue/ instead of sending it immediately. This is useful when you want to push your commits to a public tree before sending thank-you messages — the message references commit URLs that may not resolve until the push is complete.

Files are named {change-id}-v{revision}.msg and the target URL is recorded as an X-Check-URL header, so you can inspect or hand-edit queued messages with any mail tool.

The series remains in accepted status while its thank-you message is queued. The title bar shows a queue count indicator on the right side (e.g. 3 queued) and the Q keybinding appears in the footer.

Press Q to open the queue viewer, which lists all pending messages with their subjects and target URLs. From this screen, press Q again to attempt delivery: b4 checks each queued message’s commit URL with an HTTP HEAD request, and delivers the message via SMTP once the URL resolves. Successfully delivered messages are moved to .git/b4-review/queue/sent/ and their series are automatically marked as thanked.

When running with --email-dry-run, queued messages are written to .git/b4-review/queue/dryrun/ and the commit URL check is skipped, allowing end-to-end testing of the queue workflow without sending real email.

Archive and abandon

Open the action menu (a) and select Archive to archive a completed series (creates a .tar.gz in $XDG_DATA_HOME/b4/review-archived/). Select Abandon to delete the series and review branch entirely.

Snoozing a series

When you want to defer a series — perhaps waiting for a release candidate or simply clearing your queue — open the action menu (a) and select Snooze. The snooze dialog offers three modes:

  • Duration — relative time like 2w (2 weeks), 30d (30 days), or 3m (3 months).

  • Date — an absolute date in YYYY-MM-DD format.

  • Tag — a git tag name such as v6.15-rc3. The series wakes up when that tag appears in the repository.

Snoozed series move to a separate Snoozed group in the tracking list and are skipped during U (update-all). The review branch is preserved so you can pick up exactly where you left off.

When the snooze condition is met — the date passes or the tag appears — the series automatically wakes up and returns to its previous status the next time the TUI loads. You can also wake a series manually via the action menu (Unsnooze).

The snooze dialog remembers your last choice within a session, so if you are snoozing several series with the same settings the fields are pre-populated.

Working across multiple machines

Because review state is stored in b4/review/* git branches, it can be synchronised between machines using any git remote. This makes it straightforward to start reviewing a series on one machine and continue on another, or to keep a laptop and a workstation in sync.

Setting up a sync remote

Configure a dedicated remote pointing to a repository accessible from all your machines:

git remote add review-sync git@example.com:linux-review.git

Then configure push and fetch refspecs so that only b4/review/* branches are transferred:

git config --add remote.review-sync.push  '+refs/heads/b4/review/*:refs/heads/b4/review/*'
git config --add remote.review-sync.fetch  'refs/heads/b4/review/*:refs/heads/b4/review/*'

The + prefix in the push refspec enables force-push, which is required because the tracking commit at the tip of each review branch is replaced in-place whenever the series status changes.

Warning

Review branches may contain unpublished comments, draft responses, or early-stage review notes that you would not want to share publicly. Make sure the remote repository is not publicly accessible if you want to keep your in-progress review work private.

Syncing your review branches

After a review session, push all your review branches in one command:

git push review-sync

Add --prune to also remove remote branches that you have abandoned or archived locally:

git push --prune review-sync

On another machine, fetch the latest branches:

git fetch review-sync

Then launch the TUI as normal — a rescan runs automatically in the background and detects any branches whose HEAD commit changed since the last fetch, updating the tracking database to reflect their current state:

b4 review tui

Note

The TUI compares the HEAD commit SHA of each b4/review/* branch against a cached value in the database. Only branches that have actually changed are re-read, so the background rescan adds no perceptible delay even in large repositories.

Optional flags

b4 review enroll

repo_path

Path to the git repository to enrol (default: current directory).

-i IDENTIFIER, --identifier IDENTIFIER

Project identifier (default: repository directory name).

b4 review track

series_id

Series identifier: a message-id, URL, or change-id. Alternatively, pipe a message on stdin.

-i IDENTIFIER, --identifier IDENTIFIER

Project identifier (required if not in an enrolled repository).

b4 review tui

-i IDENTIFIER, --identifier IDENTIFIER

Project identifier (required if not in an enrolled repository).

--email-dry-run

Show all email dialogs and perform status transitions as normal, but print messages to stdout instead of sending them. Useful for testing the full review workflow without actually delivering emails.

--no-sign

Do not patatt-sign outgoing review emails. By default, review replies, follow-up replies, and thank-you messages are signed with your configured attestation key (same as b4 send). This flag disables signing for the current session. Can also be set permanently via b4.review-no-patatt-sign (see review settings (alpha)).

--no-mouse

Disable mouse support in the TUI. This allows the terminal’s native text selection to work normally. Can also be set permanently via b4.review-tui-disable-mouse (see review settings (alpha)).

b4 review show-info

Displays review branch metadata in a format suitable for scripting and CI integration. The output includes change-id, revision, status, commit SHAs, and other tracking data.

PARAM

Optional parameter in the form [branch:]key. The parameter can be one of the following:

  • key name to show just a specific value from the current branch

  • branch name to show all info about a specific branch

  • branch name:key name to show a specific value from a specific branch

Branch names can be given in full (b4/review/change-id) or as a shorthand (change-id), which is automatically expanded to b4/review/change-id.

For example, to show the base-commit of a specific review branch:

b4 review show-info b4/review/20250310-foo-bar:base-commit

Or using the shorthand:

b4 review show-info 20250310-foo-bar:base-commit

To show all values for a specific branch:

b4 review show-info b4/review/20250310-foo-bar

To show the series-range for the current branch:

b4 review show-info :series-range

To show all values for the current branch:

b4 review show-info
-l, --list

List all review branches with a summary of each (branch name, change-id, status, subject, sender, revision, patch count, and completeness).

b4 review show-info --list
-j, --json

Output in JSON format. Can be combined with --list to produce a JSON array of all branches, or used alone for a single branch:

b4 review show-info --json
b4 review show-info --list --json

The available keys are:

Key

Description

branch

Full branch name

change-id

Series change-id

revision

Current revision number

status

Review status (new, reviewing, accepted, etc.)

identifier

Project identifier

subject

Series subject line

sender

Author in Name <email> format

link

Link to the series on the mailing list

base-commit

Base commit SHA

first-patch-commit

SHA of the first patch commit

series-range

Commit range of the patch commits

num-patches

Number of patch commits

num-prereqs

Number of prerequisite commits

complete

Whether all expected patches were received

target-branch

Per-series target branch (or config default)

commit-HASH

Subject of each patch commit (dynamic keys)

New in version v0.15.

CI check integration

Both the tracking list (c) and the review app (c) support running CI checks on a series. Results are displayed in a matrix modal showing each patch as a row and each check tool as a column, with colour-coded status indicators. Press Enter on a row to drill into detailed results, or R to force a re-run that bypasses the cache.

Check results are cached in a SQLite database ($XDG_DATA_HOME/b4/review/ci.sqlite3) keyed by message-id and tool name, so re-running checks shows cached results instantly.

Built-in handlers

B4 includes two built-in check handlers that require no external scripts:

_builtin_checkpatch

Runs scripts/checkpatch.pl from your source tree against each patch. Auto-detected when no b4.review-perpatch-check-cmd is configured and scripts/checkpatch.pl exists and is executable.

_builtin_patchwork

Queries the Patchwork REST API for CI check results on each patch. Auto-enabled when b4.pw-url and b4.pw-project are configured. Individual check contexts (e.g. tree_selection, build_32bit) are aggregated into a single patchwork column showing the worst-case status; the detail view lists each check individually with coloured status indicators.

Writing an external check script

External check commands receive a single RFC 2822 email message on stdin (one patch for per-patch commands, or the cover letter for per-series commands) and must print a JSON array to stdout:

[
  {
    "tool": "my-ci",
    "status": "pass",
    "summary": "Build succeeded",
    "url": "https://ci.example.com/builds/12345",
    "details": "Optional multi-line details"
  }
]

Each object in the array represents one check result:

Field

Required

Description

tool

yes

Column header name in the results matrix

status

yes

One of pass, warn, fail

summary

no

One-line summary shown in the detail view

url

no

Link for the maintainer to open in a browser

details

no

Multi-line text for the scrollable detail view

An empty array [] means the tool has nothing to report for this message.

A non-zero exit code with no JSON output on stdout is treated as an execution error and displayed as a failure in the results matrix.

A script can return multiple result objects to report results from several tools in one invocation.

Environment variables

The following environment variables are set when an external check command runs:

B4_TRACKING_FILE

Path to a temporary JSON file containing the full tracking data for the series being checked. This includes revision info, patch metadata, take history, branch tips, and any other state recorded by b4. The file is removed after checks complete. Not set if the series has no tracking data (e.g. not yet checked out).

Scripts can query this file with jq or parse it in Python to extract whatever context they need — for example, looking up branch tip commits for KernelCI queries:

import json, os
tracking = json.load(open(os.environ['B4_TRACKING_FILE']))
tips = tracking.get('series', {}).get('branch-tips', [])
for tip in tips:
    # tip has 'date', 'branch', 'sha'
    query_kernelci(tip['sha'], tip['branch'])

Example configuration

[b4]
    # Built-in checkpatch (auto-detected, but can be set explicitly)
    review-perpatch-check-cmd = _builtin_checkpatch

    # Custom per-patch check
    review-perpatch-check-cmd = /path/to/my-perpatch-check.py

    # Per-series check (cover letter piped to stdin)
    review-series-check-cmd = /path/to/my-series-check.py

An example script demonstrating the JSON protocol is included in the b4 source tree at misc/review-ci-example.py. It produces random pass/warn/fail results and can be used for testing and as a starting point for your own check scripts.

Configuration

The following configuration options are specific to b4 review. Set them in your git config under the [b4] section.

See review settings (alpha) for the full reference.

Patchwork integration reuses the standard patchwork settings (b4.pw-url, b4.pw-key, b4.pw-project). See Patchwork integration settings for details.

Configuring the review agent

The a keybinding in the review interface invokes an external command that can perform AI-assisted review of the current patch. To enable it, set both b4.review-agent-command and b4.review-agent-prompt-path in your git config. For example, to use Claude Code with access to the repository:

[b4]
  review-agent-command = claude --add-dir .git --allowedTools 'Bash(git:*) Read Glob Grep Write(.git/b4-review/**) Edit(.git/b4-review/**)' --
  review-agent-prompt-path = .git/agent-reviewer.md

To use Gemini CLI instead:

[b4]
  review-agent-command = gemini --sandbox --allowed-tools 'Bash(git:*) Read Glob Grep Write(.git/b4-review/**) Edit(.git/b4-review/**)'
  review-agent-prompt-path = .git/agent-reviewer.md

To use OpenAI Codex CLI:

[b4]
  review-agent-command = codex --sandbox workspace-write
  review-agent-prompt-path = .git/agent-reviewer.md

To use GitHub Copilot CLI:

[b4]
  review-agent-command = copilot --autopilot --yolo
  review-agent-prompt-path = .git/agent-reviewer.md

Note

Only Claude Code and OpenAI Codex CLI have been directly tested. The command-line examples for Gemini CLI and GitHub Copilot CLI are best-effort suggestions. If you get another tool working (or find corrections for the above), please send your findings to tools@kernel.org.

The command is run from the repository top-level directory. The prompt file should contain instructions telling the agent how to review patches for your project. A sample prompt is included in misc/agent-reviewer.md in the b4 source tree — copy it into your repository and adapt it to your project’s coding standards and review guidelines.

Customising the colour theme

The review TUI uses Textual’s built-in theming system. Textual ships with many themes — to browse them, press ctrl+p inside the TUI to open the command palette, then select Theme. Once you find one you like, make it permanent by setting the TEXTUAL_THEME environment variable:

export TEXTUAL_THEME=monokai

A few examples worth trying:

TEXTUAL_THEME=textual-dark b4 review tui
TEXTUAL_THEME=dracula b4 review tui
TEXTUAL_THEME=textual-ansi b4 review tui

The textual-ansi theme restricts rendering to the standard 16 ANSI colours, which makes it suitable for terminals that do not support 256 or true-colour output. All UI elements — diff highlighting, reviewer badges, CI indicators, and comment panels — adapt automatically to the active theme.

Disabling colour entirely

If you prefer no colour at all — for example, when piping output to a file or when colours interfere with a screen reader — you can set the NO_COLOR environment variable (see no-color.org for the broader convention):

NO_COLOR=1 b4 review tui

This tells Textual to strip all colour information from the rendered output while keeping the layout intact.

Disabling scroll animations

By default, Textual animates page-up/page-down and other scroll operations. To disable all animations:

TEXTUAL_ANIMATIONS=none b4 review tui

Other accepted values are basic (reduced animations) and full (the default). To disable smooth scrolling specifically without affecting other animations:

TEXTUAL_SMOOTH_SCROLL=0 b4 review tui

Export either variable in your shell profile to make the change permanent.