diff --git a/.agents/skills/crit-cli/SKILL.md b/.agents/skills/crit-cli/SKILL.md new file mode 100644 index 0000000..c7e2602 --- /dev/null +++ b/.agents/skills/crit-cli/SKILL.md @@ -0,0 +1,207 @@ +--- +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..comments` +- **File comments** (`scope: "file"`) — about a file overall, stored in `files..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 # 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 `: + +```bash +crit comment --session --author : +crit comment --session --json --file comments.json --author +crit comments --session +crit share --session +crit push --session +crit pull --session +``` + +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": "Codex" } + ] + } + ], + "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": "Codex" } + ] + } + ] + } + } +} +``` + +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 'Codex' '' + +# File-level (whole file, no line numbers) +crit comment --author 'Codex' '' + +# Line (single line or range) +crit comment --author 'Codex' : '' +crit comment --author 'Codex' :- '' + +# Reply to an existing comment +crit comment --reply-to --author 'Codex' '' +``` + +Hard rules: +- **Always pass `--author 'Codex'`** 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. + +## 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 `: + +```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 'Codex' +``` + +**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 'Codex' +``` + +`--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 | + +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 'Codex' '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//`. **Always pass `--plan `** — 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 'Codex' '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 ] [-m ] [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...] # Upload and print URL +crit share --share-url # Target a specific Crit deployment +crit share --qr # Also print QR code (terminal only) +crit share --org # Share under an organization +crit share --org --visibility unlisted # Org share with explicit visibility +crit unpublish [file...] # Remove shared review +crit unpublish --share-url [file...] # Unpublish from a specific deployment +``` + +- **Always relay the output** — copy the URL (and QR if used) into your response. Don't make the user 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 `** 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`. diff --git a/.agents/skills/crit-story/SKILL.md b/.agents/skills/crit-story/SKILL.md new file mode 100644 index 0000000..6f84361 --- /dev/null +++ b/.agents/skills/crit-story/SKILL.md @@ -0,0 +1,145 @@ +--- +name: crit-story +description: "Author a crit story and continue the interactive review loop only when the user explicitly invokes $crit-story or directly asks you to generate a crit story. Do not infer this skill from generic review, PR, or diff-review requests." +--- + +# Author a crit story with `crit story` + +This skill authors a story-mode overview, then enters the same interactive +review cycle as `/crit` (wait → address comments → next round). Invoke it +only when the user explicitly asks for story generation; do not infer it from +generic review, PR, or diff-review requests. + +Primary path: author in-session with `--guide` / `--prep` / `--story-file` +(do **not** run bare `crit story`, which spends `agent_cmd` tokens), then run +bare `crit` to listen for Finish Review. + +## Step 1: Fetch the guide + +```bash +crit story --guide +``` + +This prints the resolved authoring guide (the user's customized version if +they have one — always invoke this at runtime rather than reusing this +skill's own prose) followed by `---` and the JSON schema for the fields you +must emit. Read and follow that guide's principles and JSON shape exactly — +it is the source of truth, not this file. + +## Step 2: Write the prep file + +```bash +crit story --prep /tmp/crit-story-prep.txt +``` + +This writes the full, untrimmed diff (commit messages + every hunk with its +`(file_path, old_start)` id) to the given path and prints the path. **Read +that file** — the diff is never inlined into the guide prompt. + +## Step 3: Author the story JSON + +Following the guide from Step 1, cluster hunks by theme (not by file) and +write a JSON object with **only** `prologue`, `chapters`, and `support` to a +temp file, e.g. `/tmp/crit-story.json`. Do not include `version`, +`generated_at`, `agent`, `base_sha`, `head_sha`, `scope_fingerprint`, or +`coverage` — crit fills those in. + +## Step 4: Ingest + +```bash +crit story --story-file /tmp/crit-story.json +``` + +Exit 0 means the story was saved (crit opens the browser to show it). **Then continue to Step 5** — do not stop after ingest. Exit 1 +means it was rejected — the coverage report (missing/duplicated hunks) is +printed to stdout as JSON on every attempt, success or failure. If rejected: + +- `duplicated` non-empty: a hunk is claimed by two chapters (or a chapter and + support). Decide where it belongs and re-ingest. +- `missing` non-empty with `auto_repaired: true` on exit 0: crit already + back-filled the omissions into `support[]`. Optionally re-author to place + them deliberately. +- A drift error ("diff changed since prep"): re-run `crit story --prep` and + re-author from the fresh prep file. + +## Step 5: Reconnect and wait until Finish Review + +**CRITICAL — you MUST run this step after a successful ingest. Do NOT skip it. Do NOT proceed without it.** + +Story ingest opens the review UI and exits — it does **not** wait for the human. Run `crit` and wait until it exits: + +```bash +crit +``` + +`crit` reconnects to the story session's daemon (already started by ingest) and blocks until the user clicks "Finish Review". + +If ingest printed a review URL, relay it verbatim: + +> **"Crit is open at http://localhost:. Leave inline comments on the diff, then click Finish Review."** + +**Do NOT proceed until `crit` completes.** Do NOT ask the user to type anything. Do NOT read the review file early. Wait for the command to finish — that is how you know the human is done reviewing. + +While `crit` is still running, do not send user-facing progress updates. Treat the wait loop as internal state. + +## Step 6: Read the review output + +When `crit` completes, read **stdout** and follow its instructions. Check **stderr** for `approved: true` or `approved: false`. + +If the finish prompt says the review is approved / `"approved": true`, tell the user no changes were requested and stop. + +When a comment has `quote`, `anchor`, or `drifted`: +- `quote`: the specific text the reviewer selected — focus your changes on the quoted text rather than the entire line range +- `anchor`: use it to locate the current position of the content; line numbers may be stale after edits +- `drifted: true`: original content was removed or heavily rewritten — line numbers are approximate at best + +**Fallback** (mid-round re-entry or headless workflows): `crit comments` / `crit comments --json`. + +## Step 7: Address each review comment + +Story mode is an editorial view over the underlying diff. Address comments against the **actual source files**. Do **not** edit, regenerate, or patch the saved story JSON unless the user explicitly asks. + +For each unresolved comment: + +1. Understand what the comment asks for +2. If it contains a suggestion block, apply that specific change +3. Revise the referenced source file +4. Reply with what you did: `crit comment --reply-to --author 'Codex' ''` (reply bodies support markdown) +5. **Do not pass `--resolve`.** Resolving is the reviewer's call. Only add `--resolve` if the user explicitly asks. + + + +Re-emit the revised plan inside `...` so Crit can review the new version. + +### When replying to multiple comments + +Use `--json` for a single bulk call instead of one invocation per comment: + +```bash +echo '[ + {"reply_to": "c_a1b2c3", "body": "Fixed"}, + {"reply_to": "c_d4e5f6", "body": "Refactored as suggested"} +]' | crit comment --json --author 'Codex' +``` + +## Step 8: Signal completion and start next round + +**CRITICAL — you MUST run this step. Do NOT skip it. Do NOT proceed without it.** + +The finish prompt on stdout includes the command to run again — use it to start a new round. + +On subsequent calls, `crit` automatically signals round-complete first, then blocks until the next "Finish Review" click. + +Tell the user: **"Changes applied. Review the diff in your browser and click Finish Review when ready."** + +**Do NOT proceed until the background `crit` task completes.** When it does, return to Step 6. If the user finishes with zero comments, the review is approved — stop the loop and proceed. + +## What this skill does NOT do + +- It does not produce agent-authored review comments during story authoring — + humans leave comments in the browser after ingest. +- It does not edit or regenerate the saved story JSON during the review loop + unless the user explicitly asks. +- It does not run bare `crit story` (LLM via `agent_cmd`) unless the user + explicitly asks for that path. +- It does not call `crit push` or `crit share` unless the user asks to share. diff --git a/.agents/skills/crit/SKILL.md b/.agents/skills/crit/SKILL.md new file mode 100644 index 0000000..8a22339 --- /dev/null +++ b/.agents/skills/crit/SKILL.md @@ -0,0 +1,136 @@ +--- +name: crit +description: "Review code changes, a plan, a live page (running dev server), or a local HTML file with Crit inline comments and structured human feedback. Use only when the user explicitly invokes /crit or directly asks to use Crit; a generic review request does not count." +--- + +# Review with Crit + +This is the interactive, human-in-the-browser review cycle. Run it only after +the user explicitly invokes `/crit` or directly asks to use Crit. A generic +request to review code, a plan, a diff, a PR, or a page does not count. + +Review and revise code changes, plans, live pages (running dev servers, staging URLs), or local HTML files using `crit` for inline comment review. + +## Step 1: Pass arguments to `crit` + +The CLI auto-detects the review mode from its arguments. **Do not ask the user which mode to use.** Pass arguments through: + +``` +crit # file, dir, URL, .html — CLI auto-detects mode +crit --pr # GitHub PR (range mode) +crit --mr # GitLab MR (range mode) +crit --range .. # commit range (range mode) +crit # no args → branch diff +``` +If no arguments, check conversation context: + +1. A plan file was written earlier in this conversation → `crit ` +2. Otherwise → bare `crit` (branch diff) + + +Keep crit on loopback and reverse-proxy in. Same Step 1 args still apply (file, bare `crit`, etc.): + +```bash +crit --public-url "https://.ts.net" --allow-unauthenticated-network --no-open [args…] +# then: tailscale serve --bg --https=443 http://127.0.0.1: +``` + +- `--public-url` only changes the URL crit prints — it does **not** expose the server. +- `--allow-unauthenticated-network` is required with `--public-url` (even on loopback) and with any non-loopback `--host`. Crit has no auth: anyone who can reach the URL can read the repo and post comments that may trigger agents. Confirm the user wants that blast radius. +- **Do not bind `--host` to a Tailscale/LAN IP** — proxy with `tailscale serve` (or an SSH tunnel). Get `` from crit's startup output, or fix it with `-p`. Relay the URL crit prints (the public one), not localhost. + + +## Step 2: Launch crit and wait for review completion + +**CRITICAL — you MUST run this step. Do NOT skip it. Do NOT proceed without it.** + +Run `crit` and wait until it exits: + +```bash +crit # specific file +crit # git mode +``` + +If a crit server is already running from earlier in this conversation, `crit` automatically connects to it. Starting from scratch, it spawns the daemon, opens the browser, and blocks until the user clicks "Finish Review". + +`crit` prints the review URL on startup (e.g. `Started crit daemon at http://localhost:`). Relay it verbatim: + +> **"Crit is open at http://localhost:. Leave inline comments, then click Finish Review."** + +**Do NOT proceed until `crit` completes.** Do NOT ask the user to type anything. Do NOT read the review file early. Wait for the command to finish — that is how you know the human is done reviewing. + +While `crit` is still running, do not send user-facing progress updates. Treat the wait loop as internal state. + +## Step 3: Read the review output + +When `crit` completes, read **stdout** and follow its instructions. Check **stderr** for `approved: true` or `approved: false`. + +When a comment has `quote`, `anchor`, or `drifted`: +- `quote`: the specific text the reviewer selected — focus your changes on the quoted text rather than the entire line range +- `anchor`: use it to locate the current position of the content; line numbers may be stale after edits +- `drifted: true`: original content was removed or heavily rewritten — line numbers are approximate at best + +**Fallback** (mid-round re-entry, plan hooks, or headless workflows): `crit comments` / `crit comments --json`. Use `crit comments --plan ` for plan-mode reviews. + +## Step 4: Address each review comment + +For each unresolved comment: + +1. Understand what the comment asks for +2. If it contains a suggestion block, apply that specific change +3. Revise the referenced file (plan or code file from the diff) +4. Reply with what you did: `crit comment --reply-to --author 'Codex' ''` (reply bodies support markdown) +5. **Do not pass `--resolve`.** Resolving is the reviewer's call. Only add `--resolve` if the user explicitly asks. + +Editing the plan file triggers Crit's live reload — the user sees changes in the browser immediately. + + +Re-emit the revised plan inside `...` so Crit can review the new version. + + +### When replying to multiple comments + +Use `--json` for a single bulk call instead of one invocation per comment: + +```bash +echo '[ + {"reply_to": "c_a1b2c3", "body": "Fixed"}, + {"reply_to": "c_d4e5f6", "body": "Refactored as suggested"} +]' | crit comment --json --author 'Codex' +``` + +## Step 5: Signal completion and start next round + +**CRITICAL — you MUST run this step. Do NOT skip it. Do NOT proceed without it.** + +The finish prompt on stdout includes the command to run again — use it to start a new round. + +On subsequent calls, `crit` automatically signals round-complete first, then blocks until the next "Finish Review" click. + +Tell the user: **"Changes applied. Review the diff in your browser and click Finish Review when ready."** + +**Do NOT proceed until the background `crit` task completes.** When it does, return to Step 3. If the user finishes with zero comments, the review is approved — stop the loop and proceed. + +## Sharing + +If the user asks for a URL, a shareable link, or to share the review: + +```bash +crit share +``` + +**Always relay the full output to the user** — copy the URL directly into your response. Don't make them dig through tool output. + +To remove a shared review: + +```bash +crit unpublish [file...] +``` + +### QR codes + +Only use `--qr` in real terminal environments with monospace rendering. Skip it in mobile apps or web chat UIs — Unicode block characters won't render. + +```bash +crit share --qr +```