- Add onCompromised handler to prevent uncaught throw in setTimeout
- Increase stale threshold from 5min to 30min for laptop sleep safety
- Release OS lock explicitly in SIGTERM handler
The test asserted that captureIntegrationBranch commits metadata to git,
but #1258 intentionally stopped committing .gsd/ artifacts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PR #1242 moved .gsd/ state to ~/.gsd/projects/<hash>/ with a symlink.
Git refuses to track files through symlinks, making commit_docs: true
fundamentally broken. Remove the preference and all conditional logic:
- .gsd/ is always gitignored (blanket ignore, no runtime-pattern approach)
- smartStage() always excludes .gsd/ from commits
- Prompt builders always say "do not commit planning artifacts"
- writeIntegrationBranch() writes metadata to disk without committing
- Init wizard no longer asks about commit_docs or bootstrap-commits .gsd/
- Validation emits a deprecation warning if commit_docs is still set
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a new bundled extension that proactively checks and refreshes AWS
credentials for Bedrock model users.
Startup (session_start):
- Runs 'aws sts get-caller-identity' with the profile extracted from
the configured awsAuthRefresh command
- If credentials are expired, runs the refresh command (e.g. aws sso login)
before the user sends their first prompt
- Shows 'AWS Bedrock login confirmed ✓' when credentials are valid
Mid-session (before_provider_request):
- Re-verifies credentials every 15 minutes before Bedrock API calls
- Catches credential expiry during long sessions without needing retry logic
Zero changes to base files — the entire feature is a single extension file.
Only activates when awsAuthRefresh is set in settings.json and the current
model uses bedrock-converse-stream.
The git clean -fd .gsd/ added in #1239 was too aggressive — it could
remove untracked milestone and planning files on projects where .gsd/
isn't fully gitignored (e.g., manage_gitignore: false).
Replaced with explicit removal of only runtime state files:
- STATE.md, completed-units.json, auto.lock, gsd.db
- .gsd/runtime/ directory
Milestone directories, DECISIONS.md, REQUIREMENTS.md, PROJECT.md and
all other planning artifacts are never touched.
Fixes#1250
After discussing a slice, the LLM writes S0x-CONTEXT.md. The discuss
loop re-evaluates but hits stale parse caches, showing the slice as
'not discussed' even though the context file exists on disk.
Added invalidateAllCaches() at the top of each loop iteration.
Fixes#1244
The prose fallback parser only matched H2 (## S01:) headers with
colon/dash separators. LLMs produce many variants that silently
produced 0 slices, permanently blocking auto-mode.
Expanded the regex from:
/^##\s+(?:Slice\s+)?(S\d+)[:\s—–-]+\s*(.+)/gm
to:
/^#{1,4}\s+\*{0,2}(?:Slice\s+)?(S\d+)\*{0,2}[:\s.—–-]*\s*(.+)/gm
Now handles:
- H1 through H4 headers (# ## ### ####)
- Bold-wrapped: **S01: Title**, **S01**: Title
- Dot separator: S01. Title
- Space-only separator: S01 Title (no punctuation)
- Non-zero-padded IDs: S1, S01, S001
- No-space after colon: S01:Title
- All previous separators: colon, hyphen, em dash, en dash
Also strips trailing bold markers from titles and skips matches
with empty titles.
Fixes#1243
* fix: clean up stranded .gsd.lock/ directory to prevent false lock conflicts
Three fixes for stranded proper-lockfile lock directories:
1. releaseSessionLock: explicitly removes .gsd.lock/ after releasing
the OS lock and deleting auto.lock
2. acquireSessionLock: when lock acquisition fails, checks if auto.lock
is missing or the owning PID is dead. If so, removes the stale
.gsd.lock/ dir and retries acquisition instead of failing.
3. process.on('exit') handler: registered at lock acquisition time as
a safety net — cleans up .gsd.lock/ on normal process exit if
releaseSessionLock wasn't called.
Fixes#1245
* fix: move gsdDir declaration before try/catch to fix TS2304 scope error
gsdDir was declared inside the try block but referenced in the catch
block's retry logic, causing 'Cannot find name gsdDir' build failures.
* feat: add -w/--worktree CLI flag to start in an isolated worktree
Enables `gsd -w` to auto-create a randomly-named worktree (adjective-verbing-noun
pattern) and `gsd -w my-feature` for named worktrees. Reuses existing worktree
infrastructure under .gsd/worktrees/ with worktree/<name> branches.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: full worktree lifecycle — subcommands, auto-commit on exit, status banners
Major improvements to the -w/--worktree system:
- `gsd worktree list` — show worktrees with status (files changed, commits, dirty)
- `gsd worktree merge [name]` — squash-merge into main and clean up
- `gsd worktree clean` — remove all merged/empty worktrees
- `gsd worktree remove <name>` — remove with --force safety gate
- `gsd -w` (no name) resumes the only active worktree instead of creating a new one
- `gsd -w` with multiple active worktrees shows a picker
- Auto-commit dirty work on session exit (session_shutdown hook)
- Status banner on normal `gsd` launch when unmerged worktrees exist
- Full help text with lifecycle documentation (`gsd worktree --help`)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Every extension gets a declarative extension-manifest.json (id, tier,
provides, dependencies). A persistent registry at ~/.gsd/extensions/registry.json
tracks enabled/disabled state. `gsd extensions` command family (list, enable,
disable, info) lets users manage extensions without touching source code.
Registry gate filters disabled extensions in loader.ts and resource-loader.ts
before paths reach loadExtensions(). Zero breakage: extensions without manifests
default to enabled, fresh installs have an empty registry.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move mutable .gsd/ state from inside the project directory to
~/.gsd/projects/<repo-hash>/, replacing it with a symlink. All worktrees
share the same external state — eliminating the entire bidirectional
sync layer (~370 lines) that was the source of 15+ bug fixes.
Key changes:
- repo-identity.ts: repoIdentity(), externalGsdRoot(), ensureGsdSymlink()
- gsdRoot() resolves through symlinks via realpathSync
- migrate-external.ts: automatic migration with atomic rollback
- resource-version.ts: kept utilities from deleted sync module
- Worktree detection uses git metadata (.git file) instead of path parsing
- gitignore simplified to single .gsd entry
- Doctor checks for failed_migration and broken_symlink
Deleted: auto-worktree-sync.ts, copyWorktreeDb, reconcileWorktreeDb,
reconcilePlanCheckboxes, copyPlanningArtifacts, dual state derivation.
Net: -1271 lines across 38 files. 0 sync ops per dispatch cycle.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The `name` field in `src/resources/skills/react-best-practices/SKILL.md`
was set to `vercel-react-best-practices`, which does not match the parent
directory `react-best-practices`. This triggers a validation warning on
startup: 'name "vercel-react-best-practices" does not match parent
directory "react-best-practices"'.
Updated the name field to `react-best-practices` to match the directory.
Two changes:
1. checkNeedsRunUat now reads the verdict from UAT-RESULT. Only skips
re-running UAT when verdict is PASS/passed. Non-PASS verdicts (FAIL,
surfaced-for-human-review) no longer silently advance.
2. Added uat-verdict-gate dispatch rule between run-uat and
reassess-roadmap. When uat_dispatch is enabled, scans all completed
slices for non-PASS UAT verdicts and stops auto-mode if found.
This prevents advancing to the next slice when a UAT failed or
needs human review.
Fixes#1231
After milestone creation, the file parse caches could still hold
stale results from before the ROADMAP was written. /gsd discuss checks
for ROADMAP but hits the cache, gets null, and reports 'No roadmap yet'
even though the file exists on disk.
Added invalidateAllCaches() at the top of showDiscuss() to ensure
fresh reads from disk.
Fixes#1236
Adds a traffic-light health indicator to the progress widget:
🟢 progressing, 🟡 struggling, 🔴 stuck
Uses existing health tracker signals. No separate summary model needed.
Fixes#1221
Two issues with headless new-milestone:
1. Default 300s timeout is too short — codebase investigation + artifact
writing for a new milestone regularly exceeds 5 minutes. Bumped to
600s (10 min) when the default hasn't been explicitly overridden.
2. The discuss-headless prompt's 'Investigate' step had no guidance on
how much time to spend scouting. LLMs would exhaustively explore the
codebase (50+ tool calls) before writing any artifacts, running out
of time. Added 'brief' qualifier and 5-6 tool call budget with a
note that the research phase does deeper investigation later.
The commit_docs: false preference is already respected — the prompt
correctly says 'Do not commit' when commit_docs is false, and
ensureGitignore idempotently skips when .gsd/ is already in .gitignore.
Fixes#1227
syncStateToProjectRoot copies .gsd/ files to the project root during
worktree execution. When .gsd/ is gitignored, these remain untracked.
Git refuses squash-merge because 'untracked working tree files would
be overwritten by merge.'
Added git clean -fd .gsd/ after autoCommitDirtyState and before the
branch checkout/merge sequence. This removes the untracked copies
without affecting tracked files.
Fixes#1237
Reduces auto-mode session count from ~30 to ~16 per milestone by:
1. Merging research into planning: plan-milestone and plan-slice prompts
now include exploration instructions instead of depending on separate
research sessions. All profiles default skip_research/skip_slice_research.
2. Mechanical completion: new mechanical-completion.ts deterministically
aggregates task summaries into slice/milestone artifacts (SUMMARY, UAT,
VALIDATION, roadmap checkboxes) post-verification, eliminating LLM
sessions for complete-slice and validate-milestone.
3. Reassess opt-in: reassess-roadmap now requires explicit
reassess_after_slice: true instead of firing by default.
4. Reduced context inlining: plan prompts reference PROJECT/REQUIREMENTS/
DECISIONS by path instead of inlining full content.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The plain-text fallback for depth verification asked 'Did I capture
that correctly? Anything I missed?' — two yes/no questions where a
short affirmative maps to opposite intents (yes = confirmed vs yes =
missed something).
Changed to: 'Did I capture that correctly? If not, tell me what I
missed.' — one question, then an instruction, following the pattern
established in #963.
Fixes#1224
Port the create-agent-skills skill from ~/.claude/skills/ to bundled
resources with GSD-specific adaptations: dual directory support
(~/.gsd/agent/skills/ global, .pi/agent/skills/ project-local),
auto-discovery integration, /reload activation, and telemetry/health
references. 25 files: 1 router SKILL.md, 9 workflows, 13 references,
2 templates.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the flat model list with a two-step selection: pick provider
first, then pick a model within that provider. Models are sorted
alphabetically within each group. Adds a "(type manually)" escape
hatch for arbitrary model IDs.
Background processes spawned during one task (e.g., Vite dev servers
for browser-based verification) were not cleaned up when the unit
completed. The orphaned server kept the port bound, causing the next
unit's dev server launch to fail or conflict. This led to stuck-loop
anomalies, cost spikes from timeout recovery retries, and port conflicts.
Added killSessionProcesses() to bg-shell process-manager — kills all
alive, non-persistent processes using SIGTERM. Called in auto-post-unit
after pruneDeadProcesses(). Processes with persistAcrossSessions: true
are preserved.
Fixes#1209 (orphaned processes part; the subagent bundled-extension-paths
bug is already fixed on main since a2a701b1)
* refactor: replace MCPorter CLI with native MCP client using @modelcontextprotocol/sdk
MCPorter is a third-party global CLI that fails to install on many systems,
producing error noise on every startup. Replace it with a native extension
that uses the already-bundled @modelcontextprotocol/sdk Client class directly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: update README extension table from MCPorter to MCP Client
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add .js suffix to MCP SDK subpath imports for NodeNext resolution
The SDK wildcard export (./*) requires .js suffix for TypeScript NodeNext
module resolution. Also add .js-suffixed virtual module keys so jiti
resolves them correctly in compiled Bun binaries.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(dashboard): two-column layout with task checklist
Redesign the auto-mode progress widget to use the full terminal width
with a two-column layout:
Left column (~55%): task checklist with done/active/pending glyphs
Right column (~45%): progress bar, ETA, next step, token stats, model
Additional changes:
- Merge project name, slice, and action into a single context line
- Tighten spacing (single spaces, compact hint separator)
- Collapse 5 blank separator lines down to 2
- Cache task details (id, title, done) in slice progress cache
- Footer merges pwd and keybinding hints onto one line
* refactor(dashboard): swap columns — stats left, tasks right
Move progress/ETA/tokens/model to the left column (45%) and task
checklist to the right column (55%) for better visual scanning.
* feat(dashboard): fixed-width right column with narrow fallback
Peg the task checklist to a fixed 44-char right column so it stays
readable at any width. The left column (stats/progress) flexes to
fill remaining space. Below 80 cols, falls back to single-column
stacked layout.
Also adds scripts/preview-dashboard.ts — a visual test harness
that renders the widget with mock data at any terminal width:
npx tsx scripts/preview-dashboard.ts [width]
* refactor(dashboard): swap columns — tasks left, stats right
Move task checklist back to the left column (fixed 44 chars) and
progress/ETA/tokens/model to the right column (flexes to fill).
Narrow fallback (<80 cols) stacks tasks then progress inline.
* refactor(dashboard): stats left, tasks pegged right with growing gap
Both columns are fixed width (44 chars each). The gap between them
grows as the terminal widens, keeping the task checklist anchored to
the right edge. At narrow widths (<80), falls back to single-column
with stats then tasks stacked.
* refactor(dashboard): move task column to middle, adjacent to stats
Both columns are now fixed-width and adjacent (44 + 3 + 44 = 91 chars).
Empty space flows to the right instead of between columns. The layout
stays stable regardless of terminal width.
* refactor(dashboard): flex left column, fixed right with gap
Left column now flexes to fill available space — no more truncation
on wide terminals. Right column (task checklist) stays fixed at 44
chars with a 5-char gap before the divider. Min width for two-column
mode raised to 100.
* feat: add workflow templates — named workflow shapes for different types of work
Introduces `/gsd start <template>` and `/gsd templates` commands with 8 built-in
workflow templates: bugfix, small-feature, spike, hotfix, refactor, security-audit,
dep-upgrade, and full-project. Each template defines purpose-specific phases so
work gets the right level of ceremony instead of forcing everything through the
full milestone pipeline or /gsd quick.
Includes auto-detection from natural language, --dry-run preview, state tracking
for resume support, git branch management, and artifact directory organization.
* fix: guard workflow templates against concurrent auto-mode sessions
Block /gsd start when auto-mode is active to prevent git branch conflicts
and competing message dispatch. When auto-mode is paused, allow templates
to run with an informational notice.
* feat: add workflow resume and in-progress detection
- /gsd start resume — resumes the most recent in-progress workflow
- /gsd start (no args) — shows in-progress workflow if one exists
- STATE.json tracks artifactDir and completedAt for lifecycle management
- Scans .gsd/workflows/*/STATE.json to find unfinished workflows
* chore: remove copyright headers per project conventions
Eliminates repeated try/catch JSON file load/save boilerplate across three
modules by introducing loadJsonFile, loadJsonFileOrNull, and saveJsonFile
in a shared json-persistence.ts utility.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Delete thinking-widget.ts and progress-widget.ts (fully implemented
but never imported anywhere) and remove the buildDirName identity
function from paths.ts.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
initResources() only re-synced when the GSD version changed. This meant
same-version content fixes (e.g. the subagent bundled-extension-paths.js
import fix in a2a701b1) never reached ~/.gsd/agent/extensions/ because
the version-only check saw 2.28.0 == 2.28.0 and skipped the sync.
Add a lightweight content fingerprint (sha256 of file paths + sizes) to
the managed-resources.json manifest. On startup, if the version matches
but the fingerprint doesn't, resources are re-synced. This covers:
- npm link dev workflows where source changes without version bumps
- hotfixes within a release that change bundled extension content
- upgrades from manifests without contentHash (treated as stale)
Cost: ~1ms of stat calls on ~100 files — no file reads needed.
The milestone merge dispatcher in dispatchNextUnit had two 'else if'
blocks that matched when !isInAutoWorktree() && getIsolationMode() !== 'none'.
In worktree mode, if isInAutoWorktree() returned false (e.g., after cwd
was changed back to project root), the branch-mode fallback fired and
ran 'git checkout main' — which fails because main is already checked
out at the project root.
Changed the condition from 'getIsolationMode() !== "none"' to
'getIsolationMode() === "branch"' so the branch-mode merge path only
fires when the user explicitly configured branch isolation. Worktree
mode now correctly falls through without attempting an invalid checkout.
Both instances (all-complete path and milestone-transition path) are fixed.
Fixes#1179
When the verification gate auto-discovers commands from package.json
(typecheck, lint, test), failures on pre-existing errors create a doom
loop: execute → fail → auto-fix → still fails → retry exhausted → pause.
The agent can't fix pre-existing lint/test errors it didn't introduce.
Now, when discoverySource is 'package-json', gate failures are logged
as warnings and the task proceeds without triggering the retry loop.
Explicitly configured checks (via preferences or task plan verify field)
still trigger the full retry cycle.
This preserves the safety of user-configured verification while
preventing auto-discovered checks from blocking on inherited tech debt.
Fixes#1186
Node.js's cpSync fails on Windows when the path contains non-ASCII
characters (e.g. C:\Users\Görloff) due to the \\?\ extended-length path
prefix not handling Unicode correctly. This affects both the build
script (copy-assets.cjs) and the runtime resource sync (resource-loader.ts).
Added a try/catch fallback: when cpSync throws, fall back to a manual
recursive copy using copyFileSync which handles non-ASCII paths correctly.
Changed files:
- src/resource-loader.ts: syncResourceDir() catches cpSync failure and
falls back to copyDirRecursive()
- packages/pi-coding-agent/scripts/copy-assets.cjs: all cpSync calls
wrapped in safeCpSync() with the same fallback
Fixes#1178
* fix: make package-json discovered verification commands non-blocking (advisory only)
Auto-discovered commands from package.json scripts (typecheck, lint, test) are
advisory: their failures are logged as warnings but do not block the gate or
trigger retries. Only explicitly configured preference commands and task-plan
verify commands remain blocking.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add missing blocking field to verification-evidence test fixtures
The previous commit added `blocking: boolean` to VerificationCheck but
only updated verification-gate.test.ts. The evidence test file had 26
VerificationCheck literals missing the new required field.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>