|
1 | 1 | # 044 - Paste-Free Session Resumption (Checkpoint → Fresh Session → Rehydrate) |
2 | 2 |
|
3 | | -Status: IN PROGRESS — T1-T5 + T7 COMPLETE; only T6 remains (optional, recommended DROP/defer to plan 045) |
| 3 | +Status: COMPLETE — T1-T5 + T7 COMPLETE; T6 closed WONTFIX (auto-start deferred to plan 045). Attended paste-free resume loop delivered (push hook T3 + pull `next-task` T4 + file handoff T5). Activation note: live deploy on the work host goes through the nixcfg-work flake (see §8 "Activation"). |
4 | 4 | Created: 2026-06-19 |
5 | 5 | Owner: nixcfg Claude Code config (`modules/programs/claude-code/`) |
6 | 6 | Related memory: `/home/tim/src/nixcfg/claude-runtime/.claude-max/projects/-home-tim-src-n3x/memory/session-handoff-concurrency-fragility.md` |
@@ -146,13 +146,20 @@ the template rather than a hardcoded absolute path (correct for a global cross-p |
146 | 146 | **DoD:** CLAUDE.md protocol section rewritten; clipboard/`/tmp` path removed or demoted to "last |
147 | 147 | resort, single-session machines only"; cross-reference to this plan + the memory file. |
148 | 148 |
|
149 | | -### T6 - Optional fully-hands-free start (REDESIGNED per T1) `TASK:PENDING` |
150 | | -T1 disproved `initialUserMessage` (no hook field auto-fires a turn on 2.1.158). The only hands-free path |
151 | | -is an explicit launch-time prompt argument. If pursued, implement as an opt-in wrapper/alias that runs |
152 | | -`claude "resume the active plan's next pending task"` (the prompt the SessionStart hook would otherwise |
153 | | -have surfaced), behind an explicit flag/marker since auto-starting work is not always desired. Likely |
154 | | -lower priority than the `/resume` pull-command (T4); consider dropping in favor of T4. |
155 | | -**DoD:** opt-in mechanism documented; default OFF; when ON, the wrapper self-resumes the next task without any typing. (Hook-field auto-start is ruled out — see §8.) |
| 149 | +### T6 - Optional fully-hands-free start (REDESIGNED per T1) `TASK:WONTFIX (deferred to 045)` |
| 150 | +**Disposition 2026-06-21 (user decision):** DROP from plan 044; the hands-free auto-start belongs to |
| 151 | +plan `045-unattended-plan-burndown.md`. Rationale: (1) T1 empirically disproved `initialUserMessage` |
| 152 | +on both 2.1.158 and built 2.1.183 — no hook field auto-fires a first turn, so a hook can never deliver |
| 153 | +hands-free start (§8). (2) The only viable mechanism is an explicit launch-time prompt argument |
| 154 | +(`claude "resume the active plan's next pending task"`), which is the same headless-first-turn problem |
| 155 | +plan 045 must solve for Mode B (unattended burndown) anyway — building it here would duplicate 045's |
| 156 | +core. (3) The *attended* resume path 044 set out to fix is already fully delivered: T3 (hook push) + |
| 157 | +T4 (`next-task` honoring `.claude/active-plan`) + T5 (file-based handoff) give paste-free, one-keystroke |
| 158 | +resumption. A standalone `--resume-plan` wrapper alias would be pure ergonomics over T4 with no new |
| 159 | +capability. The `--resume-plan` opt-in design sketch is preserved in §10 (Mode A bullet) as the seed for |
| 160 | +045's attended-launch ergonomics. |
| 161 | +**DoD:** N/A — task closed as WONTFIX/deferred; auto-start folded into plan 045. The attended-resume goal |
| 162 | +of 044 is satisfied by T3+T4+T5 (no typing of a continuation prompt; `/next-task` resumes the pointed plan). |
156 | 163 |
|
157 | 164 | ### T7 - Validate end-to-end across two worktrees concurrently `TASK:COMPLETE` |
158 | 165 | **Done 2026-06-21.** Reproduced the §1 concurrency scenario at the hook level and proved isolation. See "§8 T7 findings" for the full method/results. |
@@ -281,6 +288,40 @@ The `**/` form is chosen because it also catches nested/worktree paths while rem |
281 | 288 |
|
282 | 289 | **Teardown.** Throwaway worktree `/home/tim/src/nixcfg-t7b` removed; only this plan file is committed (per the untracked-files gotcha, staged by path, never `git add -A`). |
283 | 290 |
|
| 291 | +### Activation — loop deployed live, verified 2026-06-21 |
| 292 | + |
| 293 | +**Work-host indirection (non-obvious).** This machine is `pa161878-nixos`, a **work** box whose live |
| 294 | +home config is `tim@pa161878-nixos` from the **nixcfg-work** flake (which also owns the |
| 295 | +`pa161878-nixos`/`corp-wsl-dev-team` NixOS configs). nixcfg-work consumes nixcfg as a flake input |
| 296 | +(`nixcfg.url = "github:timblaktu/nixcfg"`, other inputs `follows nixcfg/*`), pinned in its `flake.lock` |
| 297 | +to github rev `f916d7cb` on main. The claude-code module/templates therefore reach this machine |
| 298 | +**through nixcfg-work's pin of nixcfg**, not from this repo directly. Consequence: a plain |
| 299 | +`home-manager switch` from nixcfg-work deploys the *pinned* nixcfg (no plan-044 hook); the plan-044 |
| 300 | +branch is an unpushed local descendant of the pin. |
| 301 | + |
| 302 | +**Activation performed (real but EPHEMERAL).** Verified the branch is a clean linear descendant of the |
| 303 | +pin (`git merge-base --is-ancestor f916d7cb HEAD` → yes) and the entire `f916d7cb..HEAD` diff is exactly |
| 304 | +the plan-044 work (no unrelated drift), then switched with the local override: |
| 305 | +``` |
| 306 | +home-manager switch --flake '/home/tim/src/nixcfg-work#tim@pa161878-nixos' \ |
| 307 | + --override-input nixcfg 'git+file:///home/tim/src/nixcfg?ref=plan-044-paste-free-resume' -b backup |
| 308 | +``` |
| 309 | +Exit 0; generation 212. Override resolved `nixcfg` → local rev `3f12389`. **This deploy is ephemeral:** |
| 310 | +nixcfg-work's lock still pins `f916d7cb`, so the *next plain* switch reverts the hook. For PERMANENT |
| 311 | +activation: merge plan-044 → nixcfg main → push → bump nixcfg-work's `flake.lock` nixcfg rev → switch |
| 312 | +(cross-repo, touches main — deliberately NOT done unsolicited). |
| 313 | + |
| 314 | +**Live verification (post-switch).** Deployed `claude-runtime/.claude-max/settings.json` now carries the |
| 315 | +`SessionStart` hook (matcher `startup|resume|compact` → `/nix/store/yvp6vyagq22j4kmq4nd301xzx70lin0h-claude-resume-hook`, |
| 316 | +the byte-for-byte store path T7 validated; file exists). `.claude-max/CLAUDE.md` regenerated with the T5 |
| 317 | +"Session Handoff Protocol". Global ignore `~/.config/git/ignore` carries `**/.claude/active-plan` + |
| 318 | +`**/.claude/HANDOFF.md` (T2). Fired the **deployed** hook with a real CC-shaped stdin |
| 319 | +(`session_id`/`transcript_path`/`cwd`/`source:startup`) + `CLAUDE_PROJECT_DIR=/home/tim/src/nixcfg`: |
| 320 | +exit 0, valid `hookSpecificOutput` envelope. Because T6 is now WONTFIX (044 has no PENDING/IN_PROGRESS |
| 321 | +task), source B correctly yielded nothing and the hook **fell through B→A** to inject `.claude/HANDOFF.md` |
| 322 | +— demonstrating the precedence chain on the real artifact. The loop fires paste-free for every new |
| 323 | +session in this worktree until a plain nixcfg-work switch reverts it. |
| 324 | + |
284 | 325 | --- |
285 | 326 |
|
286 | 327 | ## 10. Prior-art research + design decisions (2026-06-20) |
|
0 commit comments