Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions presets/lean/commands/speckit.constitution.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@ description: Create or update the project constitution.
$ARGUMENTS
```

## Scope Guard

This command's own work is limited to creating or updating the project constitution and
propagating constitution-driven changes to dependent Spec Kit artifacts.

- Classify every part of the user input as constitution content or a separate non-governance
intent. Feature implementation, code generation, refactoring, build, and deployment requests
are examples of non-governance intents.
- You **MUST NOT** execute any non-governance intent. Defer each one to `Next Actions`.
- You **MUST NOT** create, modify, or delete application source files or other artifacts
unrelated to the constitution workflow.
- If an instruction could be either constitution content or a non-governance intent, ask for
clarification before making changes.
- After updating the constitution, list each deferred intent in a `Next Actions` section with an
appropriate follow-up Spec Kit command, such as `__SPECKIT_COMMAND_SPECIFY__`, but do not
invoke it.
- Omit `Next Actions` when there are no non-governance intents.

## Outline

1. Create or update the project constitution and store it in `.specify/memory/constitution.md`.
Expand Down
20 changes: 20 additions & 0 deletions templates/commands/constitution.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,25 @@ $ARGUMENTS

You **MUST** consider the user input before proceeding (if not empty).

## Scope Guard

This command's own work is limited to updating the project constitution and propagating
constitution-driven changes to the dependent artifacts identified in this command.

- Classify every part of the user input as either constitution content or a separate,
non-governance intent.
- If the input includes feature implementation, code generation, refactoring, building, or
deployment requests, you **MUST NOT** execute them. Extract them as deferred intents instead.
- You **MUST NOT** create, modify, or delete application source files, feature routes,
components, tests, deployment files, or other artifacts unrelated to the constitution
workflow and its required propagation.
- If it is unclear whether an instruction is constitution content, ask for clarification before
making changes.
- After completing the constitution update, include a `Next Actions` section for each deferred
intent. List the original intent and suggest the appropriate follow-up Spec Kit command, such
as `__SPECKIT_COMMAND_SPECIFY__`, without invoking it.
- If there are no non-governance intents, omit the `Next Actions` section.

## Pre-Execution Checks

**Check for extension hooks (before constitution update)**:
Expand Down Expand Up @@ -104,6 +123,7 @@ Follow this execution flow:
- New version and bump rationale.
- Any files flagged for manual follow-up.
- Suggested commit message (e.g., `docs: amend constitution to vX.Y.Z (principle additions + governance update)`).
- A `Next Actions` section for any deferred non-governance intents.

Formatting & Style Requirements:

Expand Down
28 changes: 28 additions & 0 deletions tests/test_presets.py
Original file line number Diff line number Diff line change
Expand Up @@ -5381,6 +5381,9 @@ def test_disable_corrupted_registry_entry(self, project_dir, pack_dir):


LEAN_PRESET_DIR = Path(__file__).parent.parent / "presets" / "lean"
CORE_CONSTITUTION_COMMAND = (
Path(__file__).parent.parent / "templates" / "commands" / "constitution.md"
)

LEAN_COMMAND_NAMES = [
"speckit.specify",
Expand All @@ -5391,6 +5394,31 @@ def test_disable_corrupted_registry_entry(self, project_dir, pack_dir):
]


@pytest.mark.parametrize(
"command_path",
[
CORE_CONSTITUTION_COMMAND,
LEAN_PRESET_DIR / "commands" / "speckit.constitution.md",
],
ids=["core", "lean"],
)
def test_constitution_commands_guard_against_non_governance_work(command_path):
"""Constitution commands defer non-governance work instead of executing it."""
content = command_path.read_text()
lower_content = content.lower()
normalized_content = " ".join(lower_content.split())

assert "## Scope Guard" in content
assert "**MUST NOT**" in content
assert "Classify every part" in content
assert "application source files" in content
assert "non-governance intent" in content
assert "`Next Actions`" in content
assert "__SPECKIT_COMMAND_SPECIFY__" in content
assert "omit" in lower_content
assert "do not invoke it" in normalized_content or "without invoking it" in normalized_content


class TestLeanPreset:
"""Tests for the lean preset that ships with the repo."""

Expand Down