A utility to move or copy a project folder (Cursor workspace) together with the Agent history, so that after changing the path the history doesn't "disappear" from the UI.
Based on an observation from a Cursor Community thread: Lost access to 5-7 Agent conversations after workspace folder restructure.
- ✅ Copy/Move workspaces with full chat history preservation
- ✅ Merge chat histories from duplicate workspace storage entries
- ✅ Database lock checking for safe operations
- ✅ Cross-platform support (Windows, macOS, Linux)
- ✅ Interactive TUI for easy usage
- ✅ CLI mode for scripting and automation
- ✅ Workspace diagnostics (doctor command)
- ✅ Automatic backup before risky operations
- ✅ SQLite integrity checks after modifications
- Important (Data Safety)
- Features
- Installation
- Quick Start
- What exactly happens (Mode C)
- Commands
- CLI overview
- Limitations
- Tests
- Documentation
- Contributing
- License
See INSTALL.md for detailed installation instructions.
Quick install from source:
git clone https://github.com/Artemonim/CursorMover.git
cd CursorMover- Close Cursor (or at least close the workspace being operated on) before touching
workspaceStorage. Otherwise,state.vscdbcan be locked or inconsistent. - By default the tool checks for a lock on
state.vscdb(and WAL/SHM files, if present) and aborts if the files are busy. You can bypass the lock check with--unsafe-db/-UnsafeDB(not recommended). copy/movedo not modifystate.vscdbcontents as SQLite by default: they copy/move folders and clone the entireworkspaceStorage/<id>directory, updating onlyworkspace.json(metadata).- If the destination
workspaceStorage/<id>already exists (for example, you opened the new path in Cursor and created new chats there),copy/movecan merge source chat state into the existing destination (interactive prompt or--merge-workspace-storage). This does modify the destinationstate.vscdb(SQLite), runsPRAGMA integrity_check, and writes a backupstate.vscdb.premerge-<timestamp>. mergedoes modifystate.vscdbas SQLite (insert/replace only), runsPRAGMA integrity_check, and writes a backupstate.vscdb.premerge-<timestamp>next to the destination DB.- Still recommended: make a manual backup of the entire
workspaceStorage/<id>folder before experimenting.
Cursor stores workspace data in:
Cursor/User/workspaceStorage/<WORKSPACE_ID>/state.vscdbCursor/User/workspaceStorage/<WORKSPACE_ID>/workspace.json
Where <WORKSPACE_ID> is calculated from the path + file system metadata. On Windows, this is effectively md5(fsPath + birthtimeMs) (see cursor_mover/workspace_id.py).
Mode C:
- copies/moves the project folder;
- calculates the new
<WORKSPACE_ID>for the new path; - copies
workspaceStorage/<old_id>→workspaceStorage/<new_id>; - updates
workspace.jsoninsideworkspaceStorage/<new_id>to the new folder URI.
This is the migration path: use copy / move when you change the workspace folder location on disk.
In rare cases you may end up with multiple workspaceStorage/<id> entries that point to the same folder URI (for example after restores, metadata changes, or manual copying of Cursor user data). The merge command merges chat-related keys from those entries into the current one. Use --delete-sources to delete merged source entries after a successful merge.
Note: merge is not a migration. It does not move/copy your workspace folder and does not change its path. It only consolidates duplicate workspaceStorage state for the same folder URI.
doctor prints how Cursor maps a workspace folder to workspaceStorage/<id>:
- folder URI (
file:///...) used insideworkspaceStorage/*/workspace.json; - workspaceStorage id found by scanning existing
workspace.json; - workspaceStorage id computed from the folder path + filesystem metadata (what Cursor uses);
- the exact inputs used for hashing (fsPath + stat salt);
- lock check for
state.vscdb(+ WAL/SHM if present) when a workspaceStorage entry is found. - warns if multiple
workspaceStorage/<id>entries exist for the same folder URI (and suggestsmerge).
This command is read-only (no modifications).
Simplest run (Windows PowerShell):
.\run.ps1Simplest run (macOS/Linux):
./run.shManual venv activation (Windows PowerShell):
.venv\Scripts\Activate.ps1Important: when launching via python -m cursor_mover / python main.py from a repo checkout, the utility attempts to automatically use .venv and install dependencies from requirements.txt (can be disabled via environment variables CURSOR_MOVER_SKIP_BOOTSTRAP=1 and CURSOR_MOVER_SKIP_INSTALL=1).
Show help:
python -m cursor_mover --helpGlobal option:
--cursor-user-dir: override auto-detected Cursor.../Cursor/Userdirectory.
Interactive TUI (only when stdin/stdout are TTY):
python -m cursor_moverTUI includes copy, move, doctor, and merge.
Note: copy / move / merge require that the workspace folder was opened in Cursor at least once (so it has an existing workspaceStorage/<id> entry). If not, open the folder in Cursor and retry.
- Folder workspaces only (not multi-root
.code-workspacefiles). - Cursor storage format and workspace ID logic can change between versions; treat this as a best-effort utility.
About --dst semantics:
- If
--dstdoes not match the source folder name (--src), then--dstis considered a container and the actual destination will be--dst/<src name>. - If
--dstmatches the source folder name, then the copy/move is performed directly into--dst.
Check (doctor):
python -m cursor_mover doctor --path "G:\GitHub\RUSTDemo"Copy workspace + transfer chats (Mode C):
python -m cursor_mover copy --src "G:\GitHub\RUSTDemo" --dst "T:\Temp\RUSTDemo"Move workspace + transfer chats (Mode C):
python -m cursor_mover move --src "G:\GitHub\RUSTDemo" --dst "T:\Temp\RUSTDemo"Copy/move when destination workspaceStorage already exists (preserve destination chats):
python -m cursor_mover copy --src "G:\GitHub\RUSTDemo" --dst "T:\Temp\RUSTDemo" --merge-workspace-storageUnsafe copy with locked DB (experimental):
python -m cursor_mover copy -UnsafeDB --src "G:\GitHub\RUSTDemo" --dst "T:\Temp\RUSTDemo"Merge chat state from other workspaceStorage entries for the same folder URI (advanced):
python -m cursor_mover merge --path "G:\GitHub\RUSTDemo"python -m unittest -vComprehensive documentation is available:
- Installation Guide - Detailed installation instructions
- Usage Examples - Practical examples and scenarios
- FAQ - Frequently asked questions
- Contributing Guide - How to contribute to the project
- Publishing Guide - Instructions for maintainers
- Security Policy - Security information and reporting
- Changelog - Version history and changes
- Roadmap - Future plans and ideas
- Pre-Release Checklist - Release preparation checklist
Contributions are welcome! Please see CONTRIBUTING.md for details on how to contribute to this project.
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.
See CHANGELOG.md for a list of changes in each version.
If you encounter any issues or have questions:
- Check the existing issues
- Read the documentation
- Open a new issue if needed
- Inspired by the Cursor Community discussion on workspace migration
- Built with Python and love for the developer community
This is a best-effort utility. Cursor's internal storage format and workspace ID logic may change between versions. Always make backups before performing operations on important workspaces.
This project is licensed under the MIT License - see the LICENSE file for details.