A Gerrit CLI. It answers the questions a reviewer actually asks — whose turn is it, what is blocking this change, and where does this one change stand — and prints the review comments, inline and cover, including the machine-generated ones. For agent commands, see The agent tier.
Two binaries over one library: gerrit renders for a person, gerrit-axi emits
records for an agent. They are siblings, not wrappers — see
The agent tier.
It cannot vote.
gerrit, for a person, is read-only: every operation is a query.
gerrit-axi adds five writes for agents:
publishpushes torefs/for/<branch>.readyactivates a work-in-progress change.wipmarks an existing change work in progress.messageposts one change-level message with no label.submitmakes one REST call the server may refuse.
It never votes, writes an inline comment, sets reviewers, or abandons.
Gerrit evaluates its submit rules on the server and refuses a change without the required approvals.
The tests forbid REST review endpoints and label push options throughout the codebase.
Only message.js may build the SSH review command, with fixed options and a
runtime test that pins its arguments and payload.
The binding control remains the label permissions your server grants the account an agent uses.
Publish work in progress with either shape:
gerrit-axi publish --squash --wip
gerrit-axi publish --stack --topic demo --wipUse gerrit-axi ready 12345 --patch-set 2 to activate an open change without a new patch set.
Use gerrit-axi wip 12345 --patch-set 2 to mark an existing change work in progress over REST.
See Work in progress for transport,
notifications, guards and readback rules.
$ gerrit status
projects under acme/
CHANGE PROJECT BRANCH UPDATED SUBMIT BLOCKED-ON SUBJECT
184431 apps/widget-daemon release/7.2 2026-07-31 OK - Bump the retry ceiling to 5
184458 apps/widget-console main 2026-07-30 NOT_READY Zebra-Check Stop the widget from re-ent…
184402 tools/hammer main 2026-07-21 NOT_READY Release-Gate,Widget-Approval WIP Rewrite the hammer in a…Those label names are examples. The tool has no idea what your server calls its labels, and that is the point — see Configuration.
Node 20 or newer. No runtime dependencies.
Each version tag has a
GitHub Release whose
tarball CI builds from the tagged commit. Download one by version and install the
file (npm 12 refuses a remote tarball URL by default, allow-remote=none):
curl -LO https://github.com/slnkjthien/gerrit-axi/releases/download/v<version>/gerrit-axi-<version>.tgz
npm install -g ./gerrit-axi-<version>.tgz
gerrit-axi --version # prints: <version>That installs both binaries: gerrit for a person, gerrit-axi for an agent.
To work on the tool itself, run npm link in a clone instead.
You also need:
- an OpenSSH client, and an SSH key registered with your Gerrit
(
ssh -p 29418 <you>@<host> gerrit versionshould work), and - a Gerrit authentication token for the REST calls — see Authentication, and
- git, for
gerrit-axi publish.
gerrit status your attention set — the changes where it is your turn
gerrit status mine your open changes
gerrit status <change>... specific change numbers
gerrit status --query '<query>' an arbitrary Gerrit query
--labels one column per label the server reports
--patch-set add the current patch set number and revision
--limit <n> maximum changes to fetch (default 100)
gerrit show <change>... one change's review state, in full
--messages <n|all> how many cover messages to show (default 10)
gerrit comments <change> inline review comments
gerrit comments <change> --bots only machine-generated comments
gerrit comments <change> --humans only comments that are not machine-generated
gerrit auth login [--stdin] verify a Gerrit auth token and store it
gerrit auth status report whether a stored credential still works
gerrit auth logout remove the stored credential
Every command's options are listed in gerrit --help as well as in
gerrit <command> --help, so nothing is discoverable only by knowing it exists.
Global options: --host, --user, --port, --rest-base, --no-color,
-h/--help, -V/--version.
Exit codes: 0 success, 1 other error, 2 usage, 3 configuration, 4
authentication, 5 transport. gerrit-axi uses the same ones, and 6 when
watch reaches its --timeout with nothing changed.
The gerrit command has no --json, and will not grow one. Machine-readable
output is what the second binary is for.
gerrit status is the list view; gerrit show is the detail view for one
change. It exists as one command rather than three because the three facts it
prints are asked for together — is my push on the server, who has voted and how
long ago, and what did CI say and where do I read it:
$ gerrit show 184458
184458 Stop the widget from re-entering the queue twice
project acme/apps/widget-console (main)
owner ada
status NEW · submit NOT_READY
blocked on Zebra-Check
updated 2026-08-10 (1h ago)
patch set 3 aaaa111122223333444455556666777788889999
ref refs/changes/58/184458/3
uploaded ada 2026-08-10 09:12 (3h ago)
depends on 184400 dddd111122 superseded -- that change has a newer patch set
url https://gerrit.example.com/c/acme/apps/widget-console/+/184458
votes
LABEL VOTE WHO WHEN SUBMIT
Release-Gate +1 buildbot 2026-08-10 09:20 (2h ago) OK
Widget-Approval +1 grace 2026-08-10 10:04 (1h ago) OK
Zebra-Check · - - NEED
messages (the last 2 of 9, oldest first; --messages all for every one)
2026-08-10 09:20 (2h ago) [ps3] <buildbot>
Patch Set 3: Release-Gate+1
Build Successful
https://ci.example.com/job/widget-console/412/ : SUCCESS
2026-08-10 10:04 (1h ago) [ps3] <grace>
Patch Set 3: Widget-Approval+1
Reads fine to me now.Three things worth knowing about that output:
- The revision is printed whole, and the ref beside it. That line is there to
be compared against a local
git rev-parse HEADafter a push. Dependency revisions are abbreviated, because those are for recognising rather than comparing. depends onsays whether the revision it names is still that change's current patch set. A stack built on a superseded parent revision is the thing you want to find out about before re-reviewing it, not after.- Cover messages are printed exactly as the server wrote them, URLs and all.
A cover message is Gerrit's change-level conversation — vote summaries, CI
results, "Uploaded patch set N" — and is a different thing from the inline
comments
gerrit commentsprints, which belong to a file and a line and come over a different transport.[psN]is read out of the message's own first line, which is a convention of Gerrit's message text rather than a field, so a message that does not say gets no marker.
Gerrit answers WWW-Authenticate: Basic realm="Gerrit Code Review". The credential
is HTTP Basic carrying a Gerrit authentication token — not an OAuth bearer
token.
Generate one at https://<your-gerrit-host>/settings/#HTTPCredentials, then:
$ gerrit auth login
Generate a Gerrit authentication token at:
https://gerrit.example.com/settings/#HTTPCredentials
Do NOT paste your LDAP/domain password.
Some servers accept one (git_basic_auth_policy = HTTP_LDAP), and that is precisely
why we refuse it: a Gerrit token is revocable and scoped to Gerrit, a domain
password is neither. Only a token will be stored.
Gerrit auth token for ada@gerrit.example.com (input hidden):
authenticated as Ada Lovelace <ada@example.com>
credential stored in the login keyring (encrypted at rest)Non-interactively — for example from a script or an agent — pass the token on
stdin. auth login never blocks on a prompt nobody can answer; with no TTY and no
--stdin it fails immediately and tells you this:
read -rs T && printf %s "$T" | gerrit auth login --stdin && unset T-
A domain password is refused, on purpose. Some servers accept one — where
git_basic_auth_policyisHTTP_LDAP, Gerrit will authenticate a domain password — which is exactly why storing one is a bad trade: a Gerrit token is revocable and scoped, a domain password is neither. -
The credential never appears in argv.
psis world-readable. Every authenticated HTTP call passes the credential in a request header of an in-process HTTP client — nothing is ever shelled out with a credential on a command line — and the keyring and GPG helpers receive it on stdin. -
It is verified before it is persisted.
auth loginauthenticates against/a/accounts/selffirst; an unverified token is never written to disk. -
Storage is the best available, and degrades loudly rather than silently:
order backend at rest 1 secret-tool(libsecret keyring)encrypted 2 gpg --encrypt --default-recipient-selfencrypted 3 file under $XDG_CONFIG_HOME/gerrit-axi/credentials/, mode0600plaintext Every
loginreports which backend it used. When it falls back to the file it says the word plaintext and names the upgrade path;gerrit auth statusrepeats both. Directories are0700, files are0600. -
The token is never echoed, logged, or included in any output or error message, and no token — real or otherwise — appears in this repo or in any test fixture.
- The agent tier —
gerrit-axi's records, next steps, the dashboard, session integration, inline comments, publishing, submitting, posting a change message, watching changes, and failures. - Configuration — the three tiers: what is derived from the server, what from the repo, and the little that is configured.
- Architecture — the core library, the two binaries over it, and the transport.
- Contributing — running the tests, and what they cover.
- Changelog — what changed in each release.
Apache-2.0. LICENSE has the full text; NOTICE carries the copyright, which is
Spectralink Corporation's.