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

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