claude-session-sync
English | 简体中文
Make your local Claude Code CLI sessions show up in the sidebar of the Claude desktop app's Code tab, across multiple accounts and organizations. Sessions you archived or deleted in the desktop app are left out automatically. It can also permanently purge archived sessions.
⚠️ Unofficial tool, not affiliated with Anthropic. The desktop app's index format is undocumented and may change with any update. The tool previews by default, refuses to write while the desktop app is running, and every write or deletion can be undone.
Why
Local CLI and desktop sessions share the same transcripts, but each side keeps its own session list:
Desktop sidebar index (one per account/org)
claude-code-sessions/<account-id>/<org-id>/
├─ local_<uuid>.json session index; cliSessionId points to a transcript below
├─ archived-sessions.idx archived sessions (local_ IDs)
└─ deleted_<session-id> marker left when a session is deleted in the desktop app
│
▼
Transcripts (shared by CLI and desktop, account-independent)
~/.claude/projects/<project-dir>/<session-id>.jsonl
▲
└─ `claude --resume` scans these directly
As a result:
- the CLI sees sessions created in the desktop app, but the desktop app doesn't see sessions created in the CLI;
- after switching account or organization, the desktop app reads a different index directory, so the list changes;
- the official import paths (
/desktop,claude --desktop --resume <id>, desktop Help → Import CLI sessions) only import into the current account, and sometimes miss sessions.
This tool adds the missing index files for every account/org so CLI sessions appear in the sidebar. Syncing never modifies any .jsonl transcript; only --purge-archived removes transcripts of archived sessions, and it backs them up first.
Install
Requires Python 3.9+ (the python3 that ships with macOS works). Standard library only, no dependencies.
uv tool install claude-session-sync-cli
Or with pipx:
pipx install claude-session-sync-cli
The PyPI package is named claude-session-sync-cli; the command it installs is claude-session-sync. To install the latest unreleased code instead, use uv tool install git+https://github.com/xushenjie/claude-session-sync.
Or skip installing and run the single file directly — replace claude-session-sync below with python3 cli.py:
curl -LO https://raw.githubusercontent.com/xushenjie/claude-session-sync/main/src/claude_session_sync/cli.py
On Windows, use py instead of python3.
You also need at least one Code session created in the desktop app (any account), which is used as a template. Accounts/orgs that have no sessions yet borrow a template from another account.
Desktop data directories (found automatically):
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude-code-sessions |
| macOS (third-party deployment) | ~/Library/Application Support/Claude-3p/claude-code-sessions |
| Windows | %APPDATA%\Claude\claude-code-sessions |
| Windows (third-party deployment) | %APPDATA%\Claude-3p\… or %LOCALAPPDATA%\Claude-3p\… |
| Windows (Microsoft Store) | %LOCALAPPDATA%\Packages\Claude_*\LocalCache\Roaming\Claude\claude-code-sessions |
| Linux | ~/.config/Claude/claude-code-sessions |
If yours is elsewhere, pass it with --desktop-root.
Quick start
# Full help
claude-session-sync --help
# 1. Preview: list which sessions each account would get, write nothing
claude-session-sync
# 2. Fully quit the desktop app (⌘Q on macOS; closing the window or "restart" is not enough), then write
claude-session-sync --apply
# 3. Reopen the desktop app. If anything looks wrong, undo the last run
claude-session-sync --undo
If it says the desktop app is running, the app is still alive in the menu bar or system tray and nothing was written. Quit it fully and run again (in a terminal it waits for you instead).
In a terminal you can skip step 2: the preview ends with Write now? [y/N]. See Output and interactive use.
Output is in English, or in Chinese when your locale (LC_ALL / LC_MESSAGES / LANG, or the Windows display language) is Chinese. Pass --lang en or --lang zh for a single run, or set CLAUDE_SESSION_SYNC_LANG=en or zh in your shell profile to change it for good without touching your locale.
Output and interactive use
A preview looks like this (made-up data):
CLI sessions: 125 usable · desktop accounts: 3
Accounts
● [work] (66864cb7…/ed1ba056…) existing 149 · to add 2
● [al***@example.com · current CLI login] (…) existing 122 · to add 1
● [b8073c71…/ed1ba056…] existing 119 · to add 0
Sessions to add (2)
+ 2026-11-11 19:16 Fix login redirect ~/work/webapp → all accounts
+ 2026-11-10 09:02 Draft release notes ~/work/docs → work
⚠ Skipped 1 session(s) written in the last 2 minutes (probably still running). Pass --include-recent to sync them anyway.
Plan: add 2 session(s) (3 index file(s) in 2 account(s))
Write now? [y/N]
- Each session is listed once, with the accounts it goes to (
→). Up to 20 are shown;-vlists all of them, plus session IDs and extra statistics.-qprints only the summary and warnings. - Prompts only appear in a terminal. When both input and output are a terminal, the preview ends with
Write now? [y/N]— pressyto write without re-running, or Enter to keep it a preview. If the desktop app is still running, it waits for you to quit it and press Enter. Scripts, pipes, and CI never get a question;--no-inputturns prompts off in a terminal too. -i/--interactiveshows numbered lists of accounts (when more than one has something to add) and sessions to pick from. Press Enter for all, or type1-5,8to pick,!3to leave one out,none, orqto cancel. Sessions you leave out can be remembered in~/.claude-desktop-sync/exclude.txt, which every later run reads automatically; delete a line there to sync that session again.- In a terminal,
--purge-archivedonly deletes after you typeyes, and--undoshows what the last run did and asks first. --jsonprints the plan (and, with--apply, what was written) as JSON for scripts. It never prompts and has no colors.- Colors are used only in a terminal.
NO_COLORis honored;--color always|neveroverrides. If the terminal can't show symbols such as✓or→, ASCII is used instead.
Sync rules
| Case | What happens |
|---|---|
| The session is already in an account's list (archived or not) | Not added to that account again |
The session is archived in any account (isArchived field or archived-sessions.idx) |
Not added to any account. Use --per-account-archive to only consider each account's own archive state |
The session was deleted in the desktop app in any account (deleted_<session-id> marker) |
Not added to any account |
The session is listed via --exclude or --exclude-file |
Not added |
| The transcript was written within the last 2 minutes (probably still running) | Skipped; pass --include-recent to sync it anyway |
| Empty sessions (no user message) or transcripts without a working directory | Skipped |
.jsonl files in subfolders of a project directory (subagents etc.) |
Not scanned |
Each new index file is cloned from an existing desktop session in the same account: only the session ID, cliSessionId, working directory, title, and timestamps are replaced, so the rest matches your current desktop version as closely as possible. Accounts without sessions borrow a template from another account, preferring the same desktop data directory.
Session titles come from, in order: custom title → summary → first user message, truncated to 60 characters.
Running it again is safe; already-synced sessions are skipped.
Permanently purge archived sessions (--purge-archived)
Syncs as usual, then permanently deletes archived sessions across all accounts, the same way deleting them in the desktop app would:
- removes every
local_*.jsonindex pointing to the session, in all accounts; - removes it from
archived-sessions.idx; - writes a
deleted_<session-id>marker in the original account, so future syncs won't bring it back; - removes the CLI's
<session-id>.jsonland the folder of the same name (subagent transcripts etc.).
claude-session-sync --purge-archived # preview what would be deleted
claude-session-sync --purge-archived --apply # do it
- Nothing is erased outright: files are moved to
~/.claude-desktop-sync/trash-<timestamp>/, and--undorestores everything; - purging always covers all accounts, even with
--account, so no account is left with an index pointing to a removed transcript; --exclude,--exclude-file, and--projectapply to purging too — excluded sessions are never deleted;- sessions whose
.jsonlwas modified in the last 2 minutes are always skipped, even with--include-recent; - in a terminal, deletion only happens after you type
yes; anything else keeps the archived sessions and still runs the sync; - backups are not cleaned up automatically; once you're happy, delete
~/.claude-desktop-sync/trash-*yourself.
Options
| Option | Description |
|---|---|
-h, --help |
Show help, examples, and caveats |
-V, --version |
Show the version |
--lang en|zh |
Output language; overrides CLAUDE_SESSION_SYNC_LANG and the locale |
| (no options) | Preview mode |
--apply |
Actually write |
--undo |
Undo the most recent write or deletion |
--show-template |
Print each account's template fields and exit (for troubleshooting) |
--account <account-id> |
Only sync this account. A prefix such as the 8 characters in the output is enough; add /<org-id-prefix> to pick one organization. Repeatable |
--set-alias <id>=<name> |
Give an account a display name (see Account names); an empty name removes it. Repeatable; exits after saving |
--project <string> |
Only handle sessions whose working directory contains this string (sync and purge) |
--exclude <session-id> |
Exclude a session from sync and purge; repeatable |
--exclude-file <file> |
Read excluded session IDs from a file, one per line; text after # is a comment. ~/.claude-desktop-sync/exclude.txt is always read as well |
--include-recent |
Also sync sessions written in the last 2 minutes (possibly still running). They are marked in the output; purging still skips them |
--per-account-archive |
Only exclude sessions archived in the same account |
--purge-archived |
Permanently delete archived sessions after syncing (see above) |
--projects-dir <path> |
CLI sessions directory; defaults to ~/.claude/projects and honors CLAUDE_CONFIG_DIR |
--desktop-root <path> |
Path to a claude-code-sessions directory; repeatable |
--force |
Run --apply or --undo even while the desktop app is running (not recommended; the app may overwrite the changes) |
-i, --interactive |
Pick accounts and sessions from numbered lists before writing (terminal only) |
--no-input |
Never ask questions, even in a terminal |
-q, --quiet |
Only print the summary and warnings |
-v, --verbose |
List every session, with session IDs and extra statistics |
--json |
Print the result as JSON; implies --no-input and no colors |
--color auto|always|never |
Colored output; auto (default) only colors a terminal and honors NO_COLOR |
Examples:
# Sync only the myapp project into one account
claude-session-sync --account 1a2b3c4d-... --project myapp --apply
# Leave out sessions you don't want
claude-session-sync --exclude-file ~/no-sync.txt --apply
A session ID is the file name of a .jsonl under ~/.claude/projects/<project>/. An account ID is a top-level directory name under claude-code-sessions/; the preview shows the first 8 characters, which --account and --set-alias accept as-is.
Account names
The desktop app stores accounts by ID only, so the output shows names where it can find them:
[work · Acme Inc · fan***@example.com · current CLI login] (b8073c71…/677f8bdf…) existing 122, to add 1
[07ac42e2…/00000000…] existing 119, to add 1
- The account the CLI is signed in to is recognized from
~/.claude.json(only the account and organization IDs, email and organization name are read). - Accounts the CLI was signed in to before: every
--applyremembers the current CLI account in~/.claude-desktop-sync/accounts.json, so it keeps its name after you switch. - Any account, with an alias you choose:
claude-session-sync --set-alias b8073c71=work. Use<account>/<org>prefixes to name a single organization.
Emails are always shown masked (fan***@example.com), because this output often ends up in bug reports. Previews never write accounts.json.
Undo and journal
Every --apply records a journal at ~/.claude-desktop-sync/journal-<timestamp>.json (microsecond precision, so back-to-back runs never overwrite each other):
created: files created by this run (index files,deleted_markers);moved: files moved to the backup folder, plus backups ofarchived-sessions.idxtaken before it was rewritten.
--undo deletes the created files, moves backups back into place, and renames the journal to .undone. Run --undo repeatedly to step back through runs, newest first. In a terminal it first shows when the last run happened and how many files it touched, and asks before undoing.
Undo only touches files the tool itself changed, never the desktop app's existing sessions. Like --apply, --undo requires the desktop app to be fully quit.
Upgrade and uninstall
Use the package name claude-session-sync-cli (not the command name) with your installer:
| Installed with | Upgrade | Uninstall |
|---|---|---|
| uv | uv tool upgrade claude-session-sync-cli |
uv tool uninstall claude-session-sync-cli |
| pipx | pipx upgrade claude-session-sync-cli |
pipx uninstall claude-session-sync-cli |
| single file | re-run the curl command from Install |
delete cli.py |
Not sure which one you used? uv tool list or pipx list will show it.
- Upgrading replaces the old version in place; the command name stays the same. Running
uv tool installagain does not upgrade — useupgrade. Journals and backups in~/.claude-desktop-sync/are kept, so--undostill works across upgrades. Runclaude-session-sync --versionto confirm. - Uninstalling removes only the program. Sessions it added to the desktop sidebar and everything in
~/.claude-desktop-sync/stay. To revert those too, quit the desktop app and runclaude-session-sync --undorepeatedly before uninstalling, until it reports nothing left to undo; then delete~/.claude-desktop-sync/if you no longer need the backups and saved account names.
Known limitations
- The index format is inferred from existing files. Archived state is recognized from
isArchived,archived,archivedAt,status: "archived", andarchived-sessions.idx; deletions fromdeleted_<session-id>markers. If a desktop update changes the format,is_archived()orload_markers()need updating. - Templates copy most fields from the original session as-is (e.g.
envScopeId,postTurnSummary). If a session misbehaves after borrowing a template from another account, run--undofirst. - Windows and Linux support is experimental. Development and real-data testing happen on macOS; on Windows and Linux only the automated tests have run, so the desktop data paths and index format there are unverified. Reports (with redacted
--show-templateoutput) are very welcome. - On Windows, the desktop app and a natively installed CLI are both
claude.exe, so the tool tells them apart by install path. If it can't tell, it prints a warning instead of refusing — make sure the desktop app is quit yourself. - Running-app detection on Linux is best effort. There is no official Linux desktop app; the tool only looks for processes named
Claudeorclaude-desktop. Make sure the app is closed yourself. - Cloud sessions are not handled. They live on claude.ai, not in local files.
- Don't type into the same session from the CLI and the desktop app at the same time, or the transcript may get interleaved. Switching back and forth is fine.
- Claude Code keeps transcripts for 30 days by default. To keep them longer, set this in
~/.claude/settings.json:{ "cleanupPeriodDays": 3650 }
FAQ
Sessions still don't show up in the desktop app?
- Check whether the output says the desktop app is running — if so, nothing was written;
- make sure the app was fully quit before writing, and reopen it afterwards;
- make sure the account/org you're signed into is in the output's account list, and its "to add" count isn't 0;
- check whether the session landed in a different project group (e.g. a subdirectory or worktree).
A deleted session came back?
The tool honors the desktop app's deleted_ markers, so this shouldn't happen. If you deleted the .jsonl directly or some other way, exclude it with --exclude.
The desktop app errors when opening a session?
Run --undo first, then open an issue with the output of --show-template (redact paths and titles first).
Want to import a single session the official way?
claude --desktop --resume <session-id>
Contributing
Issues and pull requests are welcome, in English or Chinese. See CONTRIBUTING.md for development setup, tests, commit conventions, and releasing. Please report anything that could lose or leak data privately, as described in SECURITY.md.
License
MIT. Claude is a trademark of Anthropic. This project is not affiliated with Anthropic in any way.
Metadata
Release files for claude-session-sync-cli 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| claude_session_sync_cli-0.3.0.tar.gz | 49.1 kB | With provenance | Details for claude_session_sync_cli-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| claude_session_sync_cli-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for claude_session_sync_cli-0.3.0-py3-none-any.whl |
Total release size: 81.8 kB
Release files / claude_session_sync_cli-0.3.0.tar.gz
| Download URL | claude_session_sync_cli-0.3.0.tar.gz |
|---|---|
| Size | 49.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
215b59f5aa92aa2dd3524ae0d7b9084934c9e7b89938d640d2120b4bd7158ece
|
|
BLAKE2b-256 checksum How to use checksums |
23368e08579166da13fe7a2fe2e3cd1f8cc532ac1bca1da35c1a206910433b6b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logRelease files / claude_session_sync_cli-0.3.0-py3-none-any.whl
| Download URL | claude_session_sync_cli-0.3.0-py3-none-any.whl |
|---|---|
| Size | 32.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3ea1810b29e4052afcd540a3b6d18340be28103d5bc2c8504e5cf80f19356cf2
|
|
BLAKE2b-256 checksum How to use checksums |
03ac13a45d7c6810f80f0f3ced1184194732aa3ea4175ca68666346efa427870
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logSecurity for claude-session-sync-cli 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for claude_session_sync_cli-0.3.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.