Repository navigation
feat(share): share Claude's memory and conversations between seats, opt-in - #21
Merged
Merged
Conversation
gelzinn
force-pushed
the
feat/share-memory-history
branch
from
October 28, 2026 15:43
872fd5b to
47c694d
Compare
…pt-in seats share memory on gives every Claude seat the same per-project memory, and seats share sessions on the same conversations (claude --resume, /rewind), memory included. Both are off by default and have a dry run. The first time, every seat's copy is merged file by file: the newest transcript or memory file wins and the older ones are kept as *.seats-backup. Turning either off gives each seat a real copy of what it saw. New seats and new projects join by themselves: sync and switching link a seat added later, and the session hook links a project's memory as a session opens there. seats exclude <seat> memory|sessions keeps a client's account out of it. seats sessions lists a shared conversation once, seats move and auto-switch don't copy a conversation onto itself, and seats export leaves conversations and memory out.
…ging history Sync, launches and the session hook no longer move the conversations of a seat whose Claude is running; it joins once it's closed. Every shared history folder exists from the start, so seats only ever hold links to it. A conversation that wins a merge keeps its own timestamp instead of jumping to the top of claude --resume. seats exclude <seat> sessions now says the seat keeps a copy of everything it could see, the other seats' too.
When several seats had a pane's conversation, seats hook herdr picked the copy written to last. With seats share sessions every seat has the same file, and after an auto-switch both seats can hold copies with the same mtime, so herdr could restore the pane on the wrong seat, such as the old one at its limit. On a detection, or for a pane it has no state for yet, the hook now asks herdr which processes run in the pane (pane process-info) and takes the seat from the agent process's CLAUDE_CONFIG_DIR or CODEX_HOME (else the active seat), which follows an auto-switch, or else from the seats run <tool>:<seat> that started it. That seat wins when it has the session; otherwise the newest copy still does. A pane only changes seat with a new agent process, which herdr detects, so status changes keep to one pane get and reuse the seat saved with the pane's state.
gelzinn
force-pushed
the
feat/share-memory-history
branch
from
October 28, 2026 16:40
47c694d to
2c6f4a1
Compare
3 of 8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Each Claude seat keeps its own conversations and its own auto-memory, so
claude --resumeon one account doesn't show what you did on another, and what Claude learned about a project on one seat doesn't exist on the others.seats sessions/seats moveand auto-switch only copy one conversation on demand.seats share memory on|off|status. Each project'sprojects/<folder>/memorymoves to~/.config/seats/shared/claude/projects/<folder>/memory, and every seat links to it. Conversations stay per seat. Claude Code names that folder after the git repository's main checkout, so worktrees and subfolders share one (per its memory docs, and matching the seat layout on disk), else after the cwd.memoryProject(cwd)insrc/providers/claude/history.tsworks it out from.gitfiles only: a worktree'sgitdir:pluscommondir, without running git.seats share sessions on|off|status.projects/,file-history/(used by/rewind),plans/(a session's plan file) andtodos/(older versions) move toshared/claude/and get linked into each seat. Memory comes withprojects/. Left out on purpose:history.jsonl(up-arrow prompts),session-env/,shell-snapshots/, andsessions/(the live process registry).Merging on first enable. Files are compared byte for byte (a new
opaquemode inshareItems): the newest copy wins, nothing is merged as JSON, and every losing copy gets its own*.seats-backup(numbered). The winner is renamed into place, not rewritten, so it keeps its mtime and resume order. A link that already leads to the shared copy is unlinked instead of being backed up, which is the "memory first, sessions later" case.shareItemsalso skips a path that is the shared copy itself, reached through a linked parent.How the two switches interact. A seat that shares conversations sees the shared memory through
projects/. Turningmemoryon also links memory into the seats that keep their own conversations. Turningmemoryoff while sessions are shared only affects those seats, andstatussays so.exclude <seat> memoryimplies own conversations, since memory lives in their folders.exclude <seat> sessionsalone still lets the seat share memory when memory is on.Off / exclude replaces each link with a real copy (
preserveTimestamps), so nothing is lost. The shared tree stays where it is and its path is printed. Excluding a seat after sharing leaves it holding everything it could see; the output and README say so plainly and recommend excluding client seats beforeon.includefollows the precedent for items: the seat's own copy moves aside as*.seats-backupinstead of being merged.New seats and projects.
seats syncand activation link a seat added later. The session hook now parsescwdfrom its stdin JSON. On SessionStart and Stop it links that project's memory, creating it inshared/if nobody has it yet, and absorbs memory a seat wrote on its own.supervise()does the same before each launch, next topullTrust. All of these never throw.Running sessions.
share sessions on|offandexclude/include … sessions|memoryrefuse whileclauderuns on a seat whose conversations would move. Detection is byCLAUDE_CONFIG_DIR, or plainclaudeon~/.claude. The refusal lists the PIDs and there is no--force. In the background (sync, hook, launch), a running seat with real conversations is skipped until it's closed. Every shared item is created up front, so seats only ever hold links. Memory is moved regardless, since it is written rarely.Everything else.
seats sessionsreads each realprojects/folder once and shows a shared conversation once, as "shared".seats moveto a seat that already sees it says so, with or without--force.copyTranscriptfinds the path inside the seat even when the transcript really lives inshared/, and never copies a file onto itself, which auto-switch relied on.seats removedeletes only the links, and its prompt says shared conversations stay.renameandmigratekeep both the top-level and the nested memory links working, sincemoveTreerepoints them.seats exportleaves conversations and memory out: they aren't insharedItems.herdr resumes on the pane's own seat.
seats hook herdrused to report the most recently written copy of a pane's conversation. With shared conversations every seat has the same file, and right after an auto-switch two seats can hold copies with the same mtime, so herdr could restore the pane on the wrong seat, such as the old one at its limit. Onpane.agent_detected, or for a pane with no saved state, the hook now asks herdr forpane process-infoand takes the seat from the agent process'sCLAUDE_CONFIG_DIR/CODEX_HOME(else the active seat), or else from theseats run <tool>:<seat>that started it. That seat wins when it has the session; otherwise the newest copy still does. A pane only changes seat with a new agent process, which herdr detects, so status changes keep feat(doctor): check integrations with seats doctor, set up the herdr plugin in one step and tidy shared hooks #22's singlepane getand reuse the seat saved in the pane's state.runningProcesses(pids)reads only those pids. Covered by 5 tests with a fake herdr: shared history picks the pane's seat, the auto-switched child's env wins over theseats runargv, the active seat for a claude without a config dir, the fallback whenprocess-infofails or the seat lacks the session, and noprocess-infocall on status changes after a detection.New
SeatSource.historyfield (projects,items,memory,memoryProject); generic code lives insrc/history.tsandsrc/commands/share.ts; config getsshareMemory,shareSessions,ownMemory,ownSessions.Verified with 27 new tests in
tempHome():memoryimplying sessions, and include moving the seat's copy aside;seats sessionsdedupe,moveto a seat that already sees it, andcopyTranscriptfrom both paths;Also tried by hand with a throwaway
HOME: dry run, on, status, exclude, memory on and off, sessions off.Not verified: whether transcripts depend on
paste-cache/(left per seat), and whether SessionStart fires before Claude loads memory. Launches through seats link memory before spawning either way.autoMemoryDirectoryisn't handled; the README says so.README (new section, exclude section, table notes, herdr paragraph),
plugins/herdr/README.mdand help text updated.User-facing changes
BEGIN_COMMIT_OVERRIDE
feat(share): Claude seats can share their memory (
seats share memory on) and their conversations, so--resumeand/rewindwork from any account (seats share sessions on), both off by default and withseats exclude <seat> memory|sessionsfor a seat that keeps its ownEND_COMMIT_OVERRIDE
Type of change
Checklist
bun run checkpasses (Biome lint and format, typecheck, tests)bun src/cli.ts helpruns without errors--dry-runor a throwawayHOMEsrc/providers/<id>/and is listed insrc/providers/index.ts