Adds a `statusline.show_last_command` config toggle (default: false) that
appends ` │ last: /<cmd>` to the statusline, showing the most recently
invoked slash command in the current session.
The suffix is derived by tailing the active Claude Code transcript
(provided as transcript_path in the hook input) and extracting the last
<command-name> tag. Reads only the final 256 KiB to stay cheap per render.
Graceful degradation: missing transcript, no recorded command, unreadable
config, or parse errors all silently omit the suffix without breaking the
statusline.
Closes#2538
* fix(hooks): detect Claude Code via stdin session_id, not filtered env (#2520)
The #2344 fix assumed `CLAUDECODE` would propagate to hook subprocesses.
On Claude Code v2.1.116 it doesn't — Claude Code applies a separate env
filter to PreToolUse hook commands that drops bare CLAUDECODE and
CLAUDE_SESSION_ID, keeping only CLAUDE_CODE_*-prefixed vars plus
CLAUDE_PROJECT_DIR. As a result every Edit/Write on an existing file
produced a redundant READ-BEFORE-EDIT advisory inside Claude Code.
Use `data.session_id` from the hook's stdin JSON as the primary Claude
Code signal (it's part of Claude Code's documented PreToolUse hook-input
schema). Keep CLAUDE_CODE_ENTRYPOINT / CLAUDE_CODE_SSE_PORT env checks
as propagation-verified fallbacks, and keep the legacy
CLAUDE_SESSION_ID / CLAUDECODE checks for back-compat and
future-proofing.
Add tests/bug-2520-read-guard-hook-subprocess-env.test.cjs, which spawns
the hook with an env mirroring the actual Claude Code hook-subprocess
filter. Extend the legacy test harnesses to also strip the
propagation-verified CLAUDE_CODE_* vars so positive-path tests keep
passing when the suite itself runs inside a Claude Code session (same
class of leak as #2370 / PR #2375, now covering the new detection
signals).
Non-Claude-host behavior (OpenCode / MiniMax) is unchanged: with no
`session_id` on stdin and no CLAUDE_CODE_* env var, the advisory still
fires.
Closes#2520
* test(2520): isolate session_id signal from env fallbacks in regression test
Per reviewer feedback (Copilot + CodeRabbit on #2521): the session_id
isolation test used the helper's default CLAUDE_CODE_ENTRYPOINT /
CLAUDE_CODE_SSE_PORT values, so the env fallback would rescue the skip
even if the primary `data.session_id` check regressed. Pass an explicit
env override that clears those fallbacks, so only the stdin `session_id`
signal can trigger the skip.
Other cases (env-only fallback, negative / non-Claude host) already
override env appropriately.
---------
Co-authored-by: forfrossen <forfrossensvart@gmail.com>
Bug #2453: After tsc builds sdk/dist/cli.js, npm install -g from a local
directory does not chmod the bin-script target (unlike tarball extraction).
The file lands at mode 644, the gsd-sdk symlink points at a non-executable
file, and command -v gsd-sdk fails on every first install. Fix: explicitly
chmodSync(cliPath, 0o755) immediately after npm install -g completes,
mirroring the pattern used for hook files throughout the installer.
Bug #2451: gsd-context-monitor warning messages over-reported usage by ~13
percentage points vs CC native /context. Root cause: gsd-statusline.js
wrote a buffer-normalized used_pct (accounting for the 16.5% autocompact
reserve) to the bridge file, inflating values. The bridge used_pct is now
raw (Math.round(100 - remaining_percentage)), consistent with what CC's
native /context command reports. The statusline progress bar continues to
display the normalized value; only the bridge value changes. Updated the
existing #2219 tests to check the normalized display via hook stdout rather
than bridge.used_pct, and added a new assertion that bridge.used_pct is raw.
Closes#2453Closes#2451
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add /gsd-spec-phase — Socratic spec refinement with ambiguity scoring (#2213)
Introduces `/gsd-spec-phase <phase>` as an optional pre-step before discuss-phase.
Clarifies WHAT a phase delivers (requirements, boundaries, acceptance criteria) with
quantitative ambiguity scoring before discuss-phase handles HOW to implement.
- `commands/gsd/spec-phase.md` — slash command routing to workflow
- `get-shit-done/workflows/spec-phase.md` — full Socratic interview loop (up to 6
rounds, 5 rotating perspectives: Researcher, Simplifier, Boundary Keeper, Failure
Analyst, Seed Closer) with weighted 4-dimension ambiguity gate (≤ 0.20 to write SPEC.md)
- `get-shit-done/templates/spec.md` — SPEC.md template with falsifiable requirements
(Current/Target/Acceptance per requirement), Boundaries, Acceptance Criteria,
Ambiguity Report, and Interview Log; includes two full worked examples
- `get-shit-done/workflows/discuss-phase.md` — new `check_spec` step detects
`{padded_phase}-SPEC.md` at startup; displays "Found SPEC.md — N requirements
locked. Focusing on implementation decisions."; `analyze_phase` respects `spec_loaded`
flag to skip "what/why" gray areas; `write_context` emits `<spec_lock>` section
with boundary summary and canonical ref to SPEC.md
- `docs/ARCHITECTURE.md` — update command/workflow counts (74→75, 71→72)
Closes#2213
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(hooks): add gsd-read-injection-scanner PostToolUse hook (#2201)
Adds a new PostToolUse hook that scans content returned by the Read tool
for prompt injection patterns, including four summarisation-specific patterns
(retention-directive, permanence-claim, etc.) that survive context compression.
Defense-in-depth for long GSD sessions where the context summariser cannot
distinguish user instructions from content read from external files.
- Advisory-only (warns without blocking), consistent with gsd-prompt-guard.js
- LOW severity for 1-2 patterns, HIGH for 3+
- Inlined pattern library (hook independence)
- Exclusion list: .planning/, REVIEW.md, CHECKPOINT, security docs, hook sources
- Wired in install.js as PostToolUse matcher: Read, timeout: 5s
- Added to MANAGED_HOOKS for staleness detection
- 19 tests covering all 13 acceptance criteria (SCAN-01–07, EXCL-01–06, EDGE-01–06)
Closes#2201
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(ci): add read-injection-scanner files to prompt-injection-scan allowlist
Test payloads in tests/read-injection-scanner.test.cjs and inlined patterns
in hooks/gsd-read-injection-scanner.js legitimately contain injection strings.
Add both to the CI script allowlist to prevent false-positive failures.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(test): assert exitCode, stdout, and signal explicitly in EDGE-05
Addresses CodeRabbit feedback: the success path discarded the return
value so a malformed-JSON input that produced stdout would still pass.
Now captures and asserts all three observable properties.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
The autocompact buffer percentage was hardcoded to 16.5%. Users who set
CLAUDE_CODE_AUTO_COMPACT_WINDOW to a custom token count (e.g. 400000 on
a 1M-context model) saw a miscalibrated context meter and incorrect
warning thresholds in the context-monitor hook (which reads used_pct from
the bridge file the statusline writes).
Now reads CLAUDE_CODE_AUTO_COMPACT_WINDOW from the hook env and computes:
buffer_pct = acw_tokens / total_tokens * 100
Defaults to 16.5% when the var is absent or zero, preserving existing
behavior.
Also applies the renameDecimalPhases zero-padding fix for clean CI.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(hooks): stamp gsd-hook-version in .sh hooks and fix stale detection regex (#2136, #2206)
Three-part fix for the persistent "⚠ stale hooks — run /gsd-update" false
positive that appeared on every session after a fresh install.
Root cause: the stale-hook detector (gsd-check-update.js) could only match
the JS comment syntax // in its version regex — never the bash # syntax used
in .sh hooks. And the bash hooks had no version header at all, so they always
landed in the "unknown / stale" branch regardless.
Neither partial fix (PR #2207 regex only, PR #2215 install stamping only) was
sufficient alone:
- Regex fix without install stamping: hooks install with literal
"{{GSD_VERSION}}", the {{-guard silently skips them, bash hook staleness
permanently undetectable after future updates.
- Install stamping without regex fix: hooks are stamped correctly with
"# gsd-hook-version: 1.36.0" but the detector's // regex can't read it;
still falls to the unknown/stale branch on every session.
Fix:
1. Add "# gsd-hook-version: {{GSD_VERSION}}" header to
gsd-phase-boundary.sh, gsd-session-state.sh, gsd-validate-commit.sh
2. Extend install.js (both bundled and Codex paths) to substitute
{{GSD_VERSION}} in .sh files at install time (same as .js hooks)
3. Extend gsd-check-update.js versionMatch regex to handle bash "#"
comment syntax: /(?:\/\/|#) gsd-hook-version:\s*(.+)/
Tests: 11 new assertions across 5 describe blocks covering all three fix
parts independently plus an E2E install+detect round-trip. 3885/3885 pass.
Approach credit: PR #2207 (j2h4u / Maxim Brashenko) for the regex fix;
PR #2215 (nitsan2dots) for the install.js substitution approach.
Closes#2136, #2206, #2209, #2210, #2212
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(hooks): extract check-update worker to dedicated file, eliminating template-literal regex escaping
Move stale-hook detection logic from inline `node -e '<template literal>'` subprocess
to a standalone gsd-check-update-worker.js. Benefits:
- Regex is plain JS with no double-escaping (root cause of the (?:\\/\\/|#) confusion)
- Worker is independently testable and can be read directly by tests
- Uses execFileSync (array args) to satisfy security hook that blocks execSync
- MANAGED_HOOKS now includes gsd-check-update-worker.js itself
Update tests to read worker file instead of main hook for regex/configDir assertions.
All 3886 tests pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
When a user manually installs a dev branch where VERSION > npm latest,
gsd-check-update detects hooks as "stale" and the statusline showed
the red "⚠ stale hooks — run /gsd-update" message. Running /gsd-update
would incorrectly downgrade the dev install to the npm release.
Fix: detect dev install (cache.installed > cache.latest) in the
statusline and show an amber "⚠ dev install — re-run installer to sync
hooks" message instead, with /gsd-update reserved for normal upgrades.
Also expand the update.md workflow's installed > latest branch to
explain the situation and give the correct remediation command
(node bin/install.js --global --claude, not /gsd-update).
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(2136): add failing test for MANAGED_HOOKS missing bash hooks
Asserts that every gsd-*.js and gsd-*.sh file shipped in hooks/ appears
in the MANAGED_HOOKS array inside gsd-check-update.js. The three bash
hooks (gsd-phase-boundary.sh, gsd-session-state.sh, gsd-validate-commit.sh)
were absent, causing this test to fail before the fix.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(2136): add gsd-phase-boundary.sh, gsd-session-state.sh, gsd-validate-commit.sh to MANAGED_HOOKS
The MANAGED_HOOKS array in gsd-check-update.js only listed the 6 JS hooks.
The 3 bash hooks were never checked for staleness after a GSD update, meaning
users could run stale shell hooks indefinitely without any warning.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Review feedback from @trek-e — three blocking fixes:
1. **Sentinel prevents repeated firing**
Added warnData.criticalRecorded flag persisted to the warn state file.
Previously the subprocess fired on every DEBOUNCE_CALLS cycle (5 tool
uses) for the rest of the session, overwriting the "crash moment"
record with a new timestamp each time. Now fires exactly once per
CRITICAL session.
2. **Runtime-agnostic path via __dirname**
Replaced hardcoded `path.join(process.env.HOME, '.claude', ...)` with
`path.join(__dirname, '..', 'get-shit-done', 'bin', 'gsd-tools.cjs')`.
The hook lives at <runtime-config>/hooks/ and gsd-tools.cjs at
<runtime-config>/get-shit-done/bin/ — __dirname resolves correctly on
all runtimes (Claude Code, OpenCode, Gemini, Kilo) without assuming
~/.claude/.
3. **Correct subcommand: state record-session**
Switched from `state update "Stopped At" ...` to
`state record-session --stopped-at ...`. The dedicated command
updates Last session, Last Date, Stopped At, and Resume File
atomically under the state lock.
Also:
- Hoisted `const { spawn } = require('child_process')` to top of file
to match existing require() style.
- Coerced usedPct to Number(usedPct) || 0 to sanitize the bridge file
in case it's malformed or adversarially crafted.
Tests (tests/bug-1974-context-exhaustion-record.test.cjs, 4 cases):
- Subprocess spawns and writes "context exhaustion" on CRITICAL
- Subprocess does NOT spawn when .planning/STATE.md is absent
- Sentinel guard prevents second fire within same session
- Hook source uses __dirname-based path (not hardcoded ~/.claude/)
When the context monitor detects CRITICAL threshold (25% remaining)
and a GSD project is active, spawn a fire-and-forget subprocess to
record "Stopped At: context exhaustion at N%" in STATE.md.
This provides automatic breadcrumbs for /gsd-resume-work when sessions
crash from context exhaustion — the most common unrecoverable scenario.
Previously, session state was only saved via voluntary /gsd-pause-work.
The subprocess is detached and unref'd so it doesn't block the hook
or the agent. The advisory warning to the agent is unchanged.
Closes#1974
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When no in_progress todo is active, fill the middle slot of
gsd-statusline.js with GSD state read from .planning/STATE.md.
Format: <milestone> · <status> · <phase name> (N/total)
- Add readGsdState() — walks up from workspace dir looking for
.planning/STATE.md (bounded at 10 levels / home dir)
- Add parseStateMd() — reads YAML frontmatter (status, milestone,
milestone_name) and Phase line from body; falls back to body Status:
parsing for older STATE.md files without frontmatter
- Add formatGsdState() — joins available parts with ' · ', degrades
gracefully when fields are missing
- Wrap stdin handler in runStatusline() and export helpers so unit
tests can require the file without triggering the script behavior
Strictly additive: active todo wins the slot (unchanged); missing
STATE.md leaves the slot empty (unchanged). Only the "no active todo
AND STATE.md present" path is new.
Uses the YAML frontmatter added for #628, completing the statusline
display that issue originally proposed.
Closes#1989
* fix(hooks): skip read-guard advisory on Claude Code runtime (#1984)
Claude Code natively enforces read-before-edit at the runtime level,
so the gsd-read-guard.js advisory is redundant — it wastes ~80 tokens
per Write/Edit call and clutters tool flow with system-reminder noise.
Add early exit when CLAUDE_SESSION_ID is set (standard Claude Code
session env var). Non-Claude runtimes (OpenCode, Gemini, etc.) that
lack native read-before-edit enforcement continue to receive the
advisory as before.
Closes#1984
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(hooks): sanitize runHook env to prevent test failures in Claude Code
The runHook() test helper now blanks CLAUDE_SESSION_ID so positive-path
tests pass even when the test suite runs inside a Claude Code session.
The new skip test passes the env var explicitly via envOverrides.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The context monitor hook read and parsed config.json on every
PostToolUse event. For non-GSD projects (no .planning/ directory),
this was unnecessary I/O. Add a quick existsSync check for the
.planning/ directory before attempting to read config.json.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move .claude to the front of the detectConfigDir search array so Claude Code
sessions always find their own GSD install first, preventing false "update
available" warnings when an older OpenCode install coexists on the same machine.
Closes#1860
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* test: add stale /gsd: colon reference regression guard
Fixes#1748
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: replace 39 stale /gsd: colon references with /gsd- hyphen format
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The stale hooks detector in gsd-check-update.js used a broad
`startsWith('gsd-') && endsWith('.js')` filter that matched every
gsd-*.js file in the hooks directory. Orphaned hooks from removed
features (e.g., gsd-intel-*.js) lacked version headers and were
permanently flagged as stale, with no way to clear the warning.
Replace the broad wildcard with a MANAGED_HOOKS allowlist of the 6
JS hooks GSD currently ships. Orphaned files are now ignored.
Regression test verifies: (1) no broad wildcard filter, (2) managed
list matches build-hooks.js HOOKS_TO_COPY, (3) orphaned filenames
are excluded.
Fixes#1750
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Fixes#1696
The gsd-prompt-guard.js hook was missing the 'act as a/an/the' prompt
injection pattern that security.cjs includes. Adds the pattern with
the same (?!plan|phase|wave) negative lookahead exception to allow
legitimate GSD workflow references.
* fix(hooks): add read-before-edit guidance for non-Claude runtimes
When models that don't natively enforce read-before-edit hit the guard,
the error message now includes explicit instruction to Read first.
This prevents infinite retry loops that burn through usage.
Closes#1628
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(build): register gsd-read-guard.js in HOOKS_TO_COPY and harden tests
The hook was missing from scripts/build-hooks.js, so global installs
would never receive the hook file in hooks/dist/. Also adds tests for
build registration, install uninstall list, and non-string file_path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: replace /gsd: command format with /gsd- skill format in all suggestions
All next-step suggestions shown to users were still using the old colon
format (/gsd:xxx) which cannot be copy-pasted as skills. Migrated all
occurrences across agents/, commands/, get-shit-done/, docs/, README files,
bin/install.js (hardcoded defaults for claude runtime), and
get-shit-done/bin/lib/*.cjs (generate-claude-md templates and error messages).
Updated tests to assert new hyphen format instead of old colon format.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: migrate remaining /gsd: format to /gsd- in hooks, workflows, and sdk
Addresses remaining user-facing occurrences missed in the initial migration:
- hooks/: fix 4 user-facing messages (pause-work, update, fast, quick)
and 2 comments in gsd-workflow-guard.js
- get-shit-done/workflows/: fix 21 Skill() literal calls that Claude
executes directly (installer does not transform workflow content)
- sdk/prompt-sanitizer.ts: update regex to strip /gsd- format in addition
to legacy /gsd: format; update JSDoc comment
- tests/: update autonomous-ui-steps, prompt-sanitizer to assert new format
Note: commands/gsd/*.md frontmatter (name: gsd:xxx) intentionally unchanged
— installer derives skillName from directory path, not the name field.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(plan-phase): preserve --chain flag in auto-advance sync and handle ui-phase gate in chain mode
Bug 1: step 15 sync-flag check only guarded against --auto, causing
_auto_chain_active to be cleared when plan-phase is invoked without
--auto in ARGUMENTS even though a --chain pipeline was active. Added
--chain to the guard condition, matching discuss-phase behaviour.
Bug 2: UI Design Contract gate (step 5.6) always exited the workflow
when UI-SPEC was missing, breaking the discuss --chain pipeline
silently. When _auto_chain_active is true, the gate now auto-invokes
gsd-ui-phase --auto via Skill() and continues to step 6 without
prompting. Manual invocations retain the existing AskUserQuestion flow.
* fix: remove <sub>/clear</sub> pattern and duplicate old-format command in discuss-phase.md
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(hooks): use semver comparison for update check instead of inequality
gsd-check-update.js used `installed !== latest` to determine if an
update is available. This incorrectly flags an update when the installed
version is NEWER than npm (e.g., installing from git ahead of a release).
Replace with proper semver comparison: update_available is true only
when the npm version is strictly newer than the installed version.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(hooks): use semver comparison for update check instead of inequality
gsd-check-update.js used `installed !== latest` to determine if an
update is available. This incorrectly flags an update when the installed
version is NEWER than npm (e.g., installing from git ahead of a release).
Fix:
- Move isNewer() inside the spawned child process (was in parent scope,
causing ReferenceError in production)
- Strip pre-release suffixes before Number() to avoid NaN
- Apply same semver comparison to stale hooks check (line 95)
update_available is now true only when npm version is strictly newer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: add semver comparison tests for gsd-check-update isNewer()
12 test cases covering: major/minor/patch comparison, equal versions,
installed-ahead-of-npm scenario, pre-release suffix stripping,
null/empty handling, two-segment versions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: explain why isNewer is duplicated in test file
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- fix(#1572): phase complete now marks bold-wrapped plan checkboxes in ROADMAP.md
(`- [ ] **01-01**` format) by allowing optional `**` around plan IDs in the
planCheckboxPattern regex in both phase.cjs and roadmap.cjs
- fix(#1569): manager init no longer recommends 999.x (BACKLOG) phases as next
actions; add guard in cmdManagerInit that skips phases matching /^999(?:\.|$)/
- fix(#1568): add regression tests confirming init execute-phase respects
model_overrides for executor_model, including when resolve_model_ids is 'omit'
- fix(#1533): reject session_id values containing path traversal sequences
(../, /, \) in gsd-context-monitor and gsd-statusline before constructing
/tmp file paths; add security tests covering both hooks
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bring the latest main branch updates into feat/kilo-runtime-support while preserving KILO_CONFIG resolution, Kilo agent permission conversion, and relative .claude path rewrites.
Port 3 community hooks from gsd-skill-creator, gated behind hooks.community config flag. All hooks are registered on install but are no-ops unless the project config has hooks: { community: true }.
gsd-session-state.sh (SessionStart): outputs STATE.md head for orientation. gsd-validate-commit.sh (PreToolUse/Bash): blocks non-Conventional-Commits messages. gsd-phase-boundary.sh (PostToolUse/Write|Edit): warns when .planning/ files are modified.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two fixes for multi-runtime installations:
1. Update cache now writes to ~/.cache/gsd/ instead of the runtime-
specific config dir, preventing mismatches when check-update and
statusline resolve to different runtimes. Statusline reads from
shared path first with legacy fallback.
2. Stale hooks detection now checks configDir/hooks/ where hooks are
actually installed, not configDir/get-shit-done/hooks/ which does
not exist.
Closes#1421
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
gsd-check-update.js looked for hooks in configDir/hooks/ (e.g.,
~/.claude/hooks/) but the installer writes hooks to
configDir/get-shit-done/hooks/. This mismatch caused false stale
hook warnings that persisted even after updating.
Also clears the update cache during install so the next session
re-evaluates hook versions with the correct path.
Closes#1249
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
gsd-workflow-guard.js was missing the // gsd-hook-version: {{GSD_VERSION}}
header that all other hook files have. The stale hook detection in
gsd-check-update.js scans all gsd-*.js files for this header and flags
any without it as stale (hookVersion: 'unknown'). This caused a
persistent '⚠ stale hooks — run /gsd:update' warning in the statusline
even on the latest version.
Added the version header to gsd-workflow-guard.js. Running /gsd:update
will reinstall the hook with the correct version stamp.
gsd-check-update.js scanned ALL .js files in the hooks directory and
flagged any without a gsd-hook-version header as stale. This incorrectly
flagged user-created hooks (e.g. guard-edits-outside-project.js),
producing a persistent 'stale hooks' warning that /gsd:update couldn't
resolve.
Fix: filter hookFiles to f.startsWith('gsd-') && f.endsWith('.js')
since all GSD hooks follow the gsd-* naming convention.
Includes regression test validating the filter excludes user hooks.
Closes#1200
New opt-in PreToolUse hook that warns when Claude edits files outside
a GSD workflow context (no active /gsd: command or subagent).
Soft guard — advises, does not block. The edit proceeds but Claude
sees a reminder to use /gsd:fast or /gsd:quick for state tracking.
Enable: set hooks.workflow_guard: true in .planning/config.json
Default: disabled (false)
Allows without warning:
- .planning/ files (GSD state management)
- Config files (.gitignore, .env, CLAUDE.md, settings.json)
- Subagent contexts (executor, planner, etc.)
Includes 3s stdin timeout guard and silent fail-safe.
Closes#678
* fix: hook version tracking, stale hook detection, and stdin timeout increase
- Add gsd-hook-version header to all hook files for version tracking (#1153)
- Install.js now stamps current version into hooks during installation
- gsd-check-update.js detects stale hooks by comparing version headers
- gsd-statusline.js shows warning when stale hooks are detected
- Increase context monitor stdin timeout from 3s to 10s (#1162)
- Set +x permission on hook files during installation (#1162)
Fixes#1153, #1162, #1161
* feat: add /gsd:session-report command for post-session summary generation
Adds a new command that generates SESSION_REPORT.md with:
- Work performed summary (phases touched, commits, files changed)
- Key outcomes and decisions made
- Active blockers and open items
- Estimated resource usage metrics
Reports are written to .planning/reports/ with date-stamped filenames.
Closes#1157
* test: update expected skill count from 39 to 40 for new session-report command
- fix(frontmatter): handle CRLF line endings in extractFrontmatter,
spliceFrontmatter, and parseMustHavesBlock — fixes wave parsing on
Windows where all plans reported as wave 1 (#1085)
- fix(hooks): remove duplicate const cwd declaration in
gsd-context-monitor.js that caused SyntaxError on every PostToolUse
invocation (#1091, #1092, #1094)
- feat(state): add 'state begin-phase' command that updates STATUS,
Last Activity, Current focus, Current Position, and plan counts
when a new phase starts executing (#1102, #1103, #1104)
- docs(workflow): add state begin-phase call to execute-phase workflow
validate_phase step so STATE.md is current from the start
Add hooks.context_warnings config option (default: true) that allows
users to disable the context monitor hook's advisory messages. When
set to false, the hook exits silently, allowing Claude Code to reach
auto-compact naturally without being interrupted.
This is useful for long unattended runs where users prefer Claude to
auto-compact and continue rather than stopping to warn about context.
Changes:
- hooks/gsd-context-monitor.js: Check config before emitting warnings
- get-shit-done/templates/config.json: Add hooks.context_warnings default
- get-shit-done/workflows/settings.md: Add UI for the new setting
Fixes#976
The context monitor uses imperative language ("STOP new work
immediately. Save state NOW") that overrides user preferences and
causes autonomous state saves in non-GSD sessions. Replace with
advisory messaging that informs the user and respects their control.
- Detect GSD-active sessions via .planning/STATE.md
- GSD sessions: warn user, reference /gsd:pause-work, but don't
command autonomous saves (STATE.md already tracks state)
- Non-GSD sessions: inform user, explicitly say "Do NOT autonomously
save state unless the user asks"
- Remove all imperative language (STOP, NOW, immediately)
Closes#884
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hooks hardcode ~/.claude/ as the config directory, breaking setups
where Claude Code uses a custom config directory (e.g. multi-account
with CLAUDE_CONFIG_DIR=~/.claude-personal/). The update check hook
shows stale notifications and the statusline reads from wrong paths.
- gsd-check-update.js: check CLAUDE_CONFIG_DIR before filesystem scan
- gsd-statusline.js: use CLAUDE_CONFIG_DIR for todos and cache paths
Closes#870
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The context monitor and statusline hooks wait for stdin 'end' event
before processing. On some platforms (Windows/Git Bash), the stdin pipe
may not close cleanly, causing the script to hang until Claude Code's
hook timeout kills it — surfacing as "PostToolUse:Read hook error" after
every tool call. Add a 3-second timeout that exits silently if stdin
doesn't complete, preventing the noisy error messages.
Closes#775
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The statusline uses a hardcoded 80% scaling factor for context usage,
but Claude Code's actual autocompact buffer is 16.5% (usable context is
83.5%). This inflates the displayed percentage and causes the context
monitor's WARNING/CRITICAL thresholds to fire prematurely.
Replace the 80% scaling with proper normalization against the 16.5%
autocompact buffer. Adjust color thresholds to intuitive levels
(50/65/80% of usable context).
Closes#769
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three files had hardcoded `.claude` paths that break OpenCode and
Gemini installations where the config directory is `.config/opencode`,
`.opencode`, or `.gemini` respectively.
Changes:
- hooks/gsd-check-update.js: add detectConfigDir() helper that checks
all runtime directories for get-shit-done/VERSION, falling back to
.claude. Used for cache dir, project VERSION, and global VERSION.
- commands/gsd/reapply-patches.md: detect runtime directory for both
global and local patch directories instead of hardcoding ~/.claude/
and ./.claude/
- workflows/update.md: detect runtime directory for local and global
VERSION/marker files, and clear cache across all runtime directories
Closes#682
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Gemini CLI uses AfterTool as the post-tool hook event name, not
PostToolUse (which is Claude Code's event name). The installer was
registering the context monitor under PostToolUse for all runtimes,
causing Gemini to print "Invalid hook event name" warnings on every
run and silently disabling the context monitor.
Changes:
- install.js: use runtime-aware event name (AfterTool for Gemini,
PostToolUse for others) when registering context monitor hook
- install.js: uninstall cleans up both PostToolUse and AfterTool
entries for backward compatibility with existing installs
- gsd-context-monitor.js: runtime-aware hookEventName in output
- docs/context-monitor.md: document both event names with Gemini
example
Closes#750
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On Windows, child.unref() alone is insufficient for proper process
detachment. The child process remains in the parent's process group,
causing Claude Code to wait for the hook process tree to exit before
accepting input.
Adding detached: true allows the child process to fully detach on
Windows while maintaining existing behavior on Unix.
Closes#466
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Claude Code enforces an 80% context window limit as a safety mechanism.
The statusline was showing the raw percentage, which meant the bar never
reached 100% before Claude ran out of context.
This change scales the percentage so that:
- 0% real usage = 0% displayed
- 80% real usage (the actual limit) = 100% displayed
Color thresholds are adjusted accordingly to maintain the same visual
progression (green -> yellow -> orange -> red with skull).
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Rolled back the intel system due to overengineering concerns:
- 1200+ line hook with SQLite graph database
- 21MB sql.js dependency
- Entity generation spawning additional Claude calls
- Complex system with unclear value
Removed:
- /gsd:analyze-codebase command
- /gsd:query-intel command
- gsd-intel-index.js, gsd-intel-session.js, gsd-intel-prune.js hooks
- gsd-entity-generator, gsd-indexer agents
- entity.md template
- sql.js dependency
Preserved:
- Model profiles feature
- Statusline hook
- All other v1.9.x improvements
-3,065 lines removed
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>