|
| 1 | +# Deep Dive: Hacking Cursor's Notepad System |
| 2 | + |
| 3 | +> A technical exploration of Cursor IDE's notepad storage system and how we built tools to enhance it. |
| 4 | +
|
| 5 | +## Table of Contents |
| 6 | + |
| 7 | +- [Introduction](#introduction) |
| 8 | +- [The Problem](#the-problem) |
| 9 | +- [A Word on Problem-Solving](#a-word-on-problem-solving) |
| 10 | +- [Understanding Cursor's Architecture](#understanding-cursors-architecture) |
| 11 | +- [The Investigation](#the-investigation) |
| 12 | +- [Technical Implementation](#technical-implementation) |
| 13 | +- [Building the Solution](#building-the-solution) |
| 14 | +- [Future Improvements](#future-improvements) |
| 15 | + |
| 16 | +## Introduction |
| 17 | + |
| 18 | +This isn't how I thought I'd spend my Tuesday morning, but after renaming a project folder and losing all my Cursor settings, here I am, making the system change instead of myself. |
| 19 | + |
| 20 | +### What are Cursor Notepads? |
| 21 | + |
| 22 | +Cursor Notepads are an incredible feature that enhance output quality and let you harness literal LLM magic. They're not just text files – they're interactive AI prompts, code snippets, and project documentation that evolve with your workflow. I rarely use the AI composer without one of my many notepad templates guiding the conversation. |
| 23 | + |
| 24 | +But there's a catch: these powerful tools are locked to individual workspaces. Create a new project? Start from scratch. Rename a folder? Wave goodbye to your carefully crafted prompts. This isn't a great workflow, so I decided to change it. |
| 25 | + |
| 26 | +## The Problem |
| 27 | + |
| 28 | +It started with a simple folder rename. One morning, I opened my newly renamed project in Cursor IDE, and all my carefully crafted notepads were gone. Not just any notepads – these were my collection of AI prompts, code snippets, and project documentation that I'd been refining for weeks. |
| 29 | + |
| 30 | +The original discussion on [Cursor's forum](https://forum.cursor.com/t/where-are-notepads-stored/18659/10) showed I wasn't alone. Many developers were looking for ways to back up and manage their notepads, but there were no solutions available. |
| 31 | + |
| 32 | +## A Word on Problem-Solving |
| 33 | + |
| 34 | +Like all the most engaging rabbit holes, this one started with a hunch. I knew I wanted to get at my Notepad data, but other than that, an internet search turned up pretty much zero. If you're coming to this article off the back of your own search, I hope it helps out. |
| 35 | + |
| 36 | +When it comes to problem-solving, here's how my head normally works... very much like everyone else, but with the added benefit/hindrance of being zealously undeterred where others might give up. I am sunk cost fallacy manifest. |
| 37 | + |
| 38 | +Much like good marketing, a good problem is a rare but powerful thought. A good problem: |
| 39 | + |
| 40 | +- Sets the stage with just enough detail to nudge your thoughts in the right direction |
| 41 | +- Lets your own inquisitive thoughts fill in the gaps |
| 42 | +- Sees you, the protagonist, arrive at the gates of the dungeon, armed only with your knowledge, a poorly scribbled map from previous travelers, and a level one wooden sword |
| 43 | + |
| 44 | +The most persuasive problems are the ones that get in your future self's head. They manifest themselves not just as a bug to crush or a decision to make, but as an opportunity that lights a fire under your ass to do the hard work. |
| 45 | + |
| 46 | +As someone with an impossibly short attention span, no real direction outside "I enjoy building things", and an overindex of experience solving incredibly niche problems that nobody cares about - this is one of those problems. |
| 47 | + |
| 48 | +## Understanding Cursor's Architecture |
| 49 | + |
| 50 | +Cursor is built on VSCode's architecture, which means it's an Electron application. This gives us some immediate insights: |
| 51 | + |
| 52 | +1. **Storage Location**: Like most Electron apps, user data is stored in the AppData directory: |
| 53 | + |
| 54 | + Windows: |
| 55 | + |
| 56 | + ``` |
| 57 | + %AppData%/Roaming/Cursor/User/workspaceStorage/{workspace_id}/state.vscdb |
| 58 | + ``` |
| 59 | + |
| 60 | + macOS: |
| 61 | + |
| 62 | + ``` |
| 63 | + ~/Library/Application Support/Cursor/User/workspaceStorage/{workspace_id}/state.vscdb |
| 64 | + ``` |
| 65 | + |
| 66 | +2. **Data Structure**: |
| 67 | + - SQLite database (`state.vscdb`) |
| 68 | + - Two key tables: `ItemTable` and `cursorDiskKV` |
| 69 | + - Notepad data stored under two keys: |
| 70 | + - `notepad.reactiveStorageId` |
| 71 | + - `notepadData` |
| 72 | + |
| 73 | +```mermaid |
| 74 | +graph TD |
| 75 | + A[AppData/Roaming/Cursor] --> B[User] |
| 76 | + B --> C[workspaceStorage] |
| 77 | + C --> D[{workspace_id}] |
| 78 | + D --> E[state.vscdb] |
| 79 | + E --> F[ItemTable] |
| 80 | + F --> G[notepad.reactiveStorageId] |
| 81 | + F --> H[notepadData] |
| 82 | +``` |
| 83 | + |
| 84 | +## The Investigation |
| 85 | + |
| 86 | +### 1. Starting Knowledge |
| 87 | + |
| 88 | +First, let's break down what we know about Cursor: |
| 89 | + |
| 90 | +```mermaid |
| 91 | +graph LR |
| 92 | + A[Cursor] --> B[VSCode Fork] |
| 93 | + B --> C[Electron App] |
| 94 | + C --> D[Windows: %AppData%] |
| 95 | + C --> E[macOS: ~/Library/Application Support] |
| 96 | +``` |
| 97 | + |
| 98 | +The key insights: |
| 99 | + |
| 100 | +- Cursor is a VSCode fork |
| 101 | +- VSCode is Electron-based |
| 102 | +- Electron apps follow standard storage patterns |
| 103 | +- Windows apps store user data in `%AppData%` |
| 104 | + |
| 105 | +### 2. Initial Location Search |
| 106 | + |
| 107 | +Armed with this knowledge, our first step was obvious: |
| 108 | + |
| 109 | +```bash |
| 110 | +# Windows |
| 111 | +cd %AppData%/Roaming/Cursor/ |
| 112 | + |
| 113 | +# Look familiar? It should - it's identical to VSCode's structure |
| 114 | +User/ |
| 115 | +├── globalStorage/ # Global application data |
| 116 | +└── workspaceStorage/ # Per-workspace settings |
| 117 | + └── {uuid}/ # Individual workspace data |
| 118 | +``` |
| 119 | + |
| 120 | +### 3. Data Discovery Process |
| 121 | + |
| 122 | +This is where the real detective work began. Our process: |
| 123 | + |
| 124 | +1. **Quick File Analysis** |
| 125 | + - Drop files into text editor |
| 126 | + - Scan JSON files (mostly configuration) |
| 127 | + - Check `.txt` files (logs and metadata) |
| 128 | + - Note any `.db` or `.sqlite` files |
| 129 | + |
| 130 | +2. **Common Storage Patterns** |
| 131 | + |
| 132 | + ```bash |
| 133 | + # Look for database files |
| 134 | + find . -type f -name "*.db" -o -name "*.sqlite" -o -name "*.vscdb" |
| 135 | + |
| 136 | + # Check for JSON storage |
| 137 | + find . -type f -name "state.json" -o -name "storage.json" |
| 138 | + |
| 139 | + # Scan log files for clues |
| 140 | + find . -type f -name "*.log" |
| 141 | + ``` |
| 142 | + |
| 143 | +3. **Grep for Notepad References** |
| 144 | + |
| 145 | + ```bash |
| 146 | + grep -r "notepad" . |
| 147 | + ``` |
| 148 | + |
| 149 | + Found references in: |
| 150 | + - Log files (view initialization) |
| 151 | + - Binary files (`.code` files) |
| 152 | + - SQLite databases |
| 153 | + |
| 154 | +### 4. Database Investigation |
| 155 | + |
| 156 | +The breakthrough came when we found `state.vscdb`: |
| 157 | + |
| 158 | +```sql |
| 159 | +-- First attempt: Look for notepad-related keys |
| 160 | +SELECT * FROM ItemTable |
| 161 | +WHERE key LIKE '%notepad%'; |
| 162 | + |
| 163 | +-- Found our treasure: |
| 164 | +-- 1. notepad.reactiveStorageId |
| 165 | +-- 2. notepadData |
| 166 | +``` |
| 167 | + |
| 168 | +### 5. The "Aha" Moment |
| 169 | + |
| 170 | +Here's where it got interesting. After finding the data: |
| 171 | + |
| 172 | +1. Made an edit to a notepad in the database |
| 173 | +2. Opened Cursor... and all notepads disappeared |
| 174 | +3. **Key Learning**: File permissions matter |
| 175 | + - Database locked by viewer |
| 176 | + - Cursor couldn't access it |
| 177 | + - Close viewer, notepads return |
| 178 | + |
| 179 | +```mermaid |
| 180 | +sequenceDiagram |
| 181 | + participant DB as Database |
| 182 | + participant Viewer as DB Viewer |
| 183 | + participant Cursor as Cursor IDE |
| 184 | + |
| 185 | + Note over DB: Initial State |
| 186 | + Viewer->>DB: Open Connection |
| 187 | + Note over DB: Locked |
| 188 | + Cursor->>DB: Try to Read |
| 189 | + Note over Cursor: Notepads Missing |
| 190 | + Viewer-->>DB: Close Connection |
| 191 | + Note over DB: Unlocked |
| 192 | + Cursor->>DB: Read Success |
| 193 | + Note over Cursor: Notepads Return |
| 194 | +``` |
| 195 | + |
| 196 | +This investigation led to some important principles for our solution: |
| 197 | + |
| 198 | +1. Always check file permissions |
| 199 | +2. Implement proper database locking |
| 200 | +3. Handle connection errors gracefully |
| 201 | +4. Maintain backups (thank you, `.vscdb.backup`) |
| 202 | + |
| 203 | +## Technical Implementation |
| 204 | + |
| 205 | +### 1. Workspace Structure |
| 206 | + |
| 207 | +```typescript |
| 208 | +interface WorkspaceInfo { |
| 209 | + id: string; // Workspace UUID |
| 210 | + folderPath: string; // Absolute path |
| 211 | + dbPath: string; // Path to state.vscdb |
| 212 | +} |
| 213 | +``` |
| 214 | + |
| 215 | +### 2. Notepad Data Model |
| 216 | + |
| 217 | +```typescript |
| 218 | +interface NotepadInfo { |
| 219 | + id: string; |
| 220 | + name: string; |
| 221 | + text: string; |
| 222 | + createdAt: number; |
| 223 | + context: NotepadContext; |
| 224 | + // ... additional metadata |
| 225 | +} |
| 226 | +``` |
| 227 | + |
| 228 | +### 3. Storage Access |
| 229 | + |
| 230 | +```typescript |
| 231 | +class Workspace { |
| 232 | + async get<T>(key: string): Promise<T | null> { |
| 233 | + // Access SQLite database |
| 234 | + } |
| 235 | + |
| 236 | + async set<T>(key: string, value: T): Promise<void> { |
| 237 | + // Update database |
| 238 | + } |
| 239 | +} |
| 240 | +``` |
| 241 | + |
| 242 | +## Building the Solution |
| 243 | + |
| 244 | +### 1. Core Features |
| 245 | + |
| 246 | +- Workspace detection and management |
| 247 | +- SQLite database access |
| 248 | +- Notepad CRUD operations |
| 249 | +- Backup and restore functionality |
| 250 | + |
| 251 | +### 2. Safety Considerations |
| 252 | + |
| 253 | +- Automatic database backups |
| 254 | +- File permission handling |
| 255 | +- Cursor process detection |
| 256 | + |
| 257 | +### 3. User Interface |
| 258 | + |
| 259 | +```typescript |
| 260 | +// Example: Creating a new notepad |
| 261 | +const notepad = await notepadManager.createNotepad({ |
| 262 | + name: "My Notepad", |
| 263 | + text: "Initial content" |
| 264 | +}); |
| 265 | +``` |
| 266 | + |
| 267 | +## Future Improvements |
| 268 | + |
| 269 | +1. **Cross-Platform Support** |
| 270 | + - macOS: `~/Library/Application Support/Cursor` |
| 271 | + - Linux: `~/.config/Cursor` |
| 272 | + |
| 273 | +2. **Enhanced Features** |
| 274 | + - Template management |
| 275 | + - Cloud sync |
| 276 | + - Workspace migration tools |
| 277 | + |
| 278 | +3. **Community Contributions** |
| 279 | + - Template sharing |
| 280 | + - Plugin system |
| 281 | + - Custom storage backends |
| 282 | + |
| 283 | +## Resources |
| 284 | + |
| 285 | +- [Original Forum Discussion](https://forum.cursor.com/t/where-are-notepads-stored/18659/10) |
| 286 | +- [SQLite Documentation](https://www.sqlite.org/docs.html) |
| 287 | +- [Electron Storage Best Practices](https://www.electronjs.org/docs/latest/api/app#appgetpathname) |
0 commit comments