From 32f8e23f5d3fe04cf69025439a24f83f3daa0b58 Mon Sep 17 00:00:00 2001 From: xobotyi Date: Wed, 15 Jul 2026 13:27:15 +0200 Subject: [PATCH] rework README prose to read naturally Em dashes carried most of the sentence structure; they are replaced with plain punctuation or restructured sentences. Bold label leads on list items and paragraphs become plain text, padded participle tails and stacked negations become full clauses. Tables, code blocks, flag names, and content coverage are unchanged. --- README.md | 137 +++++++++++++++++++++++++++--------------------------- 1 file changed, 68 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index d38ff69..55f260e 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,21 @@ # go-gerrit-mcp -An MCP (Model Context Protocol) server exposing Gerrit code review operations as capability-gated tools. It lets an -AI agent search and read changes, publish review comments, vote, and drive change-state transitions — with a safety -posture that makes every write capability an explicit operator opt-in. +An MCP (Model Context Protocol) server that exposes Gerrit code review operations as capability-gated tools. An AI +agent can search and read changes, publish review comments, vote, and drive change-state transitions. Every write +capability is an explicit operator opt-in. -- **Transport:** stdio -- **Target platform:** Gerrit 3.13+, authenticated via HTTP credentials -- **Output:** llmxml — semantically tagged text meant to be read by a model (see [Output format](#output-format)) +- Transport: stdio +- Target platform: Gerrit 3.13+, authenticated via HTTP credentials +- Output: llmxml, semantically tagged text meant to be read by a model (see [Output format](#output-format)) ## Safety posture Two defaults encode it: -- **Zero configuration exposes the `read` group only.** Write capability never appears unless enabled via `--groups`. -- **The own-changes restriction is on by default.** Even with write groups enabled, trail-leaving operations — - comments, votes, state changes, anything other humans see — are refused on changes the authenticated account does - not own, until the operator explicitly passes `--own-changes-only=false`. +- Zero configuration exposes the `read` group only. Write capability never appears unless enabled via `--groups`. +- The own-changes restriction is on by default. Even with write groups enabled, trail-leaving operations (comments, + votes, state changes, anything other humans see) are refused on changes the authenticated account does not own, + until the operator explicitly passes `--own-changes-only=false`. An agent leaving unwanted trail on colleagues' changes is an externally visible failure; a missing capability is a locally discoverable inconvenience. The defaults are chosen accordingly. Widen deliberately: @@ -27,7 +27,7 @@ go-gerrit-mcp --groups read,comment,transition --own-changes-only=false --projec ## Install -**Binary release** — download the binary for your platform from +Binary release: download the binary for your platform from [GitHub Releases](https://github.com/GaijinEntertainment/go-gerrit-mcp/releases), make it executable, and put it on your `PATH`: @@ -38,13 +38,13 @@ curl -Lo /usr/local/bin/go-gerrit-mcp \ chmod +x /usr/local/bin/go-gerrit-mcp ``` -**Docker:** +Docker: ```sh docker pull ghcr.io/gaijinentertainment/go-gerrit-mcp:latest ``` -**go install:** +go install: ```sh go install dev.gaijin.team/go/go-gerrit-mcp/cmd/go-gerrit-mcp@latest @@ -52,7 +52,7 @@ go install dev.gaijin.team/go/go-gerrit-mcp/cmd/go-gerrit-mcp@latest ## Quick start -The server reads connection identity from environment variables only — credentials never travel through flags: +The server reads connection identity from environment variables only; credentials never travel through flags: | Variable | Meaning | | ----------------- | -------------------------------------------------- | @@ -116,12 +116,12 @@ claude mcp add gerrit \ ## Per-project configuration in Claude Code -Everything the server needs is read from the environment — the identity variables above plus a `GERRIT_MCP_*` -mirror for every flag (see [Configuration reference](#configuration-reference)) — and MCP server processes inherit -the session environment. In Claude Code that turns one user-level registration into per-project configuration, -down to different Gerrit instances with different credentials per repository. +Everything the server needs is read from the environment: the identity variables above plus a `GERRIT_MCP_*` mirror +for every flag (see [Configuration reference](#configuration-reference)). MCP server processes inherit the session +environment, so in Claude Code one user-level registration turns into per-project configuration, down to different +Gerrit instances with different credentials per repository. -**`~/.claude.json`** — the registration; no `env` block: +`~/.claude.json` holds the registration, with no `env` block: ```json { @@ -133,7 +133,7 @@ down to different Gerrit instances with different credentials per repository. } ``` -**`/.claude/settings.local.json`** — the project's environment; every `env` entry reaches the server +`/.claude/settings.local.json` carries the project's environment; every `env` entry reaches the server process: ```json @@ -148,22 +148,22 @@ process: } ``` -Values shared by most projects can sit one layer down in `~/.claude/settings.json` — settings files merge with -`.claude/settings.local.json` over `.claude/settings.json` over `~/.claude/settings.json` — so a project declares -only its deltas. Anything no layer sets falls back to the server's own defaults: read-only, own changes. +Values shared by most projects can sit one layer down in `~/.claude/settings.json`. Settings files merge, with +`.claude/settings.local.json` over `.claude/settings.json` over `~/.claude/settings.json`, so a project declares only +its deltas. Anything no layer sets falls back to the server's own defaults: read-only, own changes. -The registration's `env` block stays empty for a reason: a variable named there shadows every settings layer, and -references are not a way around that — they never resolve from settings files. `${VAR}` expands only from the -shell environment that launched `claude`, and anything unresolved reaches the server as a literal string. +The registration's `env` block stays empty for a reason. A variable named there shadows every settings layer, and +references are no workaround: `${VAR}` expands only from the shell environment that launched `claude`, never from +settings files, and anything unresolved reaches the server as a literal string. Other MCP clients inherit their launch environment the same way, so per-directory tooling such as [direnv](https://direnv.net/) achieves the identical split without client support. ## Capability groups -Capability is selected at startup via `--groups` as a comma-separated list. Groups are independent and combinable — -there is no ladder; each write-capable group bundles the minimal change-read subset it needs to function on its own, -and enabled groups union. +Capability is selected at startup via `--groups` as a comma-separated list. Groups are independent and combinable, +with no privilege ladder: each write-capable group bundles the minimal change-read subset it needs to work on its +own, and enabled groups union. | Group | Tools | | ------------ | ---------------------------------------------------------------------------------------- | @@ -173,63 +173,63 @@ and enabled groups union. ### Tools -- `search_changes` — query changes with Gerrit's change query syntax, paginated. -- `get_change` — one change in review-relevant detail: status, owner, labels with votes, current revision, messages. -- `list_change_files` — files touched by a revision, with per-file change stats. -- `get_file_diff` — the diff of one file in a revision. -- `get_change_comments` — comment threads on a change, with resolution state and comment ids. Returns unresolved +- `search_changes`: query changes with Gerrit's change query syntax, paginated. +- `get_change`: one change in review-relevant detail: status, owner, labels with votes, current revision, messages. +- `list_change_files`: files touched by a revision, with per-file change stats. +- `get_file_diff`: the diff of one file in a revision. +- `get_change_comments`: comment threads on a change, with resolution state and comment ids. Returns unresolved threads only by default; `status=all` fetches the full history, `status=resolved` the settled threads. -- `post_comments` — publish a review in one call: optional top-level message plus inline, range, file-level, and - reply comments; replies anchor to comment ids from `get_change_comments`; `resolved` toggles the thread state. -- `set_vote` — set a label vote (e.g. `Code-Review`) with an optional message; value `0` clears an own vote. -- `transition_change` — move a change's state: `submit`, `abandon`, `restore`, `wip`, or `ready`, with an optional - message (submit accepts none). Gerrit's refusal — a blocked submit, a restore of a merged change — is reported +- `post_comments`: publish a review in one call: optional top-level message plus inline, range, file-level, and + reply comments. Replies anchor to comment ids from `get_change_comments`; `resolved` toggles the thread state. +- `set_vote`: set a label vote (e.g. `Code-Review`) with an optional message; value `0` clears an own vote. +- `transition_change`: move a change's state: `submit`, `abandon`, `restore`, `wip`, or `ready`, with an optional + message (submit accepts none). Gerrit's refusal (a blocked submit, a restore of a merged change) is reported verbatim. ## Review notifications -An opt-in push channel for review activity. The agent subscribes to a change (`subscribe_change`), and from then on -new change messages, votes, inline comment threads, and status transitions arrive in the session by themselves as -`review_activity` blocks — the same llmxml vocabulary the read tools emit, activity carried whole, so nothing needs -fetching afterwards. `unsubscribe_change` ends a subscription early; a merged or abandoned change ends its own with -a final notification saying so, and a change that becomes unreadable (deleted, or no longer visible to the account) -does the same naming the reason. +An opt-in push channel for review activity. The agent subscribes to a change with `subscribe_change`; from then on, +new change messages, votes, inline comment threads, and status transitions arrive in the session on their own as +`review_activity` blocks. The payload uses the same llmxml vocabulary the read tools emit and carries the activity +whole, so nothing needs fetching afterwards. `unsubscribe_change` ends a subscription early. A merged or abandoned +change ends its own subscription with a final notification that says so, and a change that becomes unreadable +(deleted, or no longer visible to the account) does the same, with the reason spelled out. Subscriptions are per-session and in-memory: they leave no trace on the Gerrit instance, end with the session, and -after a server restart the agent subscribes again. With the feature off — the default — the server is byte-identical -to its pre-feature self: no extra tools, no extra capability, no background polling. +after a server restart the agent subscribes again. With the feature off (the default) the server is byte-identical +to its pre-feature self, with no extra tools or capabilities and no background polling. Enabling takes both sides: -1. **Server** — `--review-notifications=true` (or its mirror). The server registers both subscription tools and - polls Gerrit every `--review-notifications-poll-interval` (default `60s`): one batched query per tick over all - subscribed changes, detail fetches only for changes that actually moved. -2. **Client** — delivery rides the Claude Code **channels** contract (research preview, Claude Code ≥ 2.1.80). +1. Server side: pass `--review-notifications=true` (or its mirror). The server registers both subscription tools + and polls Gerrit every `--review-notifications-poll-interval` (default `60s`): one batched query per tick over + all subscribed changes, with detail fetches only for changes that actually moved. +2. Client side: delivery uses the Claude Code channels contract (research preview, Claude Code 2.1.80 or newer). For a server registered plainly under `mcpServers`, launch with - `claude --dangerously-load-development-channels server:`, where `` is the registration key — it + `claude --dangerously-load-development-channels server:`, where `` is the registration key; it becomes the `source` attribute of the injected `` blocks. Allowlisted channel plugins load with `claude --channels` instead. Research-preview caveats: organization policy can disable channels entirely; the flag syntax may change between -Claude Code releases; and a client without channel support silently drops the events — the server then degrades to -exactly its pre-feature behavior, with no errors on either side. +Claude Code releases; and a client without channel support silently drops the events, in which case the server +behaves exactly as if the feature were off, with no errors on either side. -Noise control is operator configuration, not server heuristics — nothing is filtered by message tag, because a CI -verdict is often exactly the awaited outcome: +Noise control is operator configuration. The server applies no heuristics of its own and filters nothing by message +tag, because a bot's verdict is often exactly the outcome the agent is waiting for: - the authenticated account's own activity is skipped by default (`--review-notifications-include-own` keeps it); - `--review-notifications-exclude-accounts` silences accounts by username or numeric ID; - `--review-notifications-exclude-patterns` drops events whose message or comment text matches a regular - expression; an invalid pattern fails startup naming it. + expression; an invalid pattern fails startup with an error naming it. -Every flag has a `GERRIT_MCP_*` mirror riding the same settings layering as the rest of the configuration (see -[Per-project configuration](#per-project-configuration-in-claude-code)), so a project can enable notifications and -pick its exclusions in its own settings file. +Every flag has a `GERRIT_MCP_*` mirror that follows the same settings layering as the rest of the configuration +(see [Per-project configuration](#per-project-configuration-in-claude-code)), so a project can enable notifications +and pick exclusions in its own settings file. ## Configuration reference Behavior is configured by CLI flags, each mirrored by an environment variable so one configuration style works for -binary and Docker invocations alike. Precedence: **flag wins over its mirror, the mirror wins over the default.** +binary and Docker invocations alike. Precedence: the flag wins over its mirror, and the mirror wins over the default. | Flag | Mirror | Default | Meaning | | -------------------- | ----------------------------- | ------- | -------------------------------------------------------------- | @@ -248,18 +248,17 @@ Notes: - `--own-changes-only` takes an explicit boolean value: `--own-changes-only=false`. A bare flag without a value is a configuration error. -- **Project scoping** (`--projects`) is enforced server-side: a project clause is injected into every change query +- Project scoping (`--projects`) is enforced server-side: a project clause is injected into every change query regardless of what the agent composed, and direct operations on out-of-scope changes are refused. -- **Tool filters** only narrow. `--exclude-tools` removes tools from what the groups resolved; `--include-tools` - keeps only the listed subset of it. A tool outside the enabled groups can never be activated by a filter, and - exclude wins over include. Filter entries naming no known tool fail startup, so misconfigurations surface - immediately. +- Tool filters only narrow. `--exclude-tools` removes tools from what the groups resolved; `--include-tools` keeps + only the listed subset of it. A tool outside the enabled groups can never be activated by a filter, and exclude + wins over include. Filter entries naming no known tool fail startup, so misconfigurations surface immediately. - Configuration errors are aggregated: the server reports every problem at once, then exits non-zero. ## Output format -Every tool responds in **llmxml**: an LLM-digestible subset of XML — line-structured, semantically tagged text meant -to be read by a model. Attributes carry metadata, element bodies carry content: +Every tool responds in llmxml, an LLM-digestible subset of XML: line-structured, semantically tagged text meant to +be read by a model. Attributes carry metadata; element bodies carry content: ``` @@ -268,7 +267,7 @@ to be read by a model. Attributes carry metadata, element bodies carry content: ``` There is no XML declaration, no namespaces, and no schema; nothing parses it back. If you need machine-readable -Gerrit data, use Gerrit's REST API directly — this format is for model consumption. +Gerrit data, use Gerrit's REST API directly; this format is for model consumption. ## License