Use revkit for GitHub/GitLab PR review operations — reading a PR, listing, filtering, replying to and resolving review comments, checking CI status, and fetching failure logs. Prefer it over raw `gh`/`glab` API calls: it returns compact, normalized JSON that costs far fewer tokens than parsing raw API responses, and it works identically on GitHub and GitLab.
Resources
13Install
npx skillscat add konradmichalik/revkit Install via the SkillsCat registry.
revkit is a CLI that wraps the gh and glab commands to provide structured, normalized JSON for pull request and merge request review operations on GitHub and GitLab. It reduces token usage by avoiding raw API parsing and unifies the workflow across both platforms. Agents and developers should use it for tasks like reading PRs, listing or replying to review comments, resolving threads, and checking CI status.
revkit
revkit is a CLI that wraps the gh and glab CLIs and returns structured,
normalized JSON for the review workflow. It exists so you don't spend tokens
figuring out platform-specific API routes, paginating, and parsing large raw
responses on every call. One command in, small JSON out, same shapes on GitHub
and GitLab.
Requires gh or glab installed and authenticated (revkit does not manage
auth). It auto-detects the platform from the git remote.
When to use revkit instead of raw API calls
| Instead of | Use |
|---|---|
gh pr view --json ... / glab mr view + parsing |
revkit pr |
gh api .../comments or GraphQL reviewThreads + filtering |
revkit comments --unresolved |
Manual GraphQL addPullRequestReviewThreadReply |
revkit reply <discussion-id> <body> |
Manual GraphQL resolveReviewThread |
revkit resolve <discussion-id> |
gh pr checks / pipeline API + parsing |
revkit checks --failed |
| Digging through a failed job's raw log | revkit checks --log <name> |
| Re-requesting a bot/human reviewer after a fix | revkit rerequest --reviewer <name> |
| Ad-hoc "is this PR ready?" logic | revkit status |
gh api user --jq .login / glab api user --jq .username |
revkit whoami |
If a task is covered by a revkit subcommand, reach for it before writing a rawgh/glab invocation.
Output envelope — read this first
Every command prints JSON with a top-level integer schemaVersion (currently1). The top level is always an object:
- Object commands carry
schemaVersionalongside their fields, e.g.revkit pr→{ "schemaVersion": 1, "platform": "github", "number": 42, ... }. - List commands are wrapped in an envelope — the array lives under
items:revkit comments→{ "schemaVersion": 1, "items": [ ... ] }.
Read the list results from .items, not the top level. Check schemaVersion and
reject a version you don't understand; it bumps only on a breaking shape
change (additive fields do not bump it).
Commands
Shapes below are the payload — the fields alongside schemaVersion (object
commands) or the shape of each items entry (list commands).
revkit detect # { platform, owner, repo, branch, remote, source, host }
revkit pr [--pr <n>] # { platform, number, title, url, state, author }
revkit comments [--unresolved] [--context] [--with-replies] [--author <name>] [--file <path>] [--since <iso>] [--pr <n>]
# items: [{ id, discussionId, author, body, file, line, resolved, createdAt }]
revkit reply <discussion-id> <body> [--resolve] [--pr <n>] # { success, id } — with --resolve: { success, id, resolved }
revkit resolve <discussion-id> [--pr <n>] # { success }
revkit checks [--failed] [--pr <n>] # items: [{ name, state, conclusion, duration, url }]
revkit checks --log <name> [--tail <n>] [--raw] [--pr <n>] # { name, conclusion, url, log: { lines, truncated, totalLines } }
revkit rerequest --reviewer <name> [--reviewer <name> ...] [--pr <n>] # { success, reviewers: [<login>] }
revkit status [--pr <n>] # { ready, pr, feedback, pipeline }
revkit whoami # { user, platform }Flag notes:
comments --contextadds adiffHunkfield per comment (the anchoring diff
hunk, ornullon outdated/deleted positions). Off by default.comments --with-repliesadds arepliesarray per comment — every
follow-up in the thread, chronological, excluding the opener (already at
top level).replies: []when there are none. Off by default (no extra API
calls, no cost when not requested). Capped at 100 comments per thread.commentsfilters (--authorrepeatable,--fileexact match,--since
ISO/YYYY-MM-DD) are AND-combined and composable with--unresolved.--authormatches only the thread opener, not participants inreplies.reply --resolvereplies then resolves. If the reply fails, nothing is
mutated (exit 1). If the reply succeeds but the resolve fails, it still exits 0
withresolved: falseand a stderr warning — retryresolve <discussion-id>
alone, not the whole command (which would post a duplicate reply).checks --log <name>returns a bounded, cleaned failure log (--taildefaults
to 100 lines;--rawkeeps ANSI + timestamps). GitHub external checks and
commit statuses expose no log and returnlog: nullwith the external URL.rerequestis GitHub-only and--revieweris required and repeatable; only
reviewers who already reviewed can be re-requested.[bot]suffix is optional.
A typical review loop: revkit comments --unresolved → address each →revkit reply <discussion-id> "..." --resolve → revkit status to confirmready: true.
To resolve or reply on GitHub, pass the
discussionId(a GraphQL node ID likePRRT_...) fromrevkit comments, not the numeric commentid.
Exit codes — handle these
- 0 — success. Parse stdout as JSON (top level is always an object with
schemaVersion). - 1 — error. A human-readable message is on stderr (prefixed
revkit:).
Do not parse stdout. - 2 — disambiguation required (a branch with multiple open MRs, or an
ambiguouschecks --logname). stdout is JSON:{ "schemaVersion": 1, "error": "multiple_merge_requests" | "multiple_checks", "message": "...", "candidates": [ ... ] }.
Pick a candidate and re-run with--pr <n>(or the exact check name); do not
treat this as a hard failure.
Fork-based PRs (--repo / --remote)
When the PR lives on an upstream repo but origin is your fork, target the
upstream. Every subcommand accepts these (precedence: flags > env > origin):
revkit status --remote upstream --pr 42 # resolve owner/repo from the 'upstream' remote
revkit comments --repo octocat/upstream --pr 42 # override owner/repo directly
# env equivalents: REVKIT_REPO=owner/repo, REVKIT_REMOTE=upstream