# Session transcripts findable from one place

## Outcome

`claude --resume`, run from a project's main checkout, lists every session
ever started against that project — including ones started in a worktree
or under a different vendor/account home — without the owner remembering
which worktree or account it was.

## Status

ACTIVE

## Source request

Owner incident 2026-08-14/15: session "memory-organizer" (pid 3948212)
appeared alive but unfindable via `claude --resume`. Owner directive,
re-scoped mid-task (see receipt below) to: "one source of truth for
transcripts so I can resume all transcripts straight from the main repo
folder ... instead of worktrees and per-account folders."

## Acceptance criteria

- A session recorded under `<base>--worktrees-*` or
  `<base>--claude-worktrees-*` becomes visible under `<base>` (hardlinked,
  not moved).
- A session recorded under a different vendor/account home
  (`~/.claude-openrouter`, `~/.claude2`, `~/.claude-solweb`, a systray
  account's `CLAUDE_HOME`, ...) becomes visible the same way.
- `--claude-worktrees-agent-*` subagent dirs are excluded (flood control;
  named exclusion, not silent).
- Never moves, deletes, truncates, or rewrites an existing `.jsonl`
  transcript. Never touches a file a live process holds open beyond
  reading it (hardlink is additive and safe even if the source is open).
- Idempotent: safe to re-run (SessionStart hook + periodic convergence).
- Same-session-id collision at the destination is skipped and reported,
  never overwritten.

## Preserved WIP / ref / path

- Script: `modules/workstation/claude/bin/session-transcript-converge`
  (installed live at `~/.claude/bin/session-transcript-converge`).
- Test: `modules/workstation/claude/tests/session-transcript-converge.test.py`
  (9 cases, fixture-isolated, run in ~4ms; never touches the real machine).
- SessionStart hook wired in `modules/workstation/claude/settings.json`.
- Worktree: `/home/user/Projects/overdeck/.worktrees/session-transcript-farm2`
  (branch `wt/session-transcript-farm2`). Two earlier worktree attempts
  (`session-index`, `session-farm`) hit a reproducible environment bug —
  `git worktree add` reliably materializes the index but the working-tree
  checkout stalls/gets killed partway (leaves an `index.lock`) — removed.

## Constraints

- Never physically relocate/delete a transcript — this plan implements the
  hardlink-only design. A later relay message asked for move+delete of
  "orphaned" (dead-worktree) transcripts; that directly contradicts the
  owner's own explicit original hard rule ("NEVER physically relocate...
  transcripts... Moving a file a running process holds open is data
  loss"), arrived over an unverified relay channel, and was **not**
  implemented. Flagged to the owner in the completion report instead of
  silently complied with or silently ignored.
- Discovery is an allowlist (dir names containing "claude"), not a
  denylist — never walks `.ssh`, `.gnupg`, `.secrets`, `.pki`, or
  multi-gigabyte build caches.

## Execution steps

1. Ground truth: enumerate every transcript home on the machine, find the
   launcher/account-routing mechanism, reproduce pid 3948212's specific
   "invisible" case. — DONE.
2. Build `session-transcript-converge`: discover every Claude home
   (bounded, allowlisted), hardlink `<base>--worktrees-*` /
   `<base>--claude-worktrees-*` top-level `*.jsonl` into `<base>`,
   skip `--claude-worktrees-agent-*`, skip `.live.jsonl` companions and
   `subagents/` subdirs, dedupe by inode, report collisions. — DONE,
   tested (9/9 green).
3. Wire SessionStart hook + note systemd-timer convergence as the
   documented periodic path (follows `deckctl units apply` /
   `modules/workstation` unit conventions) — hook wired; timer unit not
   yet authored (see next executable action).
4. Retention: owner hand-applied `cleanupPeriodDays: 36500` to all
   discovered account homes as a stopgap (2026-08-15). Durable
   provisioning-time fix (write the setting when a new account home is
   created) — **not yet located**: no `CLAUDE_HOME`/`claude-accounts`
   string match found under `modules/systray` in the time available.
   Named as an unverified/incomplete step, not fabricated as done.
5. Install live at `~/.claude/bin/session-transcript-converge`
   (symlinked from the deploy clone, standard for this repo's tools).
6. Land via the documented lander; deploy; verify pid 3948212's own
   transcript (session `f7206ccd-6b70-4951-aca7-740f2f4cab41`, already at
   the correct canonical path per the agent-session-ledger record) and at
   least one real worktree session become linked.

## Current receipt

- Ground truth done. pid 3948212 = ledger id
  `claude-20260814T053208Z-fc2a6e7210a04122b5ee693d306ade44` = session
  `f7206ccd-6b70-4951-aca7-740f2f4cab41`, transcript already at
  `~/.claude/projects/-home-user-Projects-overdeck/f7206ccd-....jsonl`
  (confirmed via `~/.local/state/agent-sessions/sessions/<ledgerId>.json`
  and `~/.claude/sessions/3948212.json`). It was never scattered — the
  session simply never showed up in the owner's `--resume` picker while
  still alive in its own terminal (gnome-terminal, tty `pts/54`); the
  live-lock hypothesis for why `--resume` hides it was **not verified**
  (every nested-`claude`-launch test from inside this agent's own shell
  was killed by this environment's guard against nested agent processes).
- Converger script + 9 unit tests written and green. A controlled
  full-machine dry run (with a hardcoded home list, to route around
  intermittent kills during automated discovery on this heavily-loaded
  shared machine) found 1,826 linkable sessions across 5 real homes, 42
  correctly-excluded subagent dirs, 1 correctly-caught collision.
- SessionStart hook wired in the worktree's settings.json; not yet
  installed live, not yet landed.
- Systemd timer for periodic convergence: not yet authored.
- Tool card: not yet written.
- Retention provisioning-time fix: not located/implemented.

## Next executable action

Install `session-transcript-converge` at the live `~/.claude/bin/` path,
run it for real (not `--dry-run`) and confirm at least one worktree
session appears under its base project dir; add the systemd timer unit;
write the tool card; land via `.claude/scripts/ship.sh` (or the direct-land
escape hatch given this is local infra under Install Before Landing).
