Local Cursor chat summary indexer and search tool
Project description
Curlens
Search and resume your Cursor CLI chat sessions by description.
The Problem
You use Cursor CLI across multiple projects. After a few days, you have dozens of chats scattered across different workspaces. You remember discussing "flink job optimization" somewhere, but:
- Which folder was it in?
- What was the chat called?
- How do you resume it?
Cursor stores all chats internally like this:
~/.cursor/chats/
├── a14702e33628716ed.../ # MD5 hash of workspace path (not human-readable!)
│ ├── 8616c508-cbce.../ # Chat UUID
│ │ └── store.db # Messages stored in SQLite
│ └── 2134a03e-7cdb.../
├── 1dd0fd26bc4627ee.../ # Another workspace hash
│ └── ...
└── (dozens more)
This is Cursor's internal structure—not your project folders. The hash a14702e33628... is actually MD5("/Users/you/workspace/myproject"). There's no easy way to:
- Know which workspace a hash folder belongs to
- Search chat contents without opening each
store.db - Find the right chat to resume with
cursor agent --resume <id>
The Solution
Curlens indexes your chats with AI-generated summaries and lets you search by description:
$ curlens -d "flink optimization"
Found 2 matching chat(s):
[1] Flink Job Tuning
Dir: /Users/you/workspace/data-pipeline
Optimized Flink checkpointing and parallelism settings for better throughput...
[2] Stream Processing Debug
Dir: /Users/you/workspace/analytics
Fixed watermark issues in Flink streaming job...
Select chat [1-2]: 1
→ Resuming: Flink Job Tuning
→ Directory: /Users/you/workspace/data-pipeline
How It Works
┌─────────────────────────────────────────────────────────────────┐
│ CURSOR CLI │
│ cursor agent (shell commands, file edits, MCP calls) │
└─────────────────────┬───────────────────────────────────────────┘
│ hooks fire
▼
┌─────────────────────────────────────────────────────────────────┐
│ CURLENS HOOK │
│ 1. Read chat messages from ~/.cursor/chats/<hash>/<id>/ │
│ 2. Extract user queries + assistant responses │
│ 3. Generate summary via LLM (cursor agent -p) │
│ 4. Store in ~/.cursor/curlens/summary.db │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ CURLENS SEARCH │
│ curlens -d "your query" │
│ 1. Load summaries from SQLite │
│ 2. Rank by keyword match (or LLM with --smart) │
│ 3. Display top results │
│ 4. Resume selected chat with cursor agent --resume │
└─────────────────────────────────────────────────────────────────┘
Cursor's Internal Structure
Curlens reads from Cursor's internal storage:
~/.cursor/
├── chats/
│ └── <md5(workspace_path)>/ # Hash of workspace path
│ └── <conversation_id>/
│ └── store.db # SQLite with chat messages
├── projects/
│ └── Users-you-workspace-myproject/ # Encoded workspace path
│ └── worker.log # Contains workspace mapping
└── curlens/ # Created by curlens
├── config.json
├── summary.db
└── hook.log
The hash folders in chats/ are MD5 hashes of workspace paths. Curlens maps them back using the projects/ folder names.
Install
git clone https://github.com/you/curlens
cd curlens
pip install -e .
Quick Start
1. Backfill Existing Chats (Do This First)
Index your existing chats before setting up hooks:
# Preview what will be processed
curlens --backfill --dry-run
# Process all chats (creates DB automatically)
curlens --backfill
# Or process in batches
curlens --backfill --limit 50
This scans ~/.cursor/chats/, generates summaries, and stores them. Chats with unknown workspace paths are skipped.
⚠️ Backfill is slow - Each chat requires an LLM call (~10-30 seconds). For 100+ chats, expect 30-60 minutes. Use
--limitto process in batches. Already-processed chats are skipped on re-runs.
2. Setup Hooks (For Auto-Indexing)
Hooks automatically update summaries as you chat. Without hooks, you'd need to re-run backfill manually.
Create/edit ~/.cursor/hooks.json:
{
"version": 1,
"hooks": {
"afterShellExecution": [
{"command": "python3 /path/to/curlens/curlens/hooks/session_end.py"}
],
"afterMCPExecution": [
{"command": "python3 /path/to/curlens/curlens/hooks/session_end.py"}
],
"afterFileEdit": [
{"command": "python3 /path/to/curlens/curlens/hooks/session_end.py"}
]
}
}
Important: Replace /path/to/curlens with your actual install path.
Why these hooks?
afterShellExecution- Fires after terminal commandsafterMCPExecution- Fires after MCP tool callsafterFileEdit- Fires after file modifications
These are the only hooks that work reliably with Cursor CLI.
3. Search & Resume
# Basic search (fast, keyword-based)
curlens -d "configuring nvim"
# Smart search (LLM-ranked, slower but smarter)
curlens -d "kubernetes deployment issue" --smart
Config
~/.cursor/curlens/config.json (created automatically):
{
"summary_model": "grok",
"search_model": "grok",
"summary_max_words": 70,
"search_window_days": 20,
"hooks_enabled": true,
"debug": false
}
| Key | Description |
|---|---|
summary_model |
Model for generating summaries |
search_model |
Model for --smart ranking |
summary_max_words |
Max words per summary |
search_window_days |
How far back to search |
hooks_enabled |
Enable/disable hook processing |
debug |
Log to ~/.cursor/curlens/hook.log |
Cost Considerations
Curlens uses cursor agent -p to generate summaries, which consumes API tokens from your Cursor subscription.
Estimated usage per chat:
- Summary generation: ~500-1000 tokens
- Smart search (optional): ~200 tokens per search
To minimize costs:
-
Use a cheaper/faster model in config:
{"summary_model": "grok", "search_model": "grok"}
-
Skip smart search - Default search uses keyword matching (free):
curlens -d "query" # Free (keyword match) curlens -d "query" --smart # Uses LLM tokens
-
Use self-hosted models - If you have Ollama or similar:
{"summary_model": "ollama/llama3", "search_model": "ollama/llama3"}
(Requires Cursor to be configured with your local model endpoint)
-
Backfill in batches to control spend:
curlens --backfill --limit 20 # Process 20 at a time
Note: Hooks fire frequently during active chats. Each hook only processes new messages incrementally, so repeated summaries for the same chat are efficient updates, not full regenerations.
CLI-Only
This tool is designed for Cursor CLI (cursor agent). IDE-originated chats are automatically skipped.
Tested on: Cursor CLI version 2026.01.23-6b6776e
cursor agent --version # Check your version
Troubleshooting
No chats found?
- Run
curlens --backfill --dry-runto check discovery - Ensure hooks are configured correctly
Debug mode:
{"debug": true}
Check ~/.cursor/curlens/hook.log for hook events.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file curlens-0.1.0.tar.gz.
File metadata
- Download URL: curlens-0.1.0.tar.gz
- Upload date:
- Size: 21.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
207ace3dcd8bbdbfa84415197af1bc736eb5ae1be4ef89b22bd01eda20970197
|
|
| MD5 |
b8dd65f6e9631fdcb5fdb66890ace616
|
|
| BLAKE2b-256 |
64ee3aa24525a8b017c863f47b081bf7ff6713eaff55e2f4c8ae186236c94d65
|
File details
Details for the file curlens-0.1.0-py3-none-any.whl.
File metadata
- Download URL: curlens-0.1.0-py3-none-any.whl
- Upload date:
- Size: 19.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dc171dc8c8767263f65f8b6530d1342bda3f612bd64dcff8380023d902d6d9d3
|
|
| MD5 |
cc70fbbc5eb99c5e64bf59c2be8551e4
|
|
| BLAKE2b-256 |
0f33572379795e0b1ac0c0212a530ee88b972fb09102b77d2d1a359d78c584e9
|