You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
make ci runs the Go pull-request checks (make check then make test).
A missing or empty index.jsonl is rebuilt from the run journals, and a
stale one has every newer unindexed journal appended, so gauntlet runs
and the file-signal suggester still see a run whose process died after
flushing the journal. gauntlet show already read those files.
Reconstructed rows have no args or exit_code.
GH_TOKEN is read for release lookups, the same name GitHub CLI uses. It
wins over GITHUB_TOKEN when both are set, and both now authenticate the
checksum and asset downloads as well as the release listing, so a private --update-repo can actually install.
gauntlet pick can compose --stacked-prs from the run pane. Turning it
on clears --commit, --push, and --merge-into and pins concurrency at
1, so the launcher cannot emit a command the parser would refuse.
? on the launcher opens a help overlay, the same key the dashboard uses. q / esc close it; they do not leave the picker.
A project prompt that contains the opening review marker can no longer
close the fence: both BEGIN REVIEW and END REVIEW in the body are
rewritten, matching what the end marker already did.
Conflicted paths named in the resolver prompt are fenced, dropped when they
carry the resolver's output protocol or formatting characters, and capped;
a conflict with more files than the prompt will name is left for a human
instead of launching an agent that cannot finish.
Commit subjects taken from agent output drop bidi overrides and Unicode
line separators, not only ASCII controls, so a model cannot spoof git log
or forge a commit body.
Suggestion reasons from the triage agent are rune-capped like catalog
descriptions, so one overlong line cannot flood the suggest listing.
Changed
--merge-into refuses to merge when git status cannot be read, the same
way it already refuses a dirty tree, so a merge event cannot report work
that never moved.
A missing or stale run index that cannot be reconstructed is an error
from gauntlet runs, not a listing that silently omits the newest run.
A stacked-PR reload that cannot verify its pinned base commit fails
rather than fetching a new tip and splitting the stack.
Dashboard and launcher wordmark is the path-arrow teal of the mark
(#0e96a8 on dark terminals, a darker pull of that hue on light), one
hue, not Catppuccin teal and not a per-letter gradient. Footer keys are
body-colored chrome like the launcher's. The budget meter rides the heat
ramp. Reload status uses the info hue. Panel names stay dim with the
rest of the chrome.
Dashboard lanes and the feed drop the -review suffix the grid already
omitted, so a name is spelled the same way on every instrument.
f in the dashboard footer says widen while the feed is narrowed, the
same way space says resume while paused.
home / end jump the dashboard feed the way g / G do, and jump to
the first or last row of the focused launcher pane.
The launcher shows the same "warming up" line as the dashboard until the
terminal reports its size, instead of a blank screen.
--continue-sessions with --jobs above 1 or --stacked-prs is a usage
error. Those modes give each review a fresh worktree, so there is no session
to resume; the flag used to be accepted and silently ignored. Scripts that
passed both will see exit 2.
q / esc on the live dashboard arms a hard stop instead of killing the
run on the first press (1.15.0 still documented immediate quit). A second
press, or q after the run has finished or is already draining, closes the
dashboard and cancels the run. The header shows q TO STOP while armed;
any other key disarms it. q on the help overlay still only closes help.
gauntlet runs prints STARTED as local YYYY-MM-DD HH:MM:SS. The old MM-DD HH:MM:SS column had no year and swapped day and month for readers
used to ISO dates.
gauntlet runs DURATION uses the monotonic elapsed Close records, matching
the run's Total time. An NTP step or a manual clock set between start and
end can no longer stretch or shrink the listing. Old index rows without elapsed_s still use End−Start; a pair that moved backwards prints n/a
instead of 0s.
Bundled review prompts: integer-width and abbreviation rules no longer
rewrite language-idiomatic types and names; post-quantum crypto items are
note-only; Kubernetes-native checks skip Dockerfile-only trees; docs-vs-code
disagreements have a single owner.
Ruff on scripts/ selects the bugbear, pylint, pyupgrade, and bandit
groups (and every other category those two files already pass), with a
100-column cap, instead of the default four error codes. scripts/shots.sh
is gated with shellcheck in the same CI job. Rule selection lives in pyproject.toml. make check-scripts runs the same pinned ruff, mypy, and
shellcheck steps as that job, so a scripts/ change fails locally.
Docs for --jobs N describe the persistent lane worktrees the runner
actually uses, not the per-review throwaway checkouts that 1.13.0 replaced.
Design docs name the git hardening the runner actually applies
(core.pager=cat, attr.tree, local driver blanks) and the conflict-step
cap that leaves an oversized conflict for a human. --stream is documented
as on by default, matching the flag. The landing-page trust model names core.pager=cat rather than an empty pager.
Live usage ticks on the event bus are droppable, the same as agent output:
a slow subscriber no longer stalls the scheduler on reconstructible
telemetry. Final token counts still ride on review_end.
gauntlet show and suggest history look up a generated run id by the date
it encodes, instead of probing every day directory under the journal.
gauntlet runs parses the index tail from the end, so a long index costs
the rows shown rather than a split of the whole slice.
The file-signal suggester reuses one git handle for the tree listing and
the churn window. Opening a repo no longer runs rev-parse HEAD until
line stats need a baseline. A million-file tree is listed only up to the
scan cap, so the unused tail does not stay in memory.
Project prompt discovery asks git for *-review.md by name instead of
walking the tree. Generated and hidden directories are still skipped;
a directory that is not a repository still walks.
Worktree line samples run git diff --shortstat and ls-files -o
together instead of one after the other.
Fixed
A hot-reload handoff that cannot be read or parsed now aborts the successor
instead of starting a fresh run. The unparseable case was silent, so the new
process re-ran every finished review under a new run id.
Lane worktree removal failures and unreadable HEAD reads during --jobs
scheduling are logged. Removal errors were discarded, and a failed HEAD
read was indistinguishable from an unchanged tip, so a lane silently kept
its stale base.
gauntlet update network and JSON decode errors name the URL that failed.
--merge-into no longer treats untracked files as uncommitted work. The
merge is a scratch checkout of committed work, so a local notes.txt was
never going to be in it; refusing the merge used to drop a loop's
committed changes. Tracked dirty files still block, matching --jobs.
A pump that outlives an agent's process no longer publishes output or
usage after that review has ended. Those events are keyed by agent, so
they used to land on whatever the same agent started next.
A trailing } or ] after agents.json is refused, matching encoding/json. json.Decoder.More treats those closers as end-of-value,
so {}} used to load as an empty definition set.
Listing runs recovers the whole tail of journals missing from index.jsonl, not only the newest, so two runs that died before Close
both appear. A failed index write is retried on the next Close, and a
rebuild cannot overwrite a Close that races it.
gauntlet runs and the file-signal suggester list a crashed run that
sits behind a later Close, not only an unindexed suffix. The index is
a cache of summaries; the n newest journals are the listing, so a hole
in that window is filled from the event stream without rewriting Close
rows.
Path flags (--dir, --dirs, --log, --prompt-dir, --bin) refuse an
environment variable that is unset or empty instead of expanding it to
nothing. $MISSING used to become the current directory (--dir), the
bundled prompts (--prompt-dir), or a silently dropped log (--log). An
explicit empty --prompt-dir or --log is a usage error too, matching --dir. A leading ~/ with no usable HOME is refused rather than taken
relative to the working directory.
The launcher's a key and a set header's space bar act on the reviews the
filter is showing, not the ones it hid. A fruitless filter no longer
selects the whole catalog.
Typing a review filter on the launcher replaces the key legend with the
keys that work there (enter keeps it, esc clears it). The legend used
to keep advertising run and cancel, which those keys do not do until
the filter is closed.
A --usage-limit probe that prints more than 4 KiB is ignored, the same
as any other broken probe, instead of filling memory until the timeout.
One git or gh command's captured output is capped (32 MiB and 8 MiB)
so a hostile tree or a runaway listing cannot grow without bound.
Closing --log reports a write error instead of dropping it.
The dashboard feed's scroll offset stays inside the retained ring, so a
long pause cannot claim thousands of lines back after history is trimmed.
An in-place retry restores the working tree to the snapshot taken before
the failed attempt, including the user's own uncommitted files, so the
next try starts from the same files the first one saw. Isolated reviews
already reset their worktrees. --continue-sessions no longer resumes a
failed attempt's session.
The untracked-file line-count cache drops files that have vanished or
left the untracked set, so a long loop that creates then commits files
does not fill the table with dead keys and re-read every later file.
Git and GitHub errors that quote a remote URL drop URL userinfo. A remote
stored as https://alice:token@host/repo.git is reported as https://host/repo.git, so the account name does not reach the terminal
or the run journal.
dsh model overlays are keyed uniquely: foo/bar and foo_bar no longer
share one --patch file, so a later pin cannot launch with an earlier
pair's provider and model. A deleted overlay is rewritten instead of
handed to dsh as a missing path.
The untracked-file line-count table stops admitting new keys at its cap
instead of wiping the working set, so a tree with more than 4096 new
files does not re-read every already-counted file on the next sample.
--usage-limit NaN (and nan) is a usage error. flag.Float64Var accepts
it, the 0-100 range check cannot see it, and the runner's pct < limit
comparison is then always false, so a run configured with a NaN limit
stopped before its first review. Non-finite values are refused the same
way a probe that prints them already is.
Stream-JSON token counters that are not whole numbers, or that claim more
than a trillion tokens, are ignored rather than truncated or stored. {"output_tokens": 1.9} used to record 1, because JSON numbers decode as float64 and int(1.9) is 1. A 2^62 counter fitted in int and then
overflowed the run total. Both match what json.Number parsing and the
text-usage cap already required.
The dashboard reasoning glyph no longer panics when the clock is set
before 1970. Go's remainder keeps the sign of a negative UnixNano, so
the frame index was -1.
Unknown commands and flags include a "did you mean" hint, matching unknown
review and agent names. --show-prompt does too.
gauntlet --list and --show-prompt no longer require an agent CLI in
PATH. They only read prompts; gauntlet doctor reports which agents are
installed.
Global flags (--help, --version, --log, --no-color) may precede the
subcommand, so gauntlet --no-color doctor works. gauntlet show accepts
flags before the run id, so gauntlet show --no-color RUN and gauntlet show --help after --no-color work.
gauntlet show on an unknown run id points at gauntlet runs.
Stacked PR creation treats head and base as an idempotency key: if gh pr create times out after GitHub accepted the pull request, or fails
because it already exists, the existing URL is reused instead of stopping
the stack or opening a second PR.
StartBranch on a lane or stack worktree converges when the branch already
exists at its base, the same leftover-empty-branch rule AddWorktree
already follows. A branch that carries commits is still refused.
A review that never launched (unknown name, unreadable prompt, or a command
line that could not be built) now publishes review_end like every other
outcome, so the journal, the dashboard, and gauntlet show record it. The
file-signal suggester no longer treats those, or failed, timed-out, and
interrupted launches, as finished runs that changed nothing.
gauntlet pick no longer treats untracked files as blocking --jobs.
The runner has allowed them since 1.12; the launcher was still using a
full dirty-tree check and refused a run that would have started.
Stacked PRs refuse a remote whose path is not OWNER/REPO on both sides. https://github.com/owner/.git and https://github.com//repo used to
pass the one-slash check and be handed to gh as owner/ and /repo.
The README install snippet fetches the binary for the version it just
resolved, rather than releases/latest/download, so a release published
between the two curls cannot pair a new tag with the previous binary.
The README install snippet and make install say when ~/.local/bin is
not on PATH. On macOS it is not there by default, so the binary was
installed and then not found.
The directory lock is no longer inherited by agent and git children. The
lock descriptor is opened close-on-exec, so a killed parent cannot leave
the tree locked for as long as those children live.
Agent timeout and output-drain waits no longer leave a timer running after
the process has already exited. Each wait is a timer that is stopped when
the other path wins, matching the retry backoff.
--update-repo is checked as owner/repo at startup. A URL, a missing
slash, or an extra path segment used to reach the GitHub API and fail there
with a status line, or to hit a different endpoint entirely.
--dir, --dirs, and --push-remote refuse an empty value instead of
treating it as the current directory or as origin.
A defined agent's usage with no roots is refused when the definition
is loaded, rather than later when transcript registration fails without
naming the file.
A hot-reload handoff records the predecessor's monotonic elapsed time, so --runtime and the dashboard clock do not jump when the wall clock steps
during the exec. An older handoff without the field still uses the
wall-clock span from when the run started.