--- name: ultraplan-end-session-local description: Mark the current session as complete and write session-state pointing at the next session. Helper for informal multi-session flows. argument-hint: " | --help" model: sonnet --- # Ultraplan End-Session Local v1.0 Tiny helper for **informal** multi-session flows (no formal plan with Execution Strategy). Writes a `.session-state.local.json` pointing at the next session so `/ultracontinue` can resume in a fresh Claude chat. For formal flows (a plan produced by `/ultraplan-local --project`), `/ultraexecute-local` Phase 8 already writes the state file — this helper is unnecessary there. Use this command for ad-hoc release runs, manual multi-session handovers, or any flow that does not run through `/ultraexecute-local`. Pipeline position: ``` ... session N work ... /ultraplan-end-session-local "" → writes state ... session boundary, fresh chat ... /ultracontinue → reads state, starts session N+1 ``` See **Handover 7** in `docs/HANDOVER-CONTRACTS.md` for the schema. ## Phase 0 — `--help` handling If `$ARGUMENTS` contains `--help` or `-h`, print the usage block below and exit cleanly. Do NOT proceed to any further phase. ``` /ultraplan-end-session-local — Mark current session done; point at next session. Usage: /ultraplan-end-session-local /ultraplan-end-session-local --help Both arguments are REQUIRED. No interactive prompt — headless-safe. Writes /.session-state.local.json with: schema_version 1 project next_session_brief_path next_session_label status in_progress updated_at Then validates via lib/validators/session-state-validator.mjs and prints the same 3-line narration that /ultracontinue will show in the next session. Example: /ultraplan-end-session-local .claude/projects/2026-05-01-feature/brief.md "Session 2 of 3" ``` ## Phase 1 — Resolve project directory Resolve the nearest `.claude/projects/*/brief.md` from cwd (the current working directory). Use `node -e` enumeration (NOT shell glob — harness-mode safety): ```bash !`node -e "const fs=require('fs'),path=require('path');const root='.claude/projects';if(!fs.existsSync(root)){process.exit(0)}const dirs=fs.readdirSync(root).filter(d=>fs.existsSync(path.join(root,d,'brief.md'))).map(d=>path.join(root,d));dirs.forEach(p=>process.stdout.write(p+'\\n'));"` ``` Decision tree: - **0 candidates:** print error to stderr — "no `.claude/projects//brief.md` found under cwd; cannot determine project directory" — and exit 1. Do NOT fall back to a synthesized path. - **1 candidate:** use it as ``. Continue. - **>1 candidates:** print all paths and ask the operator to `cd` into the intended project directory before retrying. Exit 1. ## Phase 2 — Required args check (headless-safe) Read `$ARGUMENTS`. Both `` and `` are required. If either is missing or empty: ``` Error: missing required args. Usage: /ultraplan-end-session-local '' ``` Print to stderr and exit 1. **No interactive prompt** — this keeps the helper headless-safe (per brief NFR; addresses adversarial-review major #11). If you want an interactive flow, use `/ultracontinue --help` to see the full pipeline. ## Phase 3 — Atomically write `.session-state.local.json` Write `/.session-state.local.json` with the schema-v1 object: ```json { "schema_version": 1, "project": "", "next_session_brief_path": "", "next_session_label": "", "status": "in_progress", "updated_at": "" } ``` Use the atomic-write util — write to `.tmp`, then `rename` into place — to avoid partial-state on crash. Inline-call pattern: ```bash !`node -e " const path=require('path'); const {atomicWriteJson}=require('./lib/util/atomic-write.mjs'); const obj={schema_version:1,project:process.argv[1],next_session_brief_path:process.argv[2],next_session_label:process.argv[3],status:'in_progress',updated_at:new Date().toISOString()}; atomicWriteJson(path.join(process.argv[1],'.session-state.local.json'),obj); console.log(path.join(process.argv[1],'.session-state.local.json')); " '' '' ''` ``` (Note: `atomic-write.mjs` is ESM; if the inline `require()` form fails in your Node version, fall back to `node --input-type=module -e "..."` with `import`.) ## Phase 4 — Validate + narrate Validate the freshly-written state file: ```bash !`node lib/validators/session-state-validator.mjs --json /.session-state.local.json` ``` If `valid: true`, print the success block matching `/ultracontinue` Phase 3 narration (SC-8 cross-project consistency — same template both sides): ``` Session state written: /.session-state.local.json Project: Next session: Brief: In a fresh Claude session, run /ultracontinue to resume. ``` If `valid: false`, print the structured `errors[]` and exit 1. Investigate before retrying — usually means a bad path or label argument. ## Hard rules - **Required args, no defaults.** Never invent a brief path or session label. If args are missing, fail loud. - **Atomic write only.** Tmp + rename — no partial state files on disk. - **Zero secrets.** Status, paths, labels — never API keys, never user content beyond filenames. - **NEVER auto-invoke this command.** It is operator-typed only at session-end. - **Idempotent within a session.** Running twice with the same args overwrites cleanly (atomic rename); does not double-advance.