feat(v0.3): add built-in project CLAUDE.md template

ClaudeMDProject returns the project-oriented default used when
--project is passed (and no project seed overrides it). Adds tests
asserting required v0.3 spec sections and ASCII-only content.
This commit is contained in:
2026-04-10 14:31:39 -04:00
parent 0439702833
commit ced0d276b4
2 changed files with 62 additions and 0 deletions
+34
View File
@@ -39,6 +39,40 @@ Keep it concise -- a few bullet points is enough.
`
}
// ClaudeMDProject returns the built-in default CLAUDE.md content for a project workspace.
func ClaudeMDProject() string {
return `# Project Workspace Guidelines
This is a ctask project workspace -- a long-lived working environment, not a disposable task.
## File Placement
- Source code -> ` + "`src/`" + ` or workspace root
- Documentation -> ` + "`docs/`" + `
- Deliverables and exports -> ` + "`output/`" + `
- Reference material -> ` + "`context/`" + `
- Tests -> ` + "`tests/`" + `
- Configuration files -> workspace root
- Do not place non-code outputs in the workspace root
## Conventions
- This project uses git. Commit meaningful changes with clear messages.
- Do not install global packages or modify system files unless asked.
- Record important assumptions and actions in notes.md.
- Keep the workspace root clean.
## Session Handoff
Before ending a session, append a brief summary to notes.md with:
- What was accomplished
- Key decisions made
- Open follow-ups or unfinished work
- How to continue from here
`
}
// NotesMD returns the skeleton notes.md content.
func NotesMD(title string) string {
return fmt.Sprintf(`# %s
+28
View File
@@ -34,6 +34,34 @@ func TestClaudeMDContainsV03Sections(t *testing.T) {
}
}
func TestClaudeMDProjectIsASCII(t *testing.T) {
content := ClaudeMDProject()
for i, b := range []byte(content) {
if b > 127 {
t.Errorf("non-ASCII byte 0x%02x at position %d in project CLAUDE.md template", b, i)
break
}
}
}
func TestClaudeMDProjectContainsRequiredSections(t *testing.T) {
content := ClaudeMDProject()
for _, want := range []string{
"# Project Workspace Guidelines",
"long-lived working environment",
"## File Placement",
"Source code -> ",
"Tests -> ",
"## Conventions",
"This project uses git",
"## Session Handoff",
} {
if !strings.Contains(content, want) {
t.Errorf("project CLAUDE.md missing required section: %q", want)
}
}
}
func TestNotesMDIsASCII(t *testing.T) {
content := NotesMD("test title")
for i, b := range []byte(content) {