crit-cli — Claude Code skill: what it does, how to install
Programmatic control for crit reviews. It allows agents to read JSON feedback, post line comments, and sync changes without entering the interactive review loop.
npx skills add tomasz-tomczyk/crit --skill crit-cli -a claude-codeWhat crit-cli does
The skill teaches an agent to run crit commands non-interactively. It details crit comment, crit pull, and crit push for scripting automated workflows. The agent learns how to parse review.json, track lines shifted by edits using the anchor field, and target web previews with CSS selectors instead of line numbers.
Line numbers always reference files on disk from line 1 rather than git diffs. Keep that in mind. If multiple review sessions match the directory, headless commands fail immediately and refuse to guess. The agent must inspect candidates via crit status --json and provide the chosen --session <id>.
What it helps with
- parse unresolved comments from a review.json file
- post inline and file-level feedback from the terminal
- reply to specific comments using their thread identifier
- submit batches of comments through a JSON payload
Example prompts for the agent
- Read unresolved issues with
crit comments --jsonand apply the fixes. - Send a reply to comment
c_a1b2c3usingcrit comment --reply-towith authorAmp. - Inspect active reviews via
crit status --jsonand submit comments with--session <id>.
How to install crit-cli
1Skills CLI (Vercel)
npx skills add tomasz-tomczyk/crit --skill crit-cli -a claude-code2Manually: put the files in place
~/.claude/skills/crit-cli/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/crit-cli/
1Skills CLI (Vercel)
npx skills add tomasz-tomczyk/crit --skill crit-cli -a codex2Manually: put the files in place
.agents/skills/crit-cli/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add tomasz-tomczyk/crit --skill crit-cli -a cursor2Manually: put the files in place
.cursor/skills/crit-cli/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install tomasz-tomczyk/crit crit-cli2Manually: put the files in place
.github/skills/crit-cli/SKILL.md1Skills CLI (Vercel)
npx skills add tomasz-tomczyk/crit --skill crit-cli -a gemini-cli2Platform CLI
gemini skills install https://github.com/tomasz-tomczyk/crit --path integrations/ampcode/skills/crit-cliManually: put the files in place
.devin/skills/crit-cli/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add tomasz-tomczyk/crit --skill crit-cli -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about crit-cli
How do I install crit-cli in Claude Code?
Run npx skills add tomasz-tomczyk/crit --skill crit-cli -a claude-code.
How does crit-cli differ from the crit skill?
The crit skill manages an interactive review cycle. In contrast, crit-cli covers scripting commands such as crit comment and reading review.json files.
What happens if multiple review sessions exist?
Headless commands will fail to avoid modifying the wrong review. Run crit status --json to get the list of sessions, then pass the target ID using --session <id>.
Source text
SKILL.md · MIT
---
name: crit-cli
description: Use when an agent needs to author or reply to crit inline comments programmatically (including multi-agent workflows commenting on shared code/plans/docs/proposals), publish or unpublish a crit review with crit share, sync a crit review to or from a GitHub PR or GitLab MR, or read/interpret a crit review JSON file. Covers crit comment, crit share, crit unpublish, crit pull, crit push, review file format, and resolution workflow. Not for invoking an interactive review loop — that's the `crit` skill.
user-invocable: false
---
# Crit CLI Reference
> If a plan was just written and the user said "crit" or "review", use the `crit` skill instead — it covers the full review loop. This skill covers CLI operations like `crit comment`, `crit pull/push`, and `crit share`.
Comments have three scopes:
- **Line comments** (`scope: "line"`) — tied to specific lines, stored in `files.<path>.comments`
- **File comments** (`scope: "file"`) — about a file overall, stored in `files.<path>.comments` with `start_line: 0`
- **Review comments** (`scope: "review"`) — general feedback, stored in the top-level `review_comments` array
The review file path is shown by `crit status`.
## Reading comments
When `crit` completes a review round, read **stdout** and follow its instructions. Unresolved comments are often embedded in that prompt as JSON. Check **stderr** for `approved: true` or `approved: false`.
When you need to read comments separately:
```bash
crit comments # human-readable, unresolved only (default)
crit comments --json # flat JSON for agents
crit comments --all # include resolved comments
crit comments --plan <slug> # plan reviews
crit comments [path] # explicit review.json or .crit directory
```
Review-level comments are listed first — easy to miss in raw `review.json`. Uses the same review resolution as `crit comment` (`--output`, `--plan`, daemon session).
## Multiple active sessions
When more than one review session matches the current directory and branch, headless commands (`crit comment`, `crit comments`, `crit share`, `crit push`, `crit pull`) refuse to guess. Run `crit status` (or `crit status --json`) to list every active session, then target the intended review with `--session <id>`:
```bash
crit comment --session <id> --author <name> <path>:<line> <body>
crit comment --session <id> --json --file comments.json --author <name>
crit comments --session <id>
crit share --session <id> <file>
crit push --session <id>
crit pull --session <id>
```
The JSON status output exposes the candidates in `sessions`.
## Review file format
```json
{
"review_comments": [
{
"id": "r_f1e2d3",
"body": "Overall the architecture looks good",
"scope": "review",
"author": "User Name",
"resolved": false,
"replies": [
{ "id": "rp_b4a5c6", "body": "Thanks, addressed the minor issues", "author": "Amp" }
]
}
],
"files": {
"path/to/file.go": {
"comments": [
{
"id": "c_a1b2c3",
"start_line": 5,
"end_line": 10,
"body": "Comment text",
"quote": "the specific words selected",
"anchor": "The sessions table needs a complete rewrite...",
"author": "User Name",
"resolved": false,
"replies": [
{ "id": "rp_c7d8e9", "body": "Fixed by extracting to helper", "author": "Amp" }
]
}
]
}
}
}
```
Field rules:
- `resolved`: `false` or **missing** — both mean unresolved. Only `true` means resolved.
- `quote` (optional): the specific text the reviewer selected — narrows scope within the line range. Focus changes on the quoted text rather than the entire range.
- `anchor` (line comments): full text of the commented lines when placed. When edits shift line numbers, locate content by anchor rather than trusting `start_line`/`end_line`.
- `drifted: true`: original content was removed or heavily rewritten — line numbers are approximate at best.
- Unresolved comments may have `replies` — read them before acting.
## Authoring comments
```bash
# Review-level (general feedback)
crit comment --author 'Amp' '<body>'
# File-level (whole file, no line numbers)
crit comment --author 'Amp' <path> '<body>'
# Line (single line or range)
crit comment --author 'Amp' <path>:<line> '<body>'
crit comment --author 'Amp' <path>:<start>-<end> '<body>'
# DOM pin (live review or HTML preview). File:line is rejected there.
crit comment --author 'Amp' --selector '<css>' '<body>'
crit comment --author 'Amp' --selector '<css>' --route <path> '<body>'
# Reply to an existing comment
crit comment --reply-to <id> --author 'Amp' '<body>'
```
Hard rules:
- **Always pass `--author 'Amp'`** so comments are attributed correctly.
- **Always single-quote the body** — double quotes break on backticks and shell metachars.
- **Line numbers reference the file on disk** (1-indexed), not diff line numbers.
- **Reply bodies support markdown** — use code fences and inline code where helpful.
- **Only pass `--resolve` when the user explicitly asks.** Never resolve proactively. Same rule applies to the `resolve` field in `--json` mode.
- **Live reviews and HTML preview** do not take `<path>:<line>`. Pin with `--selector <css>`. `--route` is the page path (default `/` for live, `/preview-content` for preview). In `--json`, use `"selector"` and `"route"`.
## Bulk commenting (3+ comments)
Use `--json` for atomicity (single write, no partial state) and speed (one process). The JSON can come from stdin or `--file <path>`:
```bash
# stdin — fine for short, single-line bodies:
echo '[
{"body": "overall feedback", "scope": "review"},
{"path": "session.go", "body": "restructure", "scope": "file"},
{"file": "src/auth.go", "line": 42, "body": "Missing null check"},
{"file": "src/auth.go", "line": "50-55", "body": "Extract to helper"},
{"reply_to": "c_a1b2c3", "body": "Fixed — added null check"},
{"reply_to": "r_f1e2d3", "body": "Done"}
]' | crit comment --json --author 'Amp'
```
**For multi-paragraph bodies, prefer `--file`.** A literal newline inside a `"body"` string breaks JSON parsing, and shell-quoted heredocs make this easy to introduce by accident. Write the JSON to a temp file (use your file-edit tool), then:
```bash
crit comment --json --file /tmp/crit-bulk.json --author 'Amp'
```
`--file -` is an explicit "read stdin" if you ever need it.
Per-entry schema:
| Field | Type | Required | Notes |
|---|---|---|---|
| `file` / `path` | string | line/file comments | Relative path. `path` alone (no `line`) → file-level. |
| `line` | int/string | line comments | `42` or `"45-47"` |
| `end_line` | int | optional | Defaults to `line` |
| `body` | string | always | |
| `author` | string | optional | Per-entry override; falls back to `--author` |
| `scope` | string | optional | `"review"` / `"file"` — usually inferred |
| `reply_to` | string | replies | Comment ID (`c_…` or `r_…`) |
| `resolve` | bool | optional | Only when user explicitly asks |
| `quote` | string | optional | Line comments only: the exact text the comment is about, when it is part of the lines |
| `quote_offset` | int | optional | Where `quote` starts in the lines' text, whitespace collapsed (as the web UI records it); needs `quote` |
Scope inference (when `scope` omitted): has `reply_to` → reply; no `file`/`path` and no `line` → review-level; `path` but no `line` → file-level; `file`/`path` + `line` → line.
## Multi-file disambiguation
Comment IDs are unique per session, but the same ID can collide across files. If `crit comment` errors with "comment found in multiple files", disambiguate with `--path`:
```bash
crit comment --reply-to c_a1b2c3 --path src/auth.go --author 'Amp' 'Fixed the null check'
```
In `--json` mode, set the `file` field on the entry. Review-level IDs (`r_…`) are globally unique and never need this.
## Plan-mode comments
Plan reviews (via `crit plan` or the ExitPlanMode hook) store the review file in `~/.crit/plans/<slug>/`. **Always pass `--plan <slug>`** — without it, `crit comment` looks in the project root and won't find the comments. The slug is shown in the review feedback prompt.
```bash
crit comment --plan my-plan-2026-03-23 --reply-to c_a1b2c3 --author 'Amp' 'Updated the plan'
```
## GitHub PR / GitLab MR Integration
```bash
crit pull [number|url] # Fetch PR/MR review comments into the review file
crit push [--dry-run] [--event <type>] [-m <msg>] [n] # Post review comments to a PR/MR
crit pull --forge gitlab 42 # Force GitLab when auto-detect is ambiguous
```
Requires `gh` CLI installed and authenticated. PR number is auto-detected from the current branch.
`--event` values: `comment` (default), `approve`, `request-changes`. `-m` adds a review-level body message.
## Sharing
```bash
crit share <file> [file...] # Upload and print URL
crit share --share-url <url> <file> # Target a specific Crit deployment
crit share --qr <file> # Also print QR code (terminal only)
crit share --org <slug> <file> # Share under an organization
crit share --org <slug> --visibility unlisted <file> # Org share with explicit visibility
crit unpublish [file...] # Remove shared review
crit unpublish --share-url <url> [file...] # Unpublish from a specific deployment
```
- **Always relay the output** — copy the URL (and QR if used) into your response. Don't make them dig through tool output.
- **`--qr` is terminal-only** — skip in mobile apps, web chat UIs, or anywhere Unicode block characters won't render correctly.
- **`--org <slug>`** shares under an organization. Visibility defaults to `organization` (members only). Override with `--visibility` (`organization`, `unlisted`, `public`).
- **`--share-url`** selects among configured `share_targets` (or overrides for one invocation). Required when multiple targets are configured and none is marked default. Empty `CRIT_SHARE_URL=` disables sharing for the process.
- If a review file exists, comments for the shared files are included automatically.
- **Unpublish uses the persisted delete token** in the review file — no extra args needed unless targeting a non-default deployment with `--share-url`.
© tomasz-tomczyk · MIT · tomasz-tomczyk/crit