Skip to content

[Feature]: Resolve constitution-template at /constitution command time; gate install-time seeding behind constitution-sync #3950

Description

@mnriem

Problem Statement

constitution-template is the only template that isn't resolved on demand. It's materialized into .specify/memory/constitution.md at init and re-composed on every preset install that ships a constitution-template (_seed_constitution_from_presetreconcile_constitution, src/specify_cli/presets/__init__.py:3470-3535). The code comment says so outright: "the constitution is the only template that is materialized to a live file rather than resolved on demand."

This asymmetry causes real pain when composing category presets. A team building an org "common constitution" as a bundle (common/security, dotnet, frontend, …), each contributing constitution content via append/wrap, finds that installing the bundle immediately regenerates constitution.md — composing every layer into a single 1200+ line file, including rules that don't apply. The workaround is a before_constitution hook that re-resolves and prunes on every /constitution run — high rework, and exactly the "materialized copies drift / composed content gets clobbered on recompose" anti-pattern that presets/constitution-sync/README.md warns about.

Structurally there's no reason for the split: spec-template → spec.md and constitution-template → constitution.md are the same shape (placeholder scaffold → filled, stateful artifact). /specify resolves spec-template through the priority stack at command time; /constitution uniquely does not.

Proposed Solution

Make runtime resolution the default and treat materialization as the opt-in, reusing the existing constitution-sync dimension rather than adding a new field:

  1. Core default — drop install-time re-seeding. Installing/removing a preset no longer regenerates the live constitution.md.
  2. Core default — resolve at command time. /constitution resolves the composed constitution-template through the priority stack (overrides → presets → extensions → core), fills placeholders, and writes constitution.md — the same model /specify uses for spec-template.
  3. Core, always — one-time init seed. Init still creates constitution.md once so plan/tasks/analyze have something to read from project start. (The command already half-does this: "if missing, copy the template first.")
  4. Gated behind constitution-sync — install-time seeding. The re-seed-on-install code stays in core but only fires when constitution-sync is installed. That preset already represents the "materialize into reviewed artifacts" camp, so one opt-in = materialization mode (command-time propagation it already ships + install-time seeding), default = runtime resolution.

This removes the surprise regeneration, makes the before_constitution pruning hook unnecessary, and avoids a new orthogonal knob for a philosophy the repo already models.

Alternatives Considered

  • Standalone apply_on_install: false preset field (default true). Works, but adds a second knob for the same materialize-vs-resolve choice constitution-sync already encodes; preferred to fold it into that preset instead.
  • before_constitution pruning hook (current workaround). Re-resolves and deletes ~1200 lines every run — high rework, fights the composition stack.
  • Provisioning-side selection (install only common + one stack preset per repo). Correct and orthogonal — it fixes which categories compose; this issue fixes when/how the template is resolved. Best done together.
  • A preset owning install-time seeding directly. Not mechanically possible — presets have no hook that fires when a different preset is installed. Hence the "core code gated on constitution-sync presence" design.

Component

Specify CLI (initialization, commands)

AI Agent (if applicable)

All agents

Use Cases

  1. Org-wide constitution bundle. A frontend repo installs common + frontend, a dotnet repo installs common + dotnet; /constitution composes exactly the applicable rules at command time — no giant file, no pruning hook.
  2. Adding a preset mid-project. Installing a new category preset no longer silently rewrites a generated constitution.md; the change lands, reviewably, on the next /constitution run.
  3. Materialization camp unaffected. Teams that want frozen, reviewed artifacts install constitution-sync and keep today's install-time seeding behavior.

Acceptance Criteria

  • With no opt-in preset: installing/removing a preset that provides constitution-template does not rewrite .specify/memory/constitution.md.
  • /constitution resolves the composed constitution-template through the priority stack at command time.
  • Init still seeds a constitution once so plan/tasks/analyze have something to read from project start.
  • With constitution-sync installed: install-time re-seeding behaves as it does today.
  • Author-edited constitutions are never overwritten (existing _constitution_is_generated guarantee preserved).
  • Existing projects keep their current constitution.md byte-for-byte after upgrade.
  • Docs updated (presets/README.md, presets/ARCHITECTURE.md, presets/constitution-sync/README.md, templates/commands/constitution.md).

Additional Context

  • Precedent: /constitution propagation was removed in the 0.14.4 baseline and preserved as the opt-in constitution-sync preset (requires: speckit_version >=0.14.4). This extends that same "runtime-resolution default + constitution-sync as the materialization escape hatch" model to install-time seeding.
  • Backwards compatibility: no data-safety impact (author edits already skipped via provenance/SHA guard). The one observable change is timing — preset-provided constitution content applies on the next /constitution run rather than at install. That timing change is the fix. Teams wanting the old timing install constitution-sync.
  • Relevant code: src/specify_cli/presets/__init__.py (_materialize_constitution_template, _seed_constitution_from_preset, reconcile_constitution, _constitution_is_generated); src/specify_cli/commands/init.py (ensure_constitution_from_template); templates/commands/constitution.md; presets/constitution-sync/.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions