fix: preserve constitution.md during reinitialization (#1541) (#1553)

Moves constitution template from memory/ to templates/ to prevent
overwrites when spec-kit is reinitialized with a different AI agent.

Changes:
- Move memory/constitution.md to templates/constitution-template.md
- Update CLI to copy template to memory/ only on first initialization
- Update constitution command to reference correct paths with .specify/ prefix
- Preserve existing constitution.md when reinitializing project

The CLI now checks if .specify/memory/constitution.md exists:
- If it exists: preserve it (no overwrite)
- If it doesn't exist: copy from .specify/templates/constitution-template.md

This allows users to customize their constitution without losing changes
when adding support for additional AI agents or reinitializing.

Fixes #1541

Co-authored-by: jjoung1128 <jinwoong.joung@gmail.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
jin-joung
2026-02-09 09:01:55 -06:00
committed by GitHub
parent b562438df9
commit 4afbd87abb
3 changed files with 48 additions and 8 deletions

View File

@@ -942,6 +942,41 @@ def ensure_executable_scripts(project_path: Path, tracker: StepTracker | None =
for f in failures:
console.print(f" - {f}")
def ensure_constitution_from_template(project_path: Path, tracker: StepTracker | None = None) -> None:
"""Copy constitution template to memory if it doesn't exist (preserves existing constitution on reinitialization)."""
memory_constitution = project_path / ".specify" / "memory" / "constitution.md"
template_constitution = project_path / ".specify" / "templates" / "constitution-template.md"
# If constitution already exists in memory, preserve it
if memory_constitution.exists():
if tracker:
tracker.add("constitution", "Constitution setup")
tracker.skip("constitution", "existing file preserved")
return
# If template doesn't exist, something went wrong with extraction
if not template_constitution.exists():
if tracker:
tracker.add("constitution", "Constitution setup")
tracker.error("constitution", "template not found")
return
# Copy template to memory directory
try:
memory_constitution.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(template_constitution, memory_constitution)
if tracker:
tracker.add("constitution", "Constitution setup")
tracker.complete("constitution", "copied from template")
else:
console.print(f"[cyan]Initialized constitution from template[/cyan]")
except Exception as e:
if tracker:
tracker.add("constitution", "Constitution setup")
tracker.error("constitution", str(e))
else:
console.print(f"[yellow]Warning: Could not initialize constitution: {e}[/yellow]")
@app.command()
def init(
project_name: str = typer.Argument(None, help="Name for your new project directory (optional if using --here, or use '.' for current directory)"),
@@ -1108,6 +1143,7 @@ def init(
("zip-list", "Archive contents"),
("extracted-summary", "Extraction summary"),
("chmod", "Ensure scripts executable"),
("constitution", "Constitution setup"),
("cleanup", "Cleanup"),
("git", "Initialize git repository"),
("final", "Finalize")
@@ -1128,6 +1164,8 @@ def init(
ensure_executable_scripts(project_path, tracker=tracker)
ensure_constitution_from_template(project_path, tracker=tracker)
if not no_git:
tracker.start("git")
if is_git_repo(project_path):