harn claude-desktop
harn claude-desktop [accounts|sessions|mirror|tidy] [options]Use the Claude Desktop session guide
for the full mirror and cleanup workflow. Read the
Session state feature page for the lifecycle model
behind tidy.
The Claude desktop app scopes its Claude Code session sidebar per signed-in
account: sign out of one Claude account and into another (a common move when
one account hits its usage limit) and every session the first account created
disappears from the sidebar. Nothing is deleted; the transcripts live
account-agnostically under ~/.claude/projects/ in the runtime environment,
and the sidebar entries themselves are plain JSON files under the desktop
app’s data directory:
<dataDir>/claude-code-sessions/<account-uuid>/<env-id>/local_<uuid>.jsonEach file is one sidebar entry ({ cliSessionId, title, cwd, model, … })
with no account binding inside it; the account scoping is purely which
directory it sits in. harn claude-desktop mirror copies entry files across
account directories so each account’s sidebar lists the union. Fully quit and
relaunch the desktop app afterward; opening a mirrored session resumes it
with full history.
harn claude-desktop tidy handles the other side of the index. It finds
sidebar rows whose mapped Harnery task is done and can archive them in one
batch.
Locating the data directory
Section titled “Locating the data directory”Auto-discovered per platform: ~/Library/Application Support/Claude (macOS),
%APPDATA%\Claude (Windows), ~/.config/Claude (Linux). Under WSL (the
desktop app runs on the Windows side but the CLI runs in the distro),
every /mnt/c/Users/<user>/AppData/Roaming/Claude is scanned. Only
directories containing a claude-code-sessions/ index count. Override with
--data-dir <path> or HARNERY_CLAUDE_DESKTOP_DIR.
Subcommands
Section titled “Subcommands”harn claude-desktop # summary: data dir(s) + accounts + CLI accountharn claude-desktop accounts # account dirs + session counts; labels the CLI's accountharn claude-desktop sessions # every entry across accounts, newest firstharn claude-desktop sessions --account 6d725f2a # one account (uuid prefix)harn claude-desktop sessions --archived # include archived entries
harn claude-desktop mirror --all # dry-run: plan the union copyharn claude-desktop mirror --all --yes # applyharn claude-desktop mirror --session "shopify theme" --yes # by title substringharn claude-desktop mirror --session <cli-session-id> --yes # by exact session idharn claude-desktop mirror --all --to 6d725f2a --yes # only INTO one accountharn claude-desktop mirror --all --from e6c7dc4f --yes # only FROM one account
harn claude-desktop tidy # dry-run: plan archives for done sessionsharn claude-desktop tidy --account 6d725f2a # limit the plan to one account prefixharn claude-desktop tidy --yes # archive the planned entriesharn claude-desktop tidy --include-legacy-prefix # include old hand-labeled [DONE] rowsmirror is dry-run by default: it prints the planned copies and exits;
--yes applies them. It is idempotent: entries the target account already
lists (matched by cliSessionId, falling back to filename) are skipped, so
re-running after every account switch is safe and cheap. Archived entries are
skipped unless --include-archived.
Archiving completed sessions
Section titled “Archiving completed sessions”tidy joins each desktop entry’s cliSessionId to Harnery’s canonical event
ledger. An entry qualifies only when its latest coord.lifecycle_changed event is
done. The command reports active, blocked, and unmatched entries, plus counts
for each skip reason. Already archived entries appear in the counts instead of
filling the output with old rows. A title that merely starts with [DONE] does
not qualify, and [BLOCKED] entries are always skipped.
The default is a dry-run. Add --yes to set isArchived: true in each
qualifying entry. Each update rereads the current JSON, changes only the archive
flag, and replaces the file atomically. Repeating the command is safe because
already archived entries become skips.
--include-legacy-prefix is an explicit compatibility mode for sessions
labeled by hand before lifecycle events existed. It accepts an unmatched
[DONE] title, but it never overrides a matching active or blocked lifecycle
event. Use --account <uuid-prefix> to limit either a dry-run or an applied
batch to selected account directories.
After an applied batch, fully quit and relaunch the desktop app. Closing its window usually leaves it running, so the sidebar may not refresh until the app process restarts.
Sharing sessions across machines
Section titled “Sharing sessions across machines”The sidebar and the transcripts it resumes are both local to one computer, so
a person with two machines sees only the sessions started on the one in front
of them. share connects them through any folder both machines sync. On macOS
the default is iCloud Drive/Harnery/claude-sessions; elsewhere pass --dir
or set HARNERY_SESSION_SHARE_DIR.
harn claude-desktop share # dry-run: what would be published and importedharn claude-desktop share --yes # applyharn claude-desktop share --days 30 --yes # widen the window (default 14 days)Each run does two things. It publishes this machine’s recent, unarchived
sessions (entry file, transcript, and the per-session sidecar folder) under
<dir>/<machine>/, where <machine> is the presence label (HARNERY_MACHINE, then
~/.config/harnery/machine, then the hostname). Then it
reads every other machine’s folder and makes those sessions listed and
resumable here, copying the transcript into ~/.claude/projects/ and adding a
sidebar entry for the signed-in account. Each machine writes only its own
folder, so the synced folder never has two writers for one file.
Transcripts only grow, which gives the merge rule. A remote transcript replaces the local one only when the local file is missing or is an exact byte prefix of the remote, which means the other machine continued the conversation. A local transcript that is longer, has diverged, or was written in the last three minutes is left alone and reported. Paths are rewritten from the other machine’s home directory to this one’s, and a session whose project folder does not exist here is skipped.
Run it on each machine, on a timer if you want it automatic. As with mirror,
fully quit and relaunch the desktop app to see newly imported entries. Work the
other machine has not committed and pushed is not part of the transcript, so
sync the repository as well before continuing a session.
Caveats
Section titled “Caveats”- The entry-file format is the desktop app’s private state, not a public API. Mirror copies files verbatim (never rewrites them), so a format change degrades to “copies stop being useful”, not corruption, though a future app version could change the layout entirely.
- After mirroring, both accounts list the same session, backed by one transcript file. Don’t drive the same session from two signed-in accounts at once.
- The desktop app reads the index at startup: fully quit it (system tray → quit; the window X usually just minimizes) and relaunch to see mirrored sessions.