@@ -1461,6 +1461,48 @@ def ensure_constitution_from_template(project_path: Path, tracker: StepTracker |
14611461 console .print (f"[yellow]Warning: Could not initialize constitution: { e } [/yellow]" )
14621462
14631463
1464+ def ensure_claude_md (project_path : Path , tracker : StepTracker | None = None ) -> None :
1465+ """Create a minimal root `CLAUDE.md` for Claude Code if missing.
1466+
1467+ Claude Code expects `CLAUDE.md` at the project root; this file acts as a
1468+ bridge to `.specify/memory/constitution.md` (the source of truth).
1469+ """
1470+ claude_file = project_path / "CLAUDE.md"
1471+ if claude_file .exists ():
1472+ if tracker :
1473+ tracker .add ("claude-md" , "Claude Code role file" )
1474+ tracker .skip ("claude-md" , "existing file preserved" )
1475+ return
1476+
1477+ content = (
1478+ "## Claude's Role\n "
1479+ "Read `.specify/memory/constitution.md` first. It is the authoritative source of truth for this project. "
1480+ "Everything in it is non-negotiable.\n \n "
1481+ "## SpecKit Commands\n "
1482+ "- `/speckit.specify` — generate spec\n "
1483+ "- `/speckit.plan` — generate plan\n "
1484+ "- `/speckit.tasks` — generate task list\n "
1485+ "- `/speckit.implement` — execute plan\n \n "
1486+ "## On Ambiguity\n "
1487+ "If a spec is missing, incomplete, or conflicts with the constitution — stop and ask. "
1488+ "Do not infer. Do not proceed.\n \n "
1489+ )
1490+
1491+ try :
1492+ claude_file .write_text (content , encoding = "utf-8" )
1493+ if tracker :
1494+ tracker .add ("claude-md" , "Claude Code role file" )
1495+ tracker .complete ("claude-md" , "created" )
1496+ else :
1497+ console .print ("[cyan]Initialized CLAUDE.md for Claude Code[/cyan]" )
1498+ except Exception as e :
1499+ if tracker :
1500+ tracker .add ("claude-md" , "Claude Code role file" )
1501+ tracker .error ("claude-md" , str (e ))
1502+ else :
1503+ console .print (f"[yellow]Warning: Could not create CLAUDE.md: { e } [/yellow]" )
1504+
1505+
14641506INIT_OPTIONS_FILE = ".specify/init-options.json"
14651507
14661508
@@ -2071,6 +2113,8 @@ def init(
20712113 ("constitution" , "Constitution setup" ),
20722114 ]:
20732115 tracker .add (key , label )
2116+ if selected_ai == "claude" :
2117+ tracker .add ("claude-md" , "Claude Code role file" )
20742118 if ai_skills :
20752119 tracker .add ("ai-skills" , "Install agent skills" )
20762120 for key , label in [
@@ -2137,6 +2181,9 @@ def init(
21372181
21382182 ensure_constitution_from_template (project_path , tracker = tracker )
21392183
2184+ if selected_ai == "claude" :
2185+ ensure_claude_md (project_path , tracker = tracker )
2186+
21402187 # Determine skills directory and migrate any legacy Kimi dotted skills.
21412188 migrated_legacy_kimi_skills = 0
21422189 removed_legacy_kimi_skills = 0
0 commit comments