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 |
|---|---|
|
Freshly tracked, not yet reviewed |
|
Review branch created, review in progress |
|
Review comments sent to the mailing list |
|
Waiting for a new revision from the submitter |
|
Deferred until a date, duration, or git tag |
|
Patches applied to the target branch |
|
Thank-you note sent to the contributor |
|
Review completed and archived |
|
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
+Nin yellow (populated after pressingu)S — single-character status symbol;
*suffix means the tracking data needs a refreshSubject — 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 series (reviewing) or open action menu (other states) |
|
Review — create or re-enter the review branch |
|
Target branch — set or clear the per-series target branch |
|
CI checks — run configured check commands and show results (see CI check integration) |
|
Thread — open the lite thread viewer (see below) |
|
Action menu — context-sensitive actions (see below) |
|
Range-diff between revisions |
|
Update — fetch latest trailers and check for newer revisions for the selected series |
|
Update all — same as |
|
Limit — filter the list of displayed series |
|
Shell — suspend to an interactive sub-shell |
|
Patchwork — switch to the Patchwork browser (if configured) |
|
Queue — view and deliver queued thank-you messages (visible only when the queue is non-empty; see thanks_queue) |
|
Move cursor down/up |
|
Help — show keybinding reference |
|
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
uto updateno 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 withFin 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 |
|---|---|
|
Open the selected message in the message viewer |
|
Move cursor down/up |
|
Close the thread viewer |
Message view keybindings
Key |
Action |
|---|---|
|
Next/previous message in thread |
|
Scroll down one line |
|
Scroll up one line |
|
Page down |
|
Page up |
|
Skip past the next block of quoted text |
|
Jump to top of message |
|
Jump to bottom of message |
|
Reply to the current message |
|
Toggle flagged (important) state |
|
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 |
|
Scroll down/up |
|
Scroll left/right |
|
Page down/up |
|
Jump to next/previous review comment |
|
Switch focus between panels |
|
Trailers — quickly add Reviewed-by, Acked-by, etc. |
|
Reply — open |
|
Notes — view or edit review notes |
|
Followups — toggle follow-up messages and external inline comments from lore |
|
Agent — run review LLM agent (if configured) |
|
Done — toggle “done” state on the current patch |
|
Skip — toggle “skip” state on the current patch |
|
Hide skipped — toggle visibility of skipped patches |
|
CI checks — run check commands and show results (see CI check integration) |
|
Toggle email mode |
|
Shell — suspend to an interactive sub-shell |
|
Help — show keybinding reference |
|
Quit |
Email preview mode keybindings
Key |
Action |
|---|---|
|
Edit To/Cc/Bcc recipients |
|
Send review emails |
|
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 |
|
|
Review complete, include in outgoing emails |
Skip |
|
|
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:
Save your review comments on each patch, keyed by stable patch-id.
Archive the current revision (creating a
.tar.gzbackup).Fetch and check out the new revision.
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-byandLink: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 (
rfrom 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 difforgit statusEdit the affected files to resolve the conflict
Stage your fixes with
git addRun
git am --continueto finish applyingType
exitto 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 difforgit statusEdit the affected files to resolve the conflict
Stage your fixes with
git addRun
git rebase --continueto move to the next patchRepeat if further patches conflict
Type
exitto 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), or3m(3 months).Date — an absolute date in
YYYY-MM-DDformat.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_pathPath to the git repository to enrol (default: current directory).
-i IDENTIFIER, --identifier IDENTIFIERProject identifier (default: repository directory name).
b4 review track
series_idSeries identifier: a message-id, URL, or change-id. Alternatively, pipe a message on stdin.
-i IDENTIFIER, --identifier IDENTIFIERProject identifier (required if not in an enrolled repository).
b4 review tui
-i IDENTIFIER, --identifier IDENTIFIERProject identifier (required if not in an enrolled repository).
--email-dry-runShow 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-signDo 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-mouseDisable 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.
PARAMOptional 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 tob4/review/change-id.For example, to show the
base-commitof 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-rangefor the current branch:b4 review show-info :series-range
To show all values for the current branch:
b4 review show-info
-l, --listList 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, --jsonOutput in JSON format. Can be combined with
--listto 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 |
|---|---|
|
Full branch name |
|
Series change-id |
|
Current revision number |
|
Review status (new, reviewing, accepted, etc.) |
|
Project identifier |
|
Series subject line |
|
Author in |
|
Link to the series on the mailing list |
|
Base commit SHA |
|
SHA of the first patch commit |
|
Commit range of the patch commits |
|
Number of patch commits |
|
Number of prerequisite commits |
|
Whether all expected patches were received |
|
Per-series target branch (or config default) |
|
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_checkpatchRuns
scripts/checkpatch.plfrom your source tree against each patch. Auto-detected when no b4.review-perpatch-check-cmd is configured andscripts/checkpatch.plexists and is executable._builtin_patchworkQueries 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 singlepatchworkcolumn 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 |
|---|---|---|
|
yes |
Column header name in the results matrix |
|
yes |
One of |
|
no |
One-line summary shown in the detail view |
|
no |
Link for the maintainer to open in a browser |
|
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_FILEPath 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
jqor 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.