claude-session-sync-cli 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ venv/
5
+ build/
6
+ dist/
7
+ *.egg-info/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ .coverage
11
+ htmlcov/
12
+ .DS_Store
13
+ uv.lock
@@ -0,0 +1,23 @@
1
+ # Changelog
2
+
3
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4
+
5
+ ## [Unreleased]
6
+
7
+ ### Fixed
8
+ - Windows: a running Claude Code CLI (`claude.exe`) was mistaken for the desktop app, blocking `--apply` and `--undo`. Processes are now told apart by install path; unknown ones only trigger a warning.
9
+
10
+ ## [0.1.0] - 2026-11-11
11
+
12
+ ### Added
13
+ - Sync CLI sessions into the desktop app sidebar, across multiple accounts and organizations.
14
+ - Honor the desktop app's archived state (`isArchived`, `archived-sessions.idx`) and deletion markers (`deleted_<id>`), so those sessions are never re-added.
15
+ - Borrow a template from another account when an account has no sessions yet.
16
+ - `--purge-archived`: permanently delete archived sessions after syncing, moving files to a backup folder first. Respects `--exclude`, `--exclude-file`, and `--project`, and skips sessions whose transcript was written in the last 2 minutes.
17
+ - `--undo`: revert the most recent write or deletion, including restoring backups.
18
+ - Refuse `--apply` and `--undo` while the desktop app is running (macOS, Windows, best effort on Linux) unless `--force` is given.
19
+ - `--version` and `--help` with examples.
20
+ - English and Chinese output, chosen from the locale; override with `CLAUDE_SESSION_SYNC_LANG=en|zh`.
21
+
22
+ [Unreleased]: https://github.com/xushenjie/claude-session-sync/compare/v0.1.0...HEAD
23
+ [0.1.0]: https://github.com/xushenjie/claude-session-sync/releases/tag/v0.1.0
@@ -0,0 +1,45 @@
1
+ # Contributing
2
+
3
+ Thanks for helping out! Issues and pull requests in English or Chinese are both welcome.
4
+
5
+ ## Development setup
6
+
7
+ Requires [uv](https://docs.astral.sh/uv/).
8
+
9
+ ```bash
10
+ git clone https://github.com/xushenjie/claude-session-sync && cd claude-session-sync
11
+ uv run pytest # tests run in temp dirs and never touch your real data
12
+ uv run ruff check . # lint
13
+ uv run ruff format . # format
14
+ ```
15
+
16
+ The `dev` dependency group in `pyproject.toml` pins the ruff version used by CI.
17
+
18
+ ## Ground rules
19
+
20
+ - **The tool must stay stdlib-only and work as a single file.** README tells users they can `curl` `cli.py` and run it with the system Python, so don't add dependencies or split `cli.py` into modules that it imports.
21
+ - **Keep Python 3.9 compatible** — it's the `python3` that ships with macOS.
22
+ - **User-facing messages go through `t(en, zh)`** so both languages stay in sync. Tests assert on English output by default.
23
+ - **Test data must be hand-written fakes.** Never copy files from your own `claude-code-sessions/` or `~/.claude/projects/`; they contain your paths, prompts, and account IDs.
24
+ - **Anything that writes or deletes must be undoable** via the journal (`--undo`), and must be covered by a test that applies and then undoes it.
25
+ - Changes to the desktop index format detection (`is_archived()`, `load_markers()`, `build_entry()`) should mention the desktop app version you observed the format in.
26
+
27
+ ## Commits and pull requests
28
+
29
+ - Use [Conventional Commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `docs:`, `test:`, `ci:`, `chore:` …
30
+ - Add a line under `## [Unreleased]` in `CHANGELOG.md` for user-visible changes.
31
+ - Make sure `uv run pytest` and `uv run ruff check . && uv run ruff format --check .` pass.
32
+
33
+ ## Releasing (maintainers)
34
+
35
+ 1. Bump `__version__` in `src/claude_session_sync/cli.py`.
36
+ 2. In `CHANGELOG.md`, rename `## [Unreleased]` to `## [x.y.z] - YYYY-MM-DD`, add a fresh `## [Unreleased]`, and update the compare links at the bottom.
37
+ 3. Commit, then tag and push:
38
+
39
+ ```bash
40
+ git tag vX.Y.Z && git push origin vX.Y.Z
41
+ ```
42
+
43
+ The `Release` workflow checks that the tag matches `__version__` and that the changelog has an entry, builds the package, publishes it to PyPI, and creates a GitHub Release with the changelog section as notes.
44
+
45
+ One-time setup before the first release: on PyPI, add a [Trusted Publisher](https://docs.pypi.org/trusted-publishers/adding-a-publisher/) for the `claude-session-sync-cli` project and this repository with workflow `release.yml` and environment `pypi`, and create an environment named `pypi` under the repository's Settings → Environments.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 xushenjie
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,265 @@
1
+ Metadata-Version: 2.5
2
+ Name: claude-session-sync-cli
3
+ Version: 0.1.0
4
+ Summary: Sync local Claude Code CLI sessions into the Claude desktop app sidebar (unofficial).
5
+ Project-URL: Homepage, https://github.com/xushenjie/claude-session-sync
6
+ Project-URL: Issues, https://github.com/xushenjie/claude-session-sync/issues
7
+ Project-URL: Changelog, https://github.com/xushenjie/claude-session-sync/blob/main/CHANGELOG.md
8
+ Author: xushenjie
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: claude,claude-code,cli,sessions,sync
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: Microsoft :: Windows
17
+ Classifier: Operating System :: POSIX :: Linux
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Programming Language :: Python :: 3.9
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Programming Language :: Python :: 3.14
26
+ Classifier: Topic :: Utilities
27
+ Requires-Python: >=3.9
28
+ Description-Content-Type: text/markdown
29
+
30
+ # claude-session-sync
31
+
32
+ **English** | [简体中文](README.zh-CN.md)
33
+
34
+ [![CI](https://github.com/xushenjie/claude-session-sync/actions/workflows/ci.yml/badge.svg)](https://github.com/xushenjie/claude-session-sync/actions/workflows/ci.yml)
35
+
36
+ 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.
37
+
38
+ > ⚠️ **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.
39
+
40
+ ---
41
+
42
+ ## Why
43
+
44
+ Local CLI and desktop sessions share the same transcripts, but **each side keeps its own session list**:
45
+
46
+ ```
47
+ Desktop sidebar index (one per account/org)
48
+ claude-code-sessions/<account-id>/<org-id>/
49
+ ├─ local_<uuid>.json session index; cliSessionId points to a transcript below
50
+ ├─ archived-sessions.idx archived sessions (local_ IDs)
51
+ └─ deleted_<session-id> marker left when a session is deleted in the desktop app
52
+ │
53
+ ▼
54
+ Transcripts (shared by CLI and desktop, account-independent)
55
+ ~/.claude/projects/<project-dir>/<session-id>.jsonl
56
+ ▲
57
+ └─ `claude --resume` scans these directly
58
+ ```
59
+
60
+ As a result:
61
+
62
+ - the CLI sees sessions created in the desktop app, but the desktop app doesn't see sessions created in the CLI;
63
+ - after switching account or organization, the desktop app reads a different index directory, so the list changes;
64
+ - the official import paths (`/desktop`, `claude --desktop --resume <id>`, desktop Help → Import CLI sessions) only import into the current account, and sometimes miss sessions.
65
+
66
+ 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.
67
+
68
+ ---
69
+
70
+ ## Install
71
+
72
+ Requires Python 3.9+ (the `python3` that ships with macOS works). Standard library only, no dependencies.
73
+
74
+ ```bash
75
+ uv tool install claude-session-sync-cli
76
+ ```
77
+
78
+ Or with pipx:
79
+
80
+ ```bash
81
+ pipx install claude-session-sync-cli
82
+ ```
83
+
84
+ 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`.
85
+
86
+ Or skip installing and run the single file directly — replace `claude-session-sync` below with `python3 cli.py`:
87
+
88
+ ```bash
89
+ curl -LO https://raw.githubusercontent.com/xushenjie/claude-session-sync/main/src/claude_session_sync/cli.py
90
+ ```
91
+
92
+ On Windows, use `py` instead of `python3`.
93
+
94
+ 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.
95
+
96
+ Desktop data directories (found automatically):
97
+
98
+ | OS | Path |
99
+ |---|---|
100
+ | macOS | `~/Library/Application Support/Claude/claude-code-sessions` |
101
+ | macOS (third-party deployment) | `~/Library/Application Support/Claude-3p/claude-code-sessions` |
102
+ | Windows | `%APPDATA%\Claude\claude-code-sessions` |
103
+ | Windows (third-party deployment) | `%APPDATA%\Claude-3p\…` or `%LOCALAPPDATA%\Claude-3p\…` |
104
+ | Windows (Microsoft Store) | `%LOCALAPPDATA%\Packages\Claude_*\LocalCache\Roaming\Claude\claude-code-sessions` |
105
+ | Linux | `~/.config/Claude/claude-code-sessions` |
106
+
107
+ If yours is elsewhere, pass it with `--desktop-root`.
108
+
109
+ ---
110
+
111
+ ## Quick start
112
+
113
+ ```bash
114
+ # Full help
115
+ claude-session-sync --help
116
+
117
+ # 1. Preview: list which sessions each account would get, write nothing
118
+ claude-session-sync
119
+
120
+ # 2. Fully quit the desktop app (⌘Q on macOS; closing the window or "restart" is not enough), then write
121
+ claude-session-sync --apply
122
+
123
+ # 3. Reopen the desktop app. If anything looks wrong, undo the last run
124
+ claude-session-sync --undo
125
+ ```
126
+
127
+ > 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.
128
+
129
+ Output is in English, or in Chinese when your locale (`LC_ALL` / `LC_MESSAGES` / `LANG`, or the Windows display language) is Chinese. Set `CLAUDE_SESSION_SYNC_LANG=en` or `zh` to override.
130
+
131
+ ---
132
+
133
+ ## Sync rules
134
+
135
+ | Case | What happens |
136
+ |---|---|
137
+ | The session is already in an account's list (archived or not) | Not added to that account again |
138
+ | 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 |
139
+ | The session was deleted in the desktop app in any account (`deleted_<session-id>` marker) | Not added to any account |
140
+ | The session is listed via `--exclude` or `--exclude-file` | Not added |
141
+ | The transcript was written within the last 2 minutes (probably still running) | Skipped |
142
+ | Empty sessions (no user message) or transcripts without a working directory | Skipped |
143
+ | `.jsonl` files in subfolders of a project directory (subagents etc.) | Not scanned |
144
+
145
+ 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.
146
+
147
+ Session titles come from, in order: custom title → summary → first user message, truncated to 60 characters.
148
+
149
+ Running it again is safe; already-synced sessions are skipped.
150
+
151
+ ---
152
+
153
+ ## Permanently purge archived sessions (`--purge-archived`)
154
+
155
+ Syncs as usual, then permanently deletes **archived sessions across all accounts**, the same way deleting them in the desktop app would:
156
+
157
+ 1. removes every `local_*.json` index pointing to the session, in all accounts;
158
+ 2. removes it from `archived-sessions.idx`;
159
+ 3. writes a `deleted_<session-id>` marker in the original account, so future syncs won't bring it back;
160
+ 4. removes the CLI's `<session-id>.jsonl` and the folder of the same name (subagent transcripts etc.).
161
+
162
+ ```bash
163
+ claude-session-sync --purge-archived # preview what would be deleted
164
+ claude-session-sync --purge-archived --apply # do it
165
+ ```
166
+
167
+ - Nothing is erased outright: files are moved to `~/.claude-desktop-sync/trash-<timestamp>/`, and `--undo` restores everything;
168
+ - purging always covers **all accounts**, even with `--account`, so no account is left with an index pointing to a removed transcript;
169
+ - `--exclude`, `--exclude-file`, and `--project` apply to purging too — excluded sessions are never deleted;
170
+ - sessions whose `.jsonl` was modified in the last 2 minutes are skipped;
171
+ - backups are not cleaned up automatically; once you're happy, delete `~/.claude-desktop-sync/trash-*` yourself.
172
+
173
+ ---
174
+
175
+ ## Options
176
+
177
+ | Option | Description |
178
+ |---|---|
179
+ | `-h`, `--help` | Show help, examples, and caveats |
180
+ | `-V`, `--version` | Show the version |
181
+ | (no options) | Preview mode |
182
+ | `--apply` | Actually write |
183
+ | `--undo` | Undo the most recent write or deletion |
184
+ | `--show-template` | Print each account's template fields and exit (for troubleshooting) |
185
+ | `--account <account-id>` | Only sync this account; repeatable |
186
+ | `--project <string>` | Only handle sessions whose working directory contains this string (sync and purge) |
187
+ | `--exclude <session-id>` | Exclude a session from sync and purge; repeatable |
188
+ | `--exclude-file <file>` | Read excluded session IDs from a file, one per line |
189
+ | `--per-account-archive` | Only exclude sessions archived in the same account |
190
+ | `--purge-archived` | Permanently delete archived sessions after syncing (see above) |
191
+ | `--projects-dir <path>` | CLI sessions directory; defaults to `~/.claude/projects` and honors `CLAUDE_CONFIG_DIR` |
192
+ | `--desktop-root <path>` | Path to a `claude-code-sessions` directory; repeatable |
193
+ | `--force` | Run `--apply` or `--undo` even while the desktop app is running (not recommended; the app may overwrite the changes) |
194
+
195
+ Examples:
196
+
197
+ ```bash
198
+ # Sync only the myapp project into one account
199
+ claude-session-sync --account 1a2b3c4d-... --project myapp --apply
200
+
201
+ # Leave out sessions you don't want
202
+ claude-session-sync --exclude-file ~/no-sync.txt --apply
203
+ ```
204
+
205
+ 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.
206
+
207
+ ---
208
+
209
+ ## Undo and journal
210
+
211
+ Every `--apply` records a journal at `~/.claude-desktop-sync/journal-<timestamp>.json` (microsecond precision, so back-to-back runs never overwrite each other):
212
+
213
+ - `created`: files created by this run (index files, `deleted_` markers);
214
+ - `moved`: files moved to the backup folder, plus backups of `archived-sessions.idx` taken before it was rewritten.
215
+
216
+ `--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.
217
+
218
+ 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.
219
+
220
+ ---
221
+
222
+ ## Known limitations
223
+
224
+ - **The index format is inferred from existing files.** Archived state is recognized from `isArchived`, `archived`, `archivedAt`, `status: "archived"`, and `archived-sessions.idx`; deletions from `deleted_<session-id>` markers. If a desktop update changes the format, `is_archived()` or `load_markers()` need updating.
225
+ - **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 `--undo` first.
226
+ - **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-template` output) are very welcome.
227
+ - **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.
228
+ - **Running-app detection on Linux is best effort.** There is no official Linux desktop app; the tool only looks for processes named `Claude` or `claude-desktop`. Make sure the app is closed yourself.
229
+ - **Cloud sessions are not handled.** They live on claude.ai, not in local files.
230
+ - **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.
231
+ - Claude Code keeps transcripts for 30 days by default. To keep them longer, set this in `~/.claude/settings.json`:
232
+ ```json
233
+ { "cleanupPeriodDays": 3650 }
234
+ ```
235
+
236
+ ---
237
+
238
+ ## FAQ
239
+
240
+ **Sessions still don't show up in the desktop app?**
241
+ 1. Check whether the output says the desktop app is running — if so, nothing was written;
242
+ 2. make sure the app was fully quit before writing, and reopen it afterwards;
243
+ 3. make sure the account/org you're signed into is in the output's account list, and its "to add" count isn't 0;
244
+ 4. check whether the session landed in a different project group (e.g. a subdirectory or worktree).
245
+
246
+ **A deleted session came back?**
247
+ 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`.
248
+
249
+ **The desktop app errors when opening a session?**
250
+ Run `--undo` first, then [open an issue](https://github.com/xushenjie/claude-session-sync/issues/new/choose) with the output of `--show-template` (**redact paths and titles first**).
251
+
252
+ **Want to import a single session the official way?**
253
+ ```bash
254
+ claude --desktop --resume <session-id>
255
+ ```
256
+
257
+ ---
258
+
259
+ ## Contributing
260
+
261
+ Issues and pull requests are welcome, in English or Chinese. See [CONTRIBUTING.md](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](SECURITY.md).
262
+
263
+ ## License
264
+
265
+ [MIT](LICENSE). Claude is a trademark of Anthropic. This project is not affiliated with Anthropic in any way.
@@ -0,0 +1,236 @@
1
+ # claude-session-sync
2
+
3
+ **English** | [简体中文](README.zh-CN.md)
4
+
5
+ [![CI](https://github.com/xushenjie/claude-session-sync/actions/workflows/ci.yml/badge.svg)](https://github.com/xushenjie/claude-session-sync/actions/workflows/ci.yml)
6
+
7
+ 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.
8
+
9
+ > ⚠️ **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.
10
+
11
+ ---
12
+
13
+ ## Why
14
+
15
+ Local CLI and desktop sessions share the same transcripts, but **each side keeps its own session list**:
16
+
17
+ ```
18
+ Desktop sidebar index (one per account/org)
19
+ claude-code-sessions/<account-id>/<org-id>/
20
+ ├─ local_<uuid>.json session index; cliSessionId points to a transcript below
21
+ ├─ archived-sessions.idx archived sessions (local_ IDs)
22
+ └─ deleted_<session-id> marker left when a session is deleted in the desktop app
23
+ │
24
+ ▼
25
+ Transcripts (shared by CLI and desktop, account-independent)
26
+ ~/.claude/projects/<project-dir>/<session-id>.jsonl
27
+ ▲
28
+ └─ `claude --resume` scans these directly
29
+ ```
30
+
31
+ As a result:
32
+
33
+ - the CLI sees sessions created in the desktop app, but the desktop app doesn't see sessions created in the CLI;
34
+ - after switching account or organization, the desktop app reads a different index directory, so the list changes;
35
+ - the official import paths (`/desktop`, `claude --desktop --resume <id>`, desktop Help → Import CLI sessions) only import into the current account, and sometimes miss sessions.
36
+
37
+ 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.
38
+
39
+ ---
40
+
41
+ ## Install
42
+
43
+ Requires Python 3.9+ (the `python3` that ships with macOS works). Standard library only, no dependencies.
44
+
45
+ ```bash
46
+ uv tool install claude-session-sync-cli
47
+ ```
48
+
49
+ Or with pipx:
50
+
51
+ ```bash
52
+ pipx install claude-session-sync-cli
53
+ ```
54
+
55
+ 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`.
56
+
57
+ Or skip installing and run the single file directly — replace `claude-session-sync` below with `python3 cli.py`:
58
+
59
+ ```bash
60
+ curl -LO https://raw.githubusercontent.com/xushenjie/claude-session-sync/main/src/claude_session_sync/cli.py
61
+ ```
62
+
63
+ On Windows, use `py` instead of `python3`.
64
+
65
+ 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.
66
+
67
+ Desktop data directories (found automatically):
68
+
69
+ | OS | Path |
70
+ |---|---|
71
+ | macOS | `~/Library/Application Support/Claude/claude-code-sessions` |
72
+ | macOS (third-party deployment) | `~/Library/Application Support/Claude-3p/claude-code-sessions` |
73
+ | Windows | `%APPDATA%\Claude\claude-code-sessions` |
74
+ | Windows (third-party deployment) | `%APPDATA%\Claude-3p\…` or `%LOCALAPPDATA%\Claude-3p\…` |
75
+ | Windows (Microsoft Store) | `%LOCALAPPDATA%\Packages\Claude_*\LocalCache\Roaming\Claude\claude-code-sessions` |
76
+ | Linux | `~/.config/Claude/claude-code-sessions` |
77
+
78
+ If yours is elsewhere, pass it with `--desktop-root`.
79
+
80
+ ---
81
+
82
+ ## Quick start
83
+
84
+ ```bash
85
+ # Full help
86
+ claude-session-sync --help
87
+
88
+ # 1. Preview: list which sessions each account would get, write nothing
89
+ claude-session-sync
90
+
91
+ # 2. Fully quit the desktop app (⌘Q on macOS; closing the window or "restart" is not enough), then write
92
+ claude-session-sync --apply
93
+
94
+ # 3. Reopen the desktop app. If anything looks wrong, undo the last run
95
+ claude-session-sync --undo
96
+ ```
97
+
98
+ > 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.
99
+
100
+ Output is in English, or in Chinese when your locale (`LC_ALL` / `LC_MESSAGES` / `LANG`, or the Windows display language) is Chinese. Set `CLAUDE_SESSION_SYNC_LANG=en` or `zh` to override.
101
+
102
+ ---
103
+
104
+ ## Sync rules
105
+
106
+ | Case | What happens |
107
+ |---|---|
108
+ | The session is already in an account's list (archived or not) | Not added to that account again |
109
+ | 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 |
110
+ | The session was deleted in the desktop app in any account (`deleted_<session-id>` marker) | Not added to any account |
111
+ | The session is listed via `--exclude` or `--exclude-file` | Not added |
112
+ | The transcript was written within the last 2 minutes (probably still running) | Skipped |
113
+ | Empty sessions (no user message) or transcripts without a working directory | Skipped |
114
+ | `.jsonl` files in subfolders of a project directory (subagents etc.) | Not scanned |
115
+
116
+ 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.
117
+
118
+ Session titles come from, in order: custom title → summary → first user message, truncated to 60 characters.
119
+
120
+ Running it again is safe; already-synced sessions are skipped.
121
+
122
+ ---
123
+
124
+ ## Permanently purge archived sessions (`--purge-archived`)
125
+
126
+ Syncs as usual, then permanently deletes **archived sessions across all accounts**, the same way deleting them in the desktop app would:
127
+
128
+ 1. removes every `local_*.json` index pointing to the session, in all accounts;
129
+ 2. removes it from `archived-sessions.idx`;
130
+ 3. writes a `deleted_<session-id>` marker in the original account, so future syncs won't bring it back;
131
+ 4. removes the CLI's `<session-id>.jsonl` and the folder of the same name (subagent transcripts etc.).
132
+
133
+ ```bash
134
+ claude-session-sync --purge-archived # preview what would be deleted
135
+ claude-session-sync --purge-archived --apply # do it
136
+ ```
137
+
138
+ - Nothing is erased outright: files are moved to `~/.claude-desktop-sync/trash-<timestamp>/`, and `--undo` restores everything;
139
+ - purging always covers **all accounts**, even with `--account`, so no account is left with an index pointing to a removed transcript;
140
+ - `--exclude`, `--exclude-file`, and `--project` apply to purging too — excluded sessions are never deleted;
141
+ - sessions whose `.jsonl` was modified in the last 2 minutes are skipped;
142
+ - backups are not cleaned up automatically; once you're happy, delete `~/.claude-desktop-sync/trash-*` yourself.
143
+
144
+ ---
145
+
146
+ ## Options
147
+
148
+ | Option | Description |
149
+ |---|---|
150
+ | `-h`, `--help` | Show help, examples, and caveats |
151
+ | `-V`, `--version` | Show the version |
152
+ | (no options) | Preview mode |
153
+ | `--apply` | Actually write |
154
+ | `--undo` | Undo the most recent write or deletion |
155
+ | `--show-template` | Print each account's template fields and exit (for troubleshooting) |
156
+ | `--account <account-id>` | Only sync this account; repeatable |
157
+ | `--project <string>` | Only handle sessions whose working directory contains this string (sync and purge) |
158
+ | `--exclude <session-id>` | Exclude a session from sync and purge; repeatable |
159
+ | `--exclude-file <file>` | Read excluded session IDs from a file, one per line |
160
+ | `--per-account-archive` | Only exclude sessions archived in the same account |
161
+ | `--purge-archived` | Permanently delete archived sessions after syncing (see above) |
162
+ | `--projects-dir <path>` | CLI sessions directory; defaults to `~/.claude/projects` and honors `CLAUDE_CONFIG_DIR` |
163
+ | `--desktop-root <path>` | Path to a `claude-code-sessions` directory; repeatable |
164
+ | `--force` | Run `--apply` or `--undo` even while the desktop app is running (not recommended; the app may overwrite the changes) |
165
+
166
+ Examples:
167
+
168
+ ```bash
169
+ # Sync only the myapp project into one account
170
+ claude-session-sync --account 1a2b3c4d-... --project myapp --apply
171
+
172
+ # Leave out sessions you don't want
173
+ claude-session-sync --exclude-file ~/no-sync.txt --apply
174
+ ```
175
+
176
+ 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.
177
+
178
+ ---
179
+
180
+ ## Undo and journal
181
+
182
+ Every `--apply` records a journal at `~/.claude-desktop-sync/journal-<timestamp>.json` (microsecond precision, so back-to-back runs never overwrite each other):
183
+
184
+ - `created`: files created by this run (index files, `deleted_` markers);
185
+ - `moved`: files moved to the backup folder, plus backups of `archived-sessions.idx` taken before it was rewritten.
186
+
187
+ `--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.
188
+
189
+ 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.
190
+
191
+ ---
192
+
193
+ ## Known limitations
194
+
195
+ - **The index format is inferred from existing files.** Archived state is recognized from `isArchived`, `archived`, `archivedAt`, `status: "archived"`, and `archived-sessions.idx`; deletions from `deleted_<session-id>` markers. If a desktop update changes the format, `is_archived()` or `load_markers()` need updating.
196
+ - **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 `--undo` first.
197
+ - **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-template` output) are very welcome.
198
+ - **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.
199
+ - **Running-app detection on Linux is best effort.** There is no official Linux desktop app; the tool only looks for processes named `Claude` or `claude-desktop`. Make sure the app is closed yourself.
200
+ - **Cloud sessions are not handled.** They live on claude.ai, not in local files.
201
+ - **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.
202
+ - Claude Code keeps transcripts for 30 days by default. To keep them longer, set this in `~/.claude/settings.json`:
203
+ ```json
204
+ { "cleanupPeriodDays": 3650 }
205
+ ```
206
+
207
+ ---
208
+
209
+ ## FAQ
210
+
211
+ **Sessions still don't show up in the desktop app?**
212
+ 1. Check whether the output says the desktop app is running — if so, nothing was written;
213
+ 2. make sure the app was fully quit before writing, and reopen it afterwards;
214
+ 3. make sure the account/org you're signed into is in the output's account list, and its "to add" count isn't 0;
215
+ 4. check whether the session landed in a different project group (e.g. a subdirectory or worktree).
216
+
217
+ **A deleted session came back?**
218
+ 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`.
219
+
220
+ **The desktop app errors when opening a session?**
221
+ Run `--undo` first, then [open an issue](https://github.com/xushenjie/claude-session-sync/issues/new/choose) with the output of `--show-template` (**redact paths and titles first**).
222
+
223
+ **Want to import a single session the official way?**
224
+ ```bash
225
+ claude --desktop --resume <session-id>
226
+ ```
227
+
228
+ ---
229
+
230
+ ## Contributing
231
+
232
+ Issues and pull requests are welcome, in English or Chinese. See [CONTRIBUTING.md](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](SECURITY.md).
233
+
234
+ ## License
235
+
236
+ [MIT](LICENSE). Claude is a trademark of Anthropic. This project is not affiliated with Anthropic in any way.