From 9282aab5a9bdb0c77fe86d261dc566dec9006b10 Mon Sep 17 00:00:00 2001 From: jjoung1128 Date: Tue, 3 Feb 2026 13:27:57 -0600 Subject: [PATCH] fix: preserve constitution.md during reinitialization (#1541) 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: Claude Sonnet 4.5 --- src/specify_cli/__init__.py | 38 +++++++++++++++++++ templates/commands/constitution.md | 18 +++++---- .../constitution-template.md | 0 3 files changed, 48 insertions(+), 8 deletions(-) rename memory/constitution.md => templates/constitution-template.md (100%) diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index 1dedb31949..464e025a55 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -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): diff --git a/templates/commands/constitution.md b/templates/commands/constitution.md index cf81f08c2f..63d4f662ae 100644 --- a/templates/commands/constitution.md +++ b/templates/commands/constitution.md @@ -16,11 +16,13 @@ You **MUST** consider the user input before proceeding (if not empty). ## Outline -You are updating the project constitution at `/memory/constitution.md`. This file is a TEMPLATE containing placeholder tokens in square brackets (e.g. `[PROJECT_NAME]`, `[PRINCIPLE_1_NAME]`). Your job is to (a) collect/derive concrete values, (b) fill the template precisely, and (c) propagate any amendments across dependent artifacts. +You are updating the project constitution at `.specify/memory/constitution.md`. This file is a TEMPLATE containing placeholder tokens in square brackets (e.g. `[PROJECT_NAME]`, `[PRINCIPLE_1_NAME]`). Your job is to (a) collect/derive concrete values, (b) fill the template precisely, and (c) propagate any amendments across dependent artifacts. + +**Note**: If `.specify/memory/constitution.md` does not exist yet, it should have been initialized from `.specify/templates/constitution-template.md` during project setup. If it's missing, copy the template first. Follow this execution flow: -1. Load the existing constitution template at `/memory/constitution.md`. +1. Load the existing constitution at `.specify/memory/constitution.md`. - Identify every placeholder token of the form `[ALL_CAPS_IDENTIFIER]`. **IMPORTANT**: The user might require less or more principles than the ones used in the template. If a number is specified, respect that - follow the general template. You will update the doc accordingly. @@ -41,10 +43,10 @@ Follow this execution flow: - Ensure Governance section lists amendment procedure, versioning policy, and compliance review expectations. 4. Consistency propagation checklist (convert prior checklist into active validations): - - Read `/templates/plan-template.md` and ensure any "Constitution Check" or rules align with updated principles. - - Read `/templates/spec-template.md` for scope/requirements alignment—update if constitution adds/removes mandatory sections or constraints. - - Read `/templates/tasks-template.md` and ensure task categorization reflects new or removed principle-driven task types (e.g., observability, versioning, testing discipline). - - Read each command file in `/templates/commands/*.md` (including this one) to verify no outdated references (agent-specific names like CLAUDE only) remain when generic guidance is required. + - Read `.specify/templates/plan-template.md` and ensure any "Constitution Check" or rules align with updated principles. + - Read `.specify/templates/spec-template.md` for scope/requirements alignment—update if constitution adds/removes mandatory sections or constraints. + - Read `.specify/templates/tasks-template.md` and ensure task categorization reflects new or removed principle-driven task types (e.g., observability, versioning, testing discipline). + - Read each command file in `.specify/templates/commands/*.md` (including this one) to verify no outdated references (agent-specific names like CLAUDE only) remain when generic guidance is required. - Read any runtime guidance docs (e.g., `README.md`, `docs/quickstart.md`, or agent-specific guidance files if present). Update references to principles changed. 5. Produce a Sync Impact Report (prepend as an HTML comment at top of the constitution file after update): @@ -61,7 +63,7 @@ Follow this execution flow: - Dates ISO format YYYY-MM-DD. - Principles are declarative, testable, and free of vague language ("should" → replace with MUST/SHOULD rationale where appropriate). -7. Write the completed constitution back to `/memory/constitution.md` (overwrite). +7. Write the completed constitution back to `.specify/memory/constitution.md` (overwrite). 8. Output a final summary to the user with: - New version and bump rationale. @@ -79,4 +81,4 @@ If the user supplies partial updates (e.g., only one principle revision), still If critical info missing (e.g., ratification date truly unknown), insert `TODO(): explanation` and include in the Sync Impact Report under deferred items. -Do not create a new template; always operate on the existing `/memory/constitution.md` file. +Do not create a new template; always operate on the existing `.specify/memory/constitution.md` file. diff --git a/memory/constitution.md b/templates/constitution-template.md similarity index 100% rename from memory/constitution.md rename to templates/constitution-template.md