The old "demoable" definition was biased toward GUI/SaaS products —
it explicitly penalized terminal commands and curl as demo surfaces.
For developer tools (CLIs, APIs, frameworks), the terminal IS the
product interface and curl IS a legitimate demo.
Redefines "demoable" as audience-appropriate: the intended user
exercising the capability through its real interface. Adds a carve-out
for infrastructure-as-product slices (protocols, extension APIs,
provider interfaces) to the foundation-only rule.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements Phase 1 of the Claude Code subscription-as-provider integration
(issue #2509). Users with a Claude Code subscription (Pro/Max/Team) can
use subsidized inference through GSD's UI via the official Agent SDK.
The extension registers a provider with authMode: "externalCli" that
delegates to the user's locally-installed claude CLI. The SDK runs the
full agentic loop (multi-turn, tool execution) in one streamSimple call.
Tool calls stream in real-time for TUI visibility but are stripped from
the final AssistantMessage so the agent loop ends cleanly without local
tool dispatch.
Zero core changes — pure extension-based implementation.
Closes#2509
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The hash included `ts` in the input despite the docstring promising
it was "independent of ts/actor/session". On Windows, millisecond
timer resolution caused two calls within the same tick to get
different timestamps, producing different hashes for identical
cmd+params.
Remove `ts` from the hash input to match documented behavior.
Revert continue-on-error on windows-portability now that the
root cause is fixed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The 13 test files in packages/pi-coding-agent/src/core/ were never executed
in CI or by `npm test`. The test:unit glob only covers src/resources/extensions/gsd/tests/
and src/tests/, leaving lifecycle-hooks, model-registry-auth-mode, auth-storage,
and 10 other suites with zero enforcement.
- Add `test:packages` script that runs compiled dist tests after build
- Wire into both the linux build job and windows-portability job in CI
- Fix two env-isolation bugs in auth-storage.test.ts: the "returns undefined"
and "falls through to fallback resolver" tests were not clearing
OPENROUTER_API_KEY before calling getApiKey, causing failures when the
env var is set in the caller's environment
continue-on-error allows CI to conclude as success even when
windows-portability fails, unblocking the Pipeline workflow.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a session disconnects after the agent writes SUMMARY + VERIFY
files but before postUnitPostVerification updates the DB, tasks
remain 'pending' in the DB despite being complete on disk.
deriveStateFromDb now checks each non-done task for a SUMMARY file
on disk before selecting the active task. If found, it updates the
DB to 'complete' and logs to stderr for observability.
Fixes#2514
Serialize pipeline runs with a fixed concurrency group (pipeline-main)
instead of per-SHA groups that allowed parallel races. Pull --rebase
before pushing the release commit so intervening main commits don't
cause non-fast-forward failures.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace v2.44.0 "What's New" section with v2.46.0 covering single-writer
state engine, /gsd rethink, /gsd mcp, offline mode, global KNOWLEDGE.md,
mobile-responsive web UI, and key fixes
- Update default git.isolation from worktree to none across all docs
- Add /gsd rethink and /gsd mcp to command tables (README + commands.mdx)
- Add offline mode and /gsd mcp to getting-started.mdx
- Add troubleshooting entries for isolation default change and startup checks
- Reference Mintlify documentation site (gsd.build) in README
- Update git-strategy.mdx with reordered isolation modes and migration note
- Update auto-mode.mdx isolation mode listing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ensureDbOpen() and the auto-start DB lifecycle block both gated DB
creation on the presence of Markdown files (DECISIONS.md, REQUIREMENTS.md,
milestones/). In a brand new project, .gsd/ exists but contains no
Markdown yet, so gsd_decision_save returned db_unavailable and the
agent derailed.
Create an empty DB whenever .gsd/ exists, regardless of Markdown content.
Migration runs only when Markdown files are present.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a proper public-facing documentation site using Mintlify with 19 MDX
pages covering getting started, auto mode, commands, configuration, and
all user-facing features. Move internal/SDK documentation (Pi SDK, TUI,
context & hooks, research notes, ADRs) to docs-internal/ since they
should not be part of the public documentation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace direct file writes and manual DECISIONS.md/REQUIREMENTS.md
mutations in GSD prompts with the correct gsd_* tool calls:
- `gsd_summary_save` for RESEARCH, CONTEXT, and SUMMARY artifacts
- `gsd_requirement_update` instead of direct REQUIREMENTS.md edits
- `gsd_decision_save` instead of append-to-DECISIONS.md
- `gsd_plan_slice` instead of manual plan file writes in guided-plan-slice
Also document intentional exceptions: quick-task (no milestone context,
outside auto-mode lifecycle) and rethink park/unpark/reorder/discard
(no tool API exists for these milestone-lifecycle operations yet).
Adds "never edited manually" clarification to system.md checkbox docs.
After slice completion + reset, the roadmap projection may not be re-rendered
in the new table format. DB state is authoritative — assert on DB status
instead of parsing projection files.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Vitest/node --test uses esbuild for transpilation and skips type-checking,
so type errors in extension tests accumulate silently until CI runs
tsc --noEmit. Adding typecheck:extensions as a pretest gate catches drift
locally before it reaches CI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DB state is authoritative (single-writer engine). The filesystem parser
doesn't parse the new table-format roadmap projections, so cross-validation
is relaxed to check DB correctness only. Undo/reset roadmap check accepts
either checkbox or emoji format.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Roadmap now uses emoji table (✅/⬜) instead of markdown checkboxes ([x]/[ ]).
Plan checkbox format changed from **T01:** to **T01: title**.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove completedUnits from WorkerInfo/SessionLockData test object literals
- Remove verifyExpectedArtifact/writeUnitRuntimeRecord from LoopDeps mocks
- Fix writeLock call signatures (remove numeric completedUnits arg)
- Fix idle-recovery imports (moved to auto-recovery.ts)
- Add full_plan_md to TaskRow test objects
- Fix WorkflowEvent type in test (exclude session_id from Omit)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Write intercept: block edit + bash tools (not just write), case-insensitive
patterns for macOS, resolve ".." path segments, use BLOCKED_WRITE_ERROR constant
- TOCTOU: move all guard reads inside transaction callbacks across all 5 handlers
(complete-task, complete-slice, complete-milestone, reopen-task, reopen-slice)
- Wrap reopen-task in a transaction (was bare updateTaskStatus call)
- Fix "done" vs "complete" status inconsistency: complete-slice task filter,
projection SUMMARY rendering, and regenerateIfMissing all accept both statuses
- Workflow reconcile: sync-lock for concurrent access, stable timestamp sort,
write event log before DB replay, wrap replayEvents in transaction, include ts
in event hash, add session_id to parsed conflict events, replay non-conflicting
events after last conflict resolution
- Manifest: wrap snapshotState queries in deferred transaction for consistent
snapshot, validate manifest structure on read
- Projections: fix regenerateIfMissing SUMMARY to check individual files not just
directory, return false for async STATE regeneration, use logWarning consistently
- Logger: hasWarnings() checks for actual warnings (not just buffer.length > 0),
stderr output on audit write failures
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
37 new tests across 4 files covering v3 features that had no test
coverage, plus regression tests for the projection bug fixes:
- reopen-task.test.ts (8): success path (reset to pending, no side
effects on other tasks) + 6 failure paths (empty ID, missing
milestone/slice/task, closed parents, already pending)
- reopen-slice.test.ts (7): success path (reset slice + all tasks,
single task variant) + 5 failure paths (empty ID, missing entities,
closed milestone, already in_progress)
- unit-ownership.test.ts (14): key builders, claim/get/release CRUD,
overwrite semantics, multi-unit independence, checkOwnership
(opt-in when no actorName, null when unclaimed, pass when owner
matches, error when mismatch)
- projection-regression.test.ts (8): renderPlanContent checkbox for
"complete"/"done"/"pending" status + mixed, parsePlan-compatible
bold format, renderRoadmapContent status icons
All 37 tests pass. Zero regressions.
Three work streams bundled into one phase to close the behavioral control
gaps identified in the v2 handler audit:
Stream 1 — State machine guards on all 8 tool handlers:
- Entity existence checks before mutations (milestone, slice, task)
- Valid status transition enforcement (can't double-complete, can't re-plan
closed work, can't complete inside a closed parent)
- depends_on validation for plan-milestone (deps must exist + be complete)
- blockerTaskId verification in replan-slice (must exist + be complete)
- Deep task check in complete-milestone (all tasks, not just slice status)
Stream 2 — Actor identity + persistent audit log:
- WorkflowEvent extended with actor_name, trigger_reason, session_id
- Engine-generated UUID session_id stable per process lifetime
- All 8 handlers accept optional actorName/triggerReason and pass through
- workflow-logger now flushes to .gsd/audit-log.jsonl (survives context resets)
- New setLogBasePath() and readAuditLog() API
Stream 3 — Reversibility + unit ownership:
- New gsd_task_reopen handler (reset task to pending with full guards)
- New gsd_slice_reopen handler (reset slice + all tasks with transaction)
- Opt-in unit ownership via .gsd/unit-claims.json (claim/release/check)
- Ownership enforced in complete-task and complete-slice when claims exist
- insertReplanHistory converted to upsert via schema v11 unique index
Bug fixes (pre-existing):
- renderPlanContent checkbox: checked "done" but tasks are "complete"
- renderRoadmapContent: same "done" vs "complete" mismatch
- renderPlanContent format: **T01:** title didn't match parsePlan regex
- Tests updated to seed DB entities and match projection output format
The previous regex `/[/\\]\.gsd[/\\]STATE\.md$/` required a path
separator *before* `.gsd`, so a bare relative path like `.gsd/STATE.md`
(no leading directory component) was not blocked. If the file doesn't
exist yet, `realpathSync` throws and the bare path slipped through
undetected.
Fix: change both patterns to `(^|[/\\])` so paths starting with `.gsd/`
are caught regardless of whether a separator precedes them.
Caught during e2e team verification (write-intercept-e2e agent).
Updated test to assert the bare path is now blocked.
62 new tests across 6 files covering the modules introduced in the v2
single-writer discipline layer that had no test coverage:
- write-intercept.test.ts (15): isBlockedStateFile path matching for
STATE.md (blocked) vs other .gsd/ files (allowed), BLOCKED_WRITE_ERROR
- sync-lock.test.ts (7): acquireSyncLock/releaseSyncLock including
lock file creation, round-trip, and stale lock override
- workflow-events.test.ts (15): appendEvent (creates dir, valid JSONL,
deterministic hash), readEvents (empty, parse, skip corrupted),
findForkPoint (edge cases), compactMilestoneEvents (archive/truncate)
- workflow-manifest.test.ts (8): snapshotState, writeManifest,
readManifest (null/parse/version guard), bootstrapFromManifest
round-trip restore
- workflow-projections.test.ts (17): renderPlanContent pure function —
H1/Goal/Demo/Tasks structure, [x]/[ ] checkboxes, Estimate/Files/
Verify/Duration sublines, task ordering
- post-mutation-hook.test.ts (5): regression — verifies that after
handleCompleteTask, event-log.jsonl and state-manifest.json are
both written by the post-mutation hook; also confirms hook failures
are non-fatal (handler still returns success)
All 62 tests pass. Zero regressions introduced.
Ports the single-writer state architecture from PRs #2288–#2293 onto the
current upstream codebase (schema v10, polymorphic engine). Original PRs
were based on a pre-v5 schema with incompatible column names and predated
the WorkflowEngine interface refactor.
New files:
- workflow-events.ts: append-only event log (.gsd/event-log.jsonl)
- workflow-manifest.ts: full DB snapshot after every mutation (crash recovery)
- workflow-projections.ts: renders PLAN/ROADMAP/SUMMARY/STATE.md from DB
- workflow-migration.ts: migrates legacy markdown projects into DB
- workflow-reconcile.ts: event log replay for diverged worktrees
- workflow-logger.ts: structured error/warning accumulation
- sync-lock.ts: advisory lock for concurrent worktree syncs
- write-intercept.ts: blocks direct writes to STATE.md
- auto-artifact-paths.ts: central artifact path registry
Modified:
- All 8 tool handlers (complete-task, complete-slice, plan-slice, etc.)
now wrap mutations in atomic transactions + emit event log + write
manifest + regenerate markdown projections after every command
- state.ts: telemetry counters for DB vs filesystem derivation paths
- register-hooks.ts: write-intercept wired into tool_call hook
- doctor.ts/doctor-checks.ts/doctor-types.ts: engine health checks,
fixable:false on completion-state issues, removed placeholder stubs
- auto.ts + supporting files: removed completedUnits tracking globally,
removed unit-runtime record reads/writes, removed inline doctor runs
- auto-post-unit.ts: detectRogueFileWrites (6 unit types), removed
doctor health tracking block, added regenerateIfMissing on retry
- 3 prompts updated to use gsd_* tool API instead of direct file edits
ADR-004: GSD had multiple writers racing to edit the same markdown files
concurrently, causing race conditions, stale reads, and corrupt state.
The single-writer discipline layer makes markdown files derived artifacts
(generated from DB after every command) rather than authoritative sources.
Supersedes closed PRs: #2288, #2289, #2290, #2291, #2292, #2293
AI assistance: implemented with Claude Code (GSD/Claude).
Generator (codebase-generator.ts):
- Fix truncation off-by-one: use filtered.length > maxFiles (not >=)
- Fix collapsed-directory round-trip: emit <!-- gsd:collapsed-descriptions -->
comment blocks so incremental updates recover descriptions for collapsed dirs
- Fix double-enumeration race in updateCodebaseMap: reuse files array from
generateCodebaseMap instead of calling enumerateFiles a second time
- Propagate truncated flag through updateCodebaseMap return type
- Fix getCodebaseMapStats to read Files: N from header (accurate for collapsed dirs)
- Remove redundant dead catch around lsFiles() in enumerateFiles
- parseCodebaseMap: use else-if for bare match (avoid unnecessary double-check)
- parseCodebaseMap: scan gsd:collapsed-descriptions comment blocks
Command handler (commands-codebase.ts):
- Bare /gsd codebase now shows stats (if map exists) or help (if no map)
instead of silently running generate
- Add explicit help subcommand with info-level output
- Guard update: warn if no CODEBASE.md exists instead of silently generating
- Validate --max-files: reject NaN, zero, and negative values with clear message
- Emit warning (not success) when generate produces 0 files
- Propagate truncated flag warning in both generate and update output
- Fix extractFlag regex: escape flag name and support --flag=value syntax
- Add actionable tip to stats output
Catalog (commands/catalog.ts):
- Add --max-files and help to codebase tab-completion entries
System context (bootstrap/system-context.ts):
- Cap CODEBASE.md injection at 8 000 chars (~2 000 tokens) per request
- Add generation timestamp and staleness notice to the injected block header
Paths (paths.ts):
- Fix LEGACY_GSD_ROOT_FILES.CODEBASE to use lowercase codebase.md (matches
the pattern of all other legacy root file names)
Tests (codebase-generator.test.ts):
- 15 new test cases: custom excludePatterns, collapseThreshold option,
truncation boundary conditions (below/at/above limit), non-git directory,
empty repo, collapsed-description round-trip, removed file tracking,
binary/lock exclusions, truncated flag propagation, collapsed-dir stats
accuracy, .gsd/ auto-creation, corrupted input, parseCodebaseMap comment blocks
- Fix collapse assertion to verify individual entries are absent from main body
- Fix git rm test to commit first so git rm succeeds
- 29/29 tests passing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add /gsd codebase command that generates .gsd/CODEBASE.md — a table of
contents for the project giving agents instant structural awareness.
Eliminates the 10-30+ tool call "exploration tax" that fresh agent
contexts pay to understand what exists and where things live.
Components:
- codebase-generator.ts: walks git ls-files, groups by directory,
renders with one-liner descriptions, supports incremental updates
that preserve existing descriptions
- commands-codebase.ts: CLI handler (generate, update, stats)
- system-context.ts: injects CODEBASE.md into system prompt at
session start (alongside KNOWLEDGE.md)
- paths.ts: adds CODEBASE to GSD_ROOT_FILES
- catalog.ts: registers command with nested completions
Features:
- Incremental update preserves agent-written descriptions
- Directories with >20 files collapsed to summary
- Token budget: ~2-4K for 100 files, scaling to ~20K for 500
- Configurable excludes and max file count
Closes#2229
14 unit tests, all passing.
Two bugs in ensureLinuxReady():
1. Branch ordering: "ModuleNotFoundError: No module named 'sounddevice'"
contains the word "sounddevice", so the portaudio branch matched first,
producing the misleading "install libportaudio2" message even when
libportaudio2 was already installed.
2. No venv auto-creation: On PEP 668 systems (Ubuntu 23.10+), system pip
is blocked. The code trusted speech-recognizer.py to self-install deps,
but its pip install also fails. Now ensureLinuxReady() auto-creates
~/.gsd/voice-venv when the sounddevice module is missing.
Fixes:
- Extract diagnoseSounddeviceError() with correct branch ordering
(check "No module"/"ModuleNotFoundError" BEFORE "sounddevice")
- Add ensureVoiceVenv() to auto-create venv with sounddevice+requests
- Refactor into linux-ready.ts for testability
- Add 20 unit tests covering all error diagnosis paths and venv creation
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dev Publish can succeed but Test & Verify fails immediately after because
npm's CDN hasn't propagated the new version yet. Adds a retry loop (6
attempts, 10s apart) so the install survives propagation latency.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When no preferences.md exists, getIsolationMode() and
shouldUseWorktreeIsolation() defaulted to "worktree", which requires
git branch infrastructure (milestone/<MID> branches) that isn't
automatically set up. This caused milestone-complete to fail with
"branch doesn't exist" when users worked directly on main without
configuring preferences.
Change the default to "none" (work on current branch) across all five
locations: getIsolationMode(), shouldUseWorktreeIsolation(),
MODE_DEFAULTS for solo/team, doctor.ts, and doctor-checks.ts.
Worktree isolation is now explicit opt-in via preferences.md.
Closes#2480
* fix(gsd): add worktree lifecycle events to journal
* fix(gsd): widen source scan window in merge-conflict test
The journal event additions in _mergeWorktreeMode pushed the
MergeConflictError re-throw past the 5000-char scan window used
by merge-conflict-stops-loop.test.ts. Increase to 6000 to
accommodate the added emitJournalEvent calls.
* fix(gsd): restore cwd before temp dir cleanup in journal test
On Windows, rmSync fails with EPERM when the process cwd is inside
the directory being deleted. Save and restore the original cwd in
afterEach before cleanup.
* feat(gsd): add workflow-logger for structured operational error/warning accumulation
Adds workflow-logger.ts — a centralized in-memory accumulator for operational
warnings and errors across the GSD engine pipeline.
Key additions vs the standalone/workflow-logger branch:
- Fix hasWarnings() to filter severity === "warn" (was returning _buffer.length > 0,
incorrectly returning true for error-only buffers)
- Add hasAnyIssues() for callers that want to check for either severity
- Add drainAndSummarize() atomic helper to prevent the drain-before-summarize footgun
- Document singleton safety requirement: callers must _resetLogs() per unit
- Document always-on stderr policy (intentional, unlike debug-logger opt-in)
- Move test from engine/ to tests/ to match project test discovery glob
- Expand test suite from 15 to 32 cases: stderr output, context handling,
hasWarnings with errors-only buffer, drainAndSummarize, double-drain,
warnings-only summarize, formatForNotification context exclusion,
buffer limit robustness, ISO timestamp validation
* feat(gsd): wire workflow-logger into engine, tool, manifest, and reconcile paths
Routes 34 previously silent/raw-stderr error and warning sites through the
structured workflow-logger so the auto-loop can drain and surface root causes.
Changes by component:
tool (12 sites) — bootstrap/db-tools.ts
All 12 gsd_* tool handler catch blocks replaced from process.stderr.write
to logError("tool", ...) with { tool, error } context.
engine (9 sites) — auto/phases.ts (7), auto/run-unit.ts (2)
7 silent catches in phases.ts annotated with logWarning("engine", ...):
health gate, milestone merge, completed-units archive, STATE.md rebuild,
baseline char count, prompt reorder failure, disk flush.
2 silent catches in run-unit.ts: chdir and clearQueue failures.
manifest (8 sites) — db-writer.ts
nextDecisionId, saveDecisionToDb, updateRequirementInDb, saveArtifactToDb
error paths replaced with logError("manifest", ...).
Shrinkage guard replaced with logWarning("manifest", ...).
reconcile (5 sites) — auto-worktree.ts (2), worktree-manager.ts (3)
Post-create hook failure, teardown directory persistence, stale worktree
removal, submodule stash, stash failure — all replaced with
logWarning("reconcile", ...) with { worktree } context.
No control flow changed. TypeScript clean. 32/32 tests pass.
* fix(gsd): use info.name instead of global name in auto-worktree logWarning call
Adds a new bundled skill `/btw` inspired by Claude Code's built-in
`/btw` command (https://code.claude.com/docs/en/interactive-mode#side-questions-with-/btw).
## What it does
`/btw` lets users ask a quick side question about their current work
without derailing the main task or polluting conversation history.
Unlike a normal prompt, it:
- Answers **only from information already in the session** (files
already read, decisions already made, code already seen)
- **Uses no tools** — no file reads, no bash commands, no search
- Returns a **single concise response** with no follow-up turns
- Gracefully declines when the answer requires new tool calls,
suggesting the user ask as a normal prompt instead
## Why it matters
When Claude is mid-task and the user wants a quick recall ("what was
that config key again?", "which branch are we on?", "did we handle
the null case?"), a full prompt interrupts the flow and adds noise to
context. `/btw` gives a fast, lightweight escape hatch for exactly
those moments.
## Implementation
New file: `src/resources/skills/btw/SKILL.md`
No other changes needed. The existing build pipeline
(`scripts/copy-resources.cjs`) copies all non-TS files from
`src/resources/` → `dist/resources/`, and `initResources()` in
`src/resource-loader.ts` syncs `dist/resources/skills/` →
`~/.gsd/agent/skills/` at startup — the same mechanism that ships
all other bundled skills (lint, review, create-skill, etc.).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>