Gitlab Review
AI-assisted GitLab merge request code review with human approval gate. Uses GraphQL for notes and MR metadata, REST fallback for diff content and approve/unapprove (no CLI dependencies). Designed to pair with @dougschaefer/writing-voice for tone-consistent reviews driven from an agent harness.
Authentication
Requires a GitLab personal access token with api scope, stored in a
swamp vault.
Methods
- get_mr_diff — Fetch MR metadata (GraphQL) and file diffs (REST)
- analyze — Store an AI-generated review draft
- edit_draft — Revise the draft (versioned, retains history)
- update_review — Edit an existing comment via GraphQL updateNote
- approve_mr — Approve the MR without posting a comment (REST)
- unapprove_mr — Remove approval / request changes (REST; idempotent — a never-approved MR is a no-op)
- post_review — Post draft via GraphQL createNote, optionally approve/unapprove
- post_line_comment — Post a comment positioned on a specific file/line in the diff (REST discussions)
- post_discussion — Open a general resolvable MR thread with no diff position (REST discussions; skips a body already posted)
- post_inline_review — Post SHA-bound, changed-line-validated inline review comments
2026.10.22.1
Fixed: post_inline_review always failed when run through swamp with
Method arguments validation failed: Unrecognized keys: "host", "token". swamp
merges a definition's globalArguments under per-method arguments before
validating them, and the method's arguments schema was .strict(), so it
rejected the merged host and token. The arguments schema now strips unknown
keys like every other method in this extension. Each comment is still validated
strictly.
Upgrade note: No schema or behavioral changes beyond the fix. The model version moves to 2026.10.22.1 with an identity upgrade.
2026.10.21.2
Changed: Documentation only: the setup example stored the token with
echo "$GITLAB_TOKEN" | swamp vault put gitlab TOKEN, which assumes the token
already sits in an environment variable. It now uses the interactive
swamp vault put gitlab TOKEN prompt, or a pipe from another secret store. The
token global argument description now says to supply it as
${{ vault.get("gitlab", "TOKEN") }} and never as a literal.
Upgrade note: No schema or behavioral changes. The model version moves to 2026.10.21.2 with an identity upgrade.
Global Arguments
| Argument | Type | Description |
|---|---|---|
| host | string | GitLab hostname (e.g. gitlab.example.com) |
| token | string | GitLab personal access token. Supply it as ${{ vault.get("gitlab", "TOKEN") }}; never pass the literal token |
| Argument | Type | Description |
|---|---|---|
| project | string | Project path (e.g. mygroup/myproject) |
| iid | number | Merge request IID |
| Argument | Type | Description |
|---|---|---|
| project | string | Project path |
| iid | number | Merge request IID |
| body | string | Review comment body (markdown) |
| Argument | Type | Description |
|---|---|---|
| project | string | Project path |
| iid | number | Merge request IID |
| body | string | Updated review comment body (markdown) |
| Argument | Type | Description |
|---|---|---|
| project | string | Project path |
| iid | number | Merge request IID |
| Argument | Type | Description |
|---|---|---|
| project | string | Project path |
| iid | number | Merge request IID |
| Argument | Type | Description |
|---|---|---|
| project | string | Project path |
| iid | number | Merge request IID |
| noteId | number | Note ID to update |
| Argument | Type | Description |
|---|---|---|
| project | string | Project path |
| iid | number | Merge request IID |
| Argument | Type | Description |
|---|---|---|
| project | string | Project path |
| iid | number | Merge request IID |
| body | string | Comment body (markdown) |
| newPath | string | File path on the new side of the diff |
| oldPath? | string | File path on the old side of the diff (defaults to newPath — |
| newLine? | number | Line number on the new side (added/changed lines) |
| oldLine? | number | Line number on the old side (deleted lines) |
| Argument | Type | Description |
|---|---|---|
| project | string | Project path |
| iid | number | Merge request IID |
| body | string | Thread body (markdown) |
Resources
2026.10.21.2
Changed: Documentation only: the setup example stored the token with
echo "$GITLAB_TOKEN" | swamp vault put gitlab TOKEN, which assumes the token
already sits in an environment variable. It now uses the interactive
swamp vault put gitlab TOKEN prompt, or a pipe from another secret store. The
token global argument description now says to supply it as
${{ vault.get("gitlab", "TOKEN") }} and never as a literal.
Upgrade note: No schema or behavioral changes. The model version moves to 2026.10.21.2 with an identity upgrade.
2026.10.21.1
Added: post_discussion opens a general resolvable thread on a merge
request, with no diff position. Use it for review points that don't sit on a
changed line, such as a stale doc outside the diff or a commit-type nit. Before
this, those points could only go into the single post_review note, which
GitLab does not let anyone resolve. Arguments are project, iid and body.
Like the other posting methods, it refuses a closed or merged MR (run
get_mr_diff first).
Added: discussionThread resource records each thread (discussionId,
noteId, body, postedAt). Instances are keyed by a SHA-256 prefix of the
body, and post_discussion skips posting when the same body is already recorded
for that MR, so a retry after a successful post does not open a duplicate
thread. The body is compared after normalising line endings and trimming
trailing whitespace.
Upgrade note: Additive only. Existing resources and methods are unchanged.
Modified 1 behaviors
2026.10.14.1
Added: The manifest now declares license: Apache-2.0 (SPDX). The registry quality rubric scores a declared license separately from the bundled LICENSE.md.
Upgrade note: Metadata only. No code, schema, or behavioral changes.
2026.09.18.1
Upgrade note: Normalized npm:zod dependency version to 4.6.5 across the
repo. No behavioral changes in this extension.
2026.09.18.1
Upgrade note: Normalized npm:zod dependency version to 4.6.5 across the
repo. No behavioral changes in this extension.
2026.09.15.1
Changed: Bump zod 4.4.3 → 4.6.5
2026.09.08.1
Added: SHA-bound, changed-line-validated batch inline review posting for approval-gated triage.
Upgrade note: Existing review resources are unchanged.
2026.08.28.1
Changed: Normalized the extension license to Apache-2.0 and corrected the copyright holder to "Sean Escriva". Extensions that previously shipped an MIT LICENSE.md are now Apache-2.0, consistent with the repository root and every other extension. No code or behavioral changes.
Upgrade note: License text only. No API, schema, or runtime behavior changed.
2026.08.26.3
Fixed: Restored inline npm:zod@4.4.3 import specifiers so the registry
quality scorer can resolve dependencies and score the extension. An earlier
release used a bare "zod" import-map specifier, which published but scored as
unscored.
Changed: Retained explicit compilerOptions.strict in deno.json. No
behavioral or schema changes.
2026.09.08.1
Added: SHA-bound, changed-line-validated batch inline review posting for approval-gated triage.
Upgrade note: Existing review resources are unchanged.
2026.08.28.1
Changed: Normalized the extension license to Apache-2.0 and corrected the copyright holder to "Sean Escriva". Extensions that previously shipped an MIT LICENSE.md are now Apache-2.0, consistent with the repository root and every other extension. No code or behavioral changes.
Upgrade note: License text only. No API, schema, or runtime behavior changed.
2026.08.26.3
Fixed: Restored inline npm:zod@4.4.3 import specifiers so the registry
quality scorer can resolve dependencies and score the extension. An earlier
release used a bare "zod" import-map specifier, which published but scored as
unscored.
Changed: Retained explicit compilerOptions.strict in deno.json. No
behavioral or schema changes.
Modified 1 behaviors
2026.08.28.1
Changed: Normalized the extension license to Apache-2.0 and corrected the copyright holder to "Sean Escriva". Extensions that previously shipped an MIT LICENSE.md are now Apache-2.0, consistent with the repository root and every other extension. No code or behavioral changes.
Upgrade note: License text only. No API, schema, or runtime behavior changed.
2026.08.26.3
Fixed: Restored inline npm:zod@4.4.3 import specifiers so the registry
quality scorer can resolve dependencies and score the extension. An earlier
release used a bare "zod" import-map specifier, which published but scored as
unscored.
Changed: Retained explicit compilerOptions.strict in deno.json. No
behavioral or schema changes.
2026.08.26.3
Fixed: Restored inline npm:zod@4.4.3 import specifiers so the registry
quality scorer can resolve dependencies and score the extension. An earlier
release used a bare "zod" import-map specifier, which published but scored as
unscored.
Changed: Retained explicit compilerOptions.strict in deno.json. No
behavioral or schema changes.
2026.08.26.1
Fixed: Added missing description field to upgrade entry for version
2026.08.24.2. The omission caused swamp extension pull to fail with a catalog
validation error ("upgrades.N.description: Invalid input: expected string,
received undefined").
2026.08.25.1
Changed: Updated labels for improved extension discoverability. Added cross-cutting category labels (security, observability, finops, infrastructure, networking, compliance, devops, ai, incident-response) where applicable.
updated labels
2026.08.24.3
Added: Output metadata attributes for observability.
durationMs: Method execution duration in milliseconds.collectedBy: Extension name that produced the data.fetchedAt: ISO 8601 timestamp when data was fetched (added to resources that previously lacked it).
2026.08.24.2
Added Troubleshooting section documenting post_review partial-failure scenario, large diff truncation, idempotent unapprove, list_mr_notes cross-extension dependency, token scope requirements, and no rate-limit retry.
2026.08.21.2
Changed: project and iid method arguments (get_mr_diff, analyze,
edit_draft, approve_mr, unapprove_mr, update_review, post_review,
post_line_comment) are now validated up front — project must be non-empty
and iid must be a positive integer. Previously an empty project path or a
zero/negative/fractional iid passed schema validation and only failed deep
inside a GitLab API call with a confusing 404 or 400. A malformed (non-JSON)
response body from GitLab's GraphQL endpoint, the MR changes endpoint, the
MR versions endpoint, or the discussions endpoint now raises a clear error
naming the request that failed, instead of a raw JSON.parse SyntaxError.
2026.08.21.1
Changed: Added .describe() documentation to every previously undocumented field in the
resource schemas (DiffFileSchema, MrDiffSchema, ReviewDraftSchema, ReviewPostedSchema,
LineCommentSchema). Tightened host and token in the global arguments to require a
non-empty string. No behavioral change — a no-op upgrades entry was added to keep the
model's typeVersion tracking in sync with the version bump.
2026.08.07.1
Added: post_line_comment method — posts a comment positioned on a specific
file/line in an MR diff (GitLab REST discussions API), for the standard
diff-level code-review UX that post_review (top-level notes only) doesn't
cover. Fetches the MR's current diff versions to build the required
base_sha/start_sha/head_sha position, then creates a positioned
discussion thread. Accepts newLine and/or oldLine (at least one required)
to comment on added, deleted, or context lines. New lineComment resource
records discussionId, noteId, and the file/line position of each posted
comment, keyed per file/line so multiple comments on the same MR are stored
as separate instances (lifetime: 30d, garbageCollection: 20, additive —
no changes to existing resources).
2026.07.18.1
Added: An upgrades array entry (no-op) to review.ts for proper typeVersion tracking on existing instances. No schema or behavior changes.
2026.07.08.1
Fixed:
unapprove_mrandpost_review action=request_changesare now idempotent. GitLab's unapprove endpoint returns HTTP 404 when the caller has no approval to remove; that is the desired end state for "request changes", not an error. A never-approved MR no longer fails the call — the comment still posts and the MR is left unapproved. Non-404 errors still propagate.
2026.08.21.1
Changed: Added .describe() documentation to every previously undocumented field in the
resource schemas (DiffFileSchema, MrDiffSchema, ReviewDraftSchema, ReviewPostedSchema,
LineCommentSchema). Tightened host and token in the global arguments to require a
non-empty string. No behavioral change — a no-op upgrades entry was added to keep the
model's typeVersion tracking in sync with the version bump.
2026.08.07.1
Added: post_line_comment method — posts a comment positioned on a specific
file/line in an MR diff (GitLab REST discussions API), for the standard
diff-level code-review UX that post_review (top-level notes only) doesn't
cover. Fetches the MR's current diff versions to build the required
base_sha/start_sha/head_sha position, then creates a positioned
discussion thread. Accepts newLine and/or oldLine (at least one required)
to comment on added, deleted, or context lines. New lineComment resource
records discussionId, noteId, and the file/line position of each posted
comment, keyed per file/line so multiple comments on the same MR are stored
as separate instances (lifetime: 30d, garbageCollection: 20, additive —
no changes to existing resources).
2026.07.18.1
Added: An upgrades array entry (no-op) to review.ts for proper typeVersion tracking on existing instances. No schema or behavior changes.
2026.07.08.1
Fixed:
unapprove_mrandpost_review action=request_changesare now idempotent. GitLab's unapprove endpoint returns HTTP 404 when the caller has no approval to remove; that is the desired end state for "request changes", not an error. A never-approved MR no longer fails the call — the comment still posts and the MR is left unapproved. Non-404 errors still propagate.
2026.08.07.1
Added: post_line_comment method — posts a comment positioned on a specific
file/line in an MR diff (GitLab REST discussions API), for the standard
diff-level code-review UX that post_review (top-level notes only) doesn't
cover. Fetches the MR's current diff versions to build the required
base_sha/start_sha/head_sha position, then creates a positioned
discussion thread. Accepts newLine and/or oldLine (at least one required)
to comment on added, deleted, or context lines. New lineComment resource
records discussionId, noteId, and the file/line position of each posted
comment, keyed per file/line so multiple comments on the same MR are stored
as separate instances (lifetime: 30d, garbageCollection: 20, additive —
no changes to existing resources).
2026.07.18.1
Added: An upgrades array entry (no-op) to review.ts for proper typeVersion tracking on existing instances. No schema or behavior changes.
2026.07.08.1
Fixed:
unapprove_mrandpost_review action=request_changesare now idempotent. GitLab's unapprove endpoint returns HTTP 404 when the caller has no approval to remove; that is the desired end state for "request changes", not an error. A never-approved MR no longer fails the call — the comment still posts and the MR is left unapproved. Non-404 errors still propagate.
Modified 1 behaviors
2026.07.18.1
Added: An upgrades array entry (no-op) to review.ts for proper typeVersion tracking on existing instances. No schema or behavior changes.
2026.07.08.1
Fixed:
unapprove_mrandpost_review action=request_changesare now idempotent. GitLab's unapprove endpoint returns HTTP 404 when the caller has no approval to remove; that is the desired end state for "request changes", not an error. A never-approved MR no longer fails the call — the comment still posts and the MR is left unapproved. Non-404 errors still propagate.
2026.07.08.1
Fixed:
unapprove_mrandpost_review action=request_changesare now idempotent. GitLab's unapprove endpoint returns HTTP 404 when the caller has no approval to remove; that is the desired end state for "request changes", not an error. A never-approved MR no longer fails the call — the comment still posts and the MR is left unapproved. Non-404 errors still propagate.
- Has README or module doc2/2earned
- README has a code example1/1earned
- README is substantive1/1earned
- Most symbols documented1/1earned
- No slow types (deprecated)1/1earned
- Dependencies pass trust audit2/2earned
- Has description1/1earned
- Platform support declared (or universal)2/2earned
- License2/2earned
- Verified public repository2/2earned