Telegram ↔ Cursor SDK bridge
Drive Cursor agents on your local repos — from your phone.
English · 简体中文
(screenshot — TBD: replace with docs/screenshots/hero.png)
Cursor's agent capability is amazing — but it lives inside the IDE on your desk. The moment you walk away, you also walk away from your agent.
cursor-claw is a tiny single-process service that runs on your dev machine and exposes Cursor agents through messengers you already carry: today Telegram, with WeChat and other channels in the roadmap. You text your bot, the bot drives Cursor agents on your local repos, the bot streams answers back. Everything runs on your hardware with your API keys — no third-party middleman.
Walking the dog — tap
/ws use myproj→fix the failing test on main. Two minutes later your home dev box has a clean test run waiting for you.
- 🤖 End-to-end text conversation — full Cursor agent capability (shell, edits, tools), with throttled streaming back to the chat (default 800ms)
- 🗂 Multi-workspace — register many local repos and
/ws use <name>to switch agents - 🧰 Command system —
/help/ws/reset/cancel/status/model/remindand a!<text>interrupt prefix - 🖼 Inbound images — send a photo (or an album) to the bot, the agent receives and analyses them automatically
- 📎 Outbound attachments — the agent calls
claw-attach-image /tmp/x.pngfrom inside its shell tool, the file is delivered to your chat - ⏰ Reminders — absolute, relative or daily times; either plain text reminders or "prompt-on-fire" reminders that auto-trigger the agent
- 🛡 Allow-list access control — only the Telegram user IDs you list can talk to the bot; everyone else is silently dropped
- ✋ Cancel & interrupt — soft
/cancel, hard!new prompt - 🐧 Service-friendly — clean
SIGTERMhandling, suitable forsystemd/pm2/launchd - 🧪 TDD-first — 141+ unit & integration tests, full
IMessenger/IAgentRuntimeabstractions so the orchestrator never knows about Telegram or the Cursor SDK directly
Need a more detailed walkthrough? See docs/INSTALL.md.
git clone https://github.com/lilyjem/cursor-claw.git
cd cursor-claw
npm install
cp config.example.json config.json
# Edit config.json (botToken, allowedUserIds, apiKey) -- or use env vars below
export TELEGRAM_BOT_TOKEN="123456:abcdef..."
export CURSOR_API_KEY="key_..."
npm run devgit clone https://github.com/lilyjem/cursor-claw.git
cd cursor-claw
npm install
Copy-Item config.example.json config.json
# Edit config.json (botToken, allowedUserIds, apiKey) -- or use env vars below
$env:TELEGRAM_BOT_TOKEN = "123456:abcdef..."
$env:CURSOR_API_KEY = "key_..."
npm run devOpen Telegram → private chat with your bot → type /start → you should see a welcome message.
| Requirement | How to get it |
|---|---|
| Node.js >= 20.10 | https://nodejs.org/ |
| Telegram bot token | Talk to @BotFather → /newbot → copy token |
| Telegram user ID (your own) | Send /start to @userinfobot → copy numeric ID into telegram.allowedUserIds |
| Cursor API key | https://cursor.com/cn/docs/sdk/typescript → settings → API keys |
Detailed step-by-step (with screenshots) in docs/PREREQUISITES.md.
| Command | Description |
|---|---|
/help |
Show help |
/ws list |
List registered workspaces |
/ws use <name> |
Switch active workspace |
/ws add <name> <abs-path> |
Register a workspace |
/ws remove <name> |
Unregister a workspace |
/ws path |
Print current workspace path |
/reset |
Reset agent for current workspace (destroy agent, clear stored agentId) |
/cancel |
Cancel the current run gracefully |
/status |
Show active agent / workspace / model |
/model <id> |
Switch the default model (next session) |
/remind add text 10m drink water |
One-shot text reminder, fires in 10 minutes |
/remind add prompt 09:00 check BTC price |
Daily-time prompt reminder, fires the agent for you |
/remind list / /remind cancel <id> |
Manage active reminders |
| (plain message) | Sent as a prompt to the active workspace agent |
!<text> |
Interrupt the running agent and start over with new text |
Send a photo (or an album of up to 8) to the bot. They are bundled together with an optional caption and forwarded to the agent. Defaults: 8 images per prompt, 800ms album debounce. Configurable in config.json under images.*.
Inside its shell tool, the agent can call:
claw-attach-image /path/to/screenshot.png
claw-attach-file /path/to/report.pdfcursor-claw locates its data directory through <workspace>/.claw/data-dir.txt (auto-written when the agent runs). If that fails, set CLAW_DATA_DIR=/path/to/data explicitly.
- Relative:
10m1h30m45s2d - Today, daily:
09:0022:30 - Absolute:
2026-05-06T09:00
Default timezone Asia/Shanghai, override with reminders.timezone in config.json.
| Layer | Module |
|---|---|
| Entry | src/bin/cursor-claw.ts |
| Adapters | src/adapters/telegram/ (grammy, implements IMessenger) |
| Commands | src/commands/ (parser + dispatcher + handlers) |
| Orchestrator core | src/core/orchestrator/ (AgentOrchestrator + StreamRenderer + busy-policy + cursorSdkRuntime) |
| Workspace / session / access | src/core/{workspace,session,access}/ |
| Reminders / attachments | src/core/{reminders,attachments}/ |
| Persistence | src/core/persist/jsonStore.ts |
| Config & logging | src/config/, src/logger.ts |
| CLI tools | src/tools/attach-image.ts, src/tools/attach-file.ts |
The two abstraction boundaries (IMessenger, IAgentRuntime) keep the orchestrator unaware of Telegram and the Cursor SDK; tests use StubMessenger + StubAgentRuntime to drive end-to-end flows.
Full design rationale: docs/superpowers/specs/2026-05-05-cursor-claw-design.md.
npm test # 141+ unit & integration tests (vitest)
npm run typecheck # tsc --noEmit
npm run lint # eslint src testsManual smoke tests (require real API keys, real Telegram chat):
export CURSOR_API_KEY="..."
npx tsx tests/manual/sdk_smoke.ts # Cursor SDK only
# tests/manual/m2-smoke.md # Full M2 e2e checklistcursor-claw is a long-running single process. Pick whichever supervisor matches your platform:
- Linux —
systemduser unit (recommended) - Linux / macOS / Windows —
pm2(Node-native cross-platform) - macOS —
launchduser agent - Windows — NSSM (run Node service as Windows Service)
- Docker — planned, not in this milestone (the process needs host filesystem + Cursor SDK access)
Concrete unit files & step-by-step in docs/DEPLOYMENT.md.
- ✅ M1 — end-to-end text chat, workspace switching, commands, streaming, cancel, allow-list, systemd-friendly exit
- ✅ M2 — bidirectional attachments, inbound images, reminders
- 🚧 M3 — WeChat adapter skeleton, Clawfox browser integration, MCP config hot-reload
A bot of this kind is essentially a shell behind a messenger. Treat it accordingly:
- Keep
TELEGRAM_BOT_TOKENandCURSOR_API_KEYout of git. The repo's.gitignorealready excludesconfig.jsonand.claw/. Use environment variables in production. - Always set
telegram.allowedUserIdsto just your own Telegram user IDs. Non-listed messages are silently dropped. - If your bot was discovered (
@yourbotis searchable), turn off groups & make the bot private; or rotate the token. - Run as a non-root OS user. Don't give the bot more filesystem access than your projects need.
- Treat Cursor SDK runs the same way you treat
bashexecuted remotely — because that is what they are.
Common errors and what they mean: docs/FAQ.md.
A few highlights:
- "Local SDK agents require an explicit 'model'" → you upgraded
@cursor/sdkpast 1.0.x;AgentOrchestratoralready passes the model on resume, but make sure yourconfig.jsonhas a validcursor.defaultModel. - "Telegram: 400 Bad Request: can't parse entities" → HTML mode tried to render a literal
<word>. Usage messages now useparseMode: "plain"; if you see this from custom code, escape angle brackets or switch parse mode. - "
claw-attach-image: command not found" → you rannpm installbut did notnpm linkornpm i -g; the agent's PATH does not see the local-only bin.
PRs and issues welcome. See .github/CONTRIBUTING.md.
Quick loop:
npm test # red/green
npm run typecheck # type safety
npm run lint # styleFix lint errors before opening a PR; the project follows a strict TDD approach (tests first).
MIT © 2026 Jem Li