Reading the repo
Reading the repo
How to install on macOS
A light-weight and powerful meta-prompting, context engineering and spec-driven development system for Claude Code by TÂCHES.
Saved setup from 5 h ago
Will it work on my device?
CONTRIBUTING.md# Clone the repo
git clone https://github.com/gsd-build/get-shit-done.git
cd get-shit-done
# Install dependencies
npm install
# Run tests
npm test
GSD accepts three types of contributions. Each type has a different process and a different bar for acceptance. Read this section before opening anything.
A fix corrects something that is broken, crashes, produces wrong output, or behaves contrary to documented behavior.
Process:
confirmed-bug). For obvious, reproducible bugs this is typically fast.Rejection reasons: Not reproducible, works-as-designed, duplicate of an existing issue.
An enhancement improves an existing feature — better output, faster execution, cleaner UX, expanded edge-case handling. It does not add new commands, new workflows, or new concepts.
The bar: Enhancements must have a scoped written proposal approved by a maintainer before any code is written. A PR for an enhancement will be closed without review if the linked issue does not carry the approved-enhancement label.
Process:
approved-enhancement before you write a single line of code. Do not open a PR against an unapproved enhancement issue — it will be closed.Rejection reasons: Issue not labeled approved-enhancement, scope exceeds what was approved, no written proposal, duplicate of existing behavior.
A feature adds something new — a new command, a new workflow, a new concept, a new integration. Features have the highest bar because they add permanent maintenance burden to a solo-developer tool maintained by a small team.
The bar: Features require a complete written specification approved by a maintainer before any code is written. A PR for a feature will be closed without review if the linked issue does not carry the approved-feature label. Incomplete specs are closed, not revised by maintainers.
Process:
approved-feature before you write a single line of code. Approval is not guaranteed — GSD is intentionally lean and many valid ideas are declined because they conflict with the project's design philosophy.Rejection reasons: Issue not labeled approved-feature, spec is incomplete, scope exceeds what was approved, feature conflicts with GSD's solo-developer focus, maintenance burden too high.
An ADR (Architecture Decision Record) documents a significant architectural decision. A PRD (Product Requirements Document) captures the what and why of a feature before implementation. Both are governed by the same issue-first rule as everything else.
Process:
approved-enhancement, approved-feature, or confirm the chore before any file is created.docs/adr/<issue#>-<slug>.md for ADRsdocs/prd/<issue#>-<slug>.md for PRDsdocs/<issue#>-<slug>Closes #<issue#> in the PR body.One issue = one ADR-or-PRD = one PR. Do not batch multiple decisions into one file or one PR.
Do not compute a "next number" locally. Any PR that uses the legacy NNNN-* sequential pattern for a new ADR or PRD will be asked to rename the file to the <issue#>-<slug>.md format before merge.
Example: Issue #3485 was opened, approved, and its number became the prefix: docs/adr/3485-adr-prd-naming-convention.md on branch docs/3485-adr-prd-naming-convention.
Rejection reasons: Issue not approved before file was created, filename uses local-compute sequential number instead of issue#, multiple decisions bundled in one PR, file placed in wrong directory (docs/adr/ vs docs/prd/).
No code before approval.
For fixes: open the issue, confirm it's a bug, then fix it.
For enhancements: open the issue, get approved-enhancement, then code.
For features: open the issue, get approved-feature, then code.
PRs that arrive without a properly-labeled linked issue are closed automatically. This is not a bureaucratic hurdle — it protects you from spending time on work that will be rejected, and it protects maintainers from reviewing code for changes that were never agreed to.
The following files are maintainer-owned coding standards and must be treated as canonical when contributing:
CONTEXT.md — domain language and module naming standardsdocs/adr/ — Architecture Decision Records (ADRs) for accepted architectural decisionsFull contributor requirements — including CONTEXT.md format, ADR governance, and AI-agent-assisted work standards — are in docs/contributor-standards.md.
Contributor requirements (summary):
CONTEXT.md before naming or refactoring modules/interfaces/seams.CONTEXT.md vocabulary consistently in code comments, tests, issue/PR text, and docs for the touched area.docs/adr/ before proposing or implementing architectural changes.CONTEXT.md/ADRs as part of drive-by cleanup; propose focused updates tied to approved scope.CONTEXT.md and the relevant ADRs before writing any code or docs, and verify it used the correct vocabulary before opening the PR.CJS↔SDK seam. When working on bin/lib/*.cjs or sdk/src/**, read docs/agents/cjs-sdk-seam.md. It documents the canonical pattern for Shared Modules (data manifest + source-of-truth file + generator + freshness check + Adapters) and the hand-sync pair lint that blocks new drift. New <name>.cjs ↔ <name>.ts pairs require either migration to a Shared Module or an explicit allowlist entry with justification in scripts/shared-module-handsync-allowlist.json. Adding an allowlist entry requires maintainer review via CODEOWNERS.
Every PR must link to an approved issue. PRs without a linked issue are closed without review, no exceptions.
Closes #123, Fixes #123, or Resolves #123 in the PR body. The CI check will fail and the PR will be auto-closed if no valid issue reference is found.docs: or unrelated commits — when a production change makes an existing test assertion stale, the test correction MUST land as its own test: (or fix:) commit, not bundled into a docs: commit that also updates the explanation. The release-sdk hotfix cherry-pick filter routes by commit-subject prefix (fix:, chore:, test:); a test-fixture correction packed under a docs: prefix is invisible to the picker and ships a half-state to the hotfix branch — production code changed, test assertion stale. v1.42.3 hit this exact mode (#3621). The fix is upstream: keep the test-fixture commit separate.Do not edit CHANGELOG.md directly. Two PRs that both append to a ### Fixed block always conflict on merge — git can't pick a serialization order without a human. Instead, every PR with user-facing changes drops a fragment file in .changeset/.
npm run changeset -- --type Fixed --pr <YOUR_PR_NUMBER> \
--body "**\`/gsd-foo\` no longer drops trailing slashes** — explain the user-visible change."
This writes .changeset/<adjective>-<noun>-<noun>.md. Three random words → concurrent PRs never collide. Allowed type: values follow Keep a Changelog: Added, Changed, Deprecated, Removed, Fixed, Security.
Fragments are consolidated into CHANGELOG.md at release time by the release workflow. See .changeset/README.md for the format spec and #2975 for the rationale.
CI enforcement: the Changeset Required workflow (scripts/changeset/lint.cjs) fails any PR that touches bin/, get-shit-done/, agents/, commands/, hooks/, or sdk/src/ without a .changeset/*.md fragment.
Opt-out: PRs with no user-facing impact (test refactors, lint config changes, CI tweaks, formatting-only changes) can add the no-changelog label. The lint honors it. When unsure whether a change is user-facing, add the fragment.
If your PR adds, changes, deprecates, or removes user-visible behavior, you must update the relevant documentation in docs/. CI will fail any PR whose changeset fragment is typed Added, Changed, Deprecated, or Removed without also modifying at least one file under docs/ (#3213).
Fixed and Security fragments do not trigger this lint — bug fixes restore documented behavior, they do not introduce new behavior to document. (Edit the docs anyway if a fix corrects something the docs got wrong.)
| Change type | Required doc updates |
|---|---|
| New command or flag | docs/COMMANDS.md, docs/FEATURES.md |
| Changed command behavior or output | docs/USER-GUIDE.md, docs/COMMANDS.md |
| Configuration / schema change | docs/CONFIGURATION.md |
| Architectural change | docs/ARCHITECTURE.md, docs/adr/ |
| Agent or skill change | docs/AGENTS.md |
| Removed command, flag, or workflow | All docs that referenced it |
All content in docs/ and the root README.md must be written in English. English is the canonical source. The translated READMEs (README.pt-BR.md, README.zh-CN.md, README.ja-JP.md, README.ko-KR.md) are community-maintained translations and do not need to be updated by every PR.
The Docs Required workflow (scripts/lint-docs-required.cjs) reads the changeset fragments touched in the PR diff. If any has type Added / Changed / Deprecated / Removed, it requires at least one file under docs/ to also appear in the diff.
When a change genuinely has no user-facing documentation impact (infrastructure rewrite, internal refactor, test-only addition, CI fix), use one of:
no-docs label to the PR. Leave a comment explaining why no docs update was needed.<!-- docs-exempt: <reason> --> on its own line inside the body of each triggering changeset fragment (typically at the end). The reason is required and must be non-empty — a bare <!-- docs-exempt --> or <!-- docs-exempt: --> is rejected (no audit trail = no exemption). The marker is extracted at parse time by scripts/changeset/parse.cjs and stripped from the body before the CHANGELOG.md and GitHub release-notes serializers see it — it leaves a paper trail in the source fragment without leaking into published release notes. Inline mentions of the marker syntax (e.g. inside backticks) are intentionally ignored; the parser only acts on a marker that occupies its own line. Both routes leave a paper trail; the label is global, the marker is per-fragment for mixed PRs.When unsure whether a change is user-facing, update the docs.
All tests use Node.js built-in test runner (node:test) and assertion library (node:assert). Do not use Jest, Mocha, Chai, or any external test framework.
Suite grouping. Tests live in named suites (
unit,integration,install,security,slow) selected by filename suffix: a file namedfoo.security.test.cjsbelongs to thesecuritysuite; a file with no suffix (foo.test.cjs) belongs tounit. See docs/TESTING-SUITES.md for the full policy, CI matrix, and per-suite scripts (npm run test:unit,npm run test:security,npm run test:coverage:unit, …). Defaultnpm teststill runs every test — backwards compatible.
const { describe, it, test, beforeEach, afterEach, before, after, mock } = require('node:test');
const assert = require('node:assert/strict');
There are two approved cleanup patterns. Choose the one that fits the situation.
Pattern 1 — Shared fixtures (beforeEach/afterEach): Use when all tests in a describe block share identical setup and teardown. This is the most common case.
// GOOD — shared setup/teardown with hooks
describe('my feature', () => {
let tmpDir;
beforeEach(() => {
tmpDir = createTempProject();
});
afterEach(() => {
cleanup(tmpDir);
});
test('does the thing', () => {
assert.strictEqual(result, expected);
});
});
Pattern 2 — Per-test cleanup (t.after()): Use when individual tests require unique teardown that differs from other tests in the same block.
// GOOD — per-test cleanup when each test needs different teardown
test('does the thing with a custom setup', (t) => {
const tmpDir = createTempProject('custom-prefix');
t.after(() => cleanup(tmpDir));
assert.strictEqual(result, expected);
});
Never use try/finally inside test bodies. It is verbose, masks test failures, and is not an approved pattern in this project.
// BAD — try/finally inside a test body
test('does the thing', () => {
const tmpDir = createTempProject();
try {
assert.strictEqual(result, expected);
} finally {
cleanup(tmpDir); // masks failures — don't do this
}
});
try/finallyis only permitted inside standalone utility or helper functions that have no access to test context.
Import helpers from tests/helpers.cjs instead of inlining temp directory creation:
const { createTempProject, createTempGitProject, createTempDir, cleanup, runGsdTools } = require('./helpers.cjs');
| Helper | Creates | Use When |
|--------|---------|----------|
| createTempProject(prefix?) | tmpDir with .planning/phases/ | Testing GSD tools that need planning structure |
| createTempGitProject(prefix?) | Same + git init + initial commit | Testing git-dependent features |
| createTempDir(prefix?) | Bare temp directory | Testing features that don't need .planning/ |
| cleanup(tmpDir) | Removes directory recursively | Always use in afterEach |
| runGsdTools(args, cwd, env?) | Executes gsd-tools.cjs | Testing CLI commands |
describe('featureName', () => {
let tmpDir;
beforeEach(() => {
tmpDir = createTempProject();
// Additional setup specific to this suite
});
afterEach(() => {
cleanup(tmpDir);
});
test('handles normal case', () => {
// Arrange
// Act
// Assert
});
test('handles edge case', () => {
// ...
});
describe('sub-feature', () => {
// Nested describes can have their own hooks
beforeEach(() => {
// Additional setup for sub-feature
});
test('sub-feature works', () => {
// ...
});
});
});
Template literals inside test blocks inherit indentation from the surrounding code. This can introduce unexpected leading whitespace that breaks regex anchors and string matching. Construct multi-line fixture strings using array join() instead:
// GOOD — no indentation bleed
const content = [
'line one',
'line two',
'line three',
].join('\n');
// BAD — template literal inherits surrounding indentation
const content = `
line one
line two
line three
`;
Happy-path tests are not enough for code that accepts user input, reads project files, writes to disk, shells out, generates artifacts, or builds prompts. New tests for those areas must include adversarial inputs and negative proof that unsafe behavior did not happen.
See TEST-EXAMPLES.md for concrete demo tests that show these requirements in practice.
Use this matrix when it applies to the changed surface:
You do not need all twelve cases for every PR. You do need to cover the cases that match the risk of the touched code. If a case is not applicable, the PR should make that obvious from the issue scope or test rationale.
Ch
Then run bash setup.sh. It stops at the first error and is safe to run again. Servers and tests aren't started; it lists them at the end. Read it first.
Needs Git: xcode-select --install
git clone https://github.com/gsd-build/get-shit-done.git cd get-shit-done
Node.js >=22.0.0
# needs nvm: brew install nvm (or https://github.com/nvm-sh/nvm) nvm install --lts
npm ci
npm test
No reports for macOS yet.
Opens a chat with this manual already filled in, for macOS. It uses your own account; gitmanual sends nothing.