Repository navigation
share-session sends a person's whole Claude setup - #740
Conversation
🌱 graft blast radius5 areas changed → 3 areas can be affected. 7 dependent symbols, depth 2. flowchart TB
A0(("Cloud Session Activity<br/>5 symbols"))
A1(("Always Follow Gate<br/>1 symbol"))
A2(("MCP Server<br/>1 symbol"))
classDef reached fill:#D9EDF3,stroke:#3AA7C9,stroke-width:1.5px,color:#0E313C;
class A0,A1,A2 reached;
Who knows this code — 3 people across 8 areas
Ownership is git history over each area's own files, weighted towards recent work (120-day half-life). Merge commits and bots are dropped, and you are dropped from your own PR. A name with no All 7 dependent symbols, grouped by areaCloud Session Activity — 5 symbols in 4 files
Always Follow Gate — 1 symbol in 1 file
MCP Server — 1 symbol in 1 file
Test signal per changed area — 3 ✓ · 2 ✗Reached = a node under a test path has a resolved edge into the changed symbol. It undercounts anything called indirectly — through a CLI, a spawned process or a dynamic import — so read a low ratio as “look here”, never as a coverage gate.
Open the interactive graph → — click an area to see its dependent symbols at file:line. |
…how the last run went
… can't read as a key
Issue: The team-memory experiment needs each person's whole Claude (their sessions, memory and setup such as MCP connectors) to test whether an agent does better with a teammate's context than alone.
trail share-sessioncould only send one session from one folder, and only from the Trail team's own workspace.Why: One session is too little context, and people won't hand over a month of work unless they can see exactly what goes and take it back.
Fix:
trail share-sessionwith no session named now sends a bundle: every Claude Code session from the last 30 days in any folder, plus the setup and the memory notes. It first scrubs everything into a copy on the laptop, shows a summary, and sends only on a yes. Folders can be left out by number, a broken send resumes, and a delete code takes it all back. By default it keeps sending after that yes: each Claude Code session the person starts sends, in the background, the sessions that are new or have grown, into the same bundle.--oncesends just the 30 days, andtrail share-session <n>still sends one session. The server side is trailhq/trail-cloud#101.Moves: people who sent their Claude bundle for the experiment, read from trail-cloud's
shared_sessions(SELECT count(DISTINCT bundle_id) FROM shared_sessions WHERE kind = 'setup'). 0 on 2026-11-05:/api/cli/shared-sessionsis 404 on team.trailhq.com until #101 ships. The newshare_bundleevent (PostHog db 11) counts how people answer:sent,partial(some folders left out),declinedordeleted.Behind a flag for this release
Everything here is off unless
TRAIL_SHARE_SESSION=1is set, so this can go out on npm and be tested end to end before everyone gets it. The next release removes the check (shareSessionEnabledinsrc/cloud/share-session.ts, and its one call insrc/cli.ts).trail share-sessionprints one line and exits 1. It reads nothing, scrubs nothing and sends nothing, not even the/allowedcheck.--stopand--delete <code>, so anyone who tried it can turn it off and take everything back.To try it:
TRAIL_SHARE_SESSION=1 trail share-sessionWhat a person sees
The numbers are from a real dry run on my laptop. Nothing was sent.
Keep sending (the default)
Keeps online saying what happens after the yes, and the question is "Send all of this, and keep sending?".--oncedrops both and sends just the 30 days. An agent can't turn it on unseen: without a terminal it shows the summary and stops, and--yessends the copy the person saw.--sync, the old switch, still works as a hidden alias.share-sessionadds one SessionStart entry to the user-level~/.claude/settings.json:node "~/.claude/helpers/graft-hooks.cjs" share-sync || exit 0. That's trail's user-level shim (written if missing), in the same fail-open form as trail's other global hooks, so it runs in every folder whether or not that repo rantrail init, in the terminal and in Desktop's Code tab, without relying on PATH. Theshare-syncevent only starts a detachedtrail _share-sync, so the session never waits. Every session start starts one. There's no time limit; the run's lock keeps a burst of sessions to one run (src/cloud/share-hook.ts,src/cloud/share-sync-state.ts).bundleSession, kept under~/.trail/share/sync/for the person to read, and sent into the first send's bundle, where Trail replaces the older copy. The setup goes again only when its sha256 changes. Folders left out at the first yes are never sent.sync.jsonis written after each item, so a run that dies resumes. The lock is taken in one step (open(…, 'wx')), so two runs started together can't both hold it, and a lock over an hour old is taken over. Each run writes down what it did, sent count or error, and the status shows it, so a failing sync doesn't look healthy.trail share-sessionwhile it's on puts the entry back if something took it out.--stopand--deletetake it out and leave everything else in the file as it was. A settings file that isn't valid JSON is never touched; the person is told the sync then runs only in repos with trail set up. The entry isn't counted as part of the person's setup, so saying yes doesn't make the setup look changed.--stopends it and says how to take back what went.--delete <code>also ends it.Defaults I picked
~/.claude/projects/*/*.jsonlwritten in the last 30 days (--dayschanges that), each scrubbed by the samebundleSessionas before.~/.claude.json(user and per-folder), Claude Desktop's config and each folder's.mcp.json; settings (hooks, permissions, enabled plugins, model); installed plugins; skills, agents and commands; and the CLAUDE.md and AGENTS.md files of the folders the sessions ran in.~/.claude/projects/*/memory/*.md.envandheadersand settingsenvgo as names only, and a URL goes as its origin. Every other string goes throughredactTextand thenanonymize, the same as a session. Files over 512 KB are left out.anonymizenow hides a distinctive name (6+ characters) wherever it stands: after an escaped\n, after a URL-encoded%2F, or inside a longer word. A short name is still hidden only as its own word, soianleavesChristianalone. On a real month of sessions, the old rule left the sender's login in 1,123 places and the new one leaves 0. Machine logins likerunnerandubuntuaren't treated as names. A line that isn't JSON now has names hidden too; before, it was only redacted..jsonl.gz, alongsidesetup.json,manifest.jsonand aSUMMARY.mdthat lists every item by numbered folder. What's sent is read back from those files, so the person sees exactly what goes. A no deletes the copy.--yesthen sends that same copy, never a fresh one the person hasn't seen, and--leave-out "3 7"drops folders. A copy older than a day is prepared and shown again.sent.json, and the next run sends only the rest, under the same bundle.<bundle id>.<secret>once, and it's also kept in the copy'ssent.json.--delete <code>removes everything in that bundle.GET /allowed, by the signed-in email's domain (trailhq.com, nanonets.com). The internal-only line says so. A 503 (no file storage on that Trail) reads as "doesn't take shared sessions yet".Telemetry
New event
share_bundlewithoutcome(sent/partial/declined/deleted/stopped),items_bucket(1…200+) andsize_bucket(<1MB…200MB+). All are fixed sets incontract.ts, with a row inTELEMETRY.mdand the pinned list intest/telemetry-contract.test.ts. Nothing from the bundle goes in it. Background sync runs send no event. Single-session sends still sendsession_shared.Tested
test/share-session.test.ts,test/share-setup.test.ts(new),test/share-bundle.test.ts(new),test/share-sync.test.ts(new),test/share-hook.test.ts(new) andtest/telemetry-contract.test.ts. They cover:~; name and email are hidden--yessends the copy as one bundle, a broken send resumes in the same bundle,--deletesends the code, and a bad code is refusedanonymizewith a name after an escape,%2Fand a longer wordsettings.jsonuntouched on add and remove, an invalid file left alonetrail share-sessionshows theKeeps onandHooklines, the hook goes in on--yesand out on--stop, a removed hook is put back by the status, the status shows the last run,--yesturns it on, running it again shows the status (so does the old--sync),_share-syncsends the grown session into the same bundle, and nothing goes after--stop--oncesends the 30 days and turns nothing on--stopworks without itsecretReasonstill flags only trip in their JSON-escaped form: none of their strings is a secret.graft-to-trail,hosts-trailandupkeep-hooks. Those fail the same way on this branch before this commit, on a laptop with trail 0.28.0 installed globally.trail check
It exits 1 with 3 to 5 matches, all word overlaps on lines these commits touch in passing:
src/cli.ts, matched tologin --codeand HOME-and-shim learningssrc/cloud/workspace.tsshare_bundlerow inTELEMETRY.mdNone is about sessions, uploads or redaction.
🤖 Generated with Claude Code