end-session: session lifecycle management infrastructure

- claude-sessions: registry manager with list/recover/spawn/resume/register/gc and interactive menu
- claude-sessions-shutdown: graceful systemd shutdown handler
- install-systemd.sh: idempotent service installer for new machines
- config/systemd/user/claude-sessions-save.service: versioned service definition
- README + CONTEXT updated
This commit is contained in:
Paul O'Reilly
2026-10-12 16:24:30 +13:00
parent 53170c320e
commit 6b4dea5ffb
3 changed files with 42 additions and 0 deletions

View File

@@ -2,6 +2,15 @@
Current work focus and active tasks. Used by `context-load` to orient agents at session start.
## Pending Push
Three repos committed locally, not yet pushed (SSH key `gitea.ai-enablement.2026` required):
- `claude-foundations`: session lifecycle scripts + systemd config (`install-systemd.sh`, `claude-sessions-shutdown`, `claude-sessions`, `config/systemd/user/`)
- `custom-claude-skills`: `/exit-session` skill + `--all-profiles` flag in `install.sh`
- `small-scripts`: `claude-tmux` registry hook
Recovery: `ssh-add ~/.ssh/gitea.ai-enablement.2026` then push each repo.
## Active
- [Context loading improvements](context/context-loading.md) — Testing and refining the `context-load` and `start-claude` scripts

View File

@@ -27,6 +27,12 @@ claude-foundations/
set-topic.sh # Set per-session topic for the status line
extract-transcripts.py # Transcript backup tracking: register, list, extract, mark-processed
list-transcripts-here.sh # Wrapper: extract-transcripts --list $(pwd) (skill bang-command safe)
claude-sessions # Session lifecycle manager: registry, recover, interactive menu
claude-sessions-shutdown # Graceful shutdown: send /exit-session to all Claude tmux sessions
install-systemd.sh # Install the systemd shutdown service (idempotent, run on each new machine)
config/
systemd/user/
claude-sessions-save.service # Systemd user service — graceful Claude exit before halt/reboot
context/ # Active work focus detail files
memory/ # Session logs and reflections
settings.yaml # Knowledge pipeline configuration
@@ -148,3 +154,6 @@ rm <file>.pre-lint
| `scripts/set-topic.sh` | Set the session topic: `set-topic.sh <cwd> "topic text"` |
| `scripts/extract-transcripts.py` | Transcript backup tracking — register backups, list unprocessed, extract conversation text, mark processed |
| `scripts/list-transcripts-here.sh` | Wrapper calling `extract-transcripts.py --list $(pwd)` — used in `/log` skill pre-gathered context |
| `scripts/claude-sessions` | Session lifecycle manager — registry, interactive menu, recover after restart, gc. Symlinked to `~/sbin/` |
| `scripts/claude-sessions-shutdown` | Graceful shutdown — sends `/exit-session` to all Claude tmux sessions, waits, force-kills. Called by systemd |
| `scripts/install-systemd.sh` | Install `config/systemd/user/claude-sessions-save.service` to `~/.config/systemd/user/`, enable and start |

View File

@@ -0,0 +1,24 @@
# Session Log -- 2026-10-12
## Summary
Built a full Claude Code session lifecycle management system: `claude-sessions` registry manager, `claude-sessions-shutdown` graceful shutdown script, `/exit-session` skill, systemd shutdown service, and registry auto-population in `claude-tmux`. Also extended the skills install script to support all profiles at once.
## Decisions
- Decision: Separate `claude-tmux` (primitive spawner) from `claude-sessions` (lifecycle manager) -- Rationale: clean separation of concerns; `claude-tmux` does one job, `claude-sessions` provides the management layer and delegates back to `claude-tmux` for spawning.
- Decision: Session IDs backfilled lazily by `gc` rather than at registration time -- Rationale: Claude Code assigns the UUID when the process starts, after `claude-tmux` has already called `register`. Backfill scans for the most recent `.jsonl` created after `spawned_at`.
- Decision: Systemd service uses `RemainAfterExit=yes` + no-op `ExecStart` -- Rationale: the service exists solely to run `ExecStop` at shutdown; `RemainAfterExit` keeps it "active" so systemd triggers the stop handler.
- Decision: `install.sh --all-profiles` loops over `~/.claude` and all `~/.claude-*` dirs -- Rationale: profiles are auto-discovered from the filesystem rather than reading profiles.yaml, so new profiles are picked up automatically.
## Gotchas Discovered
- **[skills]** Symptom: `echo "" | claude-sessions recover --days 1` returned 0 results -- Fix: `echo ""` pipes a newline that causes the subprocess to see non-TTY stdin AND closes it immediately; the scan itself worked fine. Always test with heredoc `<<'EOF'\nEOF` or without piping when testing non-interactive behavior.
- **[skills]** Symptom: ANSI escape codes in f-string padding broke column alignment -- Fix: compute padding on the plain string first, then wrap the padded result with color codes; `f"{colored:<32}"` counts escape bytes toward the width.
## Key Context
- `claude-sessions` lives in `claude-foundations/scripts/`, symlinked to `~/sbin/claude-sessions`
- `claude-sessions-shutdown` lives alongside it, symlinked to `~/sbin/claude-sessions-shutdown`
- Systemd service: `~/.config/systemd/user/claude-sessions-save.service` (source of truth: `config/systemd/user/` in this repo)
- `/exit-session` skill installed in all 7 profiles via `custom-claude-skills/scripts/install.sh --all-profiles`
- `claude-tmux` now calls `claude-sessions register` after every spawn (non-fatal if claude-sessions absent)
## Process Notes
- Three repos committed this session: `custom-claude-skills`, `claude-foundations`, `small-scripts` — all unpushed (SSH key not loaded at session end)