Skip to content

Commit f4c4525

Browse files
Usage:
specify init <project> --ai claude --format compact Default remains markdown
1 parent be701c9 commit f4c4525

File tree

17 files changed

+803
-1
lines changed

17 files changed

+803
-1
lines changed

src/specify_cli/__init__.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1290,13 +1290,31 @@ def scaffold_from_core_pack(
12901290
if f.is_file():
12911291
shutil.copy2(f, tmpl_cmds / f.name)
12921292

1293+
# Copy compact command templates subdirectory
1294+
compact_cmds_src = commands_dir / "compact"
1295+
if compact_cmds_src.is_dir():
1296+
compact_cmds_dst = tmpl_cmds / "compact"
1297+
compact_cmds_dst.mkdir(parents=True, exist_ok=True)
1298+
for f in compact_cmds_src.iterdir():
1299+
if f.is_file():
1300+
shutil.copy2(f, compact_cmds_dst / f.name)
1301+
12931302
# Page templates (needed for vscode-settings.json etc.)
12941303
if templates_dir.is_dir():
12951304
tmpl_root = tmp / "templates"
12961305
for f in templates_dir.iterdir():
12971306
if f.is_file():
12981307
shutil.copy2(f, tmpl_root / f.name)
12991308

1309+
# Copy compact templates subdirectory
1310+
compact_src = templates_dir / "compact"
1311+
if compact_src.is_dir():
1312+
compact_dst = tmpl_root / "compact"
1313+
compact_dst.mkdir(parents=True, exist_ok=True)
1314+
for f in compact_src.iterdir():
1315+
if f.is_file():
1316+
shutil.copy2(f, compact_dst / f.name)
1317+
13001318
# Scripts (bash/ and powershell/)
13011319
for subdir in ("bash", "powershell"):
13021320
src = scripts_dir / subdir
@@ -1428,7 +1446,17 @@ def ensure_executable_scripts(project_path: Path, tracker: StepTracker | None =
14281446
def ensure_constitution_from_template(project_path: Path, tracker: StepTracker | None = None) -> None:
14291447
"""Copy constitution template to memory if it doesn't exist (preserves existing constitution on reinitialization)."""
14301448
memory_constitution = project_path / ".specify" / "memory" / "constitution.md"
1431-
template_constitution = project_path / ".specify" / "templates" / "constitution-template.md"
1449+
1450+
# Choose template based on format preference
1451+
init_opts = load_init_options(project_path)
1452+
fmt = init_opts.get("format", "markdown")
1453+
if fmt == "compact":
1454+
template_constitution = project_path / ".specify" / "templates" / "compact" / "constitution-template.md"
1455+
if not template_constitution.exists():
1456+
# Fallback to standard template
1457+
template_constitution = project_path / ".specify" / "templates" / "constitution-template.md"
1458+
else:
1459+
template_constitution = project_path / ".specify" / "templates" / "constitution-template.md"
14321460

14331461
# If constitution already exists in memory, preserve it
14341462
if memory_constitution.exists():
@@ -1461,6 +1489,23 @@ def ensure_constitution_from_template(project_path: Path, tracker: StepTracker |
14611489
console.print(f"[yellow]Warning: Could not initialize constitution: {e}[/yellow]")
14621490

14631491

1492+
def resolve_template_path(project_path: Path, template_name: str) -> Path:
1493+
"""Resolve a template file path based on the configured format preference.
1494+
1495+
When format is 'compact', looks for the template in the compact/ subdirectory
1496+
first. Falls back to the standard template if compact variant is not found.
1497+
"""
1498+
init_opts = load_init_options(project_path)
1499+
fmt = init_opts.get("format", "markdown")
1500+
1501+
if fmt == "compact":
1502+
compact_path = project_path / ".specify" / "templates" / "compact" / template_name
1503+
if compact_path.exists():
1504+
return compact_path
1505+
1506+
return project_path / ".specify" / "templates" / template_name
1507+
1508+
14641509
INIT_OPTIONS_FILE = ".specify/init-options.json"
14651510

14661511

@@ -1825,6 +1870,7 @@ def init(
18251870
offline: bool = typer.Option(False, "--offline", help="Use assets bundled in the specify-cli package instead of downloading from GitHub (no network access required). Bundled assets will become the default in v0.6.0 and this flag will be removed."),
18261871
preset: str = typer.Option(None, "--preset", help="Install a preset during initialization (by preset ID)"),
18271872
branch_numbering: str = typer.Option(None, "--branch-numbering", help="Branch numbering strategy: 'sequential' (001, 002, ...) or 'timestamp' (YYYYMMDD-HHMMSS)"),
1873+
template_format: str = typer.Option(None, "--format", help="Template format: 'markdown' (full verbose) or 'compact' (token-efficient minimal format)"),
18281874
):
18291875
"""
18301876
Initialize a new Specify project.
@@ -1908,6 +1954,11 @@ def init(
19081954
console.print(f"[red]Error:[/red] Invalid --branch-numbering value '{branch_numbering}'. Choose from: {', '.join(sorted(BRANCH_NUMBERING_CHOICES))}")
19091955
raise typer.Exit(1)
19101956

1957+
TEMPLATE_FORMAT_CHOICES = {"markdown", "compact"}
1958+
if template_format and template_format not in TEMPLATE_FORMAT_CHOICES:
1959+
console.print(f"[red]Error:[/red] Invalid --format value '{template_format}'. Choose from: {', '.join(sorted(TEMPLATE_FORMAT_CHOICES))}")
1960+
raise typer.Exit(1)
1961+
19111962
if here:
19121963
project_name = Path.cwd().name
19131964
project_path = Path.cwd()
@@ -2229,6 +2280,7 @@ def init(
22292280
"ai_skills": ai_skills,
22302281
"ai_commands_dir": ai_commands_dir,
22312282
"branch_numbering": branch_numbering or "sequential",
2283+
"format": template_format or "markdown",
22322284
"here": here,
22332285
"preset": preset,
22342286
"offline": offline,

src/specify_cli/agents.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,16 @@ class CommandRegistrar:
165165
}
166166
}
167167

168+
@staticmethod
169+
def _get_template_format(project_root: Path) -> str:
170+
"""Read the template format preference from init-options.json."""
171+
try:
172+
from . import load_init_options
173+
except ImportError:
174+
return "markdown"
175+
opts = load_init_options(project_root)
176+
return opts.get("format", "markdown") if isinstance(opts, dict) else "markdown"
177+
168178
@staticmethod
169179
def parse_frontmatter(content: str) -> tuple[dict, str]:
170180
"""Parse YAML frontmatter from Markdown content.
@@ -484,11 +494,20 @@ def register_commands(
484494

485495
registered = []
486496

497+
# Determine template format preference from init options
498+
template_format = self._get_template_format(project_root)
499+
487500
for cmd_info in commands:
488501
cmd_name = cmd_info["name"]
489502
cmd_file = cmd_info["file"]
490503

504+
# Use compact command template if format is compact and compact variant exists
491505
source_file = source_dir / cmd_file
506+
if template_format == "compact":
507+
compact_file = source_dir / "compact" / cmd_file
508+
if compact_file.exists():
509+
source_file = compact_file
510+
492511
if not source_file.exists():
493512
continue
494513

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
---
2+
description: Non-destructive cross-artifact consistency and quality analysis across spec.md, plan.md, and tasks.md.
3+
scripts:
4+
sh: scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks
5+
ps: scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks
6+
---
7+
8+
## Input
9+
10+
```text
11+
$ARGUMENTS
12+
```
13+
14+
Consider user input before proceeding (if not empty).
15+
16+
## Constraints
17+
18+
**READ-ONLY**: Never modify files. Output structured analysis report only.
19+
**Constitution** (`/memory/constitution.md`) is non-negotiable - conflicts are always CRITICAL.
20+
21+
## Workflow
22+
23+
1. Run `{SCRIPT}`, parse FEATURE_DIR. Derive SPEC, PLAN, TASKS paths. Abort if any missing.
24+
25+
2. **Load** minimal context from each artifact:
26+
- spec.md: requirements, success criteria, user stories, edge cases
27+
- plan.md: architecture, data model, phases, constraints
28+
- tasks.md: IDs, descriptions, phases, [P] markers, file paths
29+
- constitution: principles, MUST/SHOULD statements
30+
31+
3. **Build models**: Requirements inventory (FR-###, SC-###), user story/action inventory, task coverage mapping, constitution rule set.
32+
33+
4. **Detection passes** (max 50 findings):
34+
- A. **Duplication**: near-duplicate requirements
35+
- B. **Ambiguity**: vague terms without metrics, unresolved placeholders
36+
- C. **Underspecification**: missing outcomes, unaligned stories, undefined references
37+
- D. **Constitution alignment**: MUST principle violations, missing mandated sections
38+
- E. **Coverage gaps**: requirements with zero tasks, orphan tasks, unbuildable success criteria
39+
- F. **Inconsistency**: terminology drift, entity mismatches, ordering contradictions
40+
41+
5. **Severity**: CRITICAL (constitution violation, zero-coverage blocking req) > HIGH (conflicts, ambiguous security/perf) > MEDIUM (terminology drift, missing NFR tasks) > LOW (style, minor redundancy)
42+
43+
6. **Report** (markdown, no file writes):
44+
45+
| ID | Category | Severity | Location(s) | Summary | Recommendation |
46+
|----|----------|----------|-------------|---------|----------------|
47+
48+
+ Coverage summary table + Constitution issues + Unmapped tasks + Metrics (total reqs, tasks, coverage%, ambiguity/duplication/critical counts)
49+
50+
7. **Next actions**: If CRITICAL → resolve before `/speckit.implement`. If LOW/MEDIUM → may proceed with suggestions.
51+
52+
8. **Offer remediation**: Ask user if they want concrete edit suggestions for top N issues (don't apply automatically).
53+
54+
Context: {ARGS}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
description: Generate a custom checklist for the current feature - "unit tests for requirements writing".
3+
scripts:
4+
sh: scripts/bash/check-prerequisites.sh --json
5+
ps: scripts/powershell/check-prerequisites.ps1 -Json
6+
---
7+
8+
## Input
9+
10+
```text
11+
$ARGUMENTS
12+
```
13+
14+
Consider user input before proceeding (if not empty).
15+
16+
## Core Concept
17+
18+
Checklists are **unit tests for requirements** - they validate quality, clarity, and completeness of requirements, NOT implementation behavior.
19+
20+
- YES: "Are visual hierarchy requirements defined?" / "Is 'fast' quantified with metrics?"
21+
- NO: "Verify button clicks" / "Test error handling works"
22+
23+
## Workflow
24+
25+
1. **Setup**: Run `{SCRIPT}`, parse FEATURE_DIR and AVAILABLE_DOCS.
26+
27+
2. **Clarify intent**: Generate up to 3 contextual questions from user phrasing + spec signals (scope, depth, audience, risk). Skip if already clear from $ARGUMENTS. May ask 2 follow-ups if gaps remain (max 5 total).
28+
29+
3. **Load context**: Read spec.md, plan.md (if exists), tasks.md (if exists) - only relevant portions.
30+
31+
4. **Generate checklist**:
32+
- Create `FEATURE_DIR/checklists/[domain].md`
33+
- If exists: append continuing from last CHK ID. Never delete existing content.
34+
- Group by: Completeness, Clarity, Consistency, Measurability, Coverage, Edge Cases, NFRs, Dependencies, Ambiguities
35+
- Each item: question format about requirement quality with [dimension] tag
36+
- Include traceability refs: `[Spec §X.Y]`, `[Gap]`, `[Ambiguity]`, `[Conflict]`
37+
- Soft cap: 40 items, merge near-duplicates, consolidate low-impact edge cases
38+
39+
5. **Report**: Path, item count, focus areas, whether created or appended.
40+
41+
## Item Format
42+
43+
```
44+
- [ ] CHK### Are [requirement type] defined/specified for [scenario]? [Dimension, Spec §X.Y]
45+
```
46+
47+
Patterns: "Are X defined?" / "Is X quantified?" / "Are X consistent between A and B?" / "Can X be measured?" / "Does spec define X?"
48+
49+
Prohibited: "Verify", "Test", "Confirm" + implementation behavior / "Displays correctly" / "Click", "navigate", "render"
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
description: Identify underspecified areas in feature spec, ask up to 5 targeted clarification questions, encode answers back into spec.
3+
handoffs:
4+
- label: Build Technical Plan
5+
agent: speckit.plan
6+
prompt: Create a plan for the spec. I am building with...
7+
scripts:
8+
sh: scripts/bash/check-prerequisites.sh --json --paths-only
9+
ps: scripts/powershell/check-prerequisites.ps1 -Json -PathsOnly
10+
---
11+
12+
## Input
13+
14+
```text
15+
$ARGUMENTS
16+
```
17+
18+
Consider user input before proceeding (if not empty).
19+
20+
## Workflow
21+
22+
1. Run `{SCRIPT}`, parse FEATURE_DIR and FEATURE_SPEC. Abort if JSON fails.
23+
24+
2. **Scan spec** using taxonomy (mark Clear/Partial/Missing):
25+
- Functional scope, domain/data model, UX flow, non-functional (perf/scale/security/observability), integrations, edge cases, constraints, terminology, completion signals, placeholders
26+
27+
3. **Generate max 5 questions** (prioritized by Impact*Uncertainty):
28+
- Must be answerable via multiple-choice (2-5 options) or short answer (<=5 words)
29+
- Only include if answer materially impacts architecture, testing, UX, or compliance
30+
- Balance category coverage
31+
32+
4. **Ask one at a time**:
33+
- Multiple-choice: show **Recommended** option with reasoning + options table. User can pick letter, say "yes"/"recommended", or custom answer
34+
- Short-answer: show **Suggested** answer. User can accept or provide own
35+
- Stop when: all resolved, user signals done, or 5 questions asked
36+
37+
5. **Integrate each answer** immediately:
38+
- Add `## Clarifications` > `### Session YYYY-MM-DD` if missing
39+
- Append `- Q: <question> → A: <answer>`
40+
- Update appropriate spec section (requirements, stories, data model, success criteria, edge cases)
41+
- Replace obsolete statements, save after each integration
42+
43+
6. **Validate**: No duplicates, <=5 questions, no lingering placeholders, consistent terminology.
44+
45+
7. **Report**: Questions asked/answered, path to updated spec, sections touched, coverage summary, next command suggestion.
46+
47+
## Rules
48+
49+
- Never exceed 5 questions | Present one at a time | Never reveal future questions
50+
- If no ambiguities: report "No critical ambiguities" and suggest proceeding
51+
- If spec missing: instruct to run `/speckit.specify` first
52+
- Respect early termination ("done", "stop", "proceed")
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
description: Create or update project constitution from interactive or provided principle inputs.
3+
handoffs:
4+
- label: Build Specification
5+
agent: speckit.specify
6+
prompt: Implement the feature specification based on the updated constitution. I want to build...
7+
---
8+
9+
## Input
10+
11+
```text
12+
$ARGUMENTS
13+
```
14+
15+
Consider user input before proceeding (if not empty).
16+
17+
## Workflow
18+
19+
1. **Load** `.specify/memory/constitution.md`. Identify all `[PLACEHOLDER]` tokens. Respect user's desired principle count.
20+
21+
2. **Collect values**: From user input, repo context, or inference. Version: semver (MAJOR=breaking, MINOR=additions, PATCH=clarifications). LAST_AMENDED_DATE=today if changes made.
22+
23+
3. **Draft**: Replace all placeholders with concrete text. Each principle: name + non-negotiable rules + rationale. Governance: amendment procedure + versioning + compliance expectations.
24+
25+
4. **Propagate**: Check alignment with plan-template.md, spec-template.md, tasks-template.md, commands/*.md. Update references if needed.
26+
27+
5. **Sync Report**: Add HTML comment at top: version change, modified/added/removed sections, templates needing updates.
28+
29+
6. **Validate**: No unexplained brackets, version matches report, dates ISO, principles are declarative+testable (MUST/SHOULD not vague "should").
30+
31+
7. **Write** to `.specify/memory/constitution.md`.
32+
33+
8. **Report**: Version + bump rationale, files needing follow-up, suggested commit message.
34+
35+
## Rules
36+
37+
- Use exact template heading hierarchy
38+
- Single blank line between sections
39+
- If partial updates: still validate and version-decide
40+
- Missing info: insert `TODO(<FIELD>): explanation`
41+
- Always operate on existing file, never create new template
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
description: Execute implementation plan by processing all tasks in tasks.md.
3+
scripts:
4+
sh: scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks
5+
ps: scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks
6+
---
7+
8+
## Input
9+
10+
```text
11+
$ARGUMENTS
12+
```
13+
14+
Consider user input before proceeding (if not empty).
15+
16+
## Pre-Execution
17+
18+
Check `.specify/extensions.yml` for `hooks.before_implement`. Run mandatory hooks, show optional. Skip silently if missing/invalid.
19+
20+
## Workflow
21+
22+
1. Run `{SCRIPT}`, parse FEATURE_DIR and AVAILABLE_DOCS.
23+
24+
2. **Check checklists** (if FEATURE_DIR/checklists/ exists):
25+
- Count total/completed/incomplete items per checklist
26+
- If incomplete: show status table, ask user to confirm proceeding
27+
- If all pass: auto-proceed
28+
29+
3. **Load context**: tasks.md (required), plan.md (required), data-model.md, contracts/, research.md, quickstart.md (if exist).
30+
31+
4. **Setup verification**: Create/verify ignore files (.gitignore, .dockerignore, etc.) based on detected tech stack from plan.md. Append missing patterns to existing files, create full set for missing files.
32+
33+
5. **Parse tasks.md**: Extract phases, dependencies, task details, parallel markers [P].
34+
35+
6. **Execute phase-by-phase**:
36+
- Setup → Tests (if any) → Core → Integration → Polish
37+
- Sequential tasks in order, [P] tasks can run together
38+
- Mark completed tasks as `[X]` in tasks.md
39+
- Report progress after each task
40+
- Halt on non-parallel task failure, continue others for [P] failures
41+
42+
7. **Validate**: All tasks complete, features match spec, tests pass.
43+
44+
8. Check `.specify/extensions.yml` for `hooks.after_implement`. Run mandatory, show optional. Skip silently if missing.
45+
46+
## Rules
47+
48+
- If tasks.md incomplete/missing: suggest `/speckit.tasks` first
49+
- Provide clear error messages with debugging context

0 commit comments

Comments
 (0)