Metadata-Version: 2.4
Name: cursorhub
Version: 0.1.3
Summary: Desktop tray toast + CLI for your Cursor subscription usage
Project-URL: Repository, https://github.com/pandiyarajk/cursorhub
Project-URL: Issues, https://github.com/pandiyarajk/cursorhub/issues
Author-email: Pandiyaraj Karuppasamy <pandiyarajk@live.com>
License: MIT
License-File: LICENSE
Keywords: cursor,cursor-ai,monitor,pyside6,toast,usage
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Win32 (MS Windows)
Classifier: Environment :: X11 Applications :: Qt
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: User Interfaces
Requires-Python: >=3.11
Requires-Dist: pyside6>=6.6
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: twine>=4.0; extra == 'dev'
Description-Content-Type: text/markdown

# cursorhub

Track your **Cursor** subscription usage from a desktop tray toast or the terminal.

- **Tray toast** (`cursorhub`): an always-on-top card in the top-right corner
  showing your included-plan percentage, on-demand spend, and when the billing
  cycle resets. Refreshes every 5 minutes; dodges out of the way when your
  cursor gets near it.
- **CLI** (`cursorhub usage`, or the dependency-free `standalone/cursor_usage.py`):
  print usage on demand as a table or JSON.
- **Day heartbeat** (`cursorhub mark`): send one tiny real Cursor request per
  calendar day so the day shows up as active in the Cursor dashboard, even if
  you never opened the editor. Off unless Cursor's CLI is installed.

## How it works

Cursor stores a session JWT in its local VS Code-style state database
(`state.vscdb`, key `cursorAuth/accessToken`). Your userId is the `sub` claim of
that token. Cursor's own web dashboard authenticates to `cursor.com/api/*` with a
cookie `WorkosCursorSessionToken={userId}::{token}`. cursorhub reads the token,
builds the same cookie, and calls `GET /api/usage-summary`.

This needs **no API key** and works for **any signed-in Cursor user** - Pro,
Business, or a member of an Enterprise team. You do **not** need to be a team
admin (the official `api.cursor.com/teams/*` Admin API is admin-only; cursorhub
does not use it).

The state DB is read from:

| OS      | Path |
|---------|------|
| Windows | `%APPDATA%\Cursor\User\globalStorage\state.vscdb` |
| macOS   | `~/Library/Application Support/Cursor/User/globalStorage/state.vscdb` |
| Linux   | `~/.config/Cursor/User/globalStorage/state.vscdb` |

## Install

```bash
pip install cursorhub
```

Or from a checkout:

```bash
pip install -e .
```

The tray app needs PySide6 (pulled in automatically). The standalone script
needs nothing but Python 3.11+.

## Usage

```bash
cursorhub                       # launch the tray toast
python -m cursorhub             # same thing

cursorhub usage                 # print a table (your usage)
cursorhub usage team            # your usage plus team usage
cursorhub usage --json          # normalized JSON
cursorhub usage --raw           # raw Cursor API responses (debugging)

cursorhub mark                  # mark today as a Cursor-used day
cursorhub mark --status         # heartbeat state, no request sent

python standalone/cursor_usage.py           # no install required
python standalone/cursor_usage.py --json
```

Example table (`cursorhub usage`):

```
Cursor usage  -  you@example.com  (enterprise)
====================================================
Included plan   [######------------------] 25.6%
                included 2000 + bonus 45 = 2045
On-demand (you) $0.00 / $300.00   left $300.00
Billing cycle   resets in 24d 13h   (2026-08-11T19:09:10.000Z)

  You've used 26% of your included total usage
```

With `cursorhub usage team`, team usage appears between the on-demand block
and the billing cycle:

```
Cursor usage  -  you@example.com  (enterprise)
====================================================
Included plan   [######------------------] 25.6%
                included 2000 + bonus 45 = 2045
On-demand (you) $0.00 / $300.00   left $300.00

Team usage
On-demand (team)$342.16 / $2,500.00   left $2,157.84

Billing cycle   resets in 24d 13h   (2026-08-11T19:09:10.000Z)

  You've used 26% of your included total usage
```

## Marking the day as used

Reading usage does **not** count as usage. `GET /api/usage-summary` is a passive
dashboard read - polling it all day long will never make a day show up as active
on cursor.com. The only thing that registers a day is a genuine model request
billed to your account.

So cursorhub can send one, once per calendar day, through Cursor's official CLI.
It looks for `cursor-agent` on `PATH`, then in `~/.local/bin`, and finally falls
back to the copy Cursor's own agent-worker extension keeps under `globalStorage`
- so on a machine with the Cursor editor installed there is usually nothing to
install. Check with `cursorhub mark --status`; if it says `not found`:

```powershell
irm 'https://cursor.com/install?win32=true' | iex   # macOS/Linux: curl https://cursor.com/install -fsS | bash
cursor-agent login
cursor-agent status
```

Then:

```bash
cursorhub mark              # mark today if it isn't already marked
cursorhub mark --force      # mark again regardless
cursorhub mark --status     # show state; makes no request
```

The tray app does this for you: once at launch and on every 5-minute tick. After
the first success each day the check is just a date comparison against
`heartbeat.json` in cursorhub's state directory - no subprocess, no request. Left
running overnight, it marks the new day on the first tick after midnight. The
tray menu also has **Mark today used now**.

Two things worth knowing:

- **It costs real usage.** One short prompt per day, on your account. Set
  `CURSORHUB_HEARTBEAT=0` to turn it off entirely.
- **It never runs tools.** The request goes out as
  `cursor-agent -p ... --mode ask --trust`: `--mode ask` is read-only (no edits,
  no shell), `--trust` skips the workspace-trust prompt that would otherwise
  block a headless run, and it all happens in a throwaway temp directory.

With no `cursor-agent` anywhere, cursorhub carries on as before: the toast shows
`no cursor-agent` and `cursorhub mark` exits non-zero with a clear message.

## Configuration (env vars)

| Variable | Purpose |
|----------|---------|
| `CURSOR_SESSION_TOKEN` | Use this raw JWT instead of reading the state DB |
| `CURSOR_STATE_DB`      | Path to a non-default `state.vscdb` |
| `CURSORHUB_HEARTBEAT`  | `0`/`false` disables the once-a-day "mark as used" request |
| `CURSORHUB_AGENT_BIN`  | Explicit path to `cursor-agent` (else PATH, then `~/.local/bin`) |
| `CURSORHUB_HEARTBEAT_MODEL` | Model for the daily request (else your account default) |
| `CURSORHUB_HEARTBEAT_PROMPT` | Prompt for the daily request |
| `CURSORHUB_STATE_DIR`  | Where `heartbeat.json` lives (default `%APPDATA%\cursorhub`) |

## Caveats

- These dashboard endpoints are **unofficial / internal** to Cursor and can
  change without notice. Every call degrades to a clear error rather than
  crashing.
- The session token **expires when you sign out** of Cursor. Sign back in and
  the tray toast recovers on its next refresh.
- On-demand amounts are reported by Cursor in cents and shown here in whole
  dollars.

## License

MIT - see [LICENSE](LICENSE).
