E53B Hotfix: Fix some commands template logic and helper scripts by barisgit · Pull Request #8 · barisgit/spec-kit-improved · GitHub
[go: up one dir, main page]

Skip to content

Hotfix: Fix some commands template logic and helper scripts#8

Merged
barisgit merged 5 commits intomainfrom
hotfix/fix-template-and-script-bugs
Oct 4, 2025
Merged

Hotfix: Fix some commands template logic and helper scripts#8
barisgit merged 5 commits intomainfrom
hotfix/fix-template-and-script-bugs

Conversation

@barisgit
Copy link
Owner
@barisgit barisgit commented Oct 2, 2025
  • Fix bugs in updating agent files and including whole repo and in refresh templates not usign correct paths
  • Make tree command OS-agnostic
  • Update implement command and scaffold-agent script
  • Update internal .specify folder

Summary by CodeRabbit

  • New Features

    • Added comprehensive agent report templates for architecture, code, docs, specs, tests, implementation, and generic analyses.
    • Added a scaffold command to discover, list, and generate agent documents with JSON output and project-context population.
    • Enhanced agent-context update to handle multiple assistants, per-assistant results, optional memory refresh, and richer JSON reporting.
  • Improvements

    • Centralized output path handling and fixed command output naming.
    • Spec tree generation now respects .gitignore with robust fallbacks.
    • Safer contract file handling and improved CLI exit behavior.
  • Chores

    • Project version bumped to 0.3.2.

@vercel
Copy link
vercel bot commented Oct 2, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
spec-kit-improved Ready Ready Preview Comment Oct 4, 2025 8:26pm

@coderabbitai
Copy link
coderabbitai bot commented Oct 2, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds many new Jinja2 agent/report templates, introduces a scaffold-agent CLI for discovering and rendering agent templates, refactors template path resolution into file-ops, enhances spec-tree generation with gitignore awareness, updates multiple scripts for multi-assistant context handling and safer file reads, and bumps the project version.

Changes

Cohort / File(s) Summary of Changes
Agent templates (new & updated)
.specify/agent-templates/architecture-reviewer.md.j2, .specify/agent-templates/code-reviewer.md.j2, .specify/agent-templates/context.md.j2, .specify/agent-templates/documentation-reviewer.md.j2, .specify/agent-templates/generic-agent.md.j2, .specify/agent-templates/implementer.md.j2, .specify/agent-templates/spec-reviewer.md.j2, .specify/agent-templates/test-reviewer.md.j2
Adds comprehensive Jinja2 Markdown templates for multiple reviewer/agent types with conditional rendering, loops, defaults, and structured sections for analyses, metrics, issues, and recommendations.
Package templates / script templates
src/specify_cli/templates/scripts/scaffold-agent.py.j2, src/specify_cli/templates/scripts/update-agent-context.py.j2, src/specify_cli/templates/commands/implement.md.j2, src/specify_cli/templates/commands/guide.md.j2
Switches scaffold/update script templates to use package-provided agent prompts, centralizes feature-dir discovery, builds richer project context (structured tasks), overhauls implement workflow (subagents, TDD enforcement, phased execution), and adjusts update-context JSON output handling.
New scaffold-agent CLI script
.specify/scripts/scaffold-agent.py
Adds a Typer CLI to discover agent templates (project or package), render templates with project context, compute sequence-numbered dated filenames, and write outputs; introduces AgentType and ScaffoldRequest dataclasses and multiple helper utilities.
Update agent-context script behavior
.specify/scripts/update-agent-context.py, src/specify_cli/templates/scripts/update-agent-context.py.j2
Changes main signature to optional assistant (updates all when omitted), adds per-assistant processing and reporting, improves spec-dir discovery, supports memory import refresh, and emits per-assistant JSON results.
Script safety & error-handling tweaks
.specify/scripts/check-prerequisites.py, .specify/scripts/generate-tasks.py, .specify/scripts/setup-plan.py
Adds 10 MB contract file safety limit, explicit UTF‑8 reads, catches OSError/MemoryError on read, re-raises Typer Exit in generate-tasks, and updates two creation-date literals.
Template service refactor
src/specify_cli/services/template_service/template_service.py, src/specify_cli/services/template_service/template_file_operations.py
Delegates AI output path determination to template_file_operations; file-ops now computes command-category filenames via centralized naming logic to ensure correct filenames and extensions.
Spec tree & helpers
src/specify_cli/utils/script_helpers.py
Adds gitignore-aware spec-tree generation: prefers system tree with --gitignore, falls back to a gitignored-aware simple listing, introduces _is_gitignored helper, and expands exception handling.
Project metadata
pyproject.toml
Bumps project version 0.3.1 → 0.3.2.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant CLI as scaffold-agent CLI
  participant Disc as Template Discovery
  participant Ctx as Project Context
  participant Render as Template Renderer
  participant FS as Filesystem

  User->>CLI: scaffold --agents <names> [--args JSON]
  CLI->>Disc: Discover templates (project or package)
  Disc-->>CLI: Agent types list
  CLI->>Ctx: Build project context (feature, branch, timestamps)
  loop For each agent
    CLI->>Render: Render template with context + args
    Render->>FS: Write YYYY-MM-DD-XXX-*.md under base_output_dir/<agent>/
    FS-->>Render: Path
    Render-->>CLI: Success/Failure + path
  end
  CLI-->>User: Summary (JSON or table)
Loading
sequenceDiagram
  autonumber
  actor User
  participant UAC as update-agent-context
  participant CFG as Project Config
  participant SH as ScriptHelpers
  participant AI as Assistant API (per assistant)
  participant FS as Filesystem

  User->>UAC: run [assistant?] [--json]
  alt assistant provided
    UAC->>SH: Locate spec dir & build context
    UAC->>AI: Update assistant context
    AI-->>UAC: Result + (optional) memory refresh
  else update all
    UAC->>CFG: Load enabled assistants
    loop For each assistant
      UAC->>SH: Locate spec dir & build context
      UAC->>AI: Update assistant context
      AI-->>UAC: Result per assistant
    end
  end
  UAC->>FS: Write/resolve context files
  UAC-->>User: Per-assistant results, overall success
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

A rabbit in code with a careful peep,
Templates planted tidy, sequence numbers keep.
Gitignore hums softly, tree shows the scheme,
Agents scaffolded, contexts gleam.
I hop, I stamp—release bumped with a cheer! 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title indicates a hotfix for commands template logic and helper scripts, which corresponds to real modifications in command templates and utility scripts, though it is somewhat vague and does not specify the exact components changed.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch hotfix/fix-template-and-script-bugs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

cursor[bot]

This comment was marked as outdated.

Copy link
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.specify/scripts/update-agent-context.py (1)

75-80: Honor --json: avoid printing non-JSON from update_context_file.

update_context_file prints console messages regardless of json_output, breaking consumers.

-def update_context_file(
-    context_file: Path, context_info: Dict[str, Any], assistant_type: str
-) -> bool:
+def update_context_file(
+    context_file: Path, context_info: Dict[str, Any], assistant_type: str, json_output: bool = False
+) -> bool:
@@
-    if not context_file.exists():
-        console.print(f"[yellow]Context file not found: {context_file}[/yellow]")
+    if not context_file.exists():
+        if not json_output:
+            console.print(f"[yellow]Context file not found: {context_file}[/yellow]")
         return False
@@
-    if not sections:
-        console.print("[yellow]No project context found to add[/yellow]")
+    if not sections:
+        if not json_output:
+            console.print("[yellow]No project context found to add[/yellow]")
         return False
@@
-    context_file.write_text(updated_content)
-    console.print(
-        f"[green]Updated {context_file.name} with comprehensive project context[/green]"
-    )
+    context_file.write_text(updated_content)
+    if not json_output:
+        console.print(
+            f"[green]Updated {context_file.name} with comprehensive project context[/green]"
+        )
     return True

And pass the flag at call site:

-            success = update_context_file(context_file, context_info, assistant_name)
+            success = update_context_file(context_file, context_info, assistant_name, json_output=json_output)

Also applies to: 97-134

🧹 Nitpick comments (6)
src/specify_cli/templates/scripts/scaffold-agent.py.j2 (4)

457-462: Update message to reflect package-based discovery.

The text still references .specify/agent-templates. It should mention package agent-prompts.

-                if not agent_types:
-                    echo_info(
-                        "No agent templates found in .specify/agent-templates/", quiet
-                    )
-                    echo_info("Create agent templates to use this feature", quiet)
+                if not agent_types:
+                    echo_info(
+                        "No agent prompts found in package resources (agent-prompts).", quiet
+                    )
+                    echo_info("Ensure your package includes agent-prompts or update to a version that does.", quiet)

74-113: Deterministic agent listing.

Sort discovered templates by filename to make --list output stable.

-                for template_file in agent_prompts_dir.iterdir():
+                for template_file in sorted(agent_prompts_dir.iterdir(), key=lambda p: p.name):
                     if template_file.is_file() and template_file.name.endswith(
                         ".md.j2"
                     ):

541-544: Guard relative_to() for non-repo output dirs.

Path.relative_to() raises ValueError if the output dir is outside repo root. Fall back to absolute path.

-                    rel_path = Path(result).relative_to(helpers.get_repo_root())
-                    echo_success(f"Generated: {rel_path}", quiet)
+                    try:
+                        rel_path = Path(result).relative_to(helpers.get_repo_root())
+                    except ValueError:
+                        rel_path = Path(result)
+                    echo_success(f"Generated: {rel_path}", quiet)

71-118: Python 3.8 compatibility for importlib.resources.files.

files() requires Python 3.9+. If you target 3.8, add a backport shim to use importlib_resources.

-import importlib.resources
+try:
+    # Python 3.9+
+    import importlib.resources as _ires
+    resource_files = _ires.files
+    as_file = _ires.as_file
+except Exception:
+    # Python 3.8 fallback
+    import importlib_resources as _ires  # type: ignore
+    resource_files = _ires.files  # type: ignore
+    as_file = _ires.as_file  # type: ignore
@@
-            agent_prompts_dir = (
-                importlib.resources.files(templates_pkg) / "agent-prompts"
-            )
+            agent_prompts_dir = resource_files(templates_pkg) / "agent-prompts"
@@
-        with importlib.resources.as_file(template_path) as real_template_path:
+        with as_file(template_path) as real_template_path:

Based on learnings

.specify/scripts/update-agent-context.py (1)

168-197: Search spec dirs from repo root, not CWD.

Using Path.cwd() can scan unintended paths. Base discovery on repo root for consistency.

-        cwd = Path.cwd()
-        spec_dir = None
+        repo_root = helpers.get_repo_root()
+        spec_dir = None
@@
-        if (cwd / "spec.md").exists() or (cwd / "plan.md").exists():
-            spec_dir = cwd
+        if (repo_root / "spec.md").exists() or (repo_root / "plan.md").exists():
+            spec_dir = repo_root
         else:
             # Look for most recent spec directory
             spec_dirs = []
-            for pattern in ["specs/*/", "features/*/", "*/specs/"]:
-                spec_dirs.extend(cwd.glob(pattern))
+            for pattern in ["specs/*/", "features/*/", "*/specs/"]:
+                spec_dirs.extend(repo_root.glob(pattern))
.specify/agent-templates/context.md.j2 (1)

421-421: Fix join/default order in metadata

-- **Data Sources**: {{ data_sources | join(", ") | default("Not specified") }}
+- **Data Sources**: {{ (data_sources | default([])) | join(", ") if data_sources is defined else "Not specified" }}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e39feba and 256e389.

📒 Files selected for processing (20)
  • .specify/agent-templates/architecture-reviewer.md.j2 (1 hunks)
  • .specify/agent-templates/code-reviewer.md.j2 (1 hunks)
  • .specify/agent-templates/context.md.j2 (1 hunks)
  • .specify/agent-templates/documentation-reviewer.md.j2 (1 hunks)
  • .specify/agent-templates/generic-agent.md.j2 (1 hunks)
  • .specify/agent-templates/implementer.md.j2 (1 hunks)
  • .specify/agent-templates/spec-reviewer.md.j2 (1 hunks)
  • .specify/agent-templates/test-reviewer.md.j2 (1 hunks)
  • .specify/scripts/check-prerequisites.py (1 hunks)
  • .specify/scripts/generate-tasks.py (1 hunks)
  • .specify/scripts/scaffold-agent.py (1 hunks)
  • .specify/scripts/setup-plan.py (2 hunks)
  • .specify/scripts/update-agent-context.py (4 hunks)
  • pyproject.toml (1 hunks)
  • src/specify_cli/services/template_service/template_file_operations.py (1 hunks)
  • src/specify_cli/services/template_service/template_service.py (2 hunks)
  • src/specify_cli/templates/commands/implement.md.j2 (1 hunks)
  • src/specify_cli/templates/scripts/scaffold-agent.py.j2 (8 hunks)
  • src/specify_cli/templates/scripts/update-agent-context.py.j2 (1 hunks)
  • src/specify_cli/utils/script_helpers.py (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/specify_cli/services/template_service/template_file_operations.py (1)
src/specify_cli/services/template_registry/models.py (1)
  • filename (37-39)
src/specify_cli/services/template_service/template_service.py (1)
src/specify_cli/services/template_service/template_file_operations.py (1)
  • determine_output_path_for_ai (100-162)
.specify/scripts/update-agent-context.py (3)
src/specify_cli/services/config_service/config_service.py (1)
  • TomlConfigService (122-838)
src/specify_cli/utils/script_helpers.py (2)
  • get_repo_root (67-103)
  • load_project_config (137-155)
src/specify_cli/services/memory_service/memory_service.py (2)
  • MemoryManager (17-158)
  • generate_import_section (105-158)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cursor Bugbot
🔇 Additional comments (8)
pyproject.toml (1)

3-3: Version bump matches the hotfix scope.

Patch increment is appropriate given the bugfix updates elsewhere in the PR.

.specify/scripts/check-prerequisites.py (3)

256-265: LGTM: Size limit prevents resource exhaustion.

The 10MB safety limit is a sensible defense against accidentally loading oversized contract files into memory. The error handling correctly stops processing and provides a clear message.


266-266: LGTM: Explicit UTF-8 encoding ensures cross-platform consistency.

Specifying encoding="utf-8" prevents platform-dependent encoding issues and aligns with JSON's UTF-8 requirement.


272-275: LGTM: Comprehensive error handling for file operations.

Catching OSError and MemoryError provides robust handling for file system errors and memory exhaustion scenarios. This complements the size check at lines 256-265 by handling edge cases where issues occur despite the safety limit.

src/specify_cli/templates/commands/implement.md.j2 (1)

24-34: Ensure check-implementation-status command is implemented and supports --spec-id and --json
The docs in src/specify_cli/templates/commands/implement.md.j2 reference this command; verify it’s registered in the CLI and that its flags match the template.

.specify/agent-templates/documentation-reviewer.md.j2 (1)

185-186: Verify custom Jinja ternary filter registration
The template uses the non-standard ternary filter:

{{ issue.auto_fixable | ternary("Yes", "No") }}

Jinja doesn’t include ternary by default—ensure you’ve registered it in your Environment or replace it with an inline expression:

{{ "Yes" if issue.auto_fixable else "No" }}
src/specify_cli/services/template_service/template_service.py (2)

22-22: No changes required; get_assistant is already imported in template_file_operations.py (line 16).


682-685: Confirm all categories and extension logic in determine_output_path_for_ai

  • commands: delegates to determine_output_filename (removes .j2, applies command_files.file_format)
  • context: returns assistant.config.context_file.file (static JSON path)
  • scripts / memory: strips .j2 → SPECIFY_SCRIPTS_DIR/, SPECIFY_MEMORY_DIR/
  • agent-prompts: strips .j2 → TEMPLATE_REGISTRY.resolve_target/
  • agent-templates: preserves .j2 → TEMPLATE_REGISTRY.resolve_target/.j2

Comment on lines +104 to +105
**Service Mesh**: {{ service_architecture.service_mesh | ternary("Implemented", "Not Implemented") }}
**Data Consistency**: {{ service_architecture.data_consistency_pattern }}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify custom Jinja ‘ternary’ filter availability.

The template relies on ‘ternary’. Ensure it’s registered, or refactor to inline if/else to avoid runtime template errors.

Example refactor:

  • {{ service_architecture.service_mesh | ternary("Implemented", "Not Implemented") }}
  • becomes: {{ "Implemented" if service_architecture.service_mesh else "Not Implemented" }}

Run to verify filter registration:

Also applies to: 114-116, 261-262, 383-387, 393-397


🏁 Script executed:

#!/bin/bash
rg -n -C2 -P 'filters\s*\[\s*[\"\']ternary[\"\']\s*\]|add_filter\(\s*[\"\']ternary[\"\']' -g '!**/node_modules/**'
rg -n -C2 -P '\|\s*ternary\s*\('

Length of output: 68


🏁 Script executed:

#!/bin/bash
rg -n -C2 "filters\[\s*['\"]ternary['\"]\s*\]|add_filter\(\s*['\"]ternary['\"]\)" -g '!**/node_modules/**'
rg -n -C2 "def\s+ternary" -g '*.py'
rg -n -C2 "\|\s*ternary\s*\(" -g '*.j2'

Length of output: 8735


Ensure the ternary filter is registered or refactor to inline conditionals.
No ternary filter definition was found in the codebase; either register it on your Jinja environment (e.g. env.filters['ternary']=lambda v,a,b: a if v else b) or replace all {{ foo | ternary("A","B") }} with {{ "A" if foo else "B" }} to prevent runtime errors.

🤖 Prompt for AI Agents
.specify/agent-templates/architecture-reviewer.md.j2 around lines 104-105: the
template uses a non-existent Jinja filter `ternary`, which will cause runtime
errors; either register the filter on the Jinja environment (e.g. add
env.filters['ternary']=...) or replace the usage with an inline conditional
expression `{{ "Implemented" if service_architecture.service_mesh else "Not
Implemented" }}` (apply the same replacement pattern for all other `|
ternary(...)` occurrences) so the template does not rely on an undefined filter.

Comment on lines +30 to +33
#### {{ issue.severity.upper() }}: {{ issue.title }}
**File**: `{{ issue.file_path }}`
**Line**: {{ issue.line_number | default("N/A") }}
**Description**: {{ issue.description }}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Blocker: non-existent Jinja filter and unsafe attribute call

  • Jinja2 has no built-in ternary filter; will raise “no filter named ‘ternary’”.
  • Calling .upper() before default will error when severity is missing.
  • Apply default before length; otherwise length on undefined may error.

Fix examples:

-#### {{ issue.severity.upper() }}: {{ issue.title }}
+#### {{ (issue.severity | default("HIGH")) | upper }}: {{ issue.title }}

-  - **Fix**: {{ violation.auto_fixable | ternary("Auto-fixable", "Manual fix required") }}
+  - **Fix**: {{ "Auto-fixable" if violation.auto_fixable else "Manual fix required" }}

-**Files Reviewed**: {{ files_reviewed | length | default(0) }}
+**Files Reviewed**: {{ (files_reviewed | default([])) | length }}

Search for similar patterns project‑wide:

Also applies to: 65-66, 187-188


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "Ternary filter uses:" >&2
rg -nP '\|\s*ternary\s*\(' .specify/agent-templates -C1 || true
echo "upper() before default:" >&2
rg -nP '\.upper\(\)\s*\|\s*default' .specify/agent-templates -n -C1 || true
echo "join before default:" >&2
rg -nP '\|\s*join\([^)]*\)\s*\|\s*default' .specify/agent-templates -n -C1 || true

Length of output: 7995


Blocker: unsupported Jinja patterns in templates

  • Remove all uses of | ternary(…); replace with inline … if … else … expressions.
  • Always apply | default(…) before calling filters/attributes (e.g., upper, join) to avoid undefined‐variable errors.
    Affects multiple files under .specify/agent-templates/ (code-reviewer.md.j2, implementer.md.j2, spec-reviewer.md.j2, context.md.j2, generic-agent.md.j2, etc.).
🤖 Prompt for AI Agents
In .specify/agent-templates/code-reviewer.md.j2 around lines 30 to 33, the
template uses unsupported Jinja patterns: remove all uses of the | ternary(...)
filter and replace them with inline conditional expressions using the Jinja
ternary syntax (value_if_true if condition else value_if_false); also ensure any
variable that will be filtered or have attributes called (e.g., | upper, | join)
is first wrapped with | default(...) to provide a safe fallback before applying
further filters. Apply these same changes across the other templates under
.specify/agent-templates/ (implementer.md.j2, spec-reviewer.md.j2,
context.md.j2, generic-agent.md.j2, etc.), replacing | ternary(...) usages and
moving/adding | default(...) before subsequent filters or attribute lookups so
templates no longer use unsupported filter patterns.

Comment on lines +318 to +319
- **CI/CD**: {{ test_strategy.cicd_integration | ternary("Integrated", "Not integrated") }}
{% endif %}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix join/default order to avoid errors

Default to a list before join:

-- **Test Types**: {{ test_strategy.test_types | join(", ") | default("Unit, Integration, E2E") }}
+- **Test Types**: {{ (test_strategy.test_types | default(["Unit","Integration","E2E"])) | join(", ") }}

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In .specify/agent-templates/context.md.j2 around lines 318-319, the template
uses a value that may be None before calling join; ensure you default that
variable to an empty list before joining. Update the template expression to
apply default([]) (or an equivalent) before |join so the join always operates on
a list and won't error when the value is missing or null.

- **Coverage Target**: {{ test_strategy.coverage_target | default("80") }}%
- **Test Types**: {{ test_strategy.test_types | join(", ") | default("Unit, Integration, E2E") }}
- **CI/CD**: {{ test_strategy.cicd_integration | ternary("Integrated", "Not integrated") }}
{% endif %}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Replace non-existent ‘ternary’ filter

-- **CI/CD**: {{ test_strategy.cicd_integration | ternary("Integrated", "Not integrated") }}
+- **CI/CD**: {{ "Integrated" if test_strategy.cicd_integration else "Not integrated" }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{% endif %}
- **CI/CD**: {{ "Integrated" if test_strategy.cicd_integration else "Not integrated" }}
{% endif %}
🤖 Prompt for AI Agents
.specify/agent-templates/context.md.j2 around line 319: the template uses a
non-existent 'ternary' filter — locate where '| ternary(...)' is used and
replace it with standard Jinja2 conditional syntax or built-in filters;
specifically refactor to either the inline expression "value_if_true if
condition else value_if_false" or use the 'default' filter for fallback values,
ensuring the logic and whitespace/escaping remain correct.

Comment on lines +431 to +434
- **Frequency**: {{ refresh_schedule.frequency }}
- **Next Refresh**: {{ refresh_schedule.next_refresh }}
- **Auto-refresh**: {{ refresh_schedule.auto_refresh | ternary("Enabled", "Disabled") }}
{% endif %}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Replace ‘ternary’ filter for refresh schedule

-- **Auto-refresh**: {{ refresh_schedule.auto_refresh | ternary("Enabled", "Disabled") }}
+- **Auto-refresh**: {{ "Enabled" if refresh_schedule.auto_refresh else "Disabled" }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **Frequency**: {{ refresh_schedule.frequency }}
- **Next Refresh**: {{ refresh_schedule.next_refresh }}
- **Auto-refresh**: {{ refresh_schedule.auto_refresh | ternary("Enabled", "Disabled") }}
{% endif %}
- **Frequency**: {{ refresh_schedule.frequency }}
- **Next Refresh**: {{ refresh_schedule.next_refresh }}
- **Auto-refresh**: {{ "Enabled" if refresh_schedule.auto_refresh else "Disabled" }}
{% endif %}
🤖 Prompt for AI Agents
.specify/agent-templates/context.md.j2 around lines 431 to 434: the template
uses the non-standard 'ternary' filter to render auto-refresh state; replace it
with a Jinja2 inline conditional expression so the line outputs "Enabled" when
refresh_schedule.auto_refresh is truthy and "Disabled" otherwise (i.e., change
the filter use to an inline if-else expression).

Comment on lines +36 to +40
#### {{ issue.severity.upper() }}: {{ issue.title }}
**Section**: {{ issue.section | default("General") }}
**Issue**: {{ issue.description }}
**Impact**: {{ issue.impact_on_implementation }}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Guard severity before upper()

-#### {{ issue.severity.upper() }}: {{ issue.title }}
+#### {{ (issue.severity | default("HIGH")) | upper }}: {{ issue.title }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
35B2
#### {{ issue.severity.upper() }}: {{ issue.title }}
**Section**: {{ issue.section | default("General") }}
**Issue**: {{ issue.description }}
**Impact**: {{ issue.impact_on_implementation }}
#### {{ (issue.severity | default("HIGH")) | upper }}: {{ issue.title }}
**Section**: {{ issue.section | default("General") }}
**Issue**: {{ issue.description }}
**Impact**: {{ issue.impact_on_implementation }}
🤖 Prompt for AI Agents
In .specify/agent-templates/spec-reviewer.md.j2 around lines 36 to 40, the
template calls issue.severity.upper() without guarding for a
missing/null/undefined severity which will raise an error; change the template
to safely access and uppercase severity (for example use a default or
conditional: render (issue.severity or 'UNKNOWN').upper() or wrap with a
conditional check and fallback to 'UNKNOWN'/'UNSPECIFIED') so the template never
fails when severity is absent.

Comment on lines +299 to +309
template_path = repo_root / ".specify" / "agent-templates" / agent_template_name

if not template_path.exists():
# Try generic agent template as fallback
generic_template = (
repo_root / ".specify" / "agent-templates" / "generic-agent.md.j2"
)
if generic_template.exists():
template_path = generic_template
else:
return False, f"Agent template not found: {template_path}"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Honor package-discovered templates when rendering

discover_agent_types happily finds templates shipped in the package, but scaffold_agent ignores that information and unconditionally looks under <repo>/.specify/agent-templates/. When the template only exists in the package (the entire point of the fallback), template_path.exists() is false and we fall back to generic or fail outright. Please plumb the discovered AgentType.template_path through so we render the actual template we just advertised.

🤖 Prompt for AI Agents
In .specify/scripts/scaffold-agent.py around lines 299 to 309, scaffold_agent
currently always checks for templates under <repo>/.specify/agent-templates and
ignores the AgentType discovered template path; update the function to prefer
and use the AgentType.template_path (if provided by discover_agent_types) before
falling back to the repo local template or generic-template. Concretely: accept
or obtain the AgentType object (or its .template_path string/Path) into
scaffold_agent, use that path as the primary template_path if present, and only
if it is missing/None proceed to check repo_root/.specify/agent-templates and
then generic; also handle package-embedded templates by detecting non-filesystem
template paths (or strings referring to package resources) and render them via
importlib.resources or pkgutil when Path.exists() is false.

Comment on lines +512 to +520
available_names = [agent.name for agent in agent_types]
if (
request.agent_name not in available_names
and not (
base_output_dir.parent
/ ".specify"
/ "agent-templates"
/ "generic-agent.md.j2"
).exists()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix generic-template fallback path

The guard that should allow unknown agents to fall back to generic-agent.md.j2 never succeeds—the path resolves to .specify/.specify/agent-templates/... when output_dir is the default .specify/agents. As a result, even with a generic template present, we wrongly reject the request.

Reuse the repo root when building this path, e.g.:

-                and not (
-                    base_output_dir.parent
-                    / ".specify"
-                    / "agent-templates"
-                    / "generic-agent.md.j2"
-                ).exists()
+                and not (
+                    helpers.get_repo_root()
+                    / ".specify"
+                    / "agent-templates"
+                    / "generic-agent.md.j2"
+                ).exists()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
available_names = [agent.name for agent in agent_types]
if (
request.agent_name not in available_names
and not (
base_output_dir.parent
/ ".specify"
/ "agent-templates"
/ "generic-agent.md.j2"
).exists()
available_names = [agent.name for agent in agent_types]
if (
request.agent_name not in available_names
and not (
helpers.get_repo_root()
/ ".specify"
/ "agent-templates"
/ "generic-agent.md.j2"
).exists()
🤖 Prompt for AI Agents
.specify/scripts/scaffold-agent.py around lines 512 to 520: the fallback check
builds the generic template path relative to base_output_dir causing
`.specify/.specify/...` and never matching; change the path construction to use
the repository root (e.g., locate repo_root =
Path(__file__).resolve().parents[...] or use a known project root) and join
repo_root / ".specify" / "agent-templates" / "generic-agent.md.j2" so the
existence check correctly finds the template and allows unknown agents to fall
back to it.

Comment on lines +264 to +270
error_msg = f"Failed to get context file for {assistant_name}: {e}"
if json_output:
print(json.dumps({"error": error_msg}))
else:
echo_error(error_msg)
results[assistant_name] = {"success": False, "error": str(e)}
continue
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don’t print per-assistant JSON errors when aggregating results.

Printing JSON mid-loop pollutes final JSON. Accumulate errors in results only.

-                if json_output:
-                    print(json.dumps({"error": error_msg}))
-                else:
-                    echo_error(error_msg)
+                if not json_output:
+                    echo_error(error_msg)
                 results[assistant_name] = {"success": False, "error": str(e)}
                 continue
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
error_msg = f"Failed to get context file for {assistant_name}: {e}"
if json_output:
print(json.dumps({"error": error_msg}))
else:
echo_error(error_msg)
results[assistant_name] = {"success": False, "error": str(e)}
continue
error_msg = f"Failed to get context file for {assistant_name}: {e}"
if not json_output:
echo_error(error_msg)
results[assistant_name] = {"success": False, "error": str(e)}
continue

Comment on lines +300 to 311
# Try to get template from package agent-prompts
try:
agent_prompts_dir = (
importlib.resources.files(templates_pkg) / "agent-prompts"
)
if generic_template.exists():
template_path = generic_template
else:
return False, f"Agent template not found: {template_path}"
template_path = agent_prompts_dir / agent_template_name

if not template_path.is_file():
return False, f"Agent prompt template not found: {agent_template_name}. Available agents: code-reviewer, documentation-reviewer, implementer, spec-reviewer, architecture-reviewer, test-reviewer"
except Exception as e:
return False, f"Failed to locate agent prompt templates: {str(e)}"

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix validation/rendering inconsistency (package prompts vs project templates).

Validation allows a project-level generic fallback, but rendering only loads package agent-prompts. This can pass validation then fail at render. Remove the dead fallback or add a package-aware fallback consistently.

Also, avoid hard-coded “Available agents” in the error; compute dynamically from discovery.

@@
-            if not template_path.is_file():
-                return False, f"Agent prompt template not found: {agent_template_name}. Available agents: code-reviewer, documentation-reviewer, implementer, spec-reviewer, architecture-reviewer, test-reviewer"
+            if not template_path.is_file():
+                # Build dynamic available list for the error
+                ok, all_types = discover_agent_types(helpers)
+                available = ", ".join(sorted([t.name for t in all_types])) if ok else "none"
+                return False, f"Agent prompt template not found: {agent_template_name}. Available agents: {available}"
@@
-            if (
-                request.agent_name not in available_names
-                and not (
-                    base_output_dir.parent
-                    / ".specify"
-                    / "agent-templates"
-                    / "generic-agent.md.j2"
-                ).exists()
-            ):
+            if request.agent_name not in available_names:
                 error_msg = f"Agent type '{request.agent_name}' not found. Available: {', '.join(available_names)}"
                 failed_agents.append({"agent": agent_spec, "error": error_msg})
                 if not json_mode:
                     echo_error(f"❌ {error_msg}")
                 continue

Also applies to: 513-523

🤖 Prompt for AI Agents
In src/specify_cli/templates/scripts/scaffold-agent.py.j2 around lines 300 to
311 (also apply same fix at 513-523): the render step only looks in the package
"agent-prompts" and returns a hard-coded "Available agents" list which can
mismatch validation; change rendering to mirror validation by first attempting
to load the template from the package agent-prompts, and if not found then
attempt the project-level templates fallback (or conversely remove the fallback
from validation to keep behavior consistent), and replace the hard-coded
available-agents message by computing the list dynamically (discover agent
template names by listing files in the package agent-prompts and the project
templates directory, deduplicate, and present that joined list in the error).

@barisgit barisgit merged commit f924316 into main Oct 4, 2025
14 of 15 checks passed
@barisgit barisgit deleted the hotfix/fix-template-and-script-bugs branch October 4, 2025 20:28
Copy link
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/specify_cli/templates/scripts/scaffold-agent.py.j2 (1)

300-311: Fix validation/rendering inconsistency and hard-coded agent list.

This issue was flagged in a previous review and remains unresolved. The rendering logic only loads templates from package agent-prompts, but the error message contains a hard-coded list of agents that may become stale. Additionally, validation at lines 515-523 checks for a project-level generic-agent.md.j2 fallback, but the rendering here doesn't support that fallback, creating an inconsistency.

Apply this diff to dynamically generate the available agents list and align validation with rendering:

         try:
             agent_prompts_dir = (
                 importlib.resources.files(templates_pkg) / "agent-prompts"
             )
             template_path = agent_prompts_dir / agent_template_name

             if not template_path.is_file():
-                return False, f"Agent prompt template not found: {agent_template_name}. Available agents: code-reviewer, documentation-reviewer, implementer, spec-reviewer, architecture-reviewer, test-reviewer"
+                # Build dynamic available list for the error
+                ok, all_types = discover_agent_types()
+                available = ", ".join(sorted([t.name for t in all_types])) if ok else "none"
+                return False, f"Agent prompt template not found: {agent_template_name}. Available agents: {available}"
         except Exception as e:
             return False, f"Failed to locate agent prompt templates: {str(e)}"

Additionally, at lines 515-523, remove the project-level fallback check to align with the package-only rendering approach:

             # Validate agent type exists
             available_names = [agent.name for agent in agent_types]
-            if (
-                request.agent_name not in available_names
-                and not (
-                    base_output_dir.parent
-                    / ".specify"
-                    / "agent-templates"
-                    / "generic-agent.md.j2"
-                ).exists()
-            ):
+            if request.agent_name not in available_names:
                 error_msg = f"Agent type '{request.agent_name}' not found. Available: {', '.join(available_names)}"
                 failed_agents.append({"agent": agent_spec, "error": error_msg})
                 if not json_mode:
                     echo_error(f"❌ {error_msg}")
                 continue
🧹 Nitpick comments (1)
src/specify_cli/templates/scripts/scaffold-agent.py.j2 (1)

69-69: Remove unused parameter.

The helpers parameter is assigned to _ but never used in the function. Consider removing it from the signature if it's not needed for future extensibility.

Apply this diff:

-def discover_agent_types(helpers: ScriptHelpers) -> Tuple[bool, List[AgentType]]:
+def discover_agent_types() -> Tuple[bool, List[AgentType]]:
     """
     Auto-discover available agent types from package agent-prompts.

     Args:
-        helpers: ScriptHelpers instance

     Returns:
         Tuple[bool, List[AgentType]]: (success, agent_types)
     """
-    _ = helpers

And update the call site at line 438:

-        success, agent_types = discover_agent_types(helpers)
+        success, agent_types = discover_agent_types()
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 256e389 and 751a286.

📒 Files selected for processing (5)
  • .specify/scripts/setup-plan.py (2 hunks)
  • src/specify_cli/templates/commands/guide.md.j2 (1 hunks)
  • src/specify_cli/templates/commands/implement.md.j2 (1 hunks)
  • src/specify_cli/templates/scripts/scaffold-agent.py.j2 (10 hunks)
  • src/specify_cli/templates/scripts/update-agent-context.py.j2 (5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: test (windows-latest, 3.13)
  • GitHub Check: test (windows-latest, 3.11)
🔇 Additional comments (8)
src/specify_cli/templates/commands/guide.md.j2 (1)

14-107: LGTM! Comprehensive manual workflow guidance.

The updated template provides clear, well-structured instructions for manual feature implementation. The phases (Setup, Task Execution Strategy, Manual Progress Tracking, Task Categories, Mixed AI/Human Workflow, Error Recovery) are logically organized and actionable.

src/specify_cli/templates/scripts/update-agent-context.py.j2 (2)

170-172: LGTM! Centralized spec directory discovery.

Using ScriptHelpers.find_feature_directory_for_workflow() centralizes the logic and reduces code duplication. This approach handles both traditional and no-branch workflows correctly.


72-137: LGTM! JSON output support added correctly.

The json_output parameter is properly threaded through the function, with conditional console prints suppressed when JSON mode is enabled. This maintains backward compatibility while adding useful structured output support.

src/specify_cli/templates/scripts/scaffold-agent.py.j2 (3)

199-199: LGTM! Centralized workflow directory discovery.

Using find_feature_directory_for_workflow() standardizes spec directory discovery across the codebase, supporting both feature branch and no-branch workflows.


221-245: LGTM! Enhanced task parsing with structured objects.

The updated task parsing creates structured task objects with id, title, status, and priority fields. The ID parsing logic handles both explicit task IDs (e.g., "T001 Task description") and auto-generates IDs when not present. The field name change from tasks to current_tasks (line 257) aligns with the updated context structure.


346-352: LGTM! Safe template rendering with package resources.

Using importlib.resource 35B2 s.as_file() properly converts the Traversable to a real filesystem Path for template rendering. This ensures compatibility with the rendering function while maintaining package-based resource loading.

src/specify_cli/templates/commands/implement.md.j2 (2)

14-33: LGTM! Subagent workflow with graceful fallback.

The addition of subagent support using scaffold-agent provides a modern workflow for environments that support it (e.g., Claude Code's Task tool), while maintaining a clear fallback path for environments without subagent support. The instructions for both paths are clear and actionable.


36-67: LGTM! Streamlined execution phases.

The phase updates improve clarity:

  • Phase 2 renamed to "TDD Enforcement (MANDATORY)" emphasizes test-first development
  • Merging Phase 3 and Phase 4 into a single "Task Execution" phase simplifies the workflow
  • Error handling and progress tracking guidance is concise and practical

"branch_name": result["BRANCH"],
"author_name": "",
"creation_date": "2025-09-18",
"creation_date": "2025-10-04",
Copy link

Choose a reason for hiding this comment

The reason w D60E ill be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Use dynamic date generation instead of hardcoded dates.

The creation_date is hardcoded to "2025-10-04", which means all generated plan and spec files will have the same creation date regardless of when they're actually created. This defeats the purpose of timestamp metadata and will require constant manual updates.

Apply this diff to use the current date dynamically:

+from datetime import datetime
+
 #!/usr/bin/env python3
 """
 Setup implementation plan structure for current branch.

Then update both occurrences:

                     context_dict={
                         "feature_name": result["BRANCH"],
                         "branch_name": result["BRANCH"],
                         "author_name": "",
-                        "creation_date": "2025-10-04",
+                        "creation_date": datetime.now().strftime("%Y-%m-%d"),
                         "project_name": "spec-kit-improved",
                     },

Also applies to: 169-169

🤖 Prompt for AI Agents
In .specify/scripts/setup-plan.py around lines 138 and 169, the creation_date
fields are hardcoded to "2025-10-04"; replace the hardcoded string with a
dynamically generated current date string (ISO YYYY-MM-DD) by importing or using
datetime.date.today().isoformat() (or equivalent) and assign that value to
creation_date in both locations so generated plan/spec files use the actual
creation date at runtime.

Copy link
@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Template Path Construction Error

The fallback logic for generic-agent.md.j2 constructs an incorrect path. Using base_output_dir.parent leads to a nested .specify/.specify directory, which prevents the generic agent template from being found.

.specify/scripts/scaffold-agent.py#L515-L520

and not (
base_output_dir.parent
/ ".specify"
/ "agent-templates"
/ "generic-agent.md.j2"
).exists()

src/specify_cli/templates/scripts/scaffold-agent.py.j2#L514-L520

available_names = [agent.name for agent in agent_types]
if (
request.agent_name not in available_names
and not (
base_output_dir.parent
/ ".specify"
/ "agent-templates"

Fix in Cursor Fix in Web


except (OSError, MemoryError) as e:
success = False
result = {"error": f"Failed to read {contract_file}: {e}"}
break
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Indentation Error in Exception Handling

The new except (OSError, MemoryError) block is incorrectly indented, placing it outside the try block that handles file opening and JSON loading. This prevents it from catching OSError or MemoryError exceptions that occur during these operations, leading to unhandled errors.

Fix in Cursor Fix in Web

"status": status,
"priority": "Medium",
})
task_counter += 1
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Template Context Structure Altered

The context dictionary passed to templates has changed its structure. specs and plans are now nested as {'spec_content': '...'} instead of providing content directly. Also, the tasks variable, now current_tasks, changed from a list of strings to a list of dictionaries. These changes will likely break existing templates expecting the previous data structures.

Fix in Cursor Fix in Web

"""Update the assistant context file with comprehensive project context."""
if not context_file.exists():
console.print(f"[yellow]Context file not found: {context_file}[/yellow]")
if not json_output:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Missing Parameter Causes Function Call Error

The update_context_file function in .specify/scripts/update-agent-context.py is missing the json_output parameter in its definition. This causes a TypeError when the function is called, as the call site now passes this argument.

Additional Locations (1)

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0