Merge pull request #1154 from gsd-build/Solvely/soft-gsd-workflow-enforcement

feat(new-project): add soft GSD workflow enforcement
This commit is contained in:
Tom Boucher
2026-03-19 12:03:31 -04:00
committed by GitHub
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 |
**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

View File

@@ -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 = [
'<!-- GSD:profile-start -->',
'## 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 = {};

View File

@@ -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-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)
```
<!-- GSD:profile-start -->
@@ -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

View File

@@ -1039,10 +1039,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
@@ -1063,6 +1071,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 ✓
```
@@ -1113,6 +1122,7 @@ Exit skill and invoke SlashCommand("/gsd:discuss-phase 1 --auto")
- `.planning/REQUIREMENTS.md`
- `.planning/ROADMAP.md`
- `.planning/STATE.md`
- `CLAUDE.md`
</output>
@@ -1134,6 +1144,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.

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