diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index 5f1c9c9fe..a48670396 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -23,7 +23,7 @@ Initialize a new project with deep context gathering. | `--auto @file.md` | Auto-extract from document, skip interactive questions | **Prerequisites:** No existing `.planning/PROJECT.md` -**Produces:** `PROJECT.md`, `REQUIREMENTS.md`, `ROADMAP.md`, `STATE.md`, `config.json`, `research/` +**Produces:** `PROJECT.md`, `REQUIREMENTS.md`, `ROADMAP.md`, `STATE.md`, `config.json`, `research/`, `CLAUDE.md` ```bash /gsd:new-project # Interactive mode diff --git a/get-shit-done/bin/lib/profile-output.cjs b/get-shit-done/bin/lib/profile-output.cjs index ec6264f52..9d2add389 100644 --- a/get-shit-done/bin/lib/profile-output.cjs +++ b/get-shit-done/bin/lib/profile-output.cjs @@ -179,6 +179,17 @@ const CLAUDE_MD_FALLBACKS = { architecture: 'Architecture not yet mapped. Follow existing patterns found in the codebase.', }; +const CLAUDE_MD_WORKFLOW_ENFORCEMENT = [ + 'Before using Edit, Write, or other file-changing tools, start work through a GSD command so planning artifacts and execution context stay in sync.', + '', + 'Use these entry points:', + '- `/gsd:quick` for small fixes, doc updates, and ad-hoc tasks', + '- `/gsd:debug` for investigation and bug fixing', + '- `/gsd:execute-phase` for planned phase work', + '', + 'Do not make direct repo edits outside a GSD workflow unless the user explicitly asks to bypass it.', +].join('\n'); + const CLAUDE_MD_PROFILE_PLACEHOLDER = [ '', '## Developer Profile', @@ -356,6 +367,14 @@ function generateArchitectureSection(cwd) { return { content: summary, source: 'ARCHITECTURE.md', hasFallback: false }; } +function generateWorkflowSection() { + return { + content: CLAUDE_MD_WORKFLOW_ENFORCEMENT, + source: 'GSD defaults', + hasFallback: false, + }; +} + // ─── Commands ───────────────────────────────────────────────────────────────── function cmdWriteProfile(cwd, options, raw) { @@ -796,18 +815,20 @@ function cmdGenerateClaudeProfile(cwd, options, raw) { } function cmdGenerateClaudeMd(cwd, options, raw) { - const MANAGED_SECTIONS = ['project', 'stack', 'conventions', 'architecture']; + const MANAGED_SECTIONS = ['project', 'stack', 'conventions', 'architecture', 'workflow']; const generators = { project: generateProjectSection, stack: generateStackSection, conventions: generateConventionsSection, architecture: generateArchitectureSection, + workflow: generateWorkflowSection, }; const sectionHeadings = { project: '## Project', stack: '## Technology Stack', conventions: '## Conventions', architecture: '## Architecture', + workflow: '## GSD Workflow Enforcement', }; const generated = {}; diff --git a/get-shit-done/templates/claude-md.md b/get-shit-done/templates/claude-md.md index f19ec3f01..240146a28 100644 --- a/get-shit-done/templates/claude-md.md +++ b/get-shit-done/templates/claude-md.md @@ -2,8 +2,8 @@ Template for project-root `CLAUDE.md` — auto-generated by `gsd-tools generate-claude-md`. -Contains 5 marker-bounded sections. Each section is independently updatable. -The `generate-claude-md` subcommand manages 4 sections (project, stack, conventions, architecture). +Contains 6 marker-bounded sections. Each section is independently updatable. +The `generate-claude-md` subcommand manages 5 sections (project, stack, conventions, architecture, workflow enforcement). The profile section is managed exclusively by `generate-claude-profile`. --- @@ -66,6 +66,22 @@ Conventions not yet established. Will populate as patterns emerge during develop Architecture not yet mapped. Follow existing patterns found in the codebase. ``` +### Workflow Enforcement Section +``` + +## GSD Workflow Enforcement + +Before using Edit, Write, or other file-changing tools, start work through a GSD command so planning artifacts and execution context stay in sync. + +Use these entry points: +- `/gsd:quick` for small fixes, doc updates, and ad-hoc tasks +- `/gsd:debug` for investigation and bug fixing +- `/gsd:execute-phase` for planned phase work + +Do not make direct repo edits outside a GSD workflow unless the user explicitly asks to bypass it. + +``` + ### Profile Section (Placeholder Only) ``` @@ -88,7 +104,8 @@ CLAUDE.md file and no profile section exists yet. 2. **Stack** — Technology choices (what tools are used) 3. **Conventions** — Code patterns and rules (how code is written) 4. **Architecture** — System structure (how components fit together) -5. **Profile** — Developer behavioral preferences (how to interact) +5. **Workflow Enforcement** — Default GSD entry points for file-changing work +6. **Profile** — Developer behavioral preferences (how to interact) ## Marker Format diff --git a/get-shit-done/workflows/new-project.md b/get-shit-done/workflows/new-project.md index 7db0e6c6b..ed52d8b8e 100644 --- a/get-shit-done/workflows/new-project.md +++ b/get-shit-done/workflows/new-project.md @@ -1011,10 +1011,18 @@ Use AskUserQuestion: **If "Review full file":** Display raw `cat .planning/ROADMAP.md`, then re-ask. +**Generate or refresh project CLAUDE.md before final commit:** + +```bash +node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" generate-claude-md +``` + +This ensures new projects get the default GSD workflow-enforcement guidance and current project context in `CLAUDE.md`. + **Commit roadmap (after approval or auto mode):** ```bash -node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" commit "docs: create roadmap ([N] phases)" --files .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md +node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" commit "docs: create roadmap ([N] phases)" --files .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md CLAUDE.md ``` ## 9. Done @@ -1035,6 +1043,7 @@ Present completion summary: | Research | `.planning/research/` | | Requirements | `.planning/REQUIREMENTS.md` | | Roadmap | `.planning/ROADMAP.md` | +| Project guide | `CLAUDE.md` | **[N] phases** | **[X] requirements** | Ready to build ✓ ``` @@ -1085,6 +1094,7 @@ Exit skill and invoke SlashCommand("/gsd:discuss-phase 1 --auto") - `.planning/REQUIREMENTS.md` - `.planning/ROADMAP.md` - `.planning/STATE.md` +- `CLAUDE.md` @@ -1106,6 +1116,7 @@ Exit skill and invoke SlashCommand("/gsd:discuss-phase 1 --auto") - [ ] ROADMAP.md created with phases, requirement mappings, success criteria - [ ] STATE.md initialized - [ ] REQUIREMENTS.md traceability updated +- [ ] CLAUDE.md generated with GSD workflow guidance - [ ] User knows next step is `/gsd:discuss-phase 1` **Atomic commits:** Each phase commits its artifacts immediately. If context is lost, artifacts persist. diff --git a/tests/claude-md.test.cjs b/tests/claude-md.test.cjs new file mode 100644 index 000000000..3443f7783 --- /dev/null +++ b/tests/claude-md.test.cjs @@ -0,0 +1,82 @@ +/** + * CLAUDE.md generation and new-project workflow tests + */ + +const { test, describe, beforeEach, afterEach } = require('node:test'); +const assert = require('node:assert'); +const fs = require('fs'); +const path = require('path'); +const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs'); + +describe('generate-claude-md', () => { + let tmpDir; + + beforeEach(() => { + tmpDir = createTempProject(); + }); + + afterEach(() => { + cleanup(tmpDir); + }); + + test('creates CLAUDE.md with workflow enforcement section', () => { + fs.writeFileSync( + path.join(tmpDir, '.planning', 'PROJECT.md'), + '# Test Project\n\n## What This Is\n\nA small test project.\n' + ); + + const result = runGsdTools('generate-claude-md', tmpDir); + assert.ok(result.success, `Command failed: ${result.error}`); + + const output = JSON.parse(result.output); + assert.strictEqual(output.action, 'created'); + assert.strictEqual(output.sections_total, 5); + assert.ok(output.sections_generated.includes('workflow')); + + const claudePath = path.join(tmpDir, 'CLAUDE.md'); + const content = fs.readFileSync(claudePath, 'utf-8'); + assert.ok(content.includes('## GSD Workflow Enforcement')); + assert.ok(content.includes('/gsd:quick')); + assert.ok(content.includes('/gsd:debug')); + assert.ok(content.includes('/gsd:execute-phase')); + assert.ok(content.includes('Do not make direct repo edits outside a GSD workflow')); + }); + + test('adds workflow enforcement section when updating an existing CLAUDE.md', () => { + fs.writeFileSync( + path.join(tmpDir, '.planning', 'PROJECT.md'), + '# Test Project\n\n## What This Is\n\nA small test project.\n' + ); + fs.writeFileSync(path.join(tmpDir, 'CLAUDE.md'), '## Local Notes\n\nKeep this intro.\n'); + + const result = runGsdTools('generate-claude-md', tmpDir); + assert.ok(result.success, `Command failed: ${result.error}`); + + const output = JSON.parse(result.output); + assert.strictEqual(output.action, 'updated'); + + const content = fs.readFileSync(path.join(tmpDir, 'CLAUDE.md'), 'utf-8'); + assert.ok(content.includes('## Local Notes')); + assert.ok(content.includes('## GSD Workflow Enforcement')); + }); +}); + +describe('new-project workflow includes CLAUDE.md generation', () => { + const workflowPath = path.join(__dirname, '..', 'get-shit-done', 'workflows', 'new-project.md'); + const commandsPath = path.join(__dirname, '..', 'docs', 'COMMANDS.md'); + + test('new-project workflow generates CLAUDE.md before final commit', () => { + const content = fs.readFileSync(workflowPath, 'utf-8'); + assert.ok(content.includes('generate-claude-md')); + assert.ok(content.includes('--files .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md CLAUDE.md')); + }); + + test('new-project artifacts mention CLAUDE.md', () => { + const workflowContent = fs.readFileSync(workflowPath, 'utf-8'); + const commandsContent = fs.readFileSync(commandsPath, 'utf-8'); + + assert.ok(workflowContent.includes('| Project guide | `CLAUDE.md`')); + assert.ok(workflowContent.includes('- `CLAUDE.md`')); + assert.ok(commandsContent.includes('`CLAUDE.md`')); + }); +});