A sixth tab: a pool of Cursor accounts. Paste cookies, see who each account is and what it has spent, and switch between the ones you have signed into Cursor.
The Cursor pool
A Cursor account is not a provider — no base URL, no API key, no model, just a session token — so it gets its own tab rather than a provider form. The five existing apps are untouched.
Add account is one paste box (or a file picker) that takes whatever you have: a Netscape cookies.txt line, a whole Cookie: header, a bare WorkosCursorSessionToken=…, a raw user_…::token, an email,token CSV row, or JSON at any nesting. Paste one line or two hundred; unrecognised lines are counted and skipped, so a whole browser export works as-is. Accounts are keyed on the user id inside the cookie, not the email, so re-pasting a rotated cookie refreshes that account in place instead of duplicating it. A credential with no user_…:: half is skipped — that is the usual reason a line lands in the skipped count.
Every account refreshes in the background on launch, against the endpoints cursor.com's own dashboard calls — /api/auth/me for name, email and avatar, /api/auth/stripe for the plan, /api/usage-summary (or the legacy /api/usage for a request-quota plan) for the meter. Those endpoints are undocumented and will change: a figure that was never learned renders as —, and one that stops arriving keeps its last value rather than blanking — a Cursor outage must not wipe a card. A cookie cursor.com rejects marks the row Expired and disables its button; a timeout or a 5xx leaves it alone.
What a cookie can and cannot do
A cookie exported from a browser reads the account — name, plan, usage — but it is a web token, and writing one into Cursor's database makes the desktop app reject it and sign itself out. Only the session token Cursor writes when you sign into an account in the app itself signs the desktop client in. So:
- U-Pool banks that session automatically the moment you are signed in — the account you are already using is added to the pool on launch and marked in use, so a first switch can never throw away a session you have no other copy of.
- The accounts you can switch to are the ones you have signed into Cursor at least once (or whose session token you paste directly).
- A browser-cookie row shows its usage but Use is disabled, with a note saying so, rather than signing you out.
Turning a browser cookie into a session token — Cursor's own deep-login exchange — is proven possible and planned, but not in this release.
What a switch touches
Use closes Cursor (only if it is running), copies state.vscdb beside itself as state.vscdb.backup, writes eight keys, and starts Cursor again (only if U-Pool was the one that closed it).
| Owned | seven cursorAuth/* rows in ItemTable, plus glass.lastSignedInAuthId |
| Never opened | cursorDiskKV and composerHeaders — your Cursor conversations |
| Never read | every other ItemTable row, including the live mcpOAuth.secret.* credentials |
| Not touched | storage.json and %APPDATA%\Cursor\machineId — the telemetry ids |
| Measured, deliberately not owned | cursorAuth/onboardingDate, which a pasted cookie cannot supply |
Ownership is by eight keys named in full, never by the cursorAuth/ prefix — a prefix sweep would take whatever Cursor adds under it next. Every statement in the writer is a SELECT or an INSERT OR REPLACE on one of those keys. There is no DELETE, no DROP, no VACUUM, no rewrite of the file. Resetting the machine ids is not part of switching accounts — other switchers do it to defeat a per-device limit, and those values are Cursor's own state.
There is no force kill. Closing Cursor is the same request the quit menu sends. If it is still there after ten seconds, not one byte is written — not even the backup — and the switch tells you to close it yourself. The failure mode of a half-applied auth record is an editor that can neither sign in nor sign out.
The key list was measured, not guessed
Cursor 3.14.7 was snapshotted signed out (100 ItemTable rows), signed in, and snapshotted again (148). Fifty rows appeared and eighteen changed; almost all of that is the session — window layout, theme, 594 KB of pushed experiment config. Eight rows are the account. Four things that measurement settled and guesswork would have got wrong:
- Values are stored raw, not JSON-encoded.
cachedEmailisyou@example.com, not"you@example.com". OnlycachedScopedProfileis JSON, being an object — and the avatar lives inside it, which is why a switch does not blank the account-menu picture. accessTokenandrefreshTokenhold the same JWT, so the single credential a cookie carries is exactly what Cursor keeps.- The Electron cookie jar is empty while signed in —
state.vscdbalone carries the session, so the jar is never opened. cachedScopedProfileandstripeSubscriptionStatusare new in the 3.x builds and in no existing switcher. Writing the ecosystem's familiar five-key list would have left the previous account's name and subscription status under the new account's token.
glass.lastSignedInAuthId is the one owned key outside the cursorAuth/ prefix, and widening the claim to reach it is stated rather than quiet: it holds the JWT's sub verbatim, and leaving it would pair account B's token with account A's id. These constants come from one sign-in on one build, not from documentation.
One fix that matters if you are on 0.7.0
clis.refresh_async(force=False) took a lock and then called snapshot(), which takes the same non-reentrant lock. Cold, the branch is skipped and nothing notices; warm, the process stops dead. bootstrap is the only force=False caller and normally runs once — but a webview reload calls it a second time, and that hung the app with a blank window and nothing in any log. Fixed here, with a regression test that fails by timing out rather than by asserting.
Also
- Session tokens live in
~/.u-pool/cursor.jsonin plain text — the same exposureconfig.jsonalready carries for provider keys — and the token never leaves the backend: the UI is told only whether one is present. - The account currently in use cannot be deleted; that row holds U-Pool's only copy of the token now in
state.vscdb. - The tab is useful with no Cursor installed — accounts still paste and refresh, only Use needs a database.
- Cross-platform where it can be: Cursor resolves
~/Library/Application Support/Cursoron macOS and~/.config/Cursoron Linux, though only the Windows path has been exercised. - 434 tests, up from 267 at 0.7.0. No new dependency — stdlib
urllibandsqlite3throughout.
Not verified
No switch between two different accounts has been applied to a live install. A round-trip against the real 148-row database — pool the account already signed in, refresh it, switch to it — came back byte-identical on all eight owned keys, with onboardingDate untouched, the row count unchanged and state.vscdb.backup in place. That proves Cursor's own sign-in state can be reproduced exactly. It cannot, on its own, prove Cursor honours a different account's keys on next start. If a switch ever goes wrong, the backup is a rename away in a folder you can already open.
Install
Download U-Pool-0.8.0-win64.zip, unzip anywhere you own (not Program Files — Windows will not let U-Pool replace itself there on update), and run U-Pool.exe.
SHA-256 36017b80aaf972f866a540f4396008967dddd7c79c623964f5f6ba5b5cce3b60
Full changelog: v0.7.0...v0.8.0
