cursor-plan-run
v0.1.1
Published
Unattended sequential execution of Cursor plans with finish notifications
Maintainers
Readme
cursor-plan-run
Unattended sequential execution of Cursor plans with finish notifications.
# Run directly with npx:
npx cursor-plan-run -- path/to/feature.plan.md
# Or install globally:
npm install -g cursor-plan-run
plan-run path/to/feature.plan.md --dry-runWhy cursor-plan-run?
Running a complex, multi-step Cursor plan interactively inside a single chat window quickly leads to context degradation, forgotten constraints, and agent exhaustion.
plan-run enables unattended execution:
- You write a
*.plan.mdin Plan mode where each todo is session-sized. - Start
plan-runand walk away. - Each todo runs in a fresh local
@cursor/sdkagent session with zero prior chat history contamination. - Each successful step is automatically git-committed. The agent's final text is printed and appended under
## Plan run noteson the plan file. - After all todos complete, a wrap-up Bugbot review writes
## Plan run review; if it lists addressable issues, one fixer session implements them and writes## Plan run fixes. - When the run completes (or if a task fails), you receive a desktop notification & chime plus an optional phone push notification (via ntfy or Telegram). The ping may include Deferred/Issues leftovers.
- If interrupted or failed, simply re-run the exact same command to resume from where it left off.
flowchart LR
initCmd["plan-run --init"]
cursorRule[".cursor/rules/plan-mode-new-chat.mdc"]
agentSkill[".cursor/skills/run-plan/SKILL.md"]
planFile["session-sized plan.md"]
runner["plan-run unattended"]
notify["desktop plus ntfy/Telegram"]
initCmd --> cursorRule --> planFile --> runner --> notify
initCmd --> agentSkill
agentSkill -->|"agent invokes CLI"| runnerThe Two Pillars: Rule & Skill
For unattended execution to succeed reliably, two things are essential:
- Session-Sized Plan Rule (
.cursor/rules/plan-mode-new-chat.mdc): Because each todo runs in a fresh agent session, plans must be self-contained handoffs (explicit file paths, clear done criteria, no "as we discussed earlier" assumptions). - Agent Skill (
.cursor/skills/run-plan/SKILL.md): Teaches Cursor agents in your project to invoke theplan-runCLI when you request overnight, unattended, or sequential execution instead of attempting to execute every step in the current chat.
Initialize your project
Run --init to install both the Cursor rule and the agent skill into your target workspace:
# In your project root:
npx cursor-plan-run -- --init
# Or point to a specific directory:
npx cursor-plan-run -- --init --cwd /path/to/project
# Overwrite existing rule/skill files:
npx cursor-plan-run -- --init --forceYou can also install the skill via skills.sh:
npx skills add lucasantalucia/cursor-plan-run@run-planQuickstart & Usage
1. Set your API Key
Get an API key from the Cursor Dashboard:
export CURSOR_API_KEY="key_..."
# Or add CURSOR_API_KEY to your project's .env file (automatically loaded via dotenv)2. Run a Plan
# Dry-run: inspect todos and auto-selected models without running agents
plan-run .cursor/plans/feature.plan.md --dry-run
# Run unattended
plan-run .cursor/plans/feature.plan.md
# Resume an interrupted or failed run (same command)
plan-run .cursor/plans/feature.plan.md
# Start from a specific todo id
plan-run .cursor/plans/feature.plan.md --from implement-auth
# Pin a specific model instead of auto-picking
plan-run .cursor/plans/feature.plan.md --model composer-2.5
# Skip wrap-up Bugbot review (+ fixer) after all todos complete
plan-run .cursor/plans/feature.plan.md --no-review
# Test your finish notification (desktop sound + phone alert)
plan-run --notify-testRunner Behavior & Defaults
- Auto-Picked Models: Unless overridden with
--model, each task dynamically selects the optimal model from your available catalog (Cursor.models.list()) based on task complexity. - Per-Task Commits: After each successful task, creates a git commit:
plan(<plan-name>): <task-content>. (Disable with--no-commit). - Per-Task Notes: After
wait(), prints the agent's final text and appends/replaces### {todoId}under## Plan run notes(8KB cap) before the per-task commit. Resume replaces that todo's subsection instead of duplicating it. - Resuming & Retries: Reads status directly from the plan frontmatter. Skips
completedtodos, and executespending,in-progress, anderrortasks. - Wrap-up review: After all todos complete (and before archive), one extra local agent compares this run's commits (
startSha..HEAD) to the plan and runs Cursor/reviewBugbot withDiff: natural language(needed when committing onmain, where branch-vs-main is empty). Appends## Plan run review(including### Issues to fix). Does not edit source. Disable with--no-revieworPLAN_RUN_REVIEW=0(also skips the fixer). Review-agent failures are logged and do not block archive. - Wrap-up fixer: When
## Plan run reviewlists addressable items under### Issues to fix, a second fresh local agent implements those only (one pass, no second Bugbot). Appends## Plan run fixes(### Fixed/### Leftover). Commits asplan(<name>): address wrap-up review issueswhen commits are enabled (orplan(<name>): record run reviewif the fixer was skipped and only review notes remain). Fixer failures still archive; leftovers stay on the plan. - Automatic Archiving: When all todos are completed, moves the plan file to a sibling
archived/folder with a localyyyymmdd-prefix (e.g..cursor/plans/foo.plan.md→.cursor/plans/archived/20260826-foo.plan.md) and commits the archive move. If that dated filename already exists, a time suffix is appended (20260826-foo-151630.plan.md). Disable with--no-archive. - Ripgrep Auto-Configuration: Automatically resolves and seeds
CURSOR_RIPGREP_PATHfrom@cursor/sdkplatform binaries or local Cursor installations to prevent search failures. - Finish Alerts & Phone Relay:
- macOS: Notification Center banner + sound (Glass on success, Basso on failure).
- Phone push: Relay alerts to iOS/Android using ntfy or Telegram. Dry runs and empty resumes stay silent. The finish summary / phone ping may include a compact Deferred/Issues/Suggestions excerpt plus review finding and leftover-unfixed counts when present.
Phone Notifications Setup
Add these optional variables to your project's .env or shell profile:
Option A: ntfy (Recommended)
- Install the ntfy app (iOS / Android).
- Subscribe to a topic name of your choice (e.g.
my-private-builds-xyz123). - Set the env var:
PLAN_RUN_NTFY_TOPIC=my-private-builds-xyz123 # Optional custom server: # PLAN_RUN_NTFY_SERVER=https://ntfy.sh # PLAN_RUN_NTFY_TOKEN=tk_...
Option B: Telegram
- Create a bot with @BotFather or use an existing bot token.
- Get your numeric chat ID from @userinfobot.
- Set the env vars:
PLAN_RUN_TELEGRAM_BOT_TOKEN=123456:ABC-DEF... # or TELEGRAM_BOT_TOKEN PLAN_RUN_TELEGRAM_CHAT_ID=123456789
Test your notification setup anytime with:
plan-run --notify-testCLI Options
| Flag | Description | Default |
|------|-------------|---------|
| <plan.plan.md> | Path to Cursor plan file | (positional) |
| --dry-run | Parse, pick models, and list tasks without executing | false |
| --model <id\|auto-pick> | Specific model ID or auto-pick per task | auto-pick |
| --from <todo-id> | Start execution at this todo ID (inclusive) | (start of plan) |
| --status <list> | Comma-separated statuses to execute | pending,in-progress,error |
| --cwd <path> | Workspace root for the agent session | process.cwd() |
| --no-commit | Disable automatic git commit after each task | false |
| --no-archive | Keep plan file in place after all todos complete | false |
| --no-update-plan | Do not update status in the .plan.md file | false |
| --no-notify | Skip desktop chime, banner, and phone relay | false |
| --no-review | Skip wrap-up Bugbot review and fixer after all todos complete | false |
| --continue-on-error | Keep running remaining tasks if a task fails | false |
| --notify-test | Send a test desktop + phone alert and exit | false |
| --init | Install session-sized plan rule and agent skill | false |
| --force | Overwrite existing files when using --init | false |
| -h, --help | Show CLI help text | |
Environment Variables
| Variable | Description |
|----------|-------------|
| CURSOR_API_KEY | Required Cursor API key (Dashboard) |
| CURSOR_MODEL | Default model override (same as --model) |
| CURSOR_RIPGREP_PATH | Absolute path to rg binary (auto-detected if unset) |
| PLAN_RUN_NOTIFY | Set to 0 to disable notifications (same as --no-notify) |
| PLAN_RUN_REVIEW | Set to 0 to skip wrap-up Bugbot review and fixer (same as --no-review) |
| PLAN_RUN_NTFY_TOPIC | ntfy topic for phone push notifications |
| PLAN_RUN_NTFY_SERVER | ntfy server URL (default: https://ntfy.sh) |
| PLAN_RUN_NTFY_TOKEN | Optional auth token for private ntfy topics |
| PLAN_RUN_TELEGRAM_CHAT_ID | Telegram chat ID for phone alerts |
| PLAN_RUN_TELEGRAM_BOT_TOKEN | Telegram Bot token (falls back to TELEGRAM_BOT_TOKEN) |
| TELEGRAM_BOT_TOKEN | Fallback Telegram Bot token |
Requirements
- Node.js:
^22.13.0or higher - Cursor API Key: cursor.com/dashboard/api
License
MIT © Luca Santalucia
