@tekyzinc/gsd-t 2.76.10 → 3.10.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -201,7 +201,7 @@ The JSON on stdout contains `{consumed, estimated_remaining, pct, threshold}`
201
201
  Exit-code handling (three-band model per `token-budget-contract.md` v3.0.0):
202
202
  - `0` (normal, <70%) → proceed to the next phase at full quality.
203
203
  - `13` (warn, 70–85%) → log the warning to `.gsd-t/token-log.md` and proceed to the next phase at full quality. **Never downgrade models or skip phases** — the runway estimator (m35-runway-estimator) is responsible for halting cleanly before reaching `stop`.
204
- - `10` (stop, ≥85%) → STOP the wave loop. Save checkpoint to `.gsd-t/progress.md` — record which phases are complete, which remain. Output exactly: `⏸️ Wave orchestrator context gate reached ({pct}% of model window). Progress saved. Run /clear then /user:gsd-t-wave to continue from the next phase.` Do NOT spawn the next phase agent.
204
+ - `10` (stop, ≥85%) → STOP the wave loop. Save checkpoint to `.gsd-t/progress.md` — record which phases are complete, which remain. Call `autoSpawnHeadless({command: 'gsd-t-wave', args, projectDir})` — this spawns a fresh headless session that auto-resumes via `/gsd-t-resume` without any manual `/clear`. Output: `⏸️ Wave orchestrator context gate reached ({pct}% of model window) handing off to a fresh headless session (ID: {id}). Progress saved.` Return cleanly. Do NOT spawn the next phase agent, do NOT exit with a special code — the handoff is the success path.
205
205
 
206
206
  As of v2.0.0 (M34), the wave orchestrator reads the SAME `bin/token-budget.js` real-source measurement as the execute orchestrator — both trace back to `.gsd-t/.context-meter-state.json` produced by the Context Meter PostToolUse hook. Each phase spawn (PARTITION, DISCUSS, PLAN, IMPACT, EXECUTE, TEST-SYNC, INTEGRATE, VERIFY+COMPLETE, DOC-RIPPLE) causes post-call updates to the state file, so each subsequent gate check reflects the real context consumption trajectory. When the state file is absent or stale, the call falls back to the historical heuristic.
207
207
 
@@ -114,6 +114,9 @@ GSD-T reads all state files and tells you exactly where you left off.
114
114
 
115
115
  | Command | Purpose | Auto |
116
116
  |---------|---------|------|
117
+ | `/user:gsd-t-unattended` | Launch detached supervisor — runs active milestone to completion with zero human intervention | Manual |
118
+ | `/user:gsd-t-unattended-watch` | Watch tick — fires every 270s via ScheduleWakeup, reports supervisor status | Auto |
119
+ | `/user:gsd-t-unattended-stop` | Touch stop sentinel — supervisor halts after current worker finishes | Manual |
117
120
  | `/user:gsd-t-wave` | Full cycle, auto-advances all phases | Manual |
118
121
  | `/user:gsd-t-status` | Cross-domain progress view with token breakdown, global ELO and cross-project rankings | Manual |
119
122
  | `/user:gsd-t-resume` | Restore context, continue | Manual |
@@ -286,6 +289,20 @@ Drop a `.md` file into `templates/stacks/` to add a new stack. Files prefixed wi
286
289
 
287
290
  ---
288
291
 
292
+ ## Unattended Execution (M36)
293
+
294
+ Run the active milestone to completion over hours or days with zero human intervention. The unattended supervisor is an OS-level process that spawns `claude -p` workers in a relay — each worker runs in a fresh context window, completing one round of wave tasks before handing off to the next. The supervisor survives `/clear`, terminal close, and sleep/wake cycles (macOS/Linux; see `docs/unattended-windows-caveats.md` for Windows).
295
+
296
+ **Relay model**: Each iteration spawns a fresh `claude -p` session with a compact prompt derived from `.gsd-t/progress.md` state. The supervisor waits for the worker to exit, records the exit code in `state.json`, runs safety checks (gutter detection, blocker sentinel scan), and spawns the next worker. Workers never overlap. Context rot is impossible — each worker starts clean.
297
+
298
+ **Watch loop**: `/user:gsd-t-unattended` starts an in-session ScheduleWakeup loop that ticks every 270 seconds. Each tick reads `state.json` and `supervisor.pid` to render a live progress block. When the supervisor reaches a terminal state (`done`, `failed`, `stopped`), the watch loop stops rescheduling and prints a final summary. A `/clear` + `/user:gsd-t-resume` transparently re-attaches: the resume command checks for a live `supervisor.pid` and re-starts the watch loop automatically.
299
+
300
+ **Safety rails**: Branch protection (refuses to run on `main`/`master`/`release/*` by default), dirty-tree check (whitelists GSD-T runtime files), per-iteration gutter detection (repeated error patterns, file thrash, no-progress stall), wall-clock and iteration caps, and a blocker sentinel that halts on unrecoverable worker errors.
301
+
302
+ **Contract**: `.gsd-t/contracts/unattended-supervisor-contract.md` v1.0.0 is the authoritative reference for the state file schema, exit codes, CLI surface, and platform matrix.
303
+
304
+ ---
305
+
289
306
  ## Headless Mode
290
307
 
291
308
  Run GSD-T non-interactively in CI/CD pipelines or automated workflows.
@@ -68,14 +68,14 @@ The framework has no runtime — it is consumed entirely by Claude Code's slash
68
68
 
69
69
  ### Headless Mode (M23 — complete)
70
70
  - **doHeadless(args)**: Dispatch function for the `headless` CLI subcommand.
71
- - **doHeadlessExec(command, cmdArgs, flags)**: Wraps `claude -p "/user:gsd-t-{command}"` via `execFileSync`. Verifies claude CLI availability, enforces timeout, writes log file if `--log` requested. Returns structured JSON if `--json` flag set.
71
+ - **doHeadlessExec(command, cmdArgs, flags)**: Wraps `claude -p "/gsd-t-{command}"` via `execFileSync`. Verifies claude CLI availability, enforces timeout, writes log file if `--log` requested. Returns structured JSON if `--json` flag set. (M36 Phase 0: prompt form is `/gsd-t-X`, NOT `/user:gsd-t-X` — non-interactive mode rejects the `/user:` namespace prefix.)
72
72
  - **parseHeadlessFlags(args)**: Extracts `--json`, `--timeout=N`, `--log` from raw args. Returns `{ flags, positional }`.
73
- - **buildHeadlessCmd(command, cmdArgs)**: Builds the `/user:gsd-t-{command}` prompt string.
74
- - **mapHeadlessExitCode(processExitCode, output)**: Maps process exit code + output text patterns to GSD-T exit codes (0–4).
73
+ - **buildHeadlessCmd(command, cmdArgs)**: Builds the bare `/gsd-t-{command}` prompt string. Interactive-mode `/user:` prefix deliberately omitted — see `.gsd-t/M36-spike-findings.md` Spike A.
74
+ - **mapHeadlessExitCode(processExitCode, output)**: Maps process exit code + output text patterns to GSD-T exit codes (0–5).
75
75
  - **headlessLogPath(projectDir, timestamp)**: Generates `.gsd-t/headless-{timestamp}.log` path.
76
76
  - **doHeadlessQuery(type)**: Dispatches to one of 7 query functions. All pure Node.js file reads, no LLM calls, <100ms.
77
77
  - **Query functions** (7): `queryStatus`, `queryDomains`, `queryContracts`, `queryDebt`, `queryContext`, `queryBacklog`, `queryGraph` — each reads corresponding `.gsd-t/` file and returns typed JSON result.
78
- - **Exit codes**: 0=success, 1=verify-fail, 2=context-budget-exceeded, 3=error, 4=blocked-needs-human
78
+ - **Exit codes**: 0=success, 1=verify-fail, 2=context-budget-exceeded, 3=error, 4=blocked-needs-human, 5=command-dispatch-failed (M36 Phase 0 — `claude -p` returned `Unknown command:` for the slash command; caller should treat as a bug not a transient failure)
79
79
  - **CI/CD examples**: `docs/ci-examples/github-actions.yml` (GitHub Actions), `docs/ci-examples/gitlab-ci.yml` (GitLab CI)
80
80
 
81
81
  ### Compaction-Proof Debug Loop (M29 — complete)
@@ -272,6 +272,83 @@ QA runs inline or as Task subagent depending on phase (M10 refactor). Removed fr
272
272
  - **Resource limits**: Heartbeat stdin capped at 1MB, HTTP responses capped at 1MB (M5), 5s/8s timeouts, 7-day file cleanup
273
273
  - **Wave security**: `bypassPermissions` mode documented with attack surface analysis and mitigations (M5)
274
274
 
275
+ ## Unattended Supervisor (M36)
276
+
277
+ The unattended supervisor is a cross-session relay engine that runs an active GSD-T milestone to completion over hours or days without human intervention. It spans the boundary between the interactive Claude session and the OS process layer.
278
+
279
+ ### Component Diagram
280
+
281
+ ```
282
+ Interactive Claude session
283
+ └── /user:gsd-t-unattended (launch command)
284
+ ├── Pre-flight safety checks (branch, dirty tree)
285
+ └── spawn(detached) → Supervisor process (bin/gsd-t-unattended.js)
286
+ ├── writes .gsd-t/.unattended/supervisor.pid
287
+ ├── writes .gsd-t/.unattended/state.json (atomic rewrite each iter)
288
+ ├── appends .gsd-t/.unattended/run.log (worker stdout+stderr)
289
+ ├── checks .gsd-t/.unattended/stop (sentinel — presence = halt)
290
+ └── relay loop:
291
+ spawnSync('claude -p "/gsd-t-resume"')
292
+ → worker exits → post-worker safety check → next iter
293
+
294
+ In-session watch loop (every 270s via ScheduleWakeup)
295
+ └── /user:gsd-t-unattended-watch
296
+ ├── reads supervisor.pid (kill -0 liveness)
297
+ ├── reads state.json (status, iter, lastTick)
298
+ └── reschedules or reports final status
299
+ ```
300
+
301
+ ### State Directory Layout
302
+
303
+ ```
304
+ .gsd-t/.unattended/
305
+ ├── supervisor.pid — Integer PID. Exists ONLY while supervisor is alive.
306
+ ├── state.json — Live state snapshot. Atomically rewritten between iterations.
307
+ ├── run.log — Append-only worker stdout+stderr. Never truncated during a run.
308
+ ├── stop — Sentinel file. Absence = run. Presence = user-requested stop.
309
+ └── config.json — Optional per-project config overrides (maxIterations, hours, etc.)
310
+ ```
311
+
312
+ Sibling: `.gsd-t/.handoff/` — owned by M35-gap-fixes for single-shot handoff locks (see below).
313
+
314
+ ### Contract
315
+
316
+ `.gsd-t/contracts/unattended-supervisor-contract.md` v1.0.0 — authoritative source for: state schema, status enum, exit-code table, launch handshake, watch tick decision tree, resume auto-reattach handshake, stop mechanism, safety-rails hook points, and CLI surface.
317
+
318
+ ### Platform Abstraction Layer (`bin/gsd-t-unattended-platform.js`)
319
+
320
+ Exports four cross-platform functions:
321
+
322
+ | Export | macOS | Linux | Windows |
323
+ |--------|-------|-------|---------|
324
+ | `spawnSupervisor(args)` | `spawn(node, ...)` detached | same | same (`windowsHide:true`) |
325
+ | `preventSleep()` | `caffeinate -i` subprocess | `systemd-inhibit` or no-op | no-op (not supported — see docs/unattended-windows-caveats.md) |
326
+ | `releaseSleep(handle)` | kill caffeinate PID | release inhibit or no-op | no-op |
327
+ | `notify(title, msg, level)` | `osascript` | `notify-send` | no-op |
328
+ | `resolveClaudePath()` | PATH lookup | PATH lookup | `claude.cmd` via PATH |
329
+
330
+ ### Safety Rails (`bin/gsd-t-unattended-safety.js`)
331
+
332
+ Called at four supervisor hook points (pre-launch, supervisor-init, pre-worker, post-worker):
333
+
334
+ - **Gutter detection**: stall pattern — repeated identical errors or no file changes for N iterations
335
+ - **Blocker sentinels**: scan worker stdout for unrecoverable-error markers (`BLOCKED_NEEDS_HUMAN`, `DISPATCH_FAILED`)
336
+ - **Iteration cap**: `maxIterations` guard (default 200)
337
+ - **Wall-clock cap**: `hours` guard (default 24h)
338
+ - **Branch/dirty-tree pre-flight**: refuses to start on protected branches or uncleaned worktrees
339
+
340
+ Each check returns `{ ok, reason?, code? }`. A `false` result halts with `status = 'failed'` and the corresponding exit code (6=gutter, 7=protected-branch, 8=dirty-tree).
341
+
342
+ ### Handoff-Lock Primitive (`bin/handoff-lock.js`)
343
+
344
+ Closes the M35 parent/child race in `bin/headless-auto-spawn.js`. When the runway estimator fires `autoSpawnHeadless()`, the parent session writes a lock file in `.gsd-t/.handoff/` before spawning the child and removes it only after the child has confirmed PID + state-ready. Prevents the child from beginning execution before the parent has cleanly exited — eliminating the race where both sessions wrote to the same `.gsd-t/` files simultaneously.
345
+
346
+ ### Resume Auto-Reattach
347
+
348
+ `/user:gsd-t-resume` Step 0 checks for a live supervisor before any other resume logic. If `supervisor.pid` exists and `kill -0` succeeds and `state.json.status` is non-terminal, the resume command skips normal resume flow entirely, prints the current watch block, and calls `ScheduleWakeup(270, '/user:gsd-t-unattended-watch', ...)`. The user transparently re-enters the watch loop without any manual step.
349
+
350
+ ---
351
+
275
352
  ## Design Decisions
276
353
 
277
354
  | Date | Decision | Rationale | Alternatives Considered |
@@ -312,6 +312,110 @@ Read-only surface onto the token telemetry stream. Backward-compatible with pre-
312
312
 
313
313
  When a sonnet-default phase hits a complexity signal that warrants opus (e.g., cross-module refactor detected mid-execution), the command may emit an `/advisor` hook line in its output — a structured suggestion for the orchestrator to escalate the **next** spawn of that phase to opus. This is a plan-time signal, not a runtime swap: the current spawn completes at its assigned tier, and the escalation applies to subsequent work. See `.gsd-t/contracts/model-selection-contract.md` for the hook schema.
314
314
 
315
+ ## Unattended Supervisor Setup (M36)
316
+
317
+ The unattended supervisor runs an active GSD-T milestone to completion in a detached OS process — no terminal needed, no human intervention required.
318
+
319
+ ### Quick Start
320
+
321
+ ```bash
322
+ # From within an interactive Claude session:
323
+ /user:gsd-t-unattended
324
+
325
+ # From the terminal (detached — returns immediately):
326
+ gsd-t unattended --hours=24 --milestone=M36
327
+
328
+ # Watch current run status (in-session, 270s tick):
329
+ /user:gsd-t-unattended-watch
330
+
331
+ # Request a graceful stop:
332
+ /user:gsd-t-unattended-stop
333
+ ```
334
+
335
+ ### CLI Flags
336
+
337
+ ```
338
+ gsd-t unattended [OPTIONS]
339
+ --hours=24 Wall-clock cap in hours (default: 24)
340
+ --max-iterations=200 Worker iteration cap (default: 200)
341
+ --project=. Project directory (default: cwd)
342
+ --branch=AUTO Branch to run on; AUTO = current non-protected branch
343
+ --on-done=print Terminal action: print | merge-commit (merge-commit is v2)
344
+ --dry-run Preflight only; no spawn
345
+ --verbose Extra log detail
346
+ --test-mode Uses stub worker; for CI and smoke tests
347
+ ```
348
+
349
+ ### Config File (optional)
350
+
351
+ `.gsd-t/unattended-config.json` — per-project overrides. Absence = hardcoded defaults.
352
+
353
+ ```json
354
+ {
355
+ "hours": 24,
356
+ "maxIterations": 200,
357
+ "gutterNoProgressIters": 5,
358
+ "workerTimeoutMs": 3600000,
359
+ "protectedBranches": ["main", "master", "develop", "trunk"],
360
+ "dirtyTreeWhitelist": [".gsd-t/.unattended/*", ".gsd-t/events/*.jsonl"]
361
+ }
362
+ ```
363
+
364
+ ### State Files
365
+
366
+ | File | Purpose |
367
+ |------|---------|
368
+ | `.gsd-t/.unattended/supervisor.pid` | Integer PID. Exists only while supervisor is alive. |
369
+ | `.gsd-t/.unattended/state.json` | Live state snapshot — status, iter, milestone, lastTick, etc. Full schema in `unattended-supervisor-contract.md`. |
370
+ | `.gsd-t/.unattended/run.log` | Append-only worker stdout+stderr. Never truncated during a run. |
371
+ | `.gsd-t/.unattended/stop` | Sentinel — touching this file requests a graceful stop. |
372
+ | `.gsd-t/.unattended/config.json` | Optional per-project config overrides (same keys as CLI flags). |
373
+
374
+ ### Required Platform Helpers
375
+
376
+ | Platform | Sleep Prevention | Notifications |
377
+ |----------|-----------------|---------------|
378
+ | macOS | `caffeinate` (built-in) | `osascript` (built-in) |
379
+ | Linux | `systemd-inhibit` or no-op | `notify-send` (install via `apt`/`dnf`) |
380
+ | Windows | NOT supported — see `docs/unattended-windows-caveats.md` | no-op |
381
+
382
+ macOS and Linux work out of the box on standard installs. Windows can run the supervisor but the machine may sleep mid-run.
383
+
384
+ ### Contract
385
+
386
+ `.gsd-t/contracts/unattended-supervisor-contract.md` v1.0.0 — authoritative state schema, exit-code table, status enum, launch/resume handshakes.
387
+
388
+ ### Troubleshooting
389
+
390
+ **Supervisor won't start**
391
+ - Check `.gsd-t/.unattended/run.log` for error output
392
+ - Run `gsd-t unattended --dry-run` to run pre-flight checks without spawning
393
+ - Verify no protected branch: `git branch --show-current`
394
+
395
+ **"Already running" error**
396
+ ```bash
397
+ # Verify supervisor is actually alive:
398
+ kill -0 $(cat .gsd-t/.unattended/supervisor.pid) && echo "alive" || echo "stale PID"
399
+
400
+ # If stale, remove PID file:
401
+ rm .gsd-t/.unattended/supervisor.pid
402
+
403
+ # Or request a graceful stop:
404
+ /user:gsd-t-unattended-stop
405
+ # (or) touch .gsd-t/.unattended/stop
406
+ ```
407
+
408
+ **Watch loop stopped firing**
409
+ - Re-invoke `/user:gsd-t-resume` from a fresh session
410
+ - Step 0 auto-reattach reads `supervisor.pid` — if the supervisor is still alive, it re-enters the watch loop automatically (no manual steps needed)
411
+
412
+ **Supervisor crashed mid-run**
413
+ - The watch loop detects crash via `kill -0` failure
414
+ - Check `.gsd-t/.unattended/run.log` and final `state.json` for diagnostics
415
+ - Resume normally with `/user:gsd-t-resume` — the milestone continues from its last checkpoint
416
+
417
+ ---
418
+
315
419
  ## Security Notes
316
420
 
317
421
  - Zero npm dependencies — no supply chain risk
@@ -119,3 +119,11 @@ Between v2.74 and v2.75, GSD-T attempted to cope with context pressure through *
119
119
  **Structural guarantee.** Because `STOP_THRESHOLD_PCT = 85` and the runway estimator refuses runs that would project past 85%, the runtime's 95% native compact is now structurally unreachable under healthy operation. `halt_type: native-compact` in `.gsd-t/token-metrics.jsonl` is a defect signal — if it appears, the estimator needs re-tuning.
120
120
 
121
121
  **Message content is never logged**: the meter writes only token counts, band names, and error category codes. Never transcript text, never API response bodies, never the API key itself. See `docs/architecture.md` for the full data-flow diagram and `.gsd-t/contracts/context-meter-contract.md` for the schema.
122
+
123
+ ## From Runway-Protected Execution to Cross-Session Relay (M36)
124
+
125
+ M34 gave GSD-T a real measurement of how much context window each session had consumed. M35 used that signal to refuse starting new work that would exceed the 85% threshold, auto-spawning a detached headless process instead so the user never had to manually run `/clear`. Both milestones still had a ceiling: the headless continuation was a single shot — it ran one Claude session, and if the milestone wasn't complete when that session exhausted its context, a human had to intervene again to trigger the next continuation. Long-running milestones (multi-day builds, large waves) still required periodic human attention to keep the relay going.
126
+
127
+ M36 (v2.77.10) makes the relay automatic and indefinite. The unattended supervisor (`bin/gsd-t-unattended.js`) is a long-lived OS process, fully detached from any Claude Code terminal session, that drives the relay itself: it spawns a fresh `claude -p "/gsd-t-resume"` worker, waits for it to exit, reads the outcome, and immediately spawns the next worker — repeating until the milestone reaches COMPLETED status or a wall-clock cap is hit. Each worker gets a pristine context window. The `/compact` that inevitably fires in a long session is irrelevant because the *next* session has already started fresh. The supervisor IS the orchestrator of runway handoffs. Safety rails (`bin/gsd-t-unattended-safety.js`) prevent infinite-loop scenarios: gutter detection catches stall patterns, blocker sentinels catch unrecoverable errors, and iteration/hour caps ensure the machine doesn't run forever on a broken state. A cross-platform abstraction layer handles macOS sleep-prevention (`caffeinate`), Linux equivalents, and Windows limitations. From the user's perspective: invoke `/user:gsd-t-unattended`, walk away, and receive a native OS notification when the milestone is done — hours or days later.
128
+
129
+ The in-session watch loop (270-second `ScheduleWakeup` ticks, chosen to stay inside the 5-minute prompt-cache TTL) closes the feedback loop for users who keep a Claude session open. And the `gsd-t-resume` Step 0 auto-reattach means that even a `/clear` or accidental session close is transparent: the next resume detects the live supervisor and silently re-enters the watch loop without any manual step. Taken together, M34 + M35 + M36 form a complete three-layer system: measure the context accurately, refuse to degrade when it runs low, and relay execution automatically across as many fresh sessions as the work requires.
@@ -254,6 +254,15 @@
254
254
  | REQ-076 | Optimization backlog — detect only, never auto-apply, user promotes or rejects | optimization-backlog | T1–T4 | complete (Wave 4) |
255
255
  | REQ-077 | Headless auto-spawn on runway refusal — user never sees a `/clear` prompt | headless-auto-spawn | T1–T5 | complete (Waves 3–4) |
256
256
  | REQ-078 | Structural elimination of native compact messages — `halt_type: native-compact` count is 0 during M35 execution | runway-estimator + headless-auto-spawn | T1–T5 (RE), T1–T5 (HAS) | complete (Wave 5) |
257
+ | REQ-079 | `gsd-t unattended` CLI subcommand runs an active milestone to completion unattended on macOS and Linux (24h+ multi-worker relay, detached OS process) | m36-supervisor-core | T1–T5 | complete (M36 Wave 1–2) |
258
+ | REQ-080 | `/user:gsd-t-unattended` slash command launches the supervisor from within a Claude session without blocking the terminal | m36-supervisor-core + m36-watch-loop | T1, T3 | complete (M36 Wave 1–3) |
259
+ | REQ-081 | In-session watch loop ticks every 270s via `ScheduleWakeup` (inside 5-min prompt-cache TTL) to report live supervisor state | m36-watch-loop | T1–T2 | complete (M36 Wave 3) |
260
+ | REQ-082 | `/clear` + `/user:gsd-t-resume` during a live unattended run transparently re-attaches to the watch loop (Step 0 auto-reattach, no user-visible disruption) | m36-watch-loop | T4 | complete (M36 Wave 3) |
261
+ | REQ-083 | Supervisor survives `/compact` and context resets — each worker is a fresh `claude -p` session; context exhaustion is structurally irrelevant | m36-supervisor-core | T1–T5 | complete (M36 Wave 1–2) |
262
+ | REQ-084 | Safety rails prevent infinite loops: gutter detection, blocker sentinels (`BLOCKED_NEEDS_HUMAN`, `DISPATCH_FAILED`), max-hours and max-iterations timeouts | m36-safety-rails | T1–T5 | complete (M36 Wave 2) |
263
+ | REQ-085 | Cross-platform support — macOS (caffeinate sleep-prevention) + Linux (systemd-inhibit or no-op) + Windows (claude.cmd via PATH; sleep-prevention not supported — see docs/unattended-windows-caveats.md) | m36-cross-platform | T1–T5 | complete (M36 Wave 2) |
264
+ | REQ-086 | Handoff-lock primitive (`bin/handoff-lock.js`) eliminates parent/child race in `headless-auto-spawn.js` runway handoffs (M35 gap fix) | m36-m35-gap-fixes | T1–T3 | complete (M36 Wave 2) |
265
+ | REQ-087 | 5 command files no longer emit "Run /clear" STOP — runway-exceeded handoff auto-invokes `autoSpawnHeadless()` seamlessly (M35 gap fix) | m36-m35-gap-fixes | T3 | complete (M36 Wave 3) |
257
266
 
258
267
  **M35 Functional Requirements:**
259
268
  - **REQ-069**: `bin/token-budget.js` `getDegradationActions()` must return `{band: 'normal'|'warn'|'stop', pct: number, message: string}` only. No `modelOverride`, no `skipPhases`, no `checkpoint` side-channel.
@@ -276,6 +285,26 @@
276
285
  **Orphaned requirements**: None — all M35 REQs mapped to tasks.
277
286
  **Unanchored tasks**: None — all 38 M35 tasks trace to REQ-069–REQ-078 or REQ-063–068 (existing requirements that M35 code continues to satisfy).
278
287
 
288
+ **M36 Functional Requirements:**
289
+ - **REQ-079**: `bin/gsd-t-unattended.js` implements the supervisor relay loop: spawn worker → await exit → post-worker safety check → next iter. State written atomically to `.gsd-t/.unattended/state.json`. Contract: `unattended-supervisor-contract.md` v1.0.0.
290
+ - **REQ-080**: `commands/gsd-t-unattended.md` pre-flights branch + dirty tree, spawns supervisor detached, polls for PID readiness, displays initial watch block, and calls `ScheduleWakeup(270, '/user:gsd-t-unattended-watch')`.
291
+ - **REQ-081**: `commands/gsd-t-unattended-watch.md` implements the watch tick decision tree (§8 of contract): reads PID → liveness probe → reads state.json → reschedule or terminal report.
292
+ - **REQ-082**: `commands/gsd-t-resume.md` Step 0 checks `supervisor.pid` before any other resume logic. If live + non-terminal: skip normal resume, print watch block, call `ScheduleWakeup(270, '/user:gsd-t-unattended-watch')`.
293
+ - **REQ-083**: Supervisor relay architecture ensures each worker gets a fresh context window. No compaction state carries over between workers — only `.gsd-t/` milestone state files.
294
+ - **REQ-084**: `bin/gsd-t-unattended-safety.js` exports: `checkGitBranch`, `checkWorktreeCleanliness`, `validateState`, `checkIterationCap`, `checkWallClockCap`, `detectBlockerSentinel`, `detectGutter`. Called at all 4 supervisor hook points.
295
+ - **REQ-085**: `bin/gsd-t-unattended-platform.js` exports: `spawnSupervisor`, `preventSleep`, `releaseSleep`, `notify`, `resolveClaudePath`. Windows: `preventSleep` is a documented no-op. Windows caveats documented in `docs/unattended-windows-caveats.md`.
296
+ - **REQ-086**: `bin/handoff-lock.js` exports: `acquireLock(dir)`, `releaseLock(dir)`, `isLocked(dir)`. Used in `bin/headless-auto-spawn.js` `autoSpawnHeadless()` to guard the parent-exits-before-child-starts window.
297
+ - **REQ-087**: `commands/gsd-t-execute.md`, `gsd-t-wave.md`, `gsd-t-integrate.md`, `gsd-t-quick.md`, `gsd-t-debug.md` — runway-exceeded path calls `autoSpawnHeadless()` and exits cleanly. No "Run /clear" instruction emitted.
298
+
299
+ **M36 Non-Functional Requirements:**
300
+ - Zero external npm dependencies (all M36 bin/ modules use Node.js built-ins only)
301
+ - Supervisor launch → PID-ready in < 5 seconds (poll timeout in launch command)
302
+ - Worker spawn overhead: < 500ms before `claude -p` subprocess starts
303
+ - Test count: 1146 → 1226 (+80 net new tests across 6 M36 domain test files)
304
+
305
+ **Orphaned requirements**: None — all M36 REQs mapped to tasks.
306
+ **Unanchored tasks**: None — all M36 tasks trace to REQ-079–REQ-087.
307
+
279
308
  ---
280
309
 
281
310
  ## M17: Scan Visual Output — Feature Specification
@@ -0,0 +1,245 @@
1
+ # Unattended Supervisor — Windows Caveats (v1.0.0)
2
+
3
+ **Status**: Windows support is **shipping but caveated** in v1.0.0.
4
+
5
+ **Contract reference**: `.gsd-t/contracts/unattended-supervisor-contract.md` v1.0.0
6
+ **Platform module**: `bin/gsd-t-unattended-platform.js`
7
+
8
+ ---
9
+
10
+ ## 0. Required Software (All Platforms)
11
+
12
+ The launch command (`/user:gsd-t-unattended`) pre-flights required software in
13
+ Step 1e and refuses to spawn if anything is missing. Install these before
14
+ launching:
15
+
16
+ **Required everywhere (hard-fail):**
17
+
18
+ | Tool | Install |
19
+ |---------|---------------------------------------------------------------|
20
+ | node | https://nodejs.org (>= 16) |
21
+ | claude | `npm install -g @anthropic-ai/claude-code` |
22
+ | git | https://git-scm.com/downloads |
23
+
24
+ **macOS — soft warnings (install for best reliability):**
25
+
26
+ | Tool | Purpose | Install |
27
+ |-------------|--------------------------|---------------------|
28
+ | caffeinate | sleep prevention | built-in (Apple) |
29
+
30
+ **Linux — soft warnings:**
31
+
32
+ | Tool | Purpose | Install |
33
+ |---------------------------|-----------------------------|--------------------------------------------|
34
+ | systemd-inhibit OR caffeine | sleep/screen-lock prevention | usually preinstalled; else `sudo apt install caffeine` |
35
+ | notify-send | desktop notifications | `sudo apt install libnotify-bin` |
36
+
37
+ **Windows — soft warnings:**
38
+
39
+ | Tool | Purpose | Install |
40
+ |--------------------|------------------------------|----------------------------------------|
41
+ | PowerShell | sleep prevention (built-in) | ships with Windows |
42
+ | BurntToast | real toast notifications | `Install-Module BurntToast` (PowerShell) |
43
+
44
+ If the pre-flight fails, the launcher prints each missing tool with its
45
+ install instructions and refuses to spawn. Soft warnings are advisory only —
46
+ the supervisor still launches without them, but with degraded resilience.
47
+
48
+ ---
49
+
50
+ ## 1. Overview
51
+
52
+ The GSD-T unattended supervisor (M36) ships cross-platform. All core supervisor
53
+ mechanics — the watch loop, state-file lifecycle, worker spawning, stop
54
+ sentinel, and safety rails — run unchanged on Windows. The darwin and linux
55
+ code paths are runtime-tested; the win32 code paths are
56
+ **implementation-complete but not runtime-tested on the dev host (macOS)**.
57
+
58
+ Three OS-integration surfaces have known limitations on Windows:
59
+
60
+ 1. **Sleep prevention** — no stock `caffeinate` equivalent ships with Windows.
61
+ 2. **Notifications** — `msg.exe` is a minimal fire-and-forget shim with real
62
+ delivery restrictions.
63
+ 3. **Process detach** — `spawn(..., { detached: true })` behaves differently
64
+ from POSIX and is not a true daemonization primitive.
65
+
66
+ This document covers what works, what doesn't, the Spike C disposition, and
67
+ the recommended usage pattern. Everything below applies to `win32` only;
68
+ darwin and linux are unaffected.
69
+
70
+ ---
71
+
72
+ ## 2. Known Gaps
73
+
74
+ ### 2.1 Sleep prevention (no-op on win32)
75
+
76
+ `preventSleep(reason)` in `bin/gsd-t-unattended-platform.js` explicitly
77
+ **returns `null` on win32** and writes a one-line notice to stderr:
78
+
79
+ ```
80
+ [platform] sleep prevention not implemented on win32 (see docs/unattended-windows-caveats.md)
81
+ ```
82
+
83
+ Windows has no stock command-line equivalent of macOS `caffeinate`. The
84
+ native API (`SetThreadExecutionState`) requires a C binding, which violates
85
+ the GSD-T zero-external-dependency constraint for `bin/`. `releaseSleep(null)`
86
+ is a safe no-op, so the supervisor still shuts down cleanly.
87
+
88
+ **Consequence**: if a Windows machine is configured to sleep on its default
89
+ power schedule, a long unattended run will pause (or outright fail) when the
90
+ machine sleeps. The supervisor has no way to prevent this.
91
+
92
+ **Workaround (v1)**: the user must configure Windows power settings manually
93
+ to keep the machine awake for the duration of the run. Microsoft's official
94
+ guidance covers both GUI and command-line approaches:
95
+
96
+ - [powercfg command-line options](https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/powercfg-command-line-options)
97
+ - [Change power plan settings](https://support.microsoft.com/en-us/windows/change-power-mode-for-your-windows-pc-c2aff038-22f9-f46a-8ca1-ba5be2b6a7b9)
98
+
99
+ Useful examples:
100
+
101
+ ```powershell
102
+ # Disable sleep while on AC power (requires admin)
103
+ powercfg /change standby-timeout-ac 0
104
+
105
+ # Disable sleep while on battery (requires admin)
106
+ powercfg /change standby-timeout-dc 0
107
+ ```
108
+
109
+ ### 2.2 Notifications (`msg.exe`, interactive-session only)
110
+
111
+ `notify(title, message, level)` in `bin/gsd-t-unattended-platform.js` uses
112
+ `msg.exe * "title: message"` on win32 with `windowsHide: true`. This is a
113
+ deliberate minimal fire-and-forget dependency: `msg.exe` ships with Windows
114
+ and has zero install cost.
115
+
116
+ **Restrictions**:
117
+
118
+ - `msg.exe` only delivers to **interactive Windows sessions**. If the
119
+ supervisor is launched under a Windows Service, a non-interactive ssh
120
+ session, or any other session without a desktop attached, `msg.exe` will
121
+ silently drop the notification (or fail with an access error). The
122
+ supervisor core is unaffected — the `child.on('error', ...)` handler logs
123
+ the failure to stderr and the relay loop continues.
124
+ - `msg.exe` is not a true toast / Action Center notification. It pops a
125
+ blocking message-box dialog into the active session. This is visible and
126
+ audible but is not the modern Windows notification experience.
127
+
128
+ **Recommended v2 enhancement**: integrate a real toast API such as
129
+ [`BurntToast`](https://github.com/Windos/BurntToast) (a PowerShell module).
130
+ `BurntToast` requires an opt-in install, so it will remain behind a capability
131
+ check; stock installs will fall back to `msg.exe`.
132
+
133
+ ### 2.3 Process detach (`detached: true` is not full daemonization)
134
+
135
+ `spawnSupervisor({ binPath, args, cwd })` uses
136
+ `spawn('node', [...], { detached: true, stdio: 'ignore', windowsHide: true })`
137
+ followed by `child.unref()`. On **POSIX** (darwin / linux) this makes the
138
+ child a new process-group leader and the supervisor survives the parent
139
+ terminal closing. On **win32** the same options produce a separate process
140
+ tree but do **not** fully detach the child from the launching console:
141
+
142
+ - Closing the launching terminal window may still deliver a console
143
+ `CTRL_CLOSE_EVENT` to the child and terminate the supervisor.
144
+ - Signing out of the user session will terminate the child along with every
145
+ other user process.
146
+ - There is no equivalent of POSIX `setsid()` purely from Node's `spawn`
147
+ options.
148
+
149
+ **Workarounds**:
150
+
151
+ - Use `start /B` via a shell wrapper to launch the supervisor in a fully
152
+ background-detached process on the current session.
153
+ - For truly-outlive-the-session runs, register the supervisor as a **Windows
154
+ Task Scheduler** task. Task Scheduler manages its own process lifetime
155
+ independent of the interactive session.
156
+ - Run inside **WSL2** (see §5) to get POSIX detach semantics end-to-end.
157
+
158
+ ---
159
+
160
+ ## 3. Spike C Disposition — Sleep Prevention Alternatives
161
+
162
+ Spike C was an exploratory investigation of Windows-native alternatives to
163
+ `caffeinate`. The question: can we keep the zero-dependency constraint and
164
+ still prevent sleep?
165
+
166
+ Three candidates were evaluated:
167
+
168
+ | Option | Mechanism | Verdict |
169
+ |--------|-----------|---------|
170
+ | `SetThreadExecutionState` Win32 API via `ffi` | Native API, exactly what caffeinate maps to. | **Reject.** Requires `ffi-napi` or equivalent — a C binding and a compiled native dep. Violates the zero-external-dependency constraint for `bin/`. |
171
+ | `powercfg` toggle | CLI that ships with Windows. `powercfg /change standby-timeout-ac 0` before run, restore after. | **Reject.** Requires administrator privileges. Persists across runs if the supervisor crashes mid-run, leaving the machine in a modified power state. Hard to guarantee restoration. |
172
+ | Task Scheduler "wake to run" / wake events | Scheduled task can force the machine to wake at interval. | **Defer.** Best user-space path but adds non-trivial scheduler management code (create task, tear down on exit, handle orphaned tasks). |
173
+
174
+ **Verdict**: **defer to v2.** v1.0.0 ships with the `null`-handle + documentation
175
+ approach described in §2.1. v2 will consider Task Scheduler integration as the
176
+ primary path, since it is the only candidate that is both user-space and
177
+ compatible with the zero-dependency constraint.
178
+
179
+ ---
180
+
181
+ ## 4. What Works Today on Windows
182
+
183
+ All of the following run on Windows with no caveats (pending runtime testing
184
+ on a real Windows host; implementation is complete):
185
+
186
+ - **Core supervisor process** — runs to completion, observes the state file,
187
+ dispatches workers, honours the watch-loop cadence, and exits cleanly.
188
+ - **State file lifecycle** — atomic write, lockfile, heartbeat updates, and
189
+ teardown all use Node built-ins and behave identically on win32.
190
+ - **Worker spawning** — `spawnWorker(projectDir, timeoutMs)` uses `claude.cmd`
191
+ via `resolveClaudePath()` with `shell: false` and `windowsHide: true`, which
192
+ avoids the Spike C PowerShell quoting hazard.
193
+ - **Stop sentinel** — sentinel-file detection is filesystem-based and is
194
+ cross-platform by construction.
195
+ - **Safety rails** — `isAlive(pid)` uses Node's `process.kill(pid, 0)`, which
196
+ implements POSIX signal-0 semantics on Windows. Liveness checks, watchdog
197
+ timers, and stuck-worker detection all work unchanged.
198
+
199
+ Exit code table (contract §5), heartbeat contract, and the launch-handshake
200
+ file contract are all platform-agnostic and fully honoured on win32.
201
+
202
+ ---
203
+
204
+ ## 5. Recommended Usage Pattern on Windows
205
+
206
+ Given the gaps above, the recommended way to run the unattended supervisor on
207
+ Windows for v1.0.0 is:
208
+
209
+ 1. **Run on a desktop that never sleeps.** Configure Windows power settings so
210
+ the machine will not sleep, hibernate, or turn off the display for the
211
+ expected duration of the run. Use `powercfg` or the Settings UI (see §2.1).
212
+ 2. **Launch from an interactive PowerShell session** (not a Windows Service,
213
+ not a non-interactive ssh session). This ensures `msg.exe` notifications
214
+ can be delivered and that the supervisor's stderr diagnostics are visible.
215
+ 3. **Monitor via the watch-tick command from the same interactive session.**
216
+ Do not close the launching terminal until the supervisor exits — see §2.3
217
+ for why.
218
+ 4. **Consider running inside WSL2** instead of native Windows. WSL2 provides a
219
+ full Linux userland where `bin/gsd-t-unattended-platform.js` takes the
220
+ `linux` branch everywhere: `isAlive`, `spawnWorker`, `spawnSupervisor`, and
221
+ `notify` all behave with POSIX semantics end-to-end. The only remaining gap
222
+ in WSL2 is sleep prevention (linux also returns `null` from `preventSleep`
223
+ in v1.0.0), which is still governed by the host Windows machine's power
224
+ settings. WSL2 is currently the closest thing to the full darwin / linux
225
+ feature set on a Windows box.
226
+
227
+ ---
228
+
229
+ ## 6. Summary Matrix
230
+
231
+ | Feature | darwin | linux | win32 |
232
+ |--------------------------|-----------|-----------|------------------------------------------------|
233
+ | `resolveClaudePath` | `claude` | `claude` | `claude.cmd` |
234
+ | `isAlive(pid)` | works | works | works (POSIX signal-0 semantics) |
235
+ | `spawnWorker` | works | works | implementation-complete, untested on real host |
236
+ | `spawnSupervisor` detach | full | full | partial — console-close may kill child |
237
+ | `preventSleep` | works | null (v1) | null (v1) — see §2.1 and §3 |
238
+ | `releaseSleep` | works | no-op | no-op |
239
+ | `notify` | works | works | works only in interactive sessions (§2.2) |
240
+
241
+ **v2 roadmap (non-binding)**:
242
+ - Linux: opt-in `systemd-inhibit` for sleep prevention.
243
+ - Windows: Task Scheduler integration for sleep prevention; `BurntToast`
244
+ capability check for real toast notifications; optional Task-Scheduler-based
245
+ daemonization path for true detachment.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tekyzinc/gsd-t",
3
- "version": "2.76.10",
4
- "description": "GSD-T: Contract-Driven Development for Claude Code — 56 slash commands with headless CI/CD mode, graph-powered code analysis, real-time agent dashboard, execution intelligence, task telemetry, doc-ripple enforcement, backlog management, impact analysis, test sync, milestone archival, and PRD generation",
3
+ "version": "3.10.10",
4
+ "description": "GSD-T: Contract-Driven Development for Claude Code — 61 slash commands with unattended supervisor relay, headless CI/CD mode, graph-powered code analysis, real-time agent dashboard, execution intelligence, task telemetry, doc-ripple enforcement, backlog management, impact analysis, test sync, milestone archival, and PRD generation",
5
5
  "author": "Tekyz, Inc.",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -44,7 +44,7 @@ const os = require("node:os");
44
44
 
45
45
  const HOOK_SCRIPT = path.resolve(__dirname, "gsd-t-context-meter.js");
46
46
  const INJECTOR = path.resolve(__dirname, "context-meter", "test-injector.js");
47
- const HARD_TIMEOUT_MS = 6000;
47
+ const HARD_TIMEOUT_MS = 12000;
48
48
 
49
49
  /* ──────────────────────────── test fixtures ──────────────────────────── */
50
50
 
@@ -68,6 +68,9 @@ PROJECT or FEATURE or SCAN
68
68
  | `/user:gsd-t-resume` | Restore context, continue |
69
69
  | `/user:gsd-t-version-update` | Update GSD-T to latest version |
70
70
  | `/user:gsd-t-version-update-all` | Update GSD-T + all registered projects |
71
+ | `/user:gsd-t-unattended` | Launch detached supervisor — runs active milestone to completion with zero human intervention |
72
+ | `/user:gsd-t-unattended-watch` | Watch tick — fires every 270s via ScheduleWakeup, reports supervisor status |
73
+ | `/user:gsd-t-unattended-stop` | Touch stop sentinel — supervisor halts after current worker finishes |
71
74
  | `/user:gsd-t-triage-and-merge` | Auto-review, merge, and publish GitHub branches |
72
75
  | `/user:gsd-t-audit` | Harness self-audit — analyze cost/benefit of enforcement components |
73
76
  | `/user:gsd-t-design-audit` | Compare built screen against Figma design — structured deviation report |
@@ -398,6 +401,15 @@ KEEP GOING. Only stop for:
398
401
  3. Milestone completion (checkpoint for user review)
399
402
  4. Destructive actions (see Destructive Action Guard above — ALWAYS stop)
400
403
 
404
+ ## Unattended Execution (M36, v3.10.10+)
405
+
406
+ `/user:gsd-t-unattended` launches a detached OS-process supervisor that drives the active milestone to completion over hours or days via a `claude -p` worker relay — each worker in a fresh context window. The interactive Claude session receives a 270-second ScheduleWakeup watch loop (`/user:gsd-t-unattended-watch`) that ticks and prints progress until the supervisor reaches a terminal state.
407
+
408
+ - **Resume re-attach**: `/user:gsd-t-resume` checks for a live `supervisor.pid`; if the supervisor is still running, it skips normal resume and re-starts the watch loop automatically.
409
+ - **Stop**: `/user:gsd-t-unattended-stop` touches `.gsd-t/.unattended/stop`; supervisor halts after the current worker finishes.
410
+ - **Contract**: `.gsd-t/contracts/unattended-supervisor-contract.md` v1.0.0 — authoritative for state schema, exit codes, CLI flags, and platform matrix.
411
+ - **Platform**: macOS and Linux fully supported. Windows supported except sleep-prevention (see `docs/unattended-windows-caveats.md`).
412
+
401
413
  ## Pre-Commit Gate (MANDATORY)
402
414
 
403
415
  NEVER commit code without running this checklist. This is not optional.