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.

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
:term:`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 :ref:`ci_check_protocol`)
``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 :ref:`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 :term:`b4.attestation-policy`
and :term:`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 :ref:`ci_check_protocol`)
``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 <https://sashiko.dev>`_ AI code review
  service (when :term:`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)*    |sp|    —       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
==========  ======  ======  ====================================================

.. |sp| unicode:: U+0020

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 :ref:`patchwork_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
:term:`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.

.. _review_conflict_resolution:

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``).

.. _thanks_queue:

**Queuing thanks for delayed delivery**

When :term:`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.

.. _snooze_details:

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
  :term:`b4.review-no-patatt-sign` (see :ref:`review_settings`).

``--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
  :term:`b4.review-tui-disable-mouse` (see :ref:`review_settings`).

``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)
========================  ================================================

.. versionadded:: v0.15

.. _ci_check_protocol:

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 :term:`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 :term:`b4.pw-url` and :term:`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 :ref:`review_settings` for the full reference.

Patchwork integration reuses the standard patchwork settings
(:term:`b4.pw-url`, :term:`b4.pw-key`, :term:`b4.pw-project`). See
:ref:`patchwork_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 :term:`b4.review-agent-command` and
:term:`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_theme:

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 <https://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.
