// changelog

v1.15.0

Four new surfaces. commitbrief leaks audits the working tree and git history for committed credentials with no provider call; commitbrief map draws the commit graph and shows exactly what a filter selected; commit-level filters (--author, --committer, --start-date, --end-date, --text) review a set of commits instead of one diff; and commitbrief upgrade updates the binary across every install method.

Released July 26, 2026

Added

  • commitbrief leaks — audit the working tree and git history for committed credentials (ADR-0036). The pre-send secret scanner is a gate: it only ever sees the one diff about to be sent, so it cannot answer “is there a key in my tree right now?” or “did anyone ever commit one?” — and a key that was committed and later removed is still in the history, still reachable in every clone and fork. leaks answers both with the same eight built-in patterns plus your guard.secret_patterns, deterministically: no provider call, no cache, no cost.

    commitbrief leaks                            # tracked files + last 200 commits
    commitbrief leaks --no-history               # working tree only, fast
    commitbrief leaks main..HEAD --no-worktree   # exactly that range
    commitbrief leaks --json | commitbrief guard --from-json -

    Both halves run by default (--no-worktree / --no-history switch either off). The working-tree half reads every tracked file whole — untracked, gitignored files like .env are deliberately out of scope, since that is where a secret is supposed to live and it cannot leak through git. The history half scans the added lines of the commits ADR-0035’s filters select, attributing each hit to its commit, author and date, because that is what decides whether a key still needs rotating. Bounded by --max-commits (default 200), and truncation is always reported.

    It exits 1 on any hit, so it gates CI out of the box; --fail-on none reports without failing. --json emits the existing schema v1 with meta.provider: "builtin", so the policy gate consumes it with no new plumbing. Findings carry a file, a line and the pattern names — never the matched text. Two limits are documented rather than hidden: it honors the ignore layers, so a key inside vendor/** is not reported, and it is regex-only, so a high-entropy blob with no recognizable prefix is invisible.

  • commitbrief map — the commit graph, and what your filter actually selected (ADR-0037). The commit filters can pick a non-contiguous set from anywhere in the history, and the only feedback was a count (“12 commits matched”) — so a wrong filter silently reviewed the wrong code. map draws the DAG with matching commits highlighted and the rest dimmed as context, which makes a filter checkable before you pay for a review. --branches switches to a branch topology summary: where each branch sits relative to the base and how far ahead / behind. Deterministic, and always exits 0 — a viewer, not a gate. Rows clip to the terminal rather than wrapping, and colour plus box-drawing fall back together, so a pipe or --color=never yields plain ASCII. No new dependencies: lane assignment is a pure function in a new internal/graph package.

  • Commit-level filters: --author, --committer, --start-date, --end-date, --text (ADR-0035). Review a set of commits rather than a single diff. git diff has no author or date options — those are git log options — so setting any of these switches diff acquisition to a commit walk: pick the matching commits, then concatenate their patches. Different filter kinds are AND’d and multiple values of one kind are OR’d, so --author alice --author bob --start-date 2026-06-01 means “(Alice or Bob) and since June”. Identity matching is a case-insensitive substring over both the name and the email. --end-date is inclusive of the day named (git’s bare --until stops at that day’s midnight and silently drops it). --text matches the commit message and the name of a branch, in which case the commits unique to that branch are pulled in — best-effort by nature, since a squash- or rebase-merged branch no longer owns its commits.

    With no explicit range the walk covers HEAD; a subcommand’s range bounds it (commitbrief diff main..develop --author alice). Two modifiers shape a walk but never start one, and are rejected if used alone: --max-commits N (default 200) caps the selection and always reports truncation rather than silently reviewing a subset, and --merges keeps merge commits, which are excluded by default.

    Available on the default review, diff, summary, dry-run, the MCP review tool and guard. Rejected by commit (it describes the staged index, which has no commits) and by remote pr (its diff comes from gh pr diff, not local git).

  • --exclude-file / --exclude-dir path denylists. The inverse of --file / --dir, sharing their exact matching rules (literal path or gitignore-style glob) and applied after them, so an exclusion always wins: --dir internal --exclude-dir internal/cli. An invalid glob errors before any provider call, as it does for the allowlist.

  • Path and commit filters are now reachable over MCP. The review tool gained file, dir, exclude_file, exclude_dir, author, committer, start_date, end_date, text, max_commits and merges arguments. --file / --dir were previously CLI-only in practice: the MCP seam resets the global flag state, so a host had no way to narrow a review by path. guard forwards the same set from its inherited persistent flags.

  • meta.filtered_commits in the JSON output. Optional and omitempty, so the schema stays 1 — the count of commits whose patches make up the reviewed diff. dry-run gains matching Commits (walked) / Commits (matched) lines and an --exclude-file / --exclude-dir row in its per-layer file accounting.

  • commitbrief upgrade — in-tool updates across every install method (ADR-0034). Detects whether the running binary came from Homebrew, Scoop, go install or a GitHub Releases tarball. Package-managed installs are delegated to their own manager (brew upgrade / scoop update / go install …@latest), because overwriting a manager-owned binary desynchronizes its metadata; only a manual install is replaced in place, after its SHA-256 is verified against the release checksums.txt. An unwritable target aborts before anything is downloaded and prints the exact command to run — CommitBrief never invokes sudo itself. --check reports without installing and always exits 0; --json implies --check. The version check runs only when you invoke the command: there is no automatic update check and no telemetry.

Changed

  • commitbrief list’s built-in command reference was several releases stale — it never listed commit, guard, mcp, remote pr, doctor, providers, config, install-hook or upgrade. Rewritten to cover the whole surface, including the path and commit filters.
  • --max-commits and --merges are usage errors on a review when no commit filter is set (nothing to modify), but ordinary bounds on leaks and map, which always walk history.

Fixed

  • commitbrief remote pr now applies --file / --dir on the posting path too. Only the --no-post path honored them, so a narrowed run that commented on GitHub reviewed a different file set than the same command with --no-post.