claude-code-sessions 0.9.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.
Files changed (27) hide show
  1. claude_code_sessions-0.9.0/LICENSE +21 -0
  2. claude_code_sessions-0.9.0/PKG-INFO +372 -0
  3. claude_code_sessions-0.9.0/README.md +342 -0
  4. claude_code_sessions-0.9.0/claude_code_sessions.egg-info/PKG-INFO +372 -0
  5. claude_code_sessions-0.9.0/claude_code_sessions.egg-info/SOURCES.txt +25 -0
  6. claude_code_sessions-0.9.0/claude_code_sessions.egg-info/dependency_links.txt +1 -0
  7. claude_code_sessions-0.9.0/claude_code_sessions.egg-info/entry_points.txt +3 -0
  8. claude_code_sessions-0.9.0/claude_code_sessions.egg-info/top_level.txt +1 -0
  9. claude_code_sessions-0.9.0/claude_code_sessions.py +3443 -0
  10. claude_code_sessions-0.9.0/pyproject.toml +42 -0
  11. claude_code_sessions-0.9.0/setup.cfg +4 -0
  12. claude_code_sessions-0.9.0/tests/test_cli.py +172 -0
  13. claude_code_sessions-0.9.0/tests/test_commands.py +238 -0
  14. claude_code_sessions-0.9.0/tests/test_containment.py +71 -0
  15. claude_code_sessions-0.9.0/tests/test_discovery.py +48 -0
  16. claude_code_sessions-0.9.0/tests/test_encoding.py +41 -0
  17. claude_code_sessions-0.9.0/tests/test_engine.py +274 -0
  18. claude_code_sessions-0.9.0/tests/test_golden.py +18 -0
  19. claude_code_sessions-0.9.0/tests/test_helpers.py +39 -0
  20. claude_code_sessions-0.9.0/tests/test_journal.py +87 -0
  21. claude_code_sessions-0.9.0/tests/test_plan_move.py +400 -0
  22. claude_code_sessions-0.9.0/tests/test_recover.py +400 -0
  23. claude_code_sessions-0.9.0/tests/test_rows.py +73 -0
  24. claude_code_sessions-0.9.0/tests/test_scaffold.py +18 -0
  25. claude_code_sessions-0.9.0/tests/test_sync.py +2322 -0
  26. claude_code_sessions-0.9.0/tests/test_transcripts.py +24 -0
  27. claude_code_sessions-0.9.0/tests/test_undo.py +298 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Craig Stoller
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,372 @@
1
+ Metadata-Version: 2.4
2
+ Name: claude-code-sessions
3
+ Version: 0.9.0
4
+ Summary: Unofficial CLI for Claude Code sessions on disk: make a session visible under your other Claude account on the same machine, or move one between project folders. Journaled, reversible, fails closed.
5
+ Author: Craig Stoller
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/craigstoller/claude-code-sessions
8
+ Project-URL: Issues, https://github.com/craigstoller/claude-code-sessions/issues
9
+ Project-URL: Companion post, https://github.com/craigstoller/claude-code-sessions/blob/main/docs/the-session-that-synced-itself.md
10
+ Keywords: claude,claude-code,claude-desktop,sessions,session,sync,move,cli,anthropic
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: Microsoft :: Windows
16
+ Classifier: Operating System :: MacOS
17
+ Classifier: Operating System :: POSIX :: Linux
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
25
+ Classifier: Topic :: Utilities
26
+ Requires-Python: >=3.9
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Dynamic: license-file
30
+
31
+ # claude-code-sessions
32
+
33
+ See your Claude Code sessions under your other Claude account on the same machine — and move
34
+ sessions between project folders. Journaled, reversible, fails closed.
35
+
36
+ > **Unofficial.** Not affiliated with Anthropic. Reverse-engineered on-disk formats; fails
37
+ > closed when it sees anything it doesn't recognize.
38
+ >
39
+ > **Not to be confused with** `claude-code-sessions\` — the folder *Claude Desktop* keeps your
40
+ > per-account session list in, which this tool reads. This tool's own bookkeeping lives in
41
+ > `~/.claude-code-journal/` and is safe to delete.
42
+
43
+ **Companion read:** [The session that synced itself](https://github.com/craigstoller/claude-code-sessions/blob/main/docs/the-session-that-synced-itself.md)
44
+ — what Claude Desktop actually keeps on disk, and why this tool is built out of refusals.
45
+
46
+ ## The problem
47
+
48
+ **Claude Desktop files its session list per account.** Switch logins and the sessions you
49
+ started under the other one disappear from the sidebar. They are not gone: the conversation
50
+ itself is a single shared file carrying no account identity at all, sitting untouched on your
51
+ disk. Only the *listing row* — the sidebar entry pointing at it — is private to each login, and
52
+ the app reads only the folder belonging to the account you are signed into right now. `sync`
53
+ copies that row into your other account's store, so the session shows up there too.
54
+
55
+ **Separately, every session is filed under the directory it was started in**, and there is no
56
+ official way to move one afterwards — a session begun in the wrong folder is stuck there.
57
+ `move` relocates the transcript and every listing row that points at it, verifying each side
58
+ before touching the other, so the session reopens cleanly in its new home.
59
+
60
+ ## Install
61
+
62
+ ```
63
+ pipx install claude-code-sessions
64
+ ```
65
+
66
+ This installs two identical commands: `claude-code-sessions`, and `ccs` as a shorter
67
+ alias for everyday use. Examples below use the long form; `ccs doctor` is the same
68
+ thing.
69
+
70
+ Or download `claude_code_sessions.py` and run it directly — the runtime has no dependencies beyond
71
+ the Python 3.9+ standard library:
72
+
73
+ ```
74
+ python claude_code_sessions.py --help
75
+ ```
76
+
77
+ ## Before any move: close the Claude app.
78
+
79
+ `move`, `undo`, `recover`, and every mutating `sync` route (`--apply`, `undo` of a completed
80
+ sync, `recover --back` on a stuck one) all refuse while they can see the Claude desktop app
81
+ running — whoever the identity files currently say is signed in. Closing the app first avoids
82
+ the refusal and guarantees nothing is actively appending to the sidebar rows you're about to
83
+ touch. A running Claude Code CLI session does **not** count: it's recognised by its own
84
+ install path and excluded from the check, so an open `claude` session never blocks any of this.
85
+ (For `move` specifically, a running CLI session *can* still be writing the transcript being
86
+ relocated — the transcript-freshness check and the last-instant content re-verification cover
87
+ that case; see Safety design.)
88
+ If `~/.claude.json` (the CLI's identity file) and the desktop app's `config.json` disagree
89
+ about which account is signed in, `sync` refuses to even plan — re-authenticate the CLI (run
90
+ `claude`, then `/login`) as the account you use, or switch the desktop app to it, so the two
91
+ files agree. Signing into the desktop app does **not** refresh `~/.claude.json`. A refused
92
+ `sync --apply` (desktop app running) refuses **before anything is journaled** — no lock file,
93
+ no op directory — so there's nothing left behind for `doctor` to flag or `recover` to clean up;
94
+ just close the app and re-run. One measured wrinkle: the desktop ships a helper for its Chrome
95
+ extension (`chrome-native-host.exe`) that can outlive the app itself, and the guard counts it —
96
+ if a refusal names that process, fully exit Chrome too (the refusal always names what it saw).
97
+
98
+ ## Usage
99
+
100
+ Six commands. All mutating commands default to a dry run; add `--apply` to execute.
101
+
102
+ **`list`** — inventory sessions, optionally filtered by a search term:
103
+
104
+ ```
105
+ claude-code-sessions list gate
106
+ ```
107
+
108
+ **`doctor`** — read-only health report (stale locks, unresolved operations, orphaned rows,
109
+ encoding-scheme ambiguity):
110
+
111
+ ```
112
+ claude-code-sessions doctor
113
+ ```
114
+
115
+ **`move`** — relocate a session to another project folder:
116
+
117
+ ```
118
+ claude-code-sessions move 3c3c3eae-0e2f-4be4-9fba-407f06816f79 "C:\path\to\project" --apply
119
+ ```
120
+
121
+ Get the full id from `claude-code-sessions list --full`.
122
+
123
+ **`undo`** — reverse the most recent completed operation:
124
+
125
+ ```
126
+ claude-code-sessions undo --apply
127
+ ```
128
+
129
+ **`recover`** — resolve an operation left non-terminal by a crash or interruption:
130
+
131
+ ```
132
+ claude-code-sessions recover
133
+ ```
134
+
135
+ **`sync`** — copy a session's sidebar **listing row** from your signed-in account into your
136
+ *other* Claude account's store on this machine, so it shows up in that account's sidebar too:
137
+
138
+ ```
139
+ claude-code-sessions sync --apply
140
+ ```
141
+
142
+ There is only one copy of the conversation itself — shared, and carrying no account identity —
143
+ so a synced session opens and resumes normally under the other account. Without `--to`, the
144
+ destination must be unambiguous: exactly one other account store on the machine, or `--to
145
+ <substring>` naming one of several by its account id, org id, **store path**, or — when it can be
146
+ recovered, see below — its email. The path is matchable because ids alone are not
147
+ always enough — Windows exposes two store roots (the MSIX package path and the classic
148
+ `%APPDATA%\Claude` path), and a machine that migrated between installers can hold the same
149
+ account under both, in which case the path is the only thing that tells the two copies apart.
150
+ Both "which store did you mean" refusals print the full path beside each candidate. `sync` refuses outright if it
151
+ cannot tell which account is signed in — either because neither `~/.claude.json` nor
152
+ `config.json` names one, or because the two disagree about which account it is. `--to`
153
+ cannot substitute for that: it only narrows *which* dormant store to use, and if we don't know
154
+ which account is live we cannot verify the one you named isn't it. A disagreement prints both
155
+ files' 8-character id prefixes; the fix is to re-authenticate the CLI (run `claude`, then
156
+ `/login`) as the account you're using, or switch the desktop app to that account, so the two
157
+ files agree.
158
+
159
+ `--json` prints the plan by itself, the same as the default dry run. Combined with `--apply` it
160
+ runs first and describes what actually happened instead — real `written` flags per row and a
161
+ `result` key, not the plan it would have executed. Automation that assumes `sync --json` output
162
+ is always a preview will misread `sync --apply --json`.
163
+
164
+ - **Sessions you deleted in the destination stay deleted.** The app writes a small record
165
+ (`deleted_<id>`) when you delete a session but does not consult it when a row for that session
166
+ reappears elsewhere — confirmed by restoring a deleted row alongside its own record and
167
+ reopening the app, which showed the session again. `sync` reads the *destination's* records and
168
+ skips any source session they cover, and names each skip in its report (`kept deleted: …`).
169
+ `--include-deleted "<title-or-id>"` overrides the skip for **one** named session; it never
170
+ applies to a whole run. The name must resolve unambiguously — a full id, or a title
171
+ substring matching exactly one deleted session. (The app files a deletion under its
172
+ session id *or* under its local id, and `sync` honours both, so either id works here.) A substring that hits several is a refusal
173
+ listing the candidates, not a silent multi-resurrection. Anything it does resurrect is printed
174
+ under a `!! RESURRECTING …` heading *before* the list of rows to copy, and flagged again in
175
+ that list, so bringing back a session you deliberately deleted is never something the command
176
+ does quietly.
177
+ - **Connector config and permission grants are not copied by default.** A row can carry a full
178
+ snapshot of the account's connected MCP servers; across 432 real rows on this machine that
179
+ field ran as large as 1.36 MB in a single row and totalled 289 MB. Stripping it is verified
180
+ safe: on a real row it cut 132,264 bytes to 715 (99.5% smaller) with the sidebar entry,
181
+ history, responses, and connectors all working normally afterward, under the account that owned
182
+ them. That proves the *app* tolerates the field's absence — it does not prove the *destination
183
+ account* has the same connectors configured. A session that relies on one opens fine either way
184
+ and fails at its first tool call if the integration isn't set up there too; set it up in the
185
+ destination account. The default transform also **resets the row's permission state**
186
+ (`alwaysAllowedReasons`, `sessionPermissionUpdates`, `chromePermissionMode`,
187
+ `chromeTabGroupId`) to its defaults: a permission you granted under one login was never granted
188
+ under the other, and the worst case of resetting it is a re-prompt.
189
+ `--verbatim` skips the whole transform — it copies connector config **and those permission
190
+ grants** across the account boundary unchanged. The permission half is the more
191
+ security-relevant of the two: use `--verbatim` only when you actually want the second account
192
+ to inherit what the first one had allowed.
193
+ - **It needs the app closed too, the same as `move`, `undo`, and `recover` — regardless of which
194
+ file resolved the signed-in account.** `sync` only ever writes the store you are *not* signed
195
+ into, and re-checks that at the moment it writes, not just when it planned; that re-check
196
+ catches an account *switch* between planning and writing, but it is the same determination run
197
+ again, not an independent second opinion. An earlier version of this tool trusted
198
+ `~/.claude.json`'s `oauthAccount` enough to skip the running-app check whenever that file
199
+ named an account outright. A real desktop account switch measured `oauthAccount` staying
200
+ *stale* while `config.json`'s `lastKnownAccountUuid` tracked the switch — the opposite of the
201
+ trust ordering that exemption assumed — and a review had already constructed the reverse
202
+ (`config.json` stale, `oauthAccount` fresh) in a synthetic store: either identity file can be the stale one, and
203
+ neither is trusted to certify "the destination is dormant" while the app is running. `--apply`,
204
+ `undo`, and `recover --back` on a sync op therefore all refuse whenever the Claude desktop app
205
+ is visible, whoever the files say is signed in. The dry run still labels a source resolved from
206
+ `config.json` rather than `oauthAccount` (`from (from config.json)`, plus a warning line) —
207
+ that's a provenance note now, not a stronger/weaker gate: the guard applies the same way either
208
+ side. A running Claude Code CLI session does not trip it — only the desktop app does. Closing
209
+ the desktop app removes the check; signing *into* it does not, since the check is about
210
+ whether its process is running, not which account it's signed into.
211
+ - **The destination's email is best-effort.** `~/.claude.json` names only the account you are
212
+ signed into, so for the *other* account `sync` looks in the per-account Claude Code config the
213
+ desktop app leaves inside its local-agent-mode sandbox
214
+ (`local-agent-mode-sessions\<accountUuid>\…\.claude\.claude.json`), and uses its email only if
215
+ the account id inside matches. That directory exists only for an account that has used local
216
+ agent mode, so it is not always there — when it isn't, the dry run prints `(email unknown)`.
217
+ Either way both endpoints also print their account/org id prefix and their full store path, so
218
+ you always have a physical folder to recognise: the home directory becomes `~` and each id is
219
+ truncated to 8 characters (e.g. `~\AppData\...\claude-code-sessions\aaaaaaaa…\bbbbbbbb…`)
220
+ unless you pass `--verbose` for the paths and ids in full. Check the path, not just the email,
221
+ before `--apply`.
222
+ - A synced row is a **snapshot**: title and last-activity time live in the row itself, so a
223
+ session you keep using shows its copy-time title and sits at its copy-time position in the
224
+ other account, indefinitely. Re-running does not refresh it — `sync` only ever adds rows that
225
+ are missing, never rewrites one that's already there. Refreshing a stale row (`--update`) is
226
+ planned but not yet built.
227
+ - **"Already there" is decided by filename, not by conversation.** A row counts as present in the
228
+ destination when a file of the *same name* (`local_<appSessionId>.json`) exists there. That is
229
+ exactly right for rows `sync` itself copied, since it copies the name along with the contents.
230
+ But a destination row pointing at the same conversation under a *different* local id — one
231
+ placed by an earlier hand-run script, say — is not detected, and `sync` would add a second row
232
+ for the same session, showing it twice in that account's sidebar. Deleting the duplicate in the
233
+ app is enough to fix it.
234
+ - Sign into the other account (or restart the app) to see the results.
235
+
236
+ ## Safety design
237
+
238
+ - **Dry-run by default.** Every mutating command prints its plan and does nothing until you
239
+ pass `--apply`.
240
+ - **Journaled copy-verify-commit-delete.** A move journals its complete intended state before
241
+ touching anything, copies to the destination, re-verifies the copy by hash, rewrites listing
242
+ rows atomically, re-verifies both sides one last time, and only then deletes the source.
243
+ Nothing is ever deleted while it is the only copy.
244
+ - **`undo`** reverses the most recent completed move or sync by running the same journaled
245
+ protocol in reverse (for a sync, that means deleting exactly the rows the op wrote, and only
246
+ while they still match what was written).
247
+ - **`recover`** classifies and resolves any operation a crash or interruption left in a
248
+ non-terminal state — nothing is left stranded.
249
+ - **`sync`** only ever writes rows into the store of the account you are *not* currently signed
250
+ into, re-verifying that at the moment it writes as well as when it planned. It refuses outright
251
+ if it cannot identify which account is signed in at all, or if `~/.claude.json` and
252
+ `config.json` disagree about which account that is: `--to` names a destination, but without a
253
+ confirmed, unambiguous live account there is nothing to check that destination against. Every
254
+ sync mutation — `--apply`, `undo`, and `recover --back` on a sync op — also refuses while it can
255
+ see the Claude desktop app running, the same guard `move`/`undo`/`recover` use, applied
256
+ regardless of which identity file resolved the signed-in account: staleness has been shown in
257
+ both directions (`oauthAccount` measured stale across a real account switch; `config.json`
258
+ stale in a review-constructed store), so no file evidence is trusted to certify the
259
+ destination is dormant while the app is visible. A running Claude Code CLI does not count
260
+ toward this — only the desktop app does.
261
+ - **Refusal philosophy.** The tool fails closed: an unrecognized on-disk layout, an unreadable
262
+ row, an ambiguous encoding scheme, or a running Claude process is a refusal, not a guess.
263
+ "Couldn't look" is never treated as "nothing there."
264
+
265
+ ## Compatibility matrix
266
+
267
+ | Platform | Status | Mutations |
268
+ |---|---|---|
269
+ | Windows 11 + Claude Desktop | verified 2026-07-31; sync end-to-end incl. live continuation 2026-08-03; sync-undo drift refusal live 2026-08-04 | read-only + mutations |
270
+ | macOS / Linux desktop | unverified | **read-only only** — desktop-store mutations refuse, with no override |
271
+ | CLI-only sessions (any OS) | transcript layout verified | mutations allowed via `--transcript-only` |
272
+
273
+ The dates are measurements against specific builds — most recently Claude Desktop
274
+ 1.24012.11.0 (Microsoft Store install) and Claude Code CLI 2.1.220. The on-disk format has
275
+ changed once already during this tool's own development; treat a much newer build as
276
+ unverified territory.
277
+
278
+ **On non-Windows, `move` and every `sync` route refuse to touch the desktop store, and there
279
+ is no flag to override that.** The layout is confirmed on Windows only; macOS reportedly has
280
+ two candidate layouts — the ordinary Application Support path and a sandboxed
281
+ `~/Library/Containers/…` one — and neither has been confirmed here. An override would let you
282
+ waive a risk you have no way to evaluate, which is the opposite of how every other refusal in
283
+ this tool works.
284
+
285
+ What *does* work there: `list` and `doctor`, which are read-only, and `move` for a session
286
+ that has **no desktop listing row** — a CLI-created one — via `--transcript-only`, because the
287
+ transcript layout is verified cross-platform. (Note `--transcript-only` does not force that
288
+ mode; it permits it when no row exists. A session that *has* a desktop row is not movable on
289
+ an unverified platform.)
290
+
291
+ **If you're on macOS and want this supported:** `claude-code-sessions doctor --verbose` output
292
+ in an issue is exactly what's needed. It's read-only, mutates nothing, and it reports the store
293
+ roots found and the layout recognised — which is the whole of what's missing.
294
+
295
+ The Windows row is an end-to-end check on a real store, not just a passing test suite:
296
+ a disposable session was moved between projects, the app was restarted and the session
297
+ resumed at its new location, `undo` correctly **refused** once that resume had appended
298
+ to the transcript (rather than discarding the new messages), and a deliberately
299
+ interrupted move was resolved in both directions with `recover`. Afterwards `doctor`
300
+ reported no new findings and the journal held no unresolved operations.
301
+
302
+ `sync`'s underlying mechanics were checked against two real, live accounts on this machine before
303
+ the command existed: rows copied by hand between them and confirmed visible in the destination's
304
+ sidebar, and — separately — a deleted session's row restored alongside its own deletion record and
305
+ confirmed visible again, which is the finding that makes `sync`'s tombstone-skipping mandatory
306
+ (see `docs/internals.md`). The `sync` command itself is covered by its test suite and, as of
307
+ 2026-08-02, its own end-to-end `--apply` run against two real, live accounts: a row synced from
308
+ one account opened in the other with its full conversation history intact. That run did not send
309
+ a new turn through the synced row; a second verification on 2026-08-03 closed that gap — a live
310
+ session's own listing row was synced across accounts and the conversation was then continued
311
+ from the destination account's sidebar, new turns flowing through the synced row. And on
312
+ 2026-08-04, `undo` of a synced row the destination account had since opened was refused on
313
+ real data: the row no longer matched what the op journaled, so the drift refusal declined
314
+ to delete it — exactly the designed behavior.
315
+
316
+ ## What's stored locally
317
+
318
+ `~/.claude-code-journal/` holds the tool's own bookkeeping, never your conversation content:
319
+
320
+ - `ops/<op-id>/manifest.json` — the journal for each move/undo/recover/sync operation (paths,
321
+ hashes, row pre-images, phase history). Rotated: the 10 most recent terminal operations are
322
+ kept, non-terminal ones never pruned automatically.
323
+ - `ops/lock` — a single-instance lock held for the duration of a mutation.
324
+ - `moved-log.jsonl` — a tiny, append-only, never-rotated record of completed moves (session id,
325
+ from-path, to-path, date), used to recognize your own past moves during future collision and
326
+ encoding-evidence checks.
327
+
328
+ To purge everything the tool has ever written, delete the whole `~/.claude-code-journal/` directory.
329
+ This does not touch any transcript or listing row — only the tool's own journal.
330
+
331
+ **`--json` output is not redacted.** Plain-text output replaces your home directory with `~`
332
+ and truncates any UUID-shaped identifier (session ids, org/account ids in store paths) to its
333
+ first 8 characters by default — pass `--verbose` to see paths and ids in full. `--json` output
334
+ always contains full paths, titles, and ids, unredacted, so it can be consumed programmatically.
335
+ Do not paste `--json` output into a public issue or forum post — copy only the fields you mean
336
+ to share.
337
+
338
+ `sync --json` is the one place this discloses **a second account's** identifiers: unlike every
339
+ other command, its output carries the destination account's account/org uuids and full store path
340
+ in the clear, regardless of `--verbose`, because those are what the plan is *about*. The
341
+ plain-text report redacts them like everything else; the JSON does not.
342
+
343
+ **Windows durability note.** The commit step fsyncs every file it writes before deleting the
344
+ source, but Windows has no equivalent of a directory fsync, so the directory-entry update
345
+ itself (the rename, the delete) is not separately forced to disk. The spec accepts this as a
346
+ residual risk rather than a defect: file-level fsync plus delete-last ordering means a power
347
+ loss in this window can only lose an already-fsynced deletion, never earlier fsynced writes —
348
+ worst case is a leftover duplicate, never lost data, and `recover` classifies exactly this
349
+ window into `journaled`/`completed`/`rolled_back`.
350
+
351
+ ## Roadmap
352
+
353
+ - **`sync --update`** (refreshing a previously synced row that the destination account has kept
354
+ using) is deferred, not dismissed. Refreshing means overwriting a row the destination account
355
+ may have changed itself since the copy — the one place `sync` could destroy something instead
356
+ of just adding to it — so it needs the same drift-refusal treatment `undo` already has before
357
+ it ships.
358
+ - Platform rows above move from "unverified" to "verified" as contributors confirm the store
359
+ paths and behavior on their own machines.
360
+
361
+ ## Reporting problems
362
+
363
+ This is a one-person project and support is best-effort. The fastest reports to act on
364
+ carry the failing command's plain-text output, `claude-code-sessions doctor` output, and —
365
+ if an operation was involved — the journal op id; the issue templates ask for each. Please
366
+ don't paste `--json` output into an issue: it is deliberately unredacted (see above).
367
+
368
+ ## More
369
+
370
+ Companion post: [The session that synced itself](https://github.com/craigstoller/claude-code-sessions/blob/main/docs/the-session-that-synced-itself.md).
371
+
372
+ MIT licensed — see [LICENSE](https://github.com/craigstoller/claude-code-sessions/blob/main/LICENSE).