Count every Cursor agent hook fire and track live AI turn time — locally, across windows and multi-root workspaces. No chat scraping, no DOM hacks, no prompts or file contents leave your machine.

v0.5.0 — Install profiles (timer / tool counts / both) · compact ledger · no HTTP server.
Why this extension?
| Problem | What we do |
|---|---|
| Port fights when two Cursor windows run agents | Hooks only append to a shared local ledger under extension storage — no shared port |
| Only one workspace folder got hooks | Install covers every multi-root folder with a stable workspace id |
| Lifetime blob, no history | Day-partitioned events-YYYY-MM-DD.jsonl + range filters |
| Privacy anxiety | Observational hooks only; ledger lines never include paths, prompts, or tool output |
| Hook spawn cost | Install profiles: timer-only · tool counts · or both |
Features
- Hook counters (this chat + selected period) for thoughts, shell, MCP, file reads/edits, tools, subagents, tab edits, compaction, …
- Project filter: All projects · This project · pick another
- Time period: Today · Last 7 days · Last 30 days · All time (within retention)
- Live status bar timer while an AI turn is running (from the same ledger ticks)
- Merges into
.cursor/hooks.jsonwithout replacing other hooks - Interval log for completed timer sessions (separate from clearing count data)

Privacy
Installed hooks are observational only (not workspaceOpen). The shim:
- Reads only the first ~24KB of stdin (hook name + session near the start — never loads multi-MB tool payloads)
- Appends one compact tick:
+\t{ws}\t{hook}\t{session}\t{epochMs}(ledger path baked into the shim at install) - Exits immediately — no HTTP. Uses Bun when on PATH, otherwise Node.
- Installs a profiled hook set: timer-only · tool counts · or both (default)
Absolute folder paths live only in local workspaces.json. Nothing is sent to the network.
Install profiles
| Profile | Hooks (summary) | Best for |
|---|---|---|
| Timer only | sessionStart, beforeSubmitPrompt, stop, subagentStart, subagentStop |
Fastest; live status-bar time |
| Tool counts | thoughts, tools, shell, MCP, reads, edits, tab edits, compact, responses | KPI tiles without timer hooks |
| Both | Union of the two | Full dashboard |
Switching profile rewrites owned hook entries (drops the other set). Unrelated workspace hooks stay.
Quick start
- Open AI Activity in the Activity Bar.
- Under Hook setup, pick a profile:
- Timer only — live turn time (few lightweight hooks)
- Tool counts — KPI counters (tools, shell, reads…; heavier)
- Both — timer + counters
- Click Install / refresh.
- Use Cursor AI. Data updates from the local ledger (watch + short poll).
- Pick a project and time period in the sidebar for historical totals.
Multi-window / multi-root
- Two windows on different projects share the same extension global storage ledger.
- Multi-root: hooks install on every folder; each gets its own
workspaceId. - After upgrading: open the workspace once (auto-refresh) or click Install / refresh hooks.
Hook KPI map
| Tile | Hook |
|---|---|
| Thoughts | afterAgentThought |
| Shell | afterShellExecution |
| MCP | afterMCPExecution |
| File reads | beforeReadFile |
| File edits | afterFileEdit |
| Tool (after) | postToolUse |
| Tool failures | postToolUseFailure |
| Responses | afterAgentResponse |
| Prompts | beforeSubmitPrompt |
| Subagent start | subagentStart |
| Tab edits | afterTabFileEdit |
| Compactions | preCompact |
Clear count data removes all saved hook counts (every day, every project). This cannot be undone. Clearing the interval log is separate.
Legacy hook-stats.json migrates once into synthetic lines under workspace id legacy (“Pre-ledger (migrated)”).
Timer rules
Derived by the extension from lifecycle ticks in the ledger:
beforeSubmitPromptstarts an intervalstopends it after all subagents stopsubagentStart/subagentStopkeep the interval open while subagents run- Duplicate stops do not double-count
- Only new ticks after extension activate advance the live timer (history is not replayed into the status bar)
Commands
| Command |
|---|
AI Activity: Focus Dashboard |
AI Activity: Install Cursor Hooks |
AI Activity: Uninstall Cursor Hooks |
AI Activity: Show Interval Log |
AI Activity: Clear Interval Log |
AI Activity: Clear Count Data |
Configuration
| Setting | Default | Description |
|---|---|---|
cursorAiActivityTimer.hookInstallProfile |
both |
Default install profile: timer / counts / both |
cursorAiActivityTimer.autoInstallHooks |
false |
Auto-install hooks on activate |
cursorAiActivityTimer.showElapsedTime |
true |
Status bar elapsed time |
cursorAiActivityTimer.logRetentionDays |
30 |
Interval log retention |
cursorAiActivityTimer.eventRetentionDays |
90 |
JSONL day-file retention |
cursorAiActivityTimer.statsRangeDefault |
today |
Default period: today / 7d / 30d / all time |
Troubleshooting
| Symptom | Try |
|---|---|
| Counters or timer stuck | Install/refresh hooks; config must have ledgerPath + workspaceId |
| After upgrade | Reopen workspace or Install / refresh hooks so the compact shim is rewritten |
| Multi-root missing counts | Install on every folder (command covers all roots) |
Development
npm install
npm run compile
npm test
npm run package
Press F5 in Cursor/VS Code for the Extension Development Host.
Maintainer docs (architecture, PDR, standards, deploy):
Links
- Marketplace / VSIX: package with
npm run package - Repository: philau2512/cursor-ai-activity-timer