name: crit description: "Review code changes, a plan, a live page (running dev server), or a local HTML file with crit inline comments. Use when asked to review code, a plan, a diff, a running web app, or when you want structured human feedback on your work. Also covers programmatic comment authoring, crit share/unpublish, GitHub PR sync, and review file interpretation." compatibility: opencode
What I do
- Launch Crit for a plan file, the current git diff, a live page (URL to a running dev server or staging site), or a local HTML file.
- Wait for the user to review changes in the browser.
- Read the review file and address unresolved inline comments.
- Signal the next review round with
critwhen edits are done. - Leave inline review comments programmatically with
crit comment. - Sync reviews with GitHub PRs via
crit pullandcrit push.
When to use me
Use this when the user asks to review a plan, spec, code changes, a live page (running dev server, staging URL), or a local HTML file in Crit, when project instructions require a Crit pass before accepting non-trivial changes, when leaving inline comments on code, or when syncing reviews with GitHub PRs.
Launching crit
The CLI auto-detects the review mode from its arguments. Do not ask the user which mode to use. Pass arguments through:
crit <arguments> # file, dir, URL, .html — CLI auto-detects mode
crit --pr <num|url> # GitHub PR (range mode)
crit --range <base>..<head> # commit range (range mode)
crit # no args → branch diff
If no arguments, check conversation context:
- A plan file was written earlier in this conversation →
crit <plan-file> - Otherwise → bare
crit(branch diff)
Review file format
Comments have three scopes:
- Line comments (
scope: "line") — tied to specific lines, stored infiles.<path>.comments - File comments (
scope: "file") — about a file overall, stored infiles.<path>.commentswithstart_line: 0 - Review comments (
scope: "review") — general feedback, stored in the top-levelreview_commentsarray
The review file path is shown by crit status.
{
"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": "OpenCode" }
]
}
],
"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": "OpenCode" }
]
}
]
}
}
}
Field rules:
resolved:falseor missing — both mean unresolved. Onlytruemeans 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 trustingstart_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 and replying with crit comment
# Review-level (general feedback)
crit comment --author 'OpenCode' '<body>'
# File-level (whole file, no line numbers)
crit comment --author 'OpenCode' <path> '<body>'
# Line (single line or range)
crit comment --author 'OpenCode' <path>:<line> '<body>'
crit comment --author 'OpenCode' <path>:<start>-<end> '<body>'
# Reply to an existing comment
crit comment --reply-to <id> --author 'OpenCode' '<body>'
Hard rules:
- Always pass
--author 'OpenCode'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
--resolvewhen the user explicitly asks. Never resolve proactively.
Bulk commenting with --json
When leaving 3+ comments, use --json for atomicity (single write, no partial state) and speed (one process). The JSON can come from stdin or --file <path>:
# stdin works 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 'OpenCode'
Prefer --file <path> when any body spans multiple paragraphs. A raw newline inside a JSON "body" string is invalid, and shell-quoted heredocs make that easy to introduce by accident. Write the JSON to a temp file, then:
cat > /tmp/crit-bulk.json <<'EOF'
[
{"file": "src/auth.go", "line": 42, "body": "Para 1.\n\nPara 2."}
]
EOF
crit comment --json --file /tmp/crit-bulk.json --author 'OpenCode'
--file - is shorthand for stdin.
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 |
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
If crit comment errors with "comment found in multiple files", IDs collided across files. Disambiguate with --path:
crit comment --reply-to c_a1b2c3 --path src/auth.go --author 'OpenCode' '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.
crit comment --plan my-plan-2026-03-23 --reply-to c_a1b2c3 --author 'OpenCode' 'Updated the plan'
GitHub PR sync
crit pull [pr-number] # Fetch PR review comments into the review file
crit push [--dry-run] [--event <type>] [-m <msg>] [pr] # Post review comments as a GitHub PR review
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.
Guardrails
- Do not continue past the review step until the user confirms they are done.
- Treat the review file as the source of truth for line references and comment status.
- If there are no unresolved comments, tell the user no changes were requested and stop.