* fix(#437): restore defaults.run.shell at job level (step-level matrix expr rejected by GHA) Per actions/runner workflow-v1.0.json schema, `jobs.<job_id>.defaults.run.shell` allows `matrix` context (job-defaults-run has context:[matrix,...]); step-level `shell:` does not (run-step's shell field is plain string with no context array). PR #434 used step-level shell:${{matrix.shell}}, which GHA's parser rejects with "Unrecognized named-value: 'matrix'" — blocking every push to next and every release.yml dispatch. This commit: - Removes step-level `shell: ${{ matrix.shell }}` from test-full (test.yml) and smoke (install-smoke.yml) jobs (17 directives). - Adds `defaults.run.shell: ${{ matrix.shell }}` at job level in those two jobs. - Fixes pre-existing shellcheck SC2129 in test.yml (individual >> redirects → grouped brace form) and SC2010 in install-smoke.yml (ls|grep → glob loop). Verified locally with actionlint 1.7.12 (exit 0). Policy linter still 0 violations (matrix.shell now resolves via job.defaults.run.shell which the linter already handles per workflow-policy.cjs:effectiveShell). Refs: actions/runner#444 (open since 2020), GHA contexts page section "Context availability". * fix(#439): inline ci-smoke-skip back to shell (Node port required pre-checkout file resolution) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#440): use platform-correct npm.cmd on Windows for spawn (and surface-check other Node ports) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#437): use 'zsh {0}' format string in matrix.shell for macOS (zsh not in GHA built-ins) Per https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions (jobs.<job_id>.defaults.run.shell section): "You can use built-in shell keywords like bash, pwsh, python, sh, cmd, and powershell, or define a custom set of shell options." zsh is not in the built-ins list. GHA accepts custom shells via a format string containing '{0}', which it replaces with the temporary script file path at runtime (same pattern as the perl {0} example in the docs). Bare `shell: zsh` triggers: "Invalid shell option. Shell must be a valid built-in or a format string containing '{0}'". Precursor: 514cb429 introduced the matrix shell-pinning pattern; this completes it by switching the macOS rows from the bare value to the required format string. Also updates scripts/workflow-policy.cjs to normalise 'zsh {0}' to 'zsh' before the policy comparison, so the repo-baseline test continues to pass (the linter was correctly treating 'zsh {0}' as a distinct value from the policy 'zsh'). Affects: - .github/workflows/test.yml: test-full matrix (node 22 + node 24 macOS rows) - .github/workflows/install-smoke.yml: smoke matrix (macOS node 24 row) - scripts/workflow-policy.cjs: detectViolation strips ' {0}' format suffix * fix(#440): add shell:true to spawnSync on Windows for .cmd files (Node docs requirement) Per https://nodejs.org/docs/latest-v22.x/api/child_process.html: ".bat and .cmd files require a terminal to run and cannot be launched directly with execFile(). To run these scripts on Windows, use child_process.spawn() with the shell option, child_process.exec(), or spawn cmd.exe with the script as an argument." "On Windows, .bat and .cmd files require a shell to execute. Use child_process.exec() or child_process.spawn() with the shell: true option." On Windows, npm is installed as npm.cmd (a batch wrapper). Without shell: true, spawnSync resolves the binary directly and fails with ENOENT / "npm binary not found on PATH" because the OS cannot execute a .cmd file without cmd.exe as the intermediary. The fix uses `shell: process.platform === 'win32'` so the shell spawning is only activated on Windows; macOS/Linux continue to resolve the plain npm binary directly with shell: false, preserving the existing behaviour on non-Windows platforms. Updated both spawnSync(npmCmd, ...) call sites: - npm --version check (line 182) - npm ci --dry-run lockfile-sync check (line 215) * fix(#437): bug-410 defaults test — set USERPROFILE for Windows os.homedir() redirect On Windows, os.homedir() reads USERPROFILE (not HOME), so the test's process.env.HOME = FAKE_HOME redirect was silently ignored. finishInstall's path.join(os.homedir(), '.gsd') resolved to the real user home and the defaults.json write either failed (permissions) or landed outside the temp dir, causing the existsSync assertion to return false. Fix: also set process.env.USERPROFILE = FAKE_HOME so os.homedir() returns the sandboxed directory on Windows. Node.js docs (os.homedir): https://nodejs.org/docs/latest-v22.x/api/os.html#oshomedir Refs: #437 (fix/437-restore-defaults-run-shell), Windows pwsh compat Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#437): precommit-alias-drift hook test — use path.delimiter for PATH Hardcoded ':' PATH separator breaks Windows where process.env.PATH uses ';'. The malformed PATH passed to bash caused the mock git/npm stubs in binDir to be invisible to the hook script; npm was never called and the marker file never written. Fix: replace ':' with path.delimiter in both PATH constructions so the env var is well-formed on Windows (';') and POSIX (':') alike. Refs: #437 (fix/437-restore-defaults-run-shell), Windows pwsh compat Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#437): prepush-enterprise-email hook test — use path.delimiter for PATH Same root cause as precommit-alias-drift: hardcoded ':' PATH separator is invalid on Windows (';' required). The malformed PATH meant bash ran the real git binary instead of the mock stub, which rejected the placeholder SHAs 'refs-local-sha' / 'refs-remote-sha' with a fatal ambiguous-argument error rather than returning the fixture commit list. Fix: replace ':' with path.delimiter in both execFileSync PATH env values. Refs: #437 (fix/437-restore-defaults-run-shell), Windows pwsh compat Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#437): set MSYS2_PATH_TYPE=inherit so mock stubs take precedence in Git Bash PATH Root cause: Git Bash (MSYS2) on Windows prepends its own system directories (/mingw64/bin, /usr/bin, /bin) to the PATH at process startup before the user-supplied Windows PATH entries. This placed the real git/npm binaries ahead of the mock stubs in binDir even though binDir was first in the Windows PATH passed to execFileSync. The path.delimiter fix (0042fe0d) made the PATH syntactically correct for Windows (semicolons) but did not change the MSYS2 system-dir prepend order. The real git rejected placeholder SHAs (refs-local-sha, refs-remote-sha) with "fatal: ambiguous argument", producing the observed Windows CI failure. For the pre-commit test, the real git output nothing (no staged files on a fresh checkout), so the grep match failed and npm was never called. Fix: set MSYS2_PATH_TYPE=inherit in the env passed to both bash spawns. With inherit, MSYS2 uses only the converted Windows PATH without prepending system directories, so binDir (converted from Windows to POSIX) is first in the search path and the mock stubs are found. grep/tr/printf remain available: the GHA Windows runner PATH includes C:\Program Files\Git\usr\bin which contains these utilities; MSYS2 converts that Windows entry to a POSIX path on startup. The /usr/bin/env shebang in mock stubs resolves through MSYS2's virtual filesystem mount (not via PATH) and is always accessible regardless of MSYS2_PATH_TYPE. On macOS/Linux this variable is ignored; no behaviour change on those platforms. Source: https://www.msys2.org/wiki/MSYS2-introduction/#path (MSYS2_PATH_TYPE controls whether system dirs are prepended to converted PATH) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#437): hook test mocks — use cmd-shim pattern for Windows bin resolution On Windows, bash (Git Bash / MSYS2) resolves PATH commands by scanning for extensionless files, but cmd.exe and Win32 process creation resolve via PATHEXT (.CMD, .BAT, .EXE). When execFileSync('bash', [hookPath]) runs a hook that calls `git` or `npm`, both resolution paths may fire. The previous approach set MSYS2_PATH_TYPE=inherit in the child env, but that variable is only read in /etc/profile (login-shell path) — bash launched without --login never sources /etc/profile, so the variable had no effect: https://github.com/msys2/MSYS2-packages/blob/master/filesystem/profile Fix: adopt the cmd-shim three-file pattern used by npm itself: https://github.com/npm/cmd-shim For each mock binary, write: <name> extensionless bash script (bash PATH scan) <name>.cmd batch wrapper delegating to bash (PATHEXT / cmd.exe) <name>.ps1 PowerShell wrapper (completeness) This is the same approach used by stevemao/mock-bin for test mocking with Windows CI green on AppVeyor: https://github.com/stevemao/mock-bin The .cmd and .ps1 files are only written on process.platform === 'win32'. MSYS2_PATH_TYPE is removed from the child env — it was ineffective and is no longer needed with the shim files in place. * fix(#437): tarball-smoke — raise CHILD_TIMEOUT_MS on Windows to 600 s The CI failure showed a test duration of 120003.1812 ms — matching the previous CHILD_TIMEOUT_MS = 120_000 exactly. When spawnSync hits its timeout, it sends SIGTERM and returns { status: null, stdout: '', stderr: '' } per the Node.js docs: https://nodejs.org/docs/latest-v22.x/api/child_process.html "status: <number> | <null> — The exit code of the subprocess, or null if the subprocess terminated due to a signal." The installResult check is `status !== 0`; null !== 0 is true, so the timeout fired the INSTALL_FAILED path with empty stdout/stderr, which made the root cause invisible in CI logs. GitHub-hosted Windows runners are slower than Linux/macOS for filesystem-heavy operations (npm install -g of a 1499-file tarball): https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories Fix: use 600_000 ms (10 min) on Windows, keeping 120_000 ms on POSIX. 600 s matches the SLOW_HOST_TIMEOUT already used in the test before() helper for the pack + install fixture step. Also expose `signal` and `installError` in the INSTALL_FAILED details object so a future timeout (status=null, signal='SIGTERM', stdout='') is immediately diagnosable in CI logs without guesswork. * fix(#437): chmod +x via bash on Windows for hook test mocks (root cause: fs.writeFileSync mode=0o755 no-op on NTFS) Root cause: Node's fs.writeFileSync mode=0o755 is a no-op for the execute bit on Windows NTFS. Per https://nodejs.org/docs/latest-v22.x/api/fs.html: "on Windows only the write permission can be changed." Bash's access(X_OK) therefore skips the mock file; the real git/npm binary is found later in PATH and the hook runs against real state instead of the test double. Fix: after writeFileSync, invoke Git Bash's chmod via the POSIX emulation layer (Cygwin/MSYS2), which sets the NTFS execute ACL that Node cannot reach: const posixPath = filePath.replace(/\\/g, '/'); execFileSync('bash', ['-c', `chmod +x "${posixPath}"`], { stdio: 'pipe' }); execFileSync('bash', ...) works because Git for Windows ships bash on PATH in all GHA Windows runners. Forward-slash conversion is required because MSYS2 bash auto-converts /c/foo paths but not mixed-separator paths. Why prior approaches didn't take effect: - MSYS2_PATH_TYPE=inherit: only read in /etc/profile (login-shell path); execFileSync('bash', ...) launches non-interactively without --login, so /etc/profile is never sourced. Ref: https://github.com/msys2/MSYS2-packages/blob/master/filesystem/profile - .cmd/.ps1 cmd-shim wrappers: bash does POSIX command resolution and does not honor PATHEXT, so wrappers are not found by bash's own PATH scan. They are not wrong (kept for non-bash callers) but do not fix bash's X_OK. Files changed: tests/precommit-alias-drift-hook.test.cjs, tests/prepush-enterprise-email-hook.test.cjs * refactor(#437): hooks use GIT_OVERRIDE/NPM_OVERRIDE env-var DI; tests drop PATH-mocking Four prior rounds (path.delimiter join, MSYS2_PATH_TYPE=inherit, cmd-shim .cmd/.ps1 wrappers, chmod-via-bash post-write) all failed to make MSYS2 bash's PATH-lookup find the mock executables. The root cause is that none of those approaches can reliably override bash's own command-resolution on NTFS without fighting NTFS execute-ACLs or login-shell profile sourcing. The simplest robust solution is to bypass PATH entirely: Hooks: each hook now binds GIT_CMD="${GIT_OVERRIDE:-git}" (and NPM_CMD for pre-commit) at the top. When env vars are unset the hooks invoke bare `git`/`npm` exactly as before — zero behavior change for users. Tests: writeMockBin/binDir/PATH manipulation replaced by writeMock(), which writes a .sh mock to a tmpDir and passes its absolute path via GIT_OVERRIDE / NPM_OVERRIDE in the execFileSync env. Bash inside the hook executes the path directly via the seam — no PATH scan, no NTFS ACL check, no MSYS2 profile dependency. Test-rigor principle: the new seam (env-var injection) is platform- independent and doesn't rely on bash's command-resolution mechanism on the host OS. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: CI Rebase Check <ci@gsd-redux> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Project Continuity Notice
GSD is maintained by the open-gsd team at:
open-gsd/get-shit-done-reduxUse only these package names:
- npm (main):
@opengsd/get-shit-done-redux- npm (sdk):
@opengsd/gsd-sdkThe legacy upstream is outside open-gsd control. Based on public transition announcements and repository ownership reality, we strongly recommend removing legacy packages and migrating to
@opengsd/*.Security status:
- maintainers completed an internal security audit
- maintainers report an independent review pass
- no known active exploit was found in tracked source during those passes
See:
- continuity announcement: https://github.com/open-gsd/get-shit-done-redux/discussions/109
- audit transparency report: https://github.com/open-gsd/get-shit-done-redux/discussions/119
GET SHIT DONE
English · Português · 简体中文 · 日本語 · 한국어
A light-weight meta-prompting, context engineering, and spec-driven development system for Claude Code, OpenCode, Gemini CLI, Kilo, Codex, Copilot, Cursor, Windsurf, and more.
Solves context rot — the quality degradation that happens as your AI fills its context window.
npx @opengsd/get-shit-done-redux@latest
Works on Mac, Windows, and Linux.
"If you know clearly what you want, this WILL build it for you. No bs."
"I've done SpecKit, OpenSpec and Taskmaster — this has produced the best results for me."
"By far the most powerful addition to my Claude Code. Nothing over-engineered. Literally just gets shit done."
Trusted by engineers at Amazon, Google, Shopify, and Webflow.
Important
Returning to GSD?
Run
/gsd-map-codebaseto re-index your codebase, then/gsd-new-projectto rebuild GSD's planning context. Your code is fine — GSD just needs its context rebuilt. See the CHANGELOG for what's new.
Why We Continue Building GSD
GSD exists to help solo builders and small teams ship reliably with AI: clear specs, controlled context, and verification before release.
In May 2026, maintainers published a continuity announcement and migrated active development to open-gsd/get-shit-done-redux after trust and ownership concerns around the former upstream, including a meme-coin rug-pull incident publicly associated with that ecosystem.
The former creator and legacy lineage are no longer part of this program. This repository is the maintained continuation under open-gsd governance.
The current team continues release operations, triage, and security hardening in public. Audit status and follow-up security work are documented in Discussion #119 and linked issues.
How It Works
The loop is six commands. Each one does exactly one thing.
1. Initialize
/gsd-new-project
Questions → research → requirements → roadmap. You approve it, then you're ready to build.
Already have code? Run
/gsd-map-codebasefirst. It analyzes your stack, architecture, and conventions so/gsd-new-projectasks the right questions.
2. Discuss
/gsd-discuss-phase 1
Your roadmap has a sentence per phase. That's not enough to build it the way you imagine it. Discuss captures your decisions before anything gets planned: layouts, API shapes, error handling, data structures — whatever gray areas exist for this specific phase.
The output feeds directly into research and planning. Skip it, get reasonable defaults. Use it, get your vision.
3. Plan
/gsd-plan-phase 1
Research → plan → verify, in a loop until the plans pass. Each plan is small enough to execute in a fresh context window.
4. Execute
/gsd-execute-phase 1
Plans run in parallel waves. Each executor gets a fresh 200k-token context. Each task gets its own atomic commit. Walk away, come back to completed work with a clean git history.
Your main context window stays at 30–40%. The work happens in the subagents.
5. Verify
/gsd-verify-work 1
Walk through what was built. Anything broken gets a diagnosed fix plan — ready for immediate re-execution. You don't debug manually; you just run execute again.
6. Repeat → Ship
/gsd-ship 1
/gsd-complete-milestone
/gsd-new-milestone
Loop discuss → plan → execute → verify → ship until the milestone is done. Then archive, tag, and start the next one fresh.
Getting Started
npx @opengsd/get-shit-done-redux@latest
The installer prompts for your runtime (Claude Code, OpenCode, Gemini CLI, Kilo, Codex, Copilot, Cursor, Windsurf, and more) and whether to install globally or locally.
claude --dangerously-skip-permissions
GSD is built for frictionless automation. Skip-permissions is how it's intended to run.
Install only the skills you need with --profile=core (six core-loop skills), --profile=standard (core + phase management), or the default full install. Profiles compose: --profile=core,audit. --minimal is an alias for --profile=core. See docs/USER-GUIDE.md for the full walkthrough, non-interactive install flags for all 15 runtimes, and permissions configuration. See ADR-0011 for the profile model and runtime surface control.
Current release highlights are in docs/RELEASE-v1.42.1.md: package legitimacy checks, safer installer migrations, runtime surface control, custom ship PR sections, reviewer defaults, fallow structural review, and quota-aware execution recovery.
Cross-runtime compatibility: installer required
The agents/ and commands/ directories in this repository are Claude Code-format source files. The installer (npx @opengsd/get-shit-done-redux@latest) transforms them per target runtime — stripping or converting frontmatter fields that Claude Code uses but other runtimes reject. For example, OpenCode requires color as a hex or semantic value from a fixed set, and does not accept a tools: frontmatter field; the installer function convertClaudeToOpencodeFrontmatter (bin/install.js) handles this automatically.
Manually copying files from agents/ or commands/ directly into a non-Claude-Code runtime config directory (e.g., ~/.config/opencode/agents) skips the conversion step and will produce schema validation errors in that runtime.
If you are on a system without Node.js or npm (Windows + OpenCode is the most common case), see docs/USER-GUIDE.md — Manual install / no-Node.js setup for the per-runtime conversion summary and alternative install paths.
Commands
The main loop:
| Command | What it does |
|---|---|
/gsd-new-project |
Questions → research → requirements → roadmap |
/gsd-discuss-phase [N] |
Capture implementation decisions before planning |
/gsd-plan-phase [N] |
Research + plan + verify |
/gsd-execute-phase <N> |
Execute plans in parallel waves |
/gsd-verify-work [N] |
Manual acceptance testing |
/gsd-ship [N] |
Create PR from verified phase work |
/gsd-progress --next |
Auto-detect and run the next step |
/gsd-complete-milestone |
Archive milestone and tag release |
/gsd-new-milestone |
Start next version |
/gsd:surface |
Enable/disable skill clusters at runtime without reinstall |
For ad-hoc tasks, autonomous mode, codebase analysis, forensics, and the full command surface — see docs/COMMANDS.md.
Why It Works
Three things most AI-coding setups get wrong:
1. Context bloat. As a session grows, quality degrades. GSD keeps your main context clean by doing the heavy work in fresh subagent contexts. Researchers, planners, and executors each start fresh with exactly what they need.
2. No shared memory. GSD maintains structured artifacts that survive session boundaries: PROJECT.md (vision), REQUIREMENTS.md (scope), ROADMAP.md (where you're going), STATE.md (current position and decisions), CONTEXT.md (per-phase implementation decisions). Every new session loads these and knows exactly where things stand.
3. No verification. Code that "runs" isn't code that "works." GSD's verify step walks you through what was built, diagnoses failures with dedicated debug agents, and generates fix plans before you declare a phase done.
See docs/ARCHITECTURE.md for how the multi-agent orchestration and context engineering work in detail.
Configuration
Settings live in .planning/config.json. Configure during /gsd-new-project or update with /gsd-settings.
Key dials:
| Setting | What it controls |
|---|---|
mode |
interactive (confirm each step) or yolo (auto-approve) |
| Model profiles | quality / balanced / budget — controls which model each agent uses |
workflow.research / plan_check / verifier |
Toggle the quality agents that add tokens and time |
parallelization.enabled |
Run independent plans simultaneously |
Optional structural review: set code_quality.fallow.enabled to true to add a fallow pre-pass to /gsd-code-review. GSD writes .planning/phases/<phase>/FALLOW.json and surfaces a Structural Findings (fallow) section in REVIEW.md. Install with npm install -D fallow@^2.70.0 (or system-wide via cargo install fallow; note that the Rust binary's JSON schema must match the documented v2.70+ contract — older versions may produce silent zero-finding output).
Package legitimacy checks are built into the research, planning, and execution path: recommended dependencies get audited, unverified packages require a human checkpoint, and failed installs stop instead of trying similarly named alternatives.
For the full configuration reference — all settings, git branching strategies, per-runtime model overrides, workstream config inheritance, agent skills injection — see docs/CONFIGURATION.md.
Documentation
| Doc | What's in it |
|---|---|
| User Guide | End-to-end walkthrough, install options, all runtime flags, configuration reference |
| Commands | Every command with flags and examples |
| Configuration | Full config schema, model profiles, git branching |
| Architecture | How the multi-agent orchestration works |
| CLI Tools | gsd-sdk query and programmatic SDK dispatch seams |
| Features | Complete feature index |
| Changelog | What changed in each release |
Troubleshooting
Commands not showing up? Restart your runtime after install. GSD installs to ~/.claude/skills/gsd-*/ (Claude Code), ~/.codex/skills/gsd-*/ (Codex), or the equivalent for your runtime.
Codex users — minimum supported CLI version is 0.130.0. Codex CLI 0.130.0 (release notes) removed extra-skill-roots discovery via openai/codex#21485; from that version onward Codex discovers skills from standard roots (including ~/.codex/skills/<name>/SKILL.md). GSD installs there directly. Earlier Codex CLI versions may still discover additional roots, which can surface duplicate gsd-* entries (one from extra-roots discovery, one from ~/.codex/skills/); restart Codex after install and either upgrade or accept the duplicate listing.
Something broken? Re-run the installer — it's idempotent:
npx @opengsd/get-shit-done-redux@latest
Containers or Docker? Set CLAUDE_CONFIG_DIR before installing to avoid tilde-expansion issues:
CLAUDE_CONFIG_DIR=/home/youruser/.claude npx @opengsd/get-shit-done-redux --global
Full troubleshooting and uninstall instructions in docs/USER-GUIDE.md.
Community
| Project | Platform |
|---|---|
| gsd-opencode | Original OpenCode port |
| Discord | Community support |
Star History
License
MIT License. See LICENSE for details.
Claude Code is powerful. GSD makes it reliable.