feat(claude-md): add workflow enforcement guidance

This commit is contained in:
Colin
2026-03-17 11:41:44 -04:00
parent 4915d28f98
commit f5167a5ca9
5 changed files with 137 additions and 6 deletions

View File

@@ -23,7 +23,7 @@ Initialize a new project with deep context gathering.
| `--auto @file.md` | Auto-extract from document, skip interactive questions | | `--auto @file.md` | Auto-extract from document, skip interactive questions |
**Prerequisites:** No existing `.planning/PROJECT.md` **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 ```bash
/gsd:new-project # Interactive mode /gsd:new-project # Interactive mode

View File

@@ -179,6 +179,17 @@ const CLAUDE_MD_FALLBACKS = {
architecture: 'Architecture not yet mapped. Follow existing patterns found in the codebase.', 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 = [ const CLAUDE_MD_PROFILE_PLACEHOLDER = [
'<!-- GSD:profile-start -->', '<!-- GSD:profile-start -->',
'## Developer Profile', '## Developer Profile',
@@ -356,6 +367,14 @@ function generateArchitectureSection(cwd) {
return { content: summary, source: 'ARCHITECTURE.md', hasFallback: false }; return { content: summary, source: 'ARCHITECTURE.md', hasFallback: false };
} }
function generateWorkflowSection() {
return {
content: CLAUDE_MD_WORKFLOW_ENFORCEMENT,
source: 'GSD defaults',
hasFallback: false,
};
}
// ─── Commands ───────────────────────────────────────────────────────────────── // ─── Commands ─────────────────────────────────────────────────────────────────
function cmdWriteProfile(cwd, options, raw) { function cmdWriteProfile(cwd, options, raw) {
@@ -796,18 +815,20 @@ function cmdGenerateClaudeProfile(cwd, options, raw) {
} }
function cmdGenerateClaudeMd(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 = { const generators = {
project: generateProjectSection, project: generateProjectSection,
stack: generateStackSection, stack: generateStackSection,
conventions: generateConventionsSection, conventions: generateConventionsSection,
architecture: generateArchitectureSection, architecture: generateArchitectureSection,
workflow: generateWorkflowSection,
}; };
const sectionHeadings = { const sectionHeadings = {
project: '## Project', project: '## Project',
stack: '## Technology Stack', stack: '## Technology Stack',
conventions: '## Conventions', conventions: '## Conventions',
architecture: '## Architecture', architecture: '## Architecture',
workflow: '## GSD Workflow Enforcement',
}; };
const generated = {}; const generated = {};

View File

@@ -2,8 +2,8 @@
Template for project-root `CLAUDE.md` — auto-generated by `gsd-tools generate-claude-md`. Template for project-root `CLAUDE.md` — auto-generated by `gsd-tools generate-claude-md`.
Contains 5 marker-bounded sections. Each section is independently updatable. Contains 6 marker-bounded sections. Each section is independently updatable.
The `generate-claude-md` subcommand manages 4 sections (project, stack, conventions, architecture). The `generate-claude-md` subcommand manages 5 sections (project, stack, conventions, architecture, workflow enforcement).
The profile section is managed exclusively by `generate-claude-profile`. 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. Architecture not yet mapped. Follow existing patterns found in the codebase.
``` ```
### Workflow Enforcement Section
```
<!-- GSD:workflow-start source:GSD defaults -->
## 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.
<!-- GSD:workflow-end -->
```
### Profile Section (Placeholder Only) ### Profile Section (Placeholder Only)
``` ```
<!-- GSD:profile-start --> <!-- GSD:profile-start -->
@@ -88,7 +104,8 @@ CLAUDE.md file and no profile section exists yet.
2. **Stack** — Technology choices (what tools are used) 2. **Stack** — Technology choices (what tools are used)
3. **Conventions** — Code patterns and rules (how code is written) 3. **Conventions** — Code patterns and rules (how code is written)
4. **Architecture** — System structure (how components fit together) 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 ## Marker Format

View File

@@ -1011,10 +1011,18 @@ Use AskUserQuestion:
**If "Review full file":** Display raw `cat .planning/ROADMAP.md`, then re-ask. **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):** **Commit roadmap (after approval or auto mode):**
```bash ```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 ## 9. Done
@@ -1035,6 +1043,7 @@ Present completion summary:
| Research | `.planning/research/` | | Research | `.planning/research/` |
| Requirements | `.planning/REQUIREMENTS.md` | | Requirements | `.planning/REQUIREMENTS.md` |
| Roadmap | `.planning/ROADMAP.md` | | Roadmap | `.planning/ROADMAP.md` |
| Project guide | `CLAUDE.md` |
**[N] phases** | **[X] requirements** | Ready to build ✓ **[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/REQUIREMENTS.md`
- `.planning/ROADMAP.md` - `.planning/ROADMAP.md`
- `.planning/STATE.md` - `.planning/STATE.md`
- `CLAUDE.md`
</output> </output>
@@ -1106,6 +1116,7 @@ Exit skill and invoke SlashCommand("/gsd:discuss-phase 1 --auto")
- [ ] ROADMAP.md created with phases, requirement mappings, success criteria - [ ] ROADMAP.md created with phases, requirement mappings, success criteria
- [ ] STATE.md initialized - [ ] STATE.md initialized
- [ ] REQUIREMENTS.md traceability updated - [ ] REQUIREMENTS.md traceability updated
- [ ] CLAUDE.md generated with GSD workflow guidance
- [ ] User knows next step is `/gsd:discuss-phase 1` - [ ] User knows next step is `/gsd:discuss-phase 1`
**Atomic commits:** Each phase commits its artifacts immediately. If context is lost, artifacts persist. **Atomic commits:** Each phase commits its artifacts immediately. If context is lost, artifacts persist.

82
tests/claude-md.test.cjs Normal file
View File

@@ -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`'));
});
});