Skip to content

/gsd doctor

/gsd doctor scans your .gsd/ directory for structural integrity issues — missing summaries, unchecked roadmap entries, stale locks, orphaned worktrees, corrupt git state, environment misconfigurations, missing API keys, and more. It operates in four modes:

  • Doctor (default) — Scans and reports issues. Read-only, changes nothing.
  • Fix — Scans and auto-repairs what it can. Creates placeholder summaries, marks tasks done, removes stale locks, cleans up git state.
  • Heal — Scans, auto-repairs fixable issues, then dispatches remaining errors and UAT warnings to the LLM for interactive investigation and resolution.
  • Audit — Full scan with all warnings included, up to 50 issues displayed, no fixes applied.

Doctor checks a large set of distinct issue codes spanning six domains (project/runtime, git/worktrees, environment, provider, milestone structure, slice structure, task structure). Each issue has a severity (error, warning, info) and a fixability flag. Fix mode only touches issues marked as fixable — it won’t rewrite plan content or make judgment calls.

During auto-mode, a proactive healing layer runs lightweight checks before each unit dispatch, tracks health trends over time (green → yellow → red), and can escalate to LLM-assisted healing after 5 consecutive units with unresolved errors.

/gsd doctor # Report issues (default scope: active slice)
/gsd doctor M001 # Report issues for milestone M001
/gsd doctor M001/S02 # Report issues for a specific slice
/gsd doctor fix # Auto-repair fixable issues
/gsd doctor fix M001 # Auto-repair within milestone M001
/gsd doctor heal # Fix what's fixable, dispatch the rest to LLM
/gsd doctor audit # Full audit — all issues, all scopes, warnings included

Flags:

FlagDescription
--buildRun npm run build and report failures as env_build (slow, opt-in)
--testRun npm test and report failures as env_test (slow, opt-in)
--dry-runShow what fix mode would change without applying any changes
--jsonOutput the doctor report as raw JSON instead of human-readable text

The scope argument is optional. Without it, doctor auto-selects the active slice (if one exists), then the active milestone, then the first incomplete milestone.

Doctor loads the full project state via deriveState() and scans the milestone registry. If no scope is provided, it selects the narrowest active context — the active slice if one exists, otherwise the active milestone, otherwise the first incomplete milestone in the registry. Audit mode always uses the explicitly requested scope without auto-selection (and defaults to full-project scan when none is given).

The scanner runs six independent check functions:

  • checkGitHealth — Orphaned auto-worktrees, stale milestone branches, corrupt merge/rebase state, tracked runtime files, legacy slice branches, missing integration branches, orphaned worktree directories, and worktree lifecycle (merged, stale, dirty, unpushed). Git checks are skipped entirely if the project is not a git repo. Worktree and branch checks are also skipped when the project’s git.isolation preference is set to "none".
  • checkRuntimeHealth — Stale crash locks, stranded lock directories, stale parallel sessions, orphaned completed-unit keys, stale hook state, activity log bloat, STATE.md drift, gitignore drift, failed migration artifacts, broken .gsd symlinks, metrics ledger integrity and bloat, large planning file detection, snapshot ref bloat.
  • checkGlobalHealth — Cross-project check that scans ~/.gsd/projects/ for orphaned project state directories whose git root no longer exists on disk.
  • checkEnvironmentHealth — Node version vs. engines requirement, node_modules staleness, missing .env files, port conflicts on common dev ports, disk space, Docker availability, package manager, TypeScript/Python/Rust/Go tool presence, and git remote reachability. The --build and --test flags add opt-in slow checks that run your build/test scripts.
  • runProviderChecks — When an active milestone exists, checks required LLM provider API keys (based on configured model preferences), remote questions channel token (Slack/Discord/Telegram), and optional tool integrations (Brave, Tavily, Jina, Context7). Fast — reads auth.json and env vars only, no network I/O.
  • Inline structural checks — Preference validation, requirement auditing, and all milestone/slice/task structural integrity checks (circular dependencies, orphaned directories, duplicate task IDs, missing plans, completion drift, must-have verification, future timestamps) run directly in runGSDDoctor.

Checks are independent — a failure in one domain doesn’t prevent others from running.

When fix mode is enabled, fixable issues are repaired in place during the scan. Fixes include:

  • Creating placeholder summary stubs for missing slice summaries
  • Creating placeholder UAT stubs for missing slice UAT files
  • Unchecking tasks in plan files when done-checked tasks are missing summaries (forces re-execution — does not create a stub)
  • Marking tasks done in plan files when summaries exist but the checkbox is unchecked
  • Marking slices done in roadmaps when all tasks are complete
  • Creating missing tasks/ or slice directories
  • Removing stale crash locks (auto.lock) where the owning process is dead
  • Removing stranded lock directories left by hard crashes
  • Cleaning up stale parallel session status files
  • Removing orphaned completed-unit keys from completed-units.json
  • Clearing stale hook state from hook-state.json
  • Removing orphaned worktrees for completed milestones
  • Deleting stale milestone branches
  • Aborting corrupt git merge/rebase state
  • Removing tracked runtime files from git index
  • Removing orphaned worktree directories that aren’t registered with git
  • Pruning activity logs (7-day retention)
  • Pruning metrics ledger to newest 1500 entries when over 2000
  • Pruning snapshot refs to newest 5 per label when over 50
  • Regenerating STATE.md from current disk state
  • Ensuring .gitignore has required patterns
  • Recovering failed external state migrations (.gsd.migrating)
  • Sanitizing delimiter characters (em dash, en dash) from milestone titles in roadmaps
  • Updating recorded integration branch to fallback when original no longer exists

Fix levels: When doctor runs automatically from auto-mode post-unit hooks, it uses a restricted fixLevel: "task" that skips two protected code sets:

  • COMPLETION_TRANSITION_CODES (all_tasks_done_missing_slice_summary): Reserved for the complete-slice dispatch unit — requires LLM-generated content. Only fixed in full fix mode (/gsd doctor fix).
  • GLOBAL_STATE_CODES (orphaned_project_state, orphaned_completed_units): Removing completed-unit keys can revert project state, treating finished tasks as incomplete. These are only fixed by explicit manual doctor runs.

All other fixable codes — including roadmap checkbox updates (all_tasks_done_roadmap_not_checked) and UAT stubs (all_tasks_done_missing_slice_uat) — are fixed immediately even at fixLevel: "task" to keep bookkeeping consistent.

Heal mode first runs all fixes, then filters the remaining issues to find actionable ones — all errors, plus UAT-related warnings (all_tasks_done_missing_slice_uat, slice_checked_missing_uat). It dispatches these to the LLM as a structured list with issue codes, unit IDs, file paths, and fixability flags. The LLM receives the full doctor report as context and can use standard tools to investigate and resolve each issue. The LLM is instructed to prefer reconstructing real artifacts from existing context over leaving placeholders.

During auto-mode, doctor runs a lightweight proactive healing layer in addition to any manual invocations:

  1. Pre-dispatch health gate — Before each unit dispatch, checks for stale crash locks, corrupt merge state, missing STATE.md, missing integration branches, and low disk space. Attempts auto-repair of each. Blocks dispatch if critical issues cannot be resolved.
  2. Health score tracking — After each unit, records a health snapshot (error count, warning count, fixes applied, top issues). Tracks trends across the last 50 snapshots to detect degradation. Emits level-change events when health transitions between green (no errors), yellow (1+ errors or degrading trend), and red (3+ consecutive error units).
  3. Auto-heal escalation — After 5 consecutive units with unresolved errors, if the trend is not improving, escalates to LLM-assisted heal. Escalation fires at most once per auto-mode session.

After every run, doctor appends a compact JSONL entry to .gsd/doctor-history.jsonl with timestamps, error/warning counts, issue codes, fix descriptions, and a human-readable summary. This history is used by auto-mode for trend analysis and by formatHealthSummary() in the dashboard overlay.

Doctor checks a large set of distinct issue codes grouped by domain.

CodeSeverityDescriptionFixable
invalid_preferenceswarningPreference file has malformed fields (lists that aren’t arrays, invalid skill rules)No
active_requirement_missing_ownererrorRequirement is Active but has no primary owning sliceNo
blocked_requirement_missing_reasonwarningRequirement is Blocked but Notes field is emptyNo
state_file_stalewarningSTATE.md active milestone/slice/phase doesn’t match derived stateYes
state_file_missingwarningSTATE.md doesn’t exist but milestones directory doesYes
gitignore_missing_patternswarning.gitignore lacks required GSD runtime exclusion patternsYes
activity_log_bloatwarningActivity log directory exceeds 500 files or 100MBYes
stale_crash_lockerrorauto.lock exists but the owning process is deadYes
stranded_lock_directoryerror.gsd.lock/ directory exists but no live process holds the session lock — blocks new sessionsYes
stale_parallel_sessionwarningParallel session status file exists but the owning process is deadYes
orphaned_completed_unitswarningcompleted-units.json references units whose expected artifacts no longer existYes
stale_hook_stateinfohook-state.json has residual cycle counts from a previous sessionYes
failed_migrationerror.gsd.migrating found — a previous external state migration failedYes
broken_symlinkerror.gsd symlink target does not exist — external state directory was deletedNo
metrics_ledger_corruptwarningmetrics.json has invalid structure or is not valid JSONNo
metrics_ledger_bloatwarningmetrics.json has over 2000 unit entriesYes
large_planning_filewarningOne or more planning .md files exceed 100KB — causes LLM context pressureNo
orphaned_project_stateinfoProject state directories in ~/.gsd/projects/ whose git root no longer existsYes
CodeSeverityDescriptionFixable
corrupt_merge_stateerrorMERGE_HEAD, SQUASH_MSG, rebase-apply, or rebase-merge state foundYes
tracked_runtime_fileswarningFiles in .gsd/activity/ or .gsd/runtime/ are tracked by gitYes
legacy_slice_branchesinfoPer-slice gsd/*/* branches found (legacy pattern, no longer used)Yes
orphaned_auto_worktreewarningWorktree exists for a completed milestoneYes
stale_milestone_branchinfomilestone/* branch exists for a completed milestoneYes
integration_branch_missingwarning/errorActive milestone’s recorded integration branch no longer exists in git (warning if fallback available, error if none)Yes (if fallback)
worktree_directory_orphanedwarningWorktree directory exists on disk but is not registered with gitYes
worktree_branch_mergedinfoGSD-managed worktree’s branch is fully merged into main — safe to removeYes
worktree_stalewarningGSD-managed worktree has had no commits in 7+ daysNo
worktree_dirtywarningStale worktree has uncommitted changesNo
worktree_unpushedwarningStale worktree has unpushed commitsNo
snapshot_ref_bloatwarningOver 50 snapshot refs under refs/gsd/snapshots/Yes
CodeSeverityDescriptionFixable
env_node_versionwarningNode.js version doesn’t meet the project’s engines.node requirementNo
env_dependencieserror/warningnode_modules missing, or lockfile is newer than node_modulesNo
env_env_filewarning.env.example exists but no .env or .env.local foundNo
env_port_conflictwarningA dev server port from package.json scripts is already in useNo
env_disk_spaceerror/warningLess than 500MB free disk space (error) or less than 2GB (warning)No
env_dockerwarningProject has Docker files but Docker is not installed or daemon is not runningNo
env_package_managerwarningProject’s packageManager field requires a tool that isn’t installedNo
env_typescriptwarningTypeScript is a dependency but tsc is not availableNo
env_pythonwarningProject has Python config but python is not installedNo
env_cargowarningProject has Cargo.toml but cargo is not installedNo
env_gowarningProject has go.mod but go is not installedNo
env_git_remotewarningGit remote origin is unreachableNo
env_builderrornpm run build exits non-zero (opt-in via --build)No
env_testwarningnpm test exits non-zero (opt-in via --test)No
CodeSeverityDescriptionFixable
provider_key_missingwarningA required LLM provider API key is not configured (based on model preferences)No
provider_key_backedoffwarningAll credentials for a required provider are currently backed off (rate limited)No
CodeSeverityDescriptionFixable
delimiter_in_titlewarningMilestone title contains em dash, en dash, or slash — breaks state parsingYes (em/en dash only)
circular_slice_dependencyerrorCircular dependency detected between slices in a milestone’s roadmapNo
orphaned_slice_directorywarningA directory in slices/ is not referenced in the roadmapNo
all_slices_done_missing_milestone_validationinfoAll slices complete but VALIDATION.md is missing — milestone is in validating-milestone phaseNo
all_slices_done_missing_milestone_summarywarningAll slices complete but SUMMARY.md is missing — milestone stuck in completing-milestone phaseNo
CodeSeverityDescriptionFixable
delimiter_in_titlewarningSlice title contains em dash, en dash, or slash — breaks state parsingNo
unresolvable_dependencywarningSlice depends on an ID that is not a known slice in this roadmap — permanently blocks the sliceNo
missing_slice_direrror/warningSlice listed in roadmap has no directory (error if incomplete, warning if complete)Yes
missing_slice_planwarningSlice directory exists but has no plan file (only reported for incomplete slices)No
missing_tasks_direrror/warningSlice has a plan but no tasks/ directory (error if incomplete, warning if complete)Yes
duplicate_task_iderrorA task ID appears more than once in a slice plan — causes dispatch failuresNo
task_file_not_in_planinfoA task summary file on disk references a task ID not found in the slice planNo
all_tasks_done_missing_slice_summaryerrorAll tasks complete but slice summary missingYes
all_tasks_done_missing_slice_uatwarningAll tasks complete but UAT script missingYes
all_tasks_done_roadmap_not_checkederrorAll tasks done but slice not checked off in roadmapYes
slice_checked_missing_summaryerrorSlice is checked done in roadmap but has no summaryYes
slice_checked_missing_uatwarningSlice is checked done but has no UATYes
blocker_discovered_no_replanwarningA task summary has blocker_discovered: true but no REPLAN.md exists for the sliceNo
stale_replan_fileinfoA REPLAN.md exists for a slice where all tasks are done — file may be staleNo
CodeSeverityDescriptionFixable
task_done_missing_summaryerrorTask is marked done but has no summary file — checkbox is unchecked to force re-executionYes
task_summary_without_done_checkboxwarningSummary exists but task not checked in planYes
task_done_must_haves_not_verifiedwarningTask done but must-haves from task plan not mentioned in summaryNo
future_timestampwarningTask summary has a completed_at more than 24h in the futureNo
FilePurpose
.gsd/STATE.mdCurrent state for scope selection and staleness check
.gsd/REQUIREMENTS.mdRequirement audit (active/blocked status)
.gsd/preferences.mdPreference shape validation
.gsd/milestones/*/Full milestone registry scan
.gsd/auto.lockCrash lock detection
.gsd/.gsd.lock/Stranded lock directory detection
.gsd/parallel/*.status.jsonParallel session staleness detection
.gsd/completed-units.jsonOrphaned key detection
.gsd/hook-state.jsonStale hook state detection
.gsd/activity/Activity log size check
.gsd/metrics.jsonMetrics ledger integrity and bloat check
.gsd/doctor-history.jsonlDoctor run history (read for trend display)
.gitignorePattern completeness check
package.jsonNode version, deps, tools, port checks
auth.jsonProvider API key presence
FilePurpose
.gsd/milestones/*/slices/*/S*-SUMMARY.mdPlaceholder summary stubs
.gsd/milestones/*/slices/*/S*-UAT.mdPlaceholder UAT stubs
.gsd/milestones/*/slices/*/S*-PLAN.mdTask checkbox updates (check done, or uncheck to force re-run)
.gsd/milestones/*/M*-ROADMAP.mdSlice checkbox updates; sanitized delimiter characters
.gsd/milestones/*/slices/*/tasks/Created when tasks/ directory is missing
.gsd/milestones/*/slices/*/Created when slice directory is missing
.gsd/STATE.mdRegenerated from disk state
.gsd/auto.lockRemoved when stale
.gsd/parallel/*.status.jsonRemoved when session is stale
.gsd/completed-units.jsonOrphaned keys removed
.gsd/hook-state.jsonCleared when auto-mode is not running
.gsd/activity/Pruned to 7-day retention
.gsd/metrics.jsonPruned to newest 1500 entries
.gsd/doctor-history.jsonlDoctor run appended after every scan
.gitignoreMissing GSD runtime patterns added

Running doctor on a project with completion drift:

> /gsd doctor
GSD doctor report.
Scope: M002/S03
Issues: 3 total · 1 error(s) · 2 warning(s) · 2 fixable
Top issue types:
- task_summary_without_done_checkbox: 1
- all_tasks_done_missing_slice_uat: 1
- stale_crash_lock: 1
Priority issues:
- [ERROR] M002/S03: stale auto.lock — PID 48221 is dead
- [WARN] M002/S03/T02: summary exists but task not checked in plan
- [WARN] M002/S03: all tasks done but UAT missing

Auto-fixing:

> /gsd doctor fix
GSD doctor report.
Scope: M002/S03
Issues: 3 total · 1 error(s) · 2 warning(s) · 2 fixable
Fixes applied:
- cleared stale auto.lock
- marked T02 done in .gsd/milestones/M002/slices/S03/S03-PLAN.md

Previewing fixes without applying them:

> /gsd doctor fix --dry-run
GSD doctor report.
Scope: M002/S03
Fixes applied:
- [dry-run] would fix: uncheck T04 in plan for M002/S03/T04
- [dry-run] would fix: create placeholder UAT for M002/S03

Heal mode dispatching to LLM:

> /gsd doctor heal
GSD doctor heal prep.
Scope: M002/S03
Issues: 1 total · 1 error(s) · 0 warning(s) · 0 fixable
Doctor heal dispatched 1 issue(s) to the LLM.
● Investigating: all_tasks_done_missing_slice_uat for M002/S03...
Reading task summaries to build UAT script...

Full audit across all scopes:

> /gsd doctor audit
GSD doctor audit.
Scope: (all)
Issues: 12 total · 2 error(s) · 7 warning(s) · 3 info(s) · 8 fixable
...

Running environment checks including a build:

> /gsd doctor --build
GSD doctor report.
Scope: M003/S01
Issues: 2 total · 1 error(s) · 1 warning(s) · 0 fixable
- [ERROR] environment: Build failed — npm run build exited non-zero
- [WARN] environment: TypeScript is a dependency but tsc is not available
  • /gsd health — Diagnose planning directory health and optionally repair issues
  • /gsd forensics — Deep post-mortem investigation of auto-mode failures
  • /gsd status — View current project state
  • /gsd cleanup — Clean up stale branches and worktrees
  • /gsd prefs — Configure preferences (doctor validates these)
  • /gsd keys — Manage provider API keys (doctor checks these)