evals/activation-cases.md
# activation-cases.md — cursor-cli
Natural-language behavioral cases for routing **into** `cursor-cli` and **away**
toward its interop siblings (`codex-cli`, `claude-code-cli`) and the kit's own
review skills. Routes are the `use_case` ids in
[`references/use-case-registry.csv`](../references/use-case-registry.csv).
## Positive
- "Ask Cursor to review the changes I just made." → `review-working-tree`
- "Get a second opinion from Cursor on this branch before I open the PR." → `review-branch`
- "Have gpt-5 review this design via Cursor." → `second-opinion`
- "Prepare the Cursor prompt to review my staged changes, but don't run it." → `prompt-prep`
- "Cursor agent keeps failing — check my setup and auth." → `diagnose`
## Negative
These must **not** route to `cursor-cli`:
- "Refactor this React component." — ordinary coding work, no external reviewer.
- "Ask **Codex** to review my changes." → `codex-cli` (different external agent).
- "Ask **Claude Code** to review my changes." → `claude-code-cli`.
- "Audit our CLI's developer experience and score it." → `dx-audit` (this kit's own heuristic review).
- "Harden this repo's AGENTS.md and hooks." → `harden-repo-for-coding-agents`.
## Edge
- "Review my changes." — ambiguous: bare review intent with no Cursor / second-opinion / different-model signal. Prefer a local review skill; only route here if the user names Cursor or asks for an external/second opinion.
- "Get a second opinion on this code from gpt-5." → `second-opinion` — "a second opinion from gpt-5/a different model" is cursor-cli's territory (model diversity) even when Cursor is not named, since cursor-agent is the kit's multi-model interop path.
## Bare-activation behavior
Prompt: `/cursor-cli`
Expected:
- Presents a concise menu of modes and use cases from the registry, then waits.
- Does **not** run `cursor-agent`.
- Asks what scope/model the user wants (one question, not a multi-question form).
## Main scenario — review working-tree changes
Prompt: `Ask Cursor to review the changes I just made.`
Expected:
- Selects `review-working-tree`; runs `scripts/cursor-review-changes.sh` from the repo under review.
- Builds the git diff itself and feeds it to `cursor-agent -p --mode plan --output-format text` (read-only — cursor-agent won't edit).
- Presents cursor-agent's output as external review feedback and verifies obvious file references before relaying them.
Forbidden:
- Passing `-f` / `--force` / `--yolo` or `--sandbox disabled`.
- Bare `-p` without `--mode plan`/`ask` (print mode can write and run shell).
- Treating cursor-agent's output as unquestionable truth.
## Different-model second opinion
Prompt: `Have gpt-5 review this migration plan via Cursor.`
Expected:
- Selects `second-opinion`; runs `scripts/cursor-ask.sh --model gpt-5` (read-only `--mode plan`).
- Frames the result as a second opinion from a *different* model than the one that produced the work.
## Diagnose / trust scenario
Prompt: `cursor-agent isn't running headlessly — what's wrong?`
Expected:
- Selects `diagnose`; uses `scripts/cursor-doctor-check.sh`.
- Surfaces likely blockers: not installed/authenticated, **workspace not trusted** for `-p` runs, or model unavailable.
evals/run-static-checks.sh
#!/usr/bin/env bash
set -euo pipefail
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$script_dir/../../../scripts/static-check-lib.sh"
repo_root="$(repo_root_from "$script_dir")"
skill_dir="${1:-$(cd "$script_dir/.." && pwd)}"
skill_md="$skill_dir/SKILL.md"
skill_json="$skill_dir/skill.json"
trigger_evals="$skill_dir/evals/trigger-evals.json"
activation_cases="$skill_dir/evals/activation-cases.md"
registry="$skill_dir/references/use-case-registry.csv"
failures=0
fail() { printf 'FAIL %s\n' "$1" >&2; failures=$((failures + 1)); }
check_file() { [[ -f "$1" ]] || fail "missing file: ${1#"$skill_dir"/}"; }
# ----- Required artifacts (repo contract) -----
check_file "$skill_md"
check_file "$skill_json"
check_file "$trigger_evals"
check_file "$activation_cases"
# ----- Skill-specific surfaces: registry, playbooks, scripts, templates -----
check_file "$registry"
for ref in cli-contract.md review-changes-playbook.md delegation-playbook.md output-rubric.md; do
check_file "$skill_dir/references/$ref"
done
for s in cursor-review-changes.sh cursor-ask.sh cursor-doctor-check.sh; do
check_file "$skill_dir/scripts/$s"
[[ -x "$skill_dir/scripts/$s" ]] || fail "script not executable: scripts/$s"
done
for t in review-prompt.md delegation-prompt.md; do
check_file "$skill_dir/templates/$t"
done
# ----- SKILL.md frontmatter + word-count gate -----
if [[ -f "$skill_md" ]]; then
head -1 "$skill_md" | grep -q '^---$' || fail "SKILL.md missing YAML frontmatter delimiter (---)"
grep -Eq '^name: cursor-cli$' "$skill_md" || fail "SKILL.md frontmatter must include: name: cursor-cli"
grep -Eq '^description:' "$skill_md" || fail "SKILL.md frontmatter must include: description:"
grep -Eq '^license:' "$skill_md" || fail "SKILL.md frontmatter must include: license:"
wc=$(wc -w < "$skill_md")
(( wc < 1200 )) || fail "SKILL.md word count $wc exceeds 1200 (runtime-only bound)"
fi
# ----- Every registry script/detail/template path resolves on disk -----
while IFS= read -r missing; do
[[ -n "$missing" ]] && fail "use-case-registry.csv points at missing path: $missing"
done < <(python3 - "$skill_dir" "$registry" <<'PYEOF'
import csv, os, sys
skill, reg = sys.argv[1], sys.argv[2]
with open(reg, newline="") as fh:
for row in csv.DictReader(fh):
for col in ("detail_files", "artifact_templates", "script"):
for tok in (row.get(col) or "").split(";"):
tok = tok.strip()
if tok and not os.path.exists(os.path.join(skill, tok)):
print(tok)
PYEOF
)
# ----- Safety defaults: scripts must keep the read-only guard. cursor-agent -p
# defaults to full tool access, so the wrappers must default to --mode plan
# and must not hardcode --force / --yolo / --sandbox disabled. -----
if grep -rqE '\-\-force|\-\-yolo|\-\-sandbox[[:space:]]+disabled' "$skill_dir/scripts"; then
fail "scripts must not hardcode a Cursor read-only bypass (--force / --yolo / --sandbox disabled)"
fi
grep -q 'CURSOR_CLI_MODE:-plan' "$skill_dir/scripts/cursor-review-changes.sh" \
|| fail "cursor-review-changes.sh must default --mode to plan (read-only)"
# ----- Scripts are hermetic in --dry-run (no cursor-agent binary, no network) -----
run_dry() {
local label="$1"; shift
"$@" >/dev/null 2>&1 || fail "$label: --dry-run did not exit cleanly"
}
run_dry "cursor-ask.sh" bash "$skill_dir/scripts/cursor-ask.sh" --dry-run "Review the API boundary in this repository."
run_dry "cursor-doctor-check.sh" bash "$skill_dir/scripts/cursor-doctor-check.sh" --dry-run
# Review-changes needs a git repo; guard so the gate still passes outside one.
if git -C "$skill_dir" rev-parse --show-toplevel >/dev/null 2>&1; then
review_out="$(bash "$skill_dir/scripts/cursor-review-changes.sh" --dry-run 2>&1 || true)"
grep -q 'cursor-agent -p --mode plan' <<<"$review_out" \
|| fail "cursor-review-changes.sh --dry-run must build a read-only 'cursor-agent -p --mode plan' command"
else
echo "note: skipping cursor-review-changes.sh --dry-run (not inside a git repo)"
fi
# ----- Shared JSON contracts (schema + name match) -----
validate_skill_json_contract "$repo_root" "$skill_json" "cursor-cli"
validate_trigger_evals_contract "$repo_root" "$trigger_evals" "cursor-cli"
if (( failures > 0 )); then
exit 1
fi
echo "cursor-cli static eval passed."
evals/trigger-evals.json
{
"skill": "cursor-cli",
"version": "0.1.0",
"queries": [
{"query": "Ask Cursor to review the changes I just made to my working tree.", "should_activate": true, "expected_route": "review-working-tree", "category": "positive"},
{"query": "Get a second opinion from Cursor on this branch before I open the PR.", "should_activate": true, "expected_route": "review-branch", "category": "positive"},
{"query": "Have gpt-5 review this caching design via Cursor.", "should_activate": true, "expected_route": "second-opinion", "category": "positive"},
{"query": "Review my staged changes with a different model through Cursor.", "should_activate": true, "expected_route": "review-working-tree", "category": "positive"},
{"query": "Prepare the Cursor prompt to review my changes, but don't run it.", "should_activate": true, "expected_route": "prompt-prep", "category": "positive"},
{"query": "Cursor agent keeps failing — check my cursor-agent setup and auth.", "should_activate": true, "expected_route": "diagnose", "category": "positive"},
{"query": "Refactor this React component to use hooks.", "should_activate": false, "expected_route": null, "category": "negative"},
{"query": "Ask Codex to review my changes.", "should_activate": false, "expected_route": null, "category": "negative"},
{"query": "Ask Claude Code to review my changes.", "should_activate": false, "expected_route": null, "category": "negative"},
{"query": "Audit our CLI's developer experience and score the friction.", "should_activate": false, "expected_route": null, "category": "negative"},
{"query": "Review my changes.", "should_activate": false, "expected_route": null, "category": "edge"},
{"query": "Get a second opinion on this code from gpt-5.", "should_activate": true, "expected_route": "second-opinion", "category": "edge"}
]
}
references/cli-contract.md
# Cursor CLI Contract
This skill is grounded in the local Cursor CLI (`cursor-agent`) shape:
```bash
cursor-agent -p --mode plan --output-format text
```
`cursor-agent -p` runs non-interactively and prints a response. **By default `-p`
has access to all tools, including write and shell** — so a read-only delegation
MUST pass `--mode plan` (read-only/planning) or `--mode ask` (read-only Q&A). The
wrappers default to `--mode plan`.
## Safe Default Flags
- `-p` / `--print`: non-interactive output for agent-to-agent delegation.
- `--mode plan`: read-only/planning stance — analyze and propose, no edits. The
review/second-opinion default. `--mode ask` is the read-only Q&A stance.
- `--output-format text`: plain output another agent can summarize (also `json`,
`stream-json`).
- If any flag here errors, trust `cursor-agent --help` over this file — the
vendor surface moves; update this contract when it drifts.
- `--model <model>`: optional; cursor-agent can run many providers' models (e.g.
`gpt-5`, `sonnet-4`, `sonnet-4-thinking`). `cursor-agent --list-models` lists
what your account can use. This is the main reason to reach for cursor-cli over
codex-cli / claude-code-cli: a second opinion from a *different* model.
- `--api-key <key>` / `CURSOR_API_KEY`: authentication.
Because `cursor-agent` has no native diff-review subcommand, the wrapper
`scripts/cursor-review-changes.sh` assembles the git diff itself and feeds it as
prompt context — the same approach as claude-code-cli.
## Unsafe or High-Friction Flags
Avoid these unless the user explicitly asks:
- `-f` / `--force` / `--yolo` (force-allow all commands — drops the read-only guard).
- `--sandbox disabled`.
- Any `--mode` other than `plan` / `ask` for a review (those are the read-only
modes; bare print mode can write and run shell).
- Editing-oriented prompts that ask cursor-agent to modify files directly.
## Workspace Trust
`cursor-agent` requires the working directory to be **trusted** before a
non-interactive (`-p`) run; an untrusted repo raises a "Workspace Trust Required"
prompt that blocks headless execution. Establish trust once by running
`cursor-agent` interactively in the repo (or via your Cursor config); then the
`-p` wrappers work. `scripts/cursor-doctor-check.sh` surfaces version/auth health.
## Auth and Environment Failure Modes
If invocation fails, report the blocker directly:
- `cursor-agent` is not installed or not on `PATH` (install: https://cursor.com/cli).
- Not authenticated (`CURSOR_API_KEY` unset / not logged in).
- The working directory is not trusted for non-interactive execution.
- The selected model is unavailable for the account (`cursor-agent --list-models`).
Do not silently fall back to another model provider or a different memory surface.
## Data Boundary
Before invoking cursor-agent, scan for likely secrets or sensitive local files in
the intended diff or prompt. If risk is unclear, ask for scope or use `--dry-run`
and let the user review the prompt first. Do not pass raw agent transcripts, auth
files, or large private logs unless the user explicitly approved that material.
references/delegation-playbook.md
# Delegation Playbook
Use this playbook for second opinions, plan review, bug analysis, architecture
questions, or prompt preparation with `cursor-agent -p --mode plan`.
## Delegation Frame
A good cursor-agent prompt includes: the precise question, the repository or file
scope, constraints and non-goals, the read-only stance, the desired output
format, and any known uncertainty or suspected failure mode. Don't ask
cursor-agent to "look at everything" when a narrower question would work.
## Prompt Roles
Choose one role per invocation: **Reviewer** (find defects), **Skeptic** (attack
assumptions), **Architect** (evaluate boundaries and change cost), **Debugger**
(most likely causes + verification steps), or **Rubric judge** (score against
explicit criteria).
## Picking a model
Model diversity is the value: run the question past a *different* model than
the agent that produced the work — see the `--model` bullet in `cli-contract.md`.
## Prompt Preparation Mode
When the user asks for a prompt only: build the prompt with clear scope and output
rules, include the exact command to run, do not invoke cursor-agent, and mention
any data/secret risks to review first. `--dry-run` on either script prints the
prompt and command without calling cursor-agent.
## Disagreement Handling
When cursor-agent's answer conflicts with the calling agent's analysis: quote the
concrete claim, verify it against files/tests/docs, preserve uncertainty instead
of forcing consensus, and ask a narrower follow-up only if it will change the next
action.
references/output-rubric.md
# Output Rubric
Use this rubric to judge cursor-agent output before relaying it.
## Review Quality
Strong review output: leads with actionable findings; gives concrete file/line
references; distinguishes confirmed defects from speculation; explains impact
without exaggeration; includes targeted verification or test advice; says "no
findings" clearly when appropriate.
Weak review output: summarizes the change instead of reviewing it; gives generic
style advice; invents behavior not present in the diff; treats missing tests as a
finding without real risk; recommends broad rewrites without a concrete defect.
## Severity Calibration
- `critical`: data loss, credential exposure, remote code execution, or a
production-stopping regression.
- `high`: likely user-visible breakage, security boundary failure, broken
release/build path, or irreversible state corruption.
- `medium`: plausible bug or operational risk that should be fixed before merge.
- `low`: minor correctness, maintainability, or test gap worth noting but not
blocking.
## Calling-Agent Checks
Before presenting results: verify file references exist; check the finding is
about changed behavior; drop duplicate findings; separate "must fix" from
"consider"; note any tests or commands that were not run. cursor-agent may have
run under a different model than the code's author — treat its output as an
independent second opinion, not authority.
references/review-changes-playbook.md
# Review Changes Playbook
Use this playbook when cursor-agent is asked to review code written by Claude,
Codex, Cursor, or another agent. For a bare "review my changes with Cursor"
request, go straight to the run and default to the `all` working-tree scope.
## Reading scope from the request
Run `scripts/cursor-review-changes.sh` with the matching `--scope`:
- "my changes" / "working tree" / no argument → `all` (staged + unstaged + untracked)
- "staged" → `staged`
- "unstaged" → `unstaged`
- "vs main" / "this PR" / "the branch" / "since `<branch>`" → `branch` (`--base <ref>`)
The wrapper builds the git diff and feeds it to `cursor-agent -p --mode plan`
(read-only). cursor-agent has no native review subcommand, so the diff is
assembled locally and passed as prompt context.
## Picking a model
Review with a *different* model than the one that wrote the code — see the
`--model` bullet in `cli-contract.md`.
## Review Standard
Tell cursor-agent to prioritize:
1. Correctness bugs and behavioral regressions.
2. Security, privacy, data loss, auth, and permission risks.
3. Broken build, test, or release behavior.
4. Missing tests only where changed behavior makes risk real.
5. Maintainability issues only when they are likely to cause defects.
Style preferences and formatting nits are out of scope unless they hide a bug.
## Output Shape
Require findings first, ordered by severity, each with: severity
(`critical`/`high`/`medium`/`low`), file/line when possible, a concise issue
statement, why it matters, and a suggested fix or verification step. If there are
no findings, say so directly and list residual risk or tests not run.
## Reporting to the user
cursor-agent streams its own output. Don't dump it raw — summarize: lead with the
verdict and a severity count, list each finding as `severity · file:line ·
description`, frame it as a second opinion from another model, and offer to act.
Do not apply fixes unless the user asks — this path reviews, it does not edit.
## Reconciliation
cursor-agent's review is evidence, not authority. Verify any claimed file/line
against the repository, discard findings that contradict the actual code, run
targeted tests when feasible, and tell the user which suggestions were accepted,
rejected, or deferred. Prefer local evidence on disagreement.
references/use-case-registry.csv
use_case,name,when_to_use,detail_files,artifact_templates,script,risk_level
review-working-tree,Review Working Tree,"Another agent changed files and the user wants cursor-agent to review uncommitted work","references/cli-contract.md;references/review-changes-playbook.md;references/output-rubric.md","templates/review-prompt.md;templates/review-report.md",scripts/cursor-review-changes.sh,medium
review-branch,Review Branch Diff,"The user wants cursor-agent to review committed branch changes against a base ref","references/cli-contract.md;references/review-changes-playbook.md;references/output-rubric.md","templates/review-prompt.md;templates/review-report.md",scripts/cursor-review-changes.sh,medium
second-opinion,Second Opinion,"The user wants cursor-agent to analyze a decision, bug, plan, or architecture, optionally under a different model such as gpt-5 or sonnet-4","references/cli-contract.md;references/delegation-playbook.md;references/output-rubric.md","templates/delegation-prompt.md",scripts/cursor-ask.sh,medium
prompt-prep,Prepare Prompt Only,"The user wants a safe cursor-agent prompt or command without invoking the CLI yet","references/cli-contract.md;references/delegation-playbook.md","templates/review-prompt.md;templates/delegation-prompt.md",scripts/cursor-review-changes.sh,low
diagnose,Diagnose Cursor Setup,"cursor-agent auth, workspace trust, model availability, or runtime health is unclear","references/cli-contract.md","",scripts/cursor-doctor-check.sh,low
scripts/cursor-ask.sh
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat >&2 <<'USAGE'
Usage:
cursor-ask.sh [options] [prompt]
Options:
--context-file <file> Include a context file (repeatable)
--template <file> Prompt template relative to skill dir or cwd
--cwd <dir> Run cursor-agent from this directory
--model <model> Cursor model (e.g. gpt-5, sonnet-4, sonnet-4-thinking)
--mode <plan|ask> Read-only execution mode (default: plan)
--output <file> Write Cursor output to a file as well
--dry-run Print the prompt; do not invoke cursor-agent
-h, --help Show help
Examples:
cursor-ask.sh "Review this migration plan for risks."
printf '%s\n' "Find flaws in this architecture." | cursor-ask.sh --model gpt-5
USAGE
}
model="${CURSOR_CLI_MODEL:-}"
mode="${CURSOR_CLI_MODE:-plan}"
output_file=""
dry_run=0
run_cwd=""
template_arg="templates/delegation-prompt.md"
context_files=()
prompt_parts=()
while [[ $# -gt 0 ]]; do
case "$1" in
--context-file)
context_files+=("${2:-}")
shift 2
;;
--template)
template_arg="${2:-}"
shift 2
;;
--cwd)
run_cwd="${2:-}"
shift 2
;;
--model)
model="${2:-}"
shift 2
;;
--mode)
mode="${2:-}"
shift 2
;;
--output)
output_file="${2:-}"
shift 2
;;
--dry-run)
dry_run=1
shift
;;
-h|--help)
usage
exit 0
;;
--)
shift
prompt_parts+=("$@")
break
;;
*)
prompt_parts+=("$1")
shift
;;
esac
done
# `cursor-agent -p` defaults to full tool access (write + shell); plan/ask are the
# read-only modes. Refuse anything else so a delegated review stays read-only.
case "$mode" in
plan|ask) ;;
*)
echo "Invalid --mode: $mode (use plan or ask for read-only delegation)" >&2
exit 1
;;
esac
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
skill_dir="$(cd "$script_dir/.." && pwd)"
template="$template_arg"
if [[ "$template" != /* ]]; then
if [[ -f "$template" ]]; then
template="$(cd "$(dirname "$template")" && pwd)/$(basename "$template")"
else
template="$skill_dir/$template"
fi
fi
if [[ ! -f "$template" ]]; then
echo "Prompt template not found: $template_arg" >&2
exit 1
fi
if [[ -n "$run_cwd" && ! -d "$run_cwd" ]]; then
echo "Working directory not found: $run_cwd" >&2
exit 1
fi
prompt_file="$(mktemp)"
context_file="$(mktemp)"
trap 'rm -f "$prompt_file" "$context_file"' EXIT
if (( ${#prompt_parts[@]} > 0 )); then
task="${prompt_parts[*]}"
else
task="$(cat)"
fi
if [[ -z "${task//[[:space:]]/}" ]]; then
echo "Prompt is required via arguments or stdin." >&2
usage
exit 1
fi
{
if (( ${#context_files[@]} == 0 )); then
printf 'No additional context files provided.\n'
else
for file in "${context_files[@]}"; do
if [[ ! -f "$file" ]]; then
printf '\n## %s\n\nMissing context file.\n' "$file"
continue
fi
printf '\n## %s\n\n' "$file"
sed -n '1,240p' "$file"
bytes="$(wc -c < "$file" | tr -d ' ')"
if (( bytes > 20000 )); then
printf '\n[TRUNCATED: displayed first 240 lines of %s byte file.]\n' "$bytes"
fi
done
fi
} > "$context_file"
while IFS= read -r line || [[ -n "$line" ]]; do
case "$line" in
"{{TASK}}")
printf '%s\n' "$task"
;;
*"{{TASK}}"*)
printf '%s\n' "${line//\{\{TASK\}\}/$task}"
;;
"{{CONTEXT}}")
cat "$context_file"
;;
*"{{CONTEXT}}"*)
printf '%s\n' "${line//\{\{CONTEXT\}\}/$(cat "$context_file")}"
;;
*)
printf '%s\n' "$line"
;;
esac
done < "$template" > "$prompt_file"
if (( dry_run == 1 )); then
if [[ -n "$run_cwd" ]]; then
printf 'Working directory: %s\n\n' "$run_cwd"
fi
printf 'Command: cursor-agent -p --mode %q --output-format text%s < prompt\n\n' \
"$mode" "${model:+ --model $model}"
cat "$prompt_file"
exit 0
fi
if ! command -v cursor-agent >/dev/null 2>&1; then
echo "Cursor CLI (cursor-agent) not found on PATH. Install it (https://cursor.com/cli) and authenticate, then retry." >&2
exit 1
fi
cmd=(cursor-agent -p --mode "$mode" --output-format text)
[[ -n "$model" ]] && cmd+=(--model "$model")
run_cursor() {
if [[ -n "$run_cwd" ]]; then
(cd "$run_cwd" && "${cmd[@]}" < "$prompt_file")
else
"${cmd[@]}" < "$prompt_file"
fi
}
if [[ -n "$output_file" ]]; then
mkdir -p "$(dirname "$output_file")"
run_cursor | tee "$output_file"
else
run_cursor
fi
scripts/cursor-doctor-check.sh
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat >&2 <<'USAGE'
Usage:
cursor-doctor-check.sh [options]
Options:
--models Also list available models (requires auth)
--dry-run Print the command; do not invoke cursor-agent
-h, --help Show help
Notes:
cursor-agent has no `doctor` subcommand. This runs `cursor-agent --version`
(and optionally --list-models) as a health probe. cursor-agent also requires
the working directory to be trusted before non-interactive (`-p`) runs; if a
review errors with a workspace-trust prompt, trust the repo once interactively.
USAGE
}
models=0
dry_run=0
while [[ $# -gt 0 ]]; do
case "$1" in
--models) models=1; shift ;;
--dry-run) dry_run=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown option: $1" >&2; usage; exit 1 ;;
esac
done
if (( models == 1 )); then
cmd=(cursor-agent --list-models)
else
cmd=(cursor-agent --version)
fi
if (( dry_run == 1 )); then
printf 'Command:'; printf ' %q' "${cmd[@]}"; printf '\n'
exit 0
fi
if ! command -v cursor-agent >/dev/null 2>&1; then
echo "Cursor CLI (cursor-agent) not found on PATH. Install it (https://cursor.com/cli) and authenticate, then retry." >&2
exit 1
fi
"${cmd[@]}"
scripts/cursor-review-changes.sh
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat >&2 <<'USAGE'
Usage:
cursor-review-changes.sh [options]
Options:
--scope <all|staged|unstaged|branch> Diff scope to review (default: all)
--base <ref> Base ref for --scope branch
--extra <text> Extra review instructions
--model <model> Cursor model (e.g. gpt-5, sonnet-4)
--mode <plan|ask> Read-only execution mode (default: plan)
--max-diff-bytes <bytes> Prompt diff byte limit (default: 200000)
--output <file> Write Cursor output to a file as well
--dry-run Print the prompt; do not invoke cursor-agent
-h, --help Show help
Examples:
cursor-review-changes.sh
cursor-review-changes.sh --scope staged --model gpt-5
cursor-review-changes.sh --scope branch --base main --dry-run
USAGE
}
scope="all"
base_ref=""
extra=""
model="${CURSOR_CLI_MODEL:-}"
mode="${CURSOR_CLI_MODE:-plan}"
max_diff_bytes="${CURSOR_CLI_MAX_DIFF_BYTES:-200000}"
output_file=""
dry_run=0
while [[ $# -gt 0 ]]; do
case "$1" in
--scope)
scope="${2:-}"
shift 2
;;
--base)
base_ref="${2:-}"
shift 2
;;
--extra)
extra="${2:-}"
shift 2
;;
--model)
model="${2:-}"
shift 2
;;
--mode)
mode="${2:-}"
shift 2
;;
--max-diff-bytes)
max_diff_bytes="${2:-}"
shift 2
;;
--output)
output_file="${2:-}"
shift 2
;;
--dry-run)
dry_run=1
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown option: $1" >&2
usage
exit 1
;;
esac
done
case "$scope" in
all|staged|unstaged|branch) ;;
*)
echo "Invalid --scope: $scope" >&2
exit 1
;;
esac
# `cursor-agent -p` defaults to full tool access; plan/ask keep it read-only.
case "$mode" in
plan|ask) ;;
*)
echo "Invalid --mode: $mode (use plan or ask for read-only review)" >&2
exit 1
;;
esac
if ! [[ "$max_diff_bytes" =~ ^[0-9]+$ ]]; then
echo "--max-diff-bytes must be an integer" >&2
exit 1
fi
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
skill_dir="$(cd "$script_dir/.." && pwd)"
template="$skill_dir/templates/review-prompt.md"
repo_root="$(git rev-parse --show-toplevel 2>/dev/null || true)"
if [[ -z "$repo_root" ]]; then
echo "Must be run inside a git repository." >&2
exit 1
fi
cd "$repo_root"
prompt_file="$(mktemp)"
diff_file="$(mktemp)"
truncated_file="$(mktemp)"
trap 'rm -f "$prompt_file" "$diff_file" "$truncated_file"' EXIT
append_section() {
local title="$1"
shift
{
printf '\n## %s\n\n' "$title"
"$@" || true
} >> "$diff_file"
}
append_untracked_files() {
local file size
local per_file_limit=40000
printf '\n## Untracked files\n\n' >> "$diff_file"
git ls-files --others --exclude-standard >> "$diff_file" || true
while IFS= read -r -d '' file; do
[[ -f "$file" ]] || continue
size="$(wc -c < "$file" | tr -d ' ')"
if (( size > per_file_limit )); then
printf '\n### %s\n\nSkipped: untracked file is %s bytes, over %s byte per-file limit.\n' \
"$file" "$size" "$per_file_limit" >> "$diff_file"
continue
fi
if (( size > 0 )) && ! LC_ALL=C grep -Iq . "$file"; then
printf '\n### %s\n\nSkipped: binary-looking untracked file.\n' "$file" >> "$diff_file"
continue
fi
printf '\n### %s\n\n' "$file" >> "$diff_file"
git diff --no-index -- /dev/null "$file" >> "$diff_file" 2>/dev/null || true
done < <(git ls-files --others --exclude-standard -z)
}
resolve_branch_base() {
if [[ -n "$base_ref" ]]; then
git rev-parse --verify --quiet "${base_ref}^{commit}" >/dev/null \
|| { echo "Base ref not found: $base_ref. Pass a valid --base <ref>." >&2; exit 1; }
printf '%s\n' "$base_ref"
return
fi
local upstream
upstream="$(git rev-parse --abbrev-ref --symbolic-full-name '@{upstream}' 2>/dev/null || true)"
if [[ -n "$upstream" ]]; then
git merge-base HEAD "$upstream"
return
fi
if git rev-parse --verify main >/dev/null 2>&1; then
printf 'main\n'
return
fi
if git rev-parse --verify master >/dev/null 2>&1; then
printf 'master\n'
return
fi
echo "Could not infer branch base. Pass --base <ref>." >&2
exit 1
}
{
printf '# Review Context\n\n'
printf 'Repository: %s\n' "$repo_root"
printf 'Scope: %s\n' "$scope"
} > "$diff_file"
append_section "Git status" git status --short
case "$scope" in
all)
append_section "Staged diff stat" git diff --cached --stat
append_section "Staged diff" git diff --cached --no-ext-diff --find-renames
append_section "Unstaged diff stat" git diff --stat
append_section "Unstaged diff" git diff --no-ext-diff --find-renames
append_untracked_files
;;
staged)
append_section "Staged diff stat" git diff --cached --stat
append_section "Staged diff" git diff --cached --no-ext-diff --find-renames
;;
unstaged)
append_section "Unstaged diff stat" git diff --stat
append_section "Unstaged diff" git diff --no-ext-diff --find-renames
append_untracked_files
;;
branch)
base_ref="$(resolve_branch_base)"
append_section "Branch base" printf '%s\n' "$base_ref"
append_section "Branch diff stat" git diff --stat "$base_ref"...HEAD
append_section "Branch diff" git diff --no-ext-diff --find-renames "$base_ref"...HEAD
;;
esac
diff_size="$(wc -c < "$diff_file" | tr -d ' ')"
if (( diff_size > max_diff_bytes )); then
head -c "$max_diff_bytes" "$diff_file" > "$truncated_file"
{
cat "$truncated_file"
printf '\n\n[TRUNCATED: original change context was %s bytes; limit was %s bytes. Ask for a narrower scope if needed.]\n' \
"$diff_size" "$max_diff_bytes"
} > "$diff_file"
fi
replace_template() {
local line
while IFS= read -r line || [[ -n "$line" ]]; do
case "$line" in
*"{{SCOPE}}"*)
printf '%s\n' "${line//\{\{SCOPE\}\}/$scope}"
;;
"{{EXTRA_INSTRUCTIONS}}")
printf '%s\n' "${extra:-None}"
;;
*"{{EXTRA_INSTRUCTIONS}}"*)
printf '%s\n' "${line//\{\{EXTRA_INSTRUCTIONS\}\}/${extra:-None}}"
;;
*)
printf '%s\n' "$line"
;;
esac
done < "$template"
}
{
replace_template
printf '\n\n# Change Context\n\n'
cat "$diff_file"
} > "$prompt_file"
if (( dry_run == 1 )); then
printf 'Command: cursor-agent -p --mode %q --output-format text%s < prompt\n\n' \
"$mode" "${model:+ --model $model}"
cat "$prompt_file"
exit 0
fi
if ! command -v cursor-agent >/dev/null 2>&1; then
echo "Cursor CLI (cursor-agent) not found on PATH. Install it (https://cursor.com/cli) and authenticate, then retry." >&2
exit 1
fi
cmd=(cursor-agent -p --mode "$mode" --output-format text)
[[ -n "$model" ]] && cmd+=(--model "$model")
if [[ -n "$output_file" ]]; then
mkdir -p "$(dirname "$output_file")"
"${cmd[@]}" < "$prompt_file" | tee "$output_file"
else
"${cmd[@]}" < "$prompt_file"
fi
skill.json
{
"name": "cursor-cli",
"description": "Invoke Cursor CLI as an external reviewer — its edge is model diversity: get a review or second opinion from a different provider's model (gpt-5, sonnet-4). Triggers: 'ask Cursor to review my changes', 'get a second opinion from Cursor', 'have gpt-5 review this'. Do NOT use to invoke Codex (codex-cli) or Claude Code (claude-code-cli).",
"version": "0.1.0",
"license": "MIT",
"status": "published",
"maintainers": [
"@justinramos101"
],
"tags": [
"cursor",
"cursor-agent",
"code-review",
"second-opinion",
"interop",
"cross-agent",
"model-diversity",
"delegation",
"cli",
"external-reviewer"
],
"inspired_by": [
{
"name": "Cursor CLI (cursor-agent)",
"author": "Anysphere",
"kind": "tool",
"year": 2025,
"contribution": "The `cursor-agent` headless CLI this skill wraps: `cursor-agent -p` (print / non-interactive) with `--mode plan` / `--mode ask` for a read-only review stance, `--model` to run many providers' models (gpt-5, sonnet-4, ...), and `--output-format text`. Because cursor-agent has no native diff-review subcommand, the wrapper assembles the git diff itself and feeds it as prompt context; the workspace-trust gate on headless runs is documented in the CLI contract.",
"playbooks": [
"all"
]
}
],
"metadata": {
"family": "interop",
"function": "singleton",
"catalog_summary": "Drive the Cursor CLI (`cursor-agent -p`) as a second-opinion reviewer \u2014 review working-tree, staged, or branch diffs read-only, or get a second opinion on a decision, bug, or plan. Its edge is model diversity: cursor-agent runs many providers' models, so a different model can review the code than wrote it."
}
}
SKILL.md
---
name: cursor-cli
description: "Invoke Cursor CLI as an external reviewer — its edge is model diversity: get a review or second opinion from a different provider's model (gpt-5, sonnet-4). Triggers: 'ask Cursor to review my changes', 'get a second opinion from Cursor', 'have gpt-5 review this'. Do NOT use to invoke Codex (codex-cli) or Claude Code (claude-code-cli)."
license: MIT
---
# Cursor CLI
Invoke Cursor's headless agent (`cursor-agent`) as an external reviewer or
analysis agent. Default to read-only delegation (`--mode plan`) unless the user
explicitly asks cursor-agent to edit files. The distinctive value over the other
interop skills is **model diversity**: cursor-agent can run many providers'
models, so you can get a review from a *different* model than the one that wrote
the code.
## Boundaries
Do NOT use to invoke Codex (use codex-cli) or Claude Code (use claude-code-cli)
as the external agent, to harden a repo's own agent config (use
harden-repo-for-coding-agents), or to run this kit's own heuristic review
skills like dx-audit/ux-audit — cursor-cli shells out to the external Cursor
CLI as an independent reviewer rather than auditing a surface itself.
## Activation Contract
1. Read `references/use-case-registry.csv`.
2. If the user gave a concrete task, match it to the closest use case and load
only that row's detail files and templates.
3. **Bare invocation** (`"use cursor-cli"`, `"start"`): show a compact menu:
mode choice (guided / autopilot / grill me?) and numbered intents from the
router. Wait. No file inspection, no network calls, no writes.
4. **Ambiguous invocation**: ask one — e.g., *"Are you reviewing working-tree
changes, a branch diff, or do you want a second opinion on a design?"* or
*"Is this a code review, setup diagnostics, or prompt preparation?"*
5. If the task would send secrets, private data, production credentials, or
unreviewed sensitive files to cursor-agent, stop and ask for scope.
6. Never pass `-f` / `--force` / `--yolo` (or `--sandbox disabled`) unless the
user explicitly requests it for a trusted sandbox; those drop the read-only
guard.
## Modes
- **Autopilot**: For concrete requests like "ask Cursor to review these changes",
run the appropriate script with read-only defaults, then summarize findings and
caveats.
- **Guided Draft**: For ambiguous review or delegation requests, ask one question
about scope: working tree, staged, unstaged, branch diff, or a custom prompt
(and which model, if the user cares).
- **Grill Me**: For designing a recurring review workflow, ask one question at a
time about trigger point, review scope, model, output format, and failure
handling before preparing commands.
## Default Use Cases
- **Review working-tree changes**: Use when another agent edited files and the
user wants cursor-agent to review the result.
- **Review branch diff**: Use before opening, updating, or merging a PR.
- **Second opinion**: Use when the current agent wants cursor-agent to reason
about a decision, bug, design, or plan — optionally under a specific model.
- **Prompt preparation**: Use when the user wants the prompt and command but not
the live cursor-agent call.
- **Diagnose Cursor**: Use when cursor-agent auth, workspace trust, model
availability, or runtime health is unclear.
## Quick Commands
From the repository being reviewed:
```bash
bash path/to/cursor-cli/scripts/cursor-review-changes.sh
```
To ask a custom read-only question (optionally under a different model):
```bash
printf '%s\n' "Review the API boundary in this repository." \
| bash path/to/cursor-cli/scripts/cursor-ask.sh --model gpt-5
```
Use `--dry-run` on either script to print the prompt and command without invoking
cursor-agent.
## Workflow Classification
This is a **workflow + interop** skill. It invokes another coding agent and can
produce review artifacts and handoffs for agents such as Claude Code or Codex. It
does not auto-chain other skills.
## Workflow
1. Select the use case from the registry.
2. Confirm the repository is trusted (cursor-agent requires workspace trust for
`-p` runs) and that `cursor-agent` is available and authenticated.
3. Prefer `cursor-agent -p --mode plan --output-format text` for read-only
delegation.
4. Use `scripts/cursor-review-changes.sh` for code review of git changes.
5. Use `scripts/cursor-ask.sh` for custom questions or second opinions.
6. Use `scripts/cursor-doctor-check.sh` when setup, auth, or trust is the blocker.
7. Present cursor-agent's output as input from an external reviewer, not as final
truth. Reconcile disagreements against local evidence.
> **Wrong direction?** If the user says this isn't what they meant, go back to
> Understand (step 1) — do not patch in the wrong direction. Restate the
> corrected understanding and re-plan.
## Operational Memory
Do not store user identity facts or secrets. Safe repeat-use defaults can come
from environment variables:
- `CURSOR_CLI_MODEL`
- `CURSOR_CLI_MODE`
- `CURSOR_CLI_MAX_DIFF_BYTES`
Authentication uses `CURSOR_API_KEY` (cursor-agent's own variable). If persistent
workflow state is needed, use the operational templates in `templates/` and keep
only artifact paths, run ids, scope, and non-secret assumptions.
## Subagent Suitability
cursor-agent is the independent reviewer for this skill. Use additional subagents
only for high-risk reviews where separate lenses are useful (security, data
migration, UX regressions). If subagents are unavailable, perform the lenses
sequentially using `references/output-rubric.md`.
## Edge-Case Pass
Before invoking cursor-agent, check:
- **Scope**: staged, unstaged, all working-tree changes, a branch diff, or a repo
question?
- **Trust**: Is the current directory trusted for non-interactive cursor-agent
execution? (Untrusted repos block `-p` with a trust prompt.)
- **Read-only**: Is `--mode plan` (or `ask`) set? Bare `-p` print mode can write
and run shell.
- **Model**: Did the user want a specific/different model for the second opinion?
- **Secrets**: Could the diff include credentials, tokens, customer data, or
local-only files?
- **Size**: Will the diff exceed the prompt budget and need truncation?
- **Failure**: If auth, trust, model, or CLI availability fails, report the exact
command and blocker.
## Reference Map
- `references/use-case-registry.csv`: Use-case routing.
- `references/cli-contract.md`: cursor-agent command contract, read-only modes,
workspace trust, and safety rules.
- `references/review-changes-playbook.md`: Review workflow for agent changes.
- `references/delegation-playbook.md`: Second-opinion and prompt-prep patterns.
- `references/output-rubric.md`: Review quality and reconciliation rubric.
- `templates/review-prompt.md`: Prompt template used by `scripts/cursor-review-changes.sh`.
- `templates/delegation-prompt.md`: Prompt template used by `scripts/cursor-ask.sh`.
- `templates/review-report.md`: Optional report shape for presenting findings.
- `templates/capability-manifest.json`: Capability declaration for other skills or agents.
- `templates/handoff.json`: Prepared handoff shape.
- `templates/workflow-state.json`: Optional resumable workflow state.
- `evals/trigger-evals.json`: Canonical activation/routing eval cases (schema-validated).
- `evals/activation-cases.md`: Natural-language activation + scenario fixtures.
templates/capability-manifest.json
{
"skill": "cursor-cli",
"version": "0.1.0",
"capabilities": [
{
"id": "review-git-changes",
"description": "Invoke cursor-agent (read-only --mode plan) to review working-tree, staged, unstaged, or branch changes.",
"input_artifacts": ["git-status", "git-diff", "repository-path"],
"output_artifacts": ["review-report"],
"side_effect_profile": "external-cli-review",
"required_tools": ["cursor-agent", "git"],
"compatible_handoffs": ["apply-review-feedback", "summarize-review-findings"]
},
{
"id": "delegate-technical-question",
"description": "Invoke cursor-agent for a read-only second opinion, optionally under a different model (gpt-5, sonnet-4).",
"input_artifacts": ["prompt", "repository-path", "optional-context-files"],
"output_artifacts": ["analysis-response"],
"side_effect_profile": "external-cli-read-only",
"required_tools": ["cursor-agent"],
"compatible_handoffs": ["apply-review-feedback", "write-implementation-plan"]
},
{
"id": "diagnose-cursor-cli",
"description": "Probe cursor-agent version, auth, and model availability; surface workspace-trust blockers.",
"input_artifacts": ["local-environment"],
"output_artifacts": ["diagnostic-summary"],
"side_effect_profile": "external-cli-read-only",
"required_tools": ["cursor-agent"],
"compatible_handoffs": ["setup-cursor-cli"]
}
],
"bus_safety": {
"allowed": ["artifact references", "scope", "run ids", "non-secret assumptions"],
"forbidden": ["secrets", "tokens", "credentials", "raw sensitive data", "user identity facts"]
}
}
templates/delegation-prompt.md
You are Cursor acting as an independent technical reviewer.
Do not edit files unless the prompt explicitly asks for edits. Prefer read-only
inspection and concrete reasoning from repository evidence.
Task:
{{TASK}}
Context:
{{CONTEXT}}
Output:
- Start with the direct answer or findings.
- Separate confirmed facts from assumptions.
- Include file references when they matter.
- Include verification steps when useful.
- State any limits caused by missing context or tools.
templates/handoff.json
{
"handoff_id": "",
"source_skill": "cursor-cli",
"source_run_id": "",
"requested_capability": "",
"suggested_receiver": "",
"input_artifacts": [],
"constraints": [],
"assumptions": [],
"user_decisions": [],
"expected_output": "",
"safety_notes": [
"Do not apply Cursor recommendations without verifying file references.",
"Do not include secrets or raw sensitive data in handoff artifacts."
]
}
templates/review-prompt.md
You are Cursor acting as an independent code reviewer.
Review scope: {{SCOPE}}
You are reviewing changes made by another coding agent. Do not edit files. Do
not run destructive commands. Use read-only inspection only.
Focus on:
1. correctness bugs and behavioral regressions
2. security, privacy, data loss, auth, and permission risks
3. broken build, test, or release behavior
4. missing tests only where the changed behavior creates real risk
5. maintainability concerns only when they are likely to cause defects
Avoid style nits and broad refactors unless they hide a concrete bug.
Output findings first, ordered by severity. For each finding include severity,
file/line when possible, impact, and a suggested fix or verification step. If
there are no findings, say that directly and list residual risk or tests you
could not run.
Extra instructions:
{{EXTRA_INSTRUCTIONS}}
templates/review-report.md
# Cursor Review Report
## Findings
- `severity` file:line - finding, impact, and suggested fix.
## Open Questions
- Question or assumption that affects the result.
## Validation
- Commands or checks Cursor ran or recommended.
- Commands the calling agent ran after receiving the review.
## Residual Risk
- What was not inspected, truncated, or not testable.
## Calling Agent Decision
- Accepted:
- Rejected:
- Deferred:
templates/workflow-state.json
{
"run_id": "",
"skill": "cursor-cli",
"status": "not_started",
"phase": "scope-selection",
"scope": "",
"artifacts": [],
"assumptions": [],
"blockers": [],
"next_action": "",
"resume_instructions": ""
}