| v0.16 |
| ----- |
| [X] `--rethread` flag for stitching unthreaded patch series |
| : Mark Brown, https://msgid.link/8637ff61-4eca-42ac-96fb-d530498b3f82@sirena.org.uk |
| : Auto-discovers sibling patches from a single msgid via lore search |
| : Integrates with review track, TUI update, and thanks/trailers paths |
| : Persists is_rethreaded in tracking commit JSON for DB rebuild safety |
| [X] Native history rewriting (replace git-filter-repo) |
| : New src/b4/_rewrite.py with rewrite_commit_messages() backed by pygit2 |
| : Drops git-filter-repo dep; adds explicit pygit2>=1.15,<2.0 |
| [X] Native rewrite for cover-letter and trailer updates in ez.py |
| : Deletes run_frf(), FRCommitMessageEditor, check_can_gfr(), already_ran kludge |
| [X] Migrate refs/notes/* entries onto new commit OIDs after rewrite |
| : Fixes upstream filter-repo silent-orphan behavior (newren/git-filter-repo#22) |
| : Yazen Ghannam, https://msgid.link/20250130-rich-orangutan-from-eldorado-04f621@lemur |
| : Supports any refs/notes/* ref (default commits ref and custom refs) |
| [X] refs/original/<branch> backup + branch reflog entry preserved |
| [X] Pre/post rewrite hooks moved into the new routine |
| [X] src/tests/test_rewrite.py — 13 unit tests (core + notes + hook integration) |
| [_] `b4 review` improvements |
| [_] Manual revision linking when auto-discovery fails (no change-id or in-reply-to chain) |
| : Mark Brown, https://msgid.link/88549a4a-cc82-4200-b73b-e335cbb2b024@sirena.org.uk |
| [_] Auto-detect existing trailers to mark patches as "done" |
| : Louis Chauvet, https://msgid.link/24351d92-3f8c-412b-807d-ed7ee0b1ebf6@bootlin.com |
| [_] Cancel background processes (e.g. base check) on exit |
| : Louis Chauvet, https://msgid.link/24351d92-3f8c-412b-807d-ed7ee0b1ebf6@bootlin.com |
| [_] Batch trailer selection across multiple patches |
| : Louis Chauvet, https://msgid.link/24351d92-3f8c-412b-807d-ed7ee0b1ebf6@bootlin.com |
| [_] Keep trailers in-place when added via reply editor |
| : Louis Chauvet, https://msgid.link/24351d92-3f8c-412b-807d-ed7ee0b1ebf6@bootlin.com |
| [_] Show context in checkpatch output for commit message complaints |
| : Chris Samuel, https://msgid.link/2c1ab8a2-8a86-48a7-9a53-ef3a00ab4bd2@csamuel.org |
| [_] `b4 review` editor directives |
| [_] #!notrim — preserve blank lines and trailing whitespace in comments |
| [_] #!verbatim — use editor text as-is for the outgoing email |
| : Stashed as "WIP: #!verbatim and #!notrim editor directives" |
| [_] Warn on empty commit message body during prep --check / send |
| : Dave Marquardt, https://msgid.link/20260320-ambrosial-strange-sidewinder-60216e@lemur |
| : Detect commits where the body is empty but below-the-cut content exists |
| : This likely means the developer accidentally put the description in the wrong place |
| [X] Multiple lore endpoints with failover |
| : "Maintainer container" project — local 3-month lore mirror for decentralized workflows |
| : Query local endpoint first, fail over to upstream lore if unavailable or stale |
| : Implemented via liblore 0.6 failover features + git config integration |
| [X] Config for ordered list of endpoints via lore.fallback git config (multi-valued) |
| : Origins are scheme://host prefixes; path preserved from canonical URL |
| : Tried in order listed, canonical server is always the final fallback |
| [X] Failover logic — transparent retry on connection error, timeout, or HTTP 5xx |
| : Implemented in liblore's _request() method; 4xx returns immediately (no retry) |
| : b4 uses LoreNode.from_git_config() to pick up all failover settings from git |
| [X] Latency-based origin probing via lore.autoprobe git config |
| : Concurrent HEAD requests to /manifest.js.gz; reorders origins fastest-first |
| : Results cached to disk for lore.probettl seconds (default 3600) |
| [X] User-Agent identification via lore.useragentplus git config |
| : Appends +IDENTIFIER to b4/version header for server operator prioritization |
| [X] Documentation in docs/config.rst — "Server failover settings" section |
| [_] Staleness detection — how to know when local mirror is behind? |
| : Compare message counts? Check dt: query freshness? HEAD request timestamp? |
| : Not yet addressed — requires liblore-side design work |
| [X] Migrate lore access to liblore library |
| : ~/work/git/liblore — standalone library for public-inbox/lore access |
| [X] Add liblore as a dependency in pyproject.toml |
| [X] Replace get_pi_thread_by_msgid() / get_pi_thread_by_url() with LoreNode.get_mbox_by_msgid() |
| : get_pi_thread_by_url() removed (was only called internally) |
| [X] Replace get_pi_search_results() / get_msgs_by_patch_id() with LoreNode.get_mbox_by_query() |
| : Added full_threads parameter to liblore for t=1 support |
| [X] Replace split_and_dedupe_pi_results() / mailsplit_bytes() with liblore.split_and_dedupe() |
| : mailsplit_bytes() outdir parameter removed; pipesep path retained |
| [X] Replace get_strict_thread() with liblore.get_strict_thread() |
| : b4's auto-noparent heuristic kept as wrapper |
| [X] Replace review/tracking.py _resolve_canonical_url / _fetch_mbox_bytes / _fetch_new_since |
| : Collapsed into _fetch_thread_mbox_bytes() via LoreNode; _fetch_new_since uses get_thread_updates_since() |
| [X] Caching handled by liblore's filesystem cache with per-request TTL validation |
| : Fixes stale-cache issues in long-running processes (review TUI) |
| : b4's .pi.msgs directory cache removed; nocache passthrough via liblore API |
| [X] Migrate get_clean_msgid() and duplicate resolution to liblore equivalents |
| [X] Update all callers: mbox.py, ez.py, dig.py, pr.py, diff.py, review_tui/*.py |
| : Callers use unchanged b4 wrapper functions; internal delegation to liblore |
| [X] Keep Patchwork integration as-is (separate from lore access) |
| [_] Maintainer feed — public outbox via ezpi |
| : ~/work/git/ezpi — writes RFC2822 messages to public-inbox v2 git repos |
| : Maintainers get a browsable/searchable archive of all emails sent through b4 |
| [_] Add ezpi as an optional dependency in pyproject.toml |
| [_] Add b4.maintainer-feed-path config option (path to v2 inbox) |
| [_] Hook into send_mail() to archive a copy of every outgoing message |
| : Review replies, thank-you messages, patch submissions, quick-replies |
| : Use ezpi.add_rfc822_v2() with the configured path |
| [_] b4 feed --init to set up the v2 inbox and print instructions |
| [_] b4 feed --export to export/push the feed to a remote |
| [_] Privacy guardrails — ensure private emails never end up in the feed |
| : Needs brainstorming: allowlist by list-id? opt-in per send? exclude drafts/dry-run? |
| [_] `b4 bugs` integration |
| [X] `b4 bugs` subcommand for git-bug integration |
| : Import mailing list discussions as git-bug entries |
| : TUI with bug list, detail panel, import and label modals |
| : Uses ezgb library for git-bug access via pygit2 |
| : Fast listing via git-bug CLI excerpt cache (~90ms) |
| : Comment removal (tombstoning) for data removal requests |
| : Shared TUI utilities extracted to b4.tui package |
| : Auto-initializes git-bug identity from git config |
| : Auto-reload on external cache changes |
| : 53 unit tests for helpers, 866 total tests passing |
| [_] Arbitrary labels on tracked review series |
| : Reuse LabelScreen/AddLabelScreen from bugs TUI (extract to _common.py) |
| : New series_labels table keyed by change_id (survives revision upgrades) |
| : Colored dot display in tracking list (git-bug deterministic color algorithm) |
| : Extend limit command to filter by label: prefix |
| : Depends on bugs subcommand for shared label UI components |
| [ ] `b4 ty` interactive mode |
| [_] Similar to above, a mode to review auto-ty messages and drop false-positives |
| [ ] `b4 trailers` interactive mode |
| [_] Similar to above, a mode to review incoming trailers |
| |
| v0.15 |
| ----- |
| [X] `b4 review` interactive patch review workflow |
| [X] Retrieve series from lore and apply to a review branch |
| [X] Use tracking commit for cover letter and review state metadata |
| [X] Project enrolment and SQLite tracking database |
| [X] Multi-project support via per-repository identifiers |
| [X] Series and revisions tables with status lifecycle |
| [X] Review TUI (b4 review branch) |
| [X] Split-pane interface with patch list and diff viewer |
| [X] Inline comment editing via $EDITOR with delimiter-based parsing |
| [X] Trailer selection and management modal |
| [X] Follow-up comment display from mailing list threads |
| [X] Agent integration for automated/AI-assisted reviews |
| [X] Email preview mode with To/Cc/Bcc editing and send workflow |
| [X] Per-patch check command execution |
| [X] Note editing for patches and cover letter |
| [X] Multi-reviewer comment support with attribution |
| [X] Comment navigation and horizontal scroll bindings |
| [X] Shell suspension and resume |
| [X] Tracking TUI (b4 review tui) |
| [X] Browse and manage tracked series with status indicators |
| [X] Series lifecycle management (new/reviewing/replied/archived) |
| [X] Take action with merge, linear, and cherry-pick methods |
| [X] Range-diff display between revisions |
| [X] Rebase review branches on current HEAD |
| [X] Thank-you message composition and preview |
| [X] Archive and abandon actions with confirmation |
| [X] Mutt-style limit filtering |
| [X] View/preview series details |
| [X] Patchwork TUI integration |
| [X] Patchwork TUI (b4 review pw) |
| [X] Browse outstanding Patchwork series via REST API |
| [X] Set Patchwork state and archived flag |
| [X] Track series from Patchwork into b4 database |
| [X] Hide/unhide series |
| [X] Mutt-style limit filtering |
| [X] Prerequisite series handling |
| [X] Revision tracking and discovery |
| [X] Patchwork state synchronisation on review lifecycle transitions |
| [X] Update review branch to a newer revision |
| [X] `b4 review` feedback |
| [X] Worktree support and configurable default target branch |
| [X] Add git_get_common_dir() helper using git rev-parse --git-common-dir |
| [X] Fix get_repo_identifier() to resolve metadata via shared .git directory |
| [X] Fix cmd_enroll() to write metadata from worktrees to shared .git |
| [X] Handle already-enrolled repos gracefully (exit 0 for same id, exit 1 for conflict) |
| [X] Add review-target-branch config option to DEFAULT_CONFIG |
| [X] Use review-target-branch as first choice in take flow branch defaulting |
| [X] Update tests for real worktree scenarios instead of faked .git files |
| [X] Cross-machine review synchronisation via private remote |
| [X] Embed status and identifier in tracking commit JSON for portability |
| [X] rescan_branches() — rebuild tracking DB from b4/review/* branch metadata |
| [X] Tracking TUI runs rescan automatically |
| [X] "gone" series lifecycle state |
| [X] Multi-machine workflow: push b4/review/* branches to a private remote, |
| [X] Show followup activity count in series list |
| [X] Track followup count and unseen delta via public-inbox t.mbox.gz |
| [X] Incremental updates via public-inbox dt: query (no DB write on no-op) |
| [X] last_activity_at column — updated by thread activity and local status changes |
| [X] Within-group sort by last_activity_at for most-recently-active series first |
| [X] Single-char Unicode status symbols column replacing verbose status text |
| [X] Four status groups in listing: Active, New, Waiting, Gone |
| [X] Compact [subsystem,vN,0/M] subject prefix in listing via LoreSubject |
| [X] Msgs column in listing showing total+unseen message count |
| [X] A·R·T trailer count column in listing |
| [X] Cache thread mbox as git blob; pass community context to AI agent |
| [X] _store_thread_blob() serializes via save_mboxrd_mbox() and writes git blob |
| [X] get_thread_mbox() reads blob back; returns None on GC so callers fall back |
| [X] update_followup_counts() stores blob on first-fetch and incremental paths |
| [X] 'f' key toggled: second press clears comments; first press tries local blob |
| [X] Falls back to live lore fetch only when blob absent; caches result immediately |
| [X] _parse_msgs_to_followup_comments() / _render_thread_context() distil thread |
| into plain-text context blob (thread-context-blob) for the AI agent |
| [X] _store_thread_blob() writes both blobs in one save_tracking_ref() call |
| [X] ensure_thread_context_blob() migrates existing tracking commits on first open |
| [X] _prepare_review_session() calls ensure_thread_context_blob() so agent always |
| has context before the review app starts |
| [X] agent-reviewer.md documents thread-context-blob and how to use it |
| [X] Differentiate drafted vs sent review completion indicators |
| [X] Per-patch state machine: draft/done/skip with reactive derivation |
| [X] Visual indicators: ✎/✓/✕ glyphs with opacity/bold styling |
| [X] d/x key bindings to toggle done/skip in review and preview modes |
| [X] Draft guard on send action with actionable warning |
| [X] Skipped patches excluded from collect_review_emails |
| [X] Cherry-pick auto-default and pre-deselection for skipped patches |
| [X] review-default-take-method config option (merge/linear/cherry-pick) |
| [X] Recently-used branch list in take dialog |
| [X] Store recent branches in metadata.json, suggest via SuggestFromList |
| [X] Rebase screen with branch input and suggestions (replaces simple confirm) |
| [X] Default to most recently used branch; validate branch exists before proceeding |
| [X] Configured target branch always included in suggestion list |
| [X] Cherry-pick patch selection honours skip state |
| [X] Skipped patches auto-deselected in cherry-pick dialog |
| [X] Auto-defaults to cherry-pick method when any patch is skipped |
| [X] Better followup threading detail and message-id display |
| [X] Depth field computed by walking in_reply_to chain, capped at 5 |
| [X] Panels indented by depth * 2 columns using rich Padding |
| [X] Msgid header shown in each follow-up panel |
| [X] Quick-reply to follow-up messages from within review TUI |
| [X] ↩ symbol in panel header row; click opens external editor with quoted body |
| [X] Preview screen (Send/Edit/Abandon) matches patch email preview rendering |
| [X] LoreMessage.make_reply() core method handles all reply-header construction |
| [X] _render_email_to_viewer() shared helper used by both preview screens |
| [X] From header shown in email preview to catch misconfigured identities |
| [X] Dry-run mode shows accurate "logged, not sent" notification |
| [X] Per-patch signoffs and Link tags with merge take strategy |
| [X] Apply per-commit trailers (Signed-off-by, Link) during merge take |
| [X] Honour user-edited To/Cc fields instead of overriding with reply-composition |
| [X] "Applied but not taken" state for CI-testing workflows |
| [X] Rename "taken" → "accepted" for clarity |
| [X] Decouple git take from accepted state via checkbox |
| [X] Record take history in tracking commit (takes list) |
| [X] Snooze/unsnooze feature for deferring series |
| [X] SnoozeScreen dialog with days/date/note inputs |
| [X] Auto-wake expired snoozed series on app load |
| [X] Skip snoozed series during update-all |
| [X] Database schema v3 with snoozed_until column |
| [X] Remember snooze choices across consecutive uses within a session |
| [X] Action screen keyboard shortcuts and state workflow fixes |
| [X] Single-keypress shortcuts on action modal (case-sensitive, no "a" binding) |
| [X] Waiting series: offer review instead of snooze |
| [X] Snoozed series: add archive option |
| [X] Mutt-style lite thread viewer |
| [X] Two-level modal UI: thread index with tree art and message viewer |
| [X] Enter opens lite viewer from both tracking and patchwork apps |
| [X] Message viewer with mutt-style keybindings (j/k, Enter, Space, S, ^, $) |
| [X] Skip-quoted (S) scrolls past quoted blocks with trailing context |
| [X] j/k navigates between messages without returning to thread index |
| [X] Reply flow reuses FollowupReplyPreviewScreen and b4.send_mail() |
| [X] Attestation status display in message view headers |
| [X] Link header using linkmask for lore archive URLs |
| [X] Address line packing for To/Cc headers |
| [X] Per-message flags (seen, flagged, answered) |
| [X] Standalone messages.sqlite3 database keyed by msgid (cross-project) |
| [X] IMAP-style flags: Seen, Flagged, Answered stored as space-separated string |
| [X] Visual indicators in thread index: N (unseen), star (flagged), reply-arrow (answered) |
| [X] Flag toggling with F in message viewer (mutt-style) |
| [X] Auto-mark patches + cover as Seen on review branch checkout |
| [X] Auto-mark follow-ups as Seen when loaded in review app |
| [X] Auto-mark patches as Answered when review emails sent |
| [X] Auto-mark messages as Answered on reply from lite thread viewer |
| [X] Detect maintainer replies from external email clients |
| [X] Automatic cleanup of flags older than 180 days via msg_date |
| [X] Full-width CJK character alignment in all TUI apps |
| [X] Tracking app UX: show 0 in Fups column when known, hint to update when data missing |
| [X] Carry prior review context across revision upgrades |
| [X] Render maintainer's notes and replies into plain-text summary |
| [X] Store as series['prior-review-context'] in tracking dict (survives git gc) |
| [X] Carry forward prior thread-context-blob and revision msgid for agent |
| [X] PriorReviewScreen modal for maintainer to review own prior feedback |
| [X] P keybinding (hidden when no context available) |
| [X] Agent prompt: prior-review-context and prior-thread-context-blob sections |
| [X] Non-Patchwork CI integration for external tool results |
| [X] Combine reply and inline comment as a single mode |
| [X] Per-series target vs base branch tracking |
| [X] Respect sendemail.from in review emails |
| [X] CLI for listing review branches and their commits/bases |
| [X] b4 review show-info (similar to b4 prep --show-info) |
| [X] Allow "waiting for new version" from new/unimported series |
| [X] Expose CI/checkpatch action inside the review TUI |
| [X] Improved thanks integration for review workflow |
| [X] proper treename for review branches |
| [X] ability to send thanks based on a published branch |
| [X] General improvements |
| [X] Consolidate duplicated base-commit guessing logic in _tracking_app.py (~30 lines at _do_checkout and _do_update_revision) |
| [X] Consolidate duplicated post-take finalization in _tracking_app.py (~15 lines at _do_take_merge and _do_take_am) |
| [X] Consolidate duplicated newer_versions discovery in _tracking_app.py (~18 lines at action_take and action_update_revision) |
| [X] Consolidate multiple DB connection opens in action_review (_tracking_app.py) |
| [X] Fix potential conn leak in _load_series — use try/finally pattern (_tracking_app.py) |
| [X] Move deferred imports to top-level: datetime (_tracking_app.py), re (_review_app.py), email.utils (_review_app.py) |
| [X] Replace __import__('re') hack with top-level import re in _modals.py |
| [X] Remove redundant local import io statements in _tracking_app.py |
| [X] Move inline from typing import Set to top-level in _review.py |
| |
| v0.14 |
| ----- |
| [X] Switch to using pyproject.toml |
| [X] Automatic dependency resolution |
| [X] Retrieve dependencies using the standard prerequisite-patch-id |
| [X] Define the prerequisite-change-id trailer |
| [X] Expand prerequisite-change-id into prerequisite-patch-id for locally sent series |
| [X] Add b4 prep --edit-deps to open an editor with dependencies |
| [X] Add b4 prep --check-deps to report if there are problems or updates available |
| [X] Expand non-local change-id and message-id deps into prerequisite-patch-id |
| [X] --check-deps should check if everything can be cleanly applied |
| [X] Checkpatch and other pre-submit checks |
| [X] Configurable checks to run on each patch |
| [X] When checks are not defined, use Linux kernel defaults |
| [X] Display checkpatch checks using output similar to CI checks |
| [X] Cache checks for commits that haven't changed if the check command is the same |
| [X] Add --check to am/shazam and display checkpatch report |
| [X] Run b4-specific checks automatically (needs-editing, needs-auto-to-cc) |
| [X] Refuse to send if checks haven't been run |
| [X] Allow turning off pre-flight check all together, or by individual check |
| [X] Document new features |
| [X] prep --check |
| [X] Series dependencies overview |
| [X] prep --edit-deps |
| [X] prep --check-deps |
| [X] Pre-flight checks overview |
| [X] How to turn off pre-flight checks |
| [X] Document config file changes (am-perpatch-check-cmd, prep-perpatch-check-cmd, etc) |
| [X] Update manpages |
| [X] Miscellaneous enhancements |
| [X] Add prep --add-prefixes |
| [X] Add trailers --since-commit |
| [X] Automatically no-parent standalone patches in the middle of long threads |
| [X] Prevent overwriting cover letters when the tree changes while editing |
| [X] More bug avoidance in send-receive for python SMTP implementations |
| [X] Add ability to specify DNS resolvers for DKIM |
| [X] Add tab-completion generation with shtab |
| [X] Allow inserting a range-diff into the cover letter |
| [X] Use hashed requirements for added security and reproducible installs |
| [X] Introduce the -i switch to am/shazam to insert the Message-ID trailer |
| |