* feat(dev): add integration scaffolder
* fix(dev): address integration scaffold review feedback
* fix(dev): address scaffold follow-up review
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* fix(dev): default scaffolded integrations to multi_install_safe = False
The scaffold template emitted `multi_install_safe = True` alongside a
placeholder `context_file = "AGENTS.md"`. Registered as-is, that violates the
registry contract (test_safe_integrations_have_distinct_context_files): codex
already pairs AGENTS.md with multi_install_safe = True, so the generated
boilerplate would collide on first registration.
Default the scaffold to False (matching IntegrationBase) so generated code is
registry-test-friendly out of the box; contributors opt in once they pick a
unique context_file. Aligns the generated test skeleton and both scaffold
tests, which previously contradicted each other (one expected True, one False).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(dev): harden scaffold writes and accept case-insensitive --type
- Guard scaffold_integration() against symlinked target directories: walk
each path component under the repo root and refuse symlinked dirs, then
confirm the write destination resolves inside the repo (mirrors the
manifest directory guard). Prevents scaffolding outside the repo when a
contributor's integrations/tests path is symlinked.
- Make the `--type` click.Choice case-insensitive so `--type YAML` is
accepted, matching scaffold_integration()'s strip()/lower() normalization
instead of rejecting at the CLI layer.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(dev): report scaffold filesystem failures as a clean CLI error
The `dev integration scaffold` command only caught FileExistsError/ValueError,
so an OSError raised during mkdir()/write_text() (permission denied, read-only
checkout, a path component that is a file, ...) bubbled up as a traceback
instead of a clean error + exit code. Broaden the handler to OSError (which
also covers FileExistsError) and add coverage for the filesystem-error path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(dev): move scaffold command under integration
* fix(dev): roll back partial scaffold writes
* fix(dev): correct lint docs and generated test docstring
- local-development.md: ruff check src/ is enforced in CI, not absent
- scaffolded test docstring: drop misleading 'scaffold' wording
* fix(scaffold): create only leaf integration directory
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: add Zed integration
* fix: update integrations stats grid to 31 for consistency
* fix: address Copilot review feedback
- Remove non-actionable --skills flag from ZedIntegration (Zed is always
skills-based, like Agy)
- Align zed_skill_mode predicate with ai_skills for consistency across
init output and hook rendering
- Consolidate claude/cursor/zed slash-skill return blocks in
_render_hook_invocation to reduce duplication
- Override test_options_include_skills_flag for Zed (no --skills flag)
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* fix: address Copilot review round 2
- Make zed_skill_mode unconditional in hook rendering (Zed is always
skills-based, no --skills option)
- Add test_init_persists_ai_skills_for_zed that exercises the actual
CLI init path and verifies HookExecutor renders /speckit-plan
without manual init-options manipulation
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* fix: address copilot review feedback for zed integration
- Update integration count from 31 to 33 in docs/index.md (32 integrations + Generic)
- Make zed_skill_mode unconditional to match extensions.py behavior
- Consolidate slash-skill integrations into a set for consistency
- Move os import to module level in test_integration_zed.py
* fix: refine slash-skill logic and ai-skills validation
- Fix slash-skill integrations: Claude/Cursor require ai_skills=true; Zed/Agy/Devin are always skills
- Allow --ai-skills with --integration (not just --ai) to fix validation error
* fix: remove unused variables and update ai-skills help text
- Add agy_skill_mode and devin_skill_mode variables to fix F841 lint error
- Use all skill mode variables in the slash-skill conditional check
- Update --ai-skills help text to reflect it works with --integration too
* fix: add trae_skill_mode to hook invocation for consistency
Trae is a SkillsIntegration like Zed/Agy/Devin, so it should also be treated
as always-skills-based in hook invocation rendering.
* fix: make Agy always skills-based for consistency
AgyIntegration is a SkillsIntegration subclass with no --skills option,
so it should be treated as always skills-based (like Zed, Devin, Trae).
This aligns init.py skill mode detection with extensions.py hook rendering.
* fix: gate agy_skill_mode and refactor _render_hook_invocation to use sets
Addressed Copilot review comments:
- Restored _is_skills_integration guard on agy_skill_mode in init.py
to be defensive about runtime integration type.
- Refactored _render_hook_invocation() in extensions.py to use
always_slash/conditional_slash frozensets instead of individual
per-agent booleans, eliminating unused variables (F841) and making
it harder for conditions to drift between integrations.
- Centralized slash-skill determination so adding a new unconditional
slash-skill integration is a one-key addition.
* fix: address latest Copilot review comments
- Added copilot to CONDITIONAL_SLASH_AGENTS for consistent
hook invocation rendering with init.py
- Moved always_slash/conditional_slash frozensets to module
scope to avoid per-call reallocation
- Replaced manual os.chdir() with monkeypatch.chdir() in test
- Overrode test_options_include_skills_flag for Zed (no --skills)
* fix: address latest Copilot review comments
- Removed redundant local import yaml in _register_extension_skills
(yaml is already imported at module scope)
- Split --ai-skills usage hint into two separate print statements
for better readability
- Changed integrations count from '33' to '30+' to avoid future drift
* fix: re-add _is_skills_integration definition lost in merge
The _is_skills_integration variable was accidentally dropped during the
web UI merge resolution of upstream/main's removal of legacy --ai flags.
Re-added the definition via isinstance(resolved_integration, SkillsIntegration)
check so that skill-mode booleans work correctly.
* fix: gate zed_skill_mode on _is_skills_integration for consistency
Aligns zed_skill_mode with the other skills-based agents (codex, claude,
cursor-agent, copilot) which all use _is_skills_integration gating.
Since ZedIntegration extends SkillsIntegration, behavior is unchanged.
* fix: remove unused claude_skill_mode and cursor_skill_mode locals in _render_hook_invocation
These variables became unused after the refactor to ALWAYS_SLASH_AGENTS /
CONDITIONAL_SLASH_AGENTS sets. Claude and Cursor-Agent are now handled by the
CONDITIONAL_SLASH_AGENTS path, so the separate boolean locals are dead code.
Fixes ruff F841 and addresses Copilot review feedback that was repeated across
multiple review rounds.
* fix: align agy/trae invocation format in init next-steps with hook rendering and build_command_invocation
- Moved agy and trae from '-<name>' (dollar/Codex format) to
'/speckit-<name>' (slash format) in _display_cmd() to match:
- HookExecutor._render_hook_invocation() (ALWAYS_SLASH_AGENTS for trae,
CONDITIONAL_SLASH_AGENTS for agy)
- SkillsIntegration.build_command_invocation() (default: /speckit-<name>)
- The '$' prefix is specific to Codex; all other skills agents use '/'.
* fix: address Copilot review comments on hook invocation consistency
- Add is_slash_skills_agent() helper to extensions.py to centralize the
agent-to-invocation-format mapping, reducing drift risk between
HookExecutor._render_hook_invocation() and init.py _display_cmd()
- Use the shared helper in both locations; init.py now imports and
delegates to is_slash_skills_agent() instead of maintaining its own
per-agent boolean matrix
- Fix test_hooks_render_skill_invocation to use ai_skills=False,
proving Zed renders /speckit-<name> unconditionally
- Add parameterized TestSlashSkillsSets covering all agents in
ALWAYS_SLASH_AGENTS and CONDITIONAL_SLASH_AGENTS with ai_skills
both true and false
* fix: address Copilot review comments on type safety and test API
- Make is_slash_skills_agent() accept str | None to match its call sites
(init_options.get("ai") can return None)
- Refactor TestSlashSkillsSets to use public execute_hook() API instead of
private _render_hook_invocation() method
* fix: address Copilot review comments on typing and naming clarity
- Add from __future__ import annotations to extensions.py so PEP 604
unions (str | None) are safe regardless of Python version
- Add clarifying _ai_skills_enabled local variable in init.py's
_display_cmd() to make the semantic meaning explicit when passing it
to is_slash_skills_agent()
* fix: move invocation-style logic into shared _invocation_style module
- Extract ALWAYS_SLASH_AGENTS, CONDITIONAL_SLASH_AGENTS, and
is_slash_skills_agent() from extensions.py into new _invocation_style.py
module, eliminating the awkward init.py -> extensions.py import
dependency for invocation-style decision logic
- Both HookExecutor._render_hook_invocation() and init.py _display_cmd()
now import from the shared module instead of one subsystem importing
from the other
- Revert /SKILL.md change: the leading slash is semantically significant
(path component vs filename suffix)
* fix: add None guard before i.options() in test_options_include_skills_flag
get_integration() returns IntegrationBase | None, so i.options()
is a type error without a None check.
* fix: override test_options_include_skills_flag for Zed (always skills, no --skills flag)
Zed is always skills-based and doesn't expose a --skills option.
Override the inherited base test to assert --skills is absent.
* fix: rename test and skip inherited test_options_include_skills_flag for Zed
- Skip inherited test_options_include_skills_flag (not applicable — Zed
is always skills-based with no --skills flag)
- Add test_options_do_not_include_skills_flag with correct name matching
the assertion (--skills is absent)
* fix: add defensive non-string check in is_slash_skills_agent
Reject non-string values for selected_ai to prevent TypeError from
set membership checks when persisted init-options contain corrupted
data (e.g. list or dict instead of string).
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* docs: add guide for handling complex features
Add a Concepts page documenting strategies for dealing with large or
complex features where context window exhaustion degrades agent
performance during implementation. Covers limiting tasks per run,
sub-agent delegation, combining both, and decomposing into smaller
specs, with a guideline table for choosing an approach.
Closes#2986
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: address review feedback on complex features guide
Use task IDs (T001-T010) instead of bare numbers to match the tasks.md
template format, and add the combined scoping + delegation approach to
the selection table for completeness.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: align complex features guide with command naming conventions
Use the full /speckit.implement command name throughout, match the
command template wording ('must consider'), and use the product names
GitHub Copilot CLI and the GitHub Copilot extension for VS Code.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Manfred Riem <mnriem@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add Spec Trace extension to community catalog
* docs(catalog): mark Spec Trace as Read+Write
The /speckit.trace.build command writes .specify/trace.md, so the
catalog row's Effect column was wrong. Aligning with the extension's
documented behavior.
* docs(community): add Spec Trace row to extensions.md
The public community extensions table moved from README.md to
docs/community/extensions.md per the repo convention documented in
.github/skills/add-community-extension/SKILL.md. Adding the Spec Trace
row alphabetically between Spec Sync and Spec Validate so the doc stays
in sync with the catalog entry already added.
* fix(catalog): use literal Unicode characters in Spec Trace description
Copilot's review on this PR noted that the Spec Trace entry was the
only one in catalog.community.json using JSON Unicode escape sequences
(\u2192 for the arrow, \u2014 for the em-dash). Every other entry
that uses those characters writes them as literal multi-byte UTF-8
(18 entries with literal em-dash, 5 with literal arrow), so the
escaped form made this row harder to read and review in plain text
and stood out as the only inconsistency in the file.
Replacing the escapes with the literal characters keeps the entry
visually consistent with the rest of the catalog and decodes to the
same string at runtime, so no consumer changes.
* chore(catalog): set Spec Trace timestamps to catalog-add date
Per add-community-extension SKILL.md, a new entry's created_at/updated_at
should reflect the date it is added to the catalog, and the top-level
catalog updated_at must be refreshed on any add. Set the Spec Trace
entry and the catalog-level updated_at to 2026-06-09.
* docs(community): categorize Spec Trace as code
Spec Trace analyzes the test suite (source) and produces a coverage/
traceability report, matching the documented 'code' category (reviews/
validates source) rather than 'process' (orchestrates workflow across
phases). Aligns with the sibling SpecTest row.
* feat: add category and effect as first-class fields in extension schema
Add `category` and `effect` as optional fields in the extension schema
(`extension.yml`) and community catalog (`catalog.community.json`).
Schema changes:
- Valid categories: docs, code, process, integration, visibility
- Valid effects: read-only, read-write
- Both fields are optional (backward-compatible with existing extensions)
- Validation raises ValidationError for invalid values when present
Propagation:
- Added `category` and `effect` to all 108 entries in catalog.community.json
(populated from the existing docs/community/extensions.md table)
- Updated extension template with commented category/effect fields
- Updated add-community-extension skill with new JSON template fields
- Updated `specify extension info` CLI output to display category/effect
- Added properties to ExtensionManifest class
Tests:
- test_valid_category: all 5 category values pass
- test_valid_effect: both effect values pass
- test_invalid_category: invalid value raises ValidationError
- test_invalid_effect: invalid value raises ValidationError
- test_category_and_effect_optional: omitting fields still works
Closes#2874
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: make category free-form, keep effect validated
Category is a free-form string (only validated as non-empty when present),
while effect remains restricted to 'read-only' or 'read-write'.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: address PR review feedback
- Add type guard before 'in' check for effect to prevent TypeError on
unhashable YAML values (list/dict)
- Comment out category/effect in template so authors must opt in
- Use VALID_EFFECTS constant in test instead of hard-coded values
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: update category docstring to reflect free-form semantics
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: clarify canonical extension effect values
---------
Co-authored-by: Manfred Riem <mnriem@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* chore(catalog): add Jira Integration (Sync Engine) extension
Adds a new community-catalog listing for `spec-kit-jira-sync`
(ashbrener/spec-kit-jira-sync), a reconcile-engine bridge that mirrors
spec-kit specs into Jira (Epic per repo, Story per spec, Subtask per
phase): idempotent, drift-aware, fail-closed.
Catalog id is `jira-sync` because the `jira` id is already taken by an
unrelated extension; display name "Jira Integration (Sync Engine)"
disambiguates from the existing "Jira Integration" listing.
Touches the two catalog surfaces:
1. extensions/catalog.community.json - the new "jira-sync" entry,
inserted after the existing "jira" entry. Field shape matches the
sibling "linear" entry exactly.
2. docs/community/extensions.md - the table row, after the existing
Jira Integration row.
JSON validated; diff is the single entry + the one table row.
* catalog(jira-sync): neutral capability-focused description (address Copilot review)
Drop the comparative/absolute framing ('A real …', 'never corrupts your board')
flagged by Copilot; keep the factual, tested capability descriptors (idempotent,
drift-aware, fail-closed). Applies to both the catalog entry and the docs table row.
* chore(catalog): bump jira-sync to v0.2.0 (re-mode + engine unification)
* fix(catalog): jira-sync download_url .tar.gz -> .zip (installer is ZIP-only)
The spec-kit extension installer saves {id}-{version}.zip and extracts via
zipfile.ZipFile (src/specify_cli/extensions.py) — a .tar.gz asset downloads but
fails extraction. Matches every other catalog entry's /archive/refs/tags/vX.zip
convention. Addresses the Copilot review on PR #2895.
---------
Co-authored-by: Ash Brener <ashley@midletearth.com>
* chore(catalog): bump linear to v0.3.0 + spec-kit-linear-sync URLs
The Linear extension repo was renamed ashbrener/spec-kit-linear -> spec-kit-linear-sync
and shipped v0.3.0. Update the community catalog entry's download_url (was pinned to
v0.2.0), repository/homepage/documentation/changelog URLs, and version. extension id
stays 'linear' (commands unchanged); old GitHub URLs redirect.
* docs(community): point Linear extension table row at spec-kit-linear-sync
---------
Co-authored-by: Ash Brener <ashley@midletearth.com>
Bump the docguard community catalog entry 0.9.11 -> 0.25.0, point the
download at the v0.25.0 release asset, and update the description to
reflect the single pinned runtime dependency (@babel/parser, added in
v0.24 for AST-based validation). Sync the docs/community table row to
match. Rebased onto current main to clear the prior merge conflict.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(integration): add status reporting
* docs(integration): include status in query command docstring
* fix(integration): handle Windows extended-length paths in status containment
On Windows, os.readlink() (and sometimes Path.resolve()) return paths with
the \\?\ extended-length prefix. Comparing such a target against a plain
project root via Path.relative_to() spuriously fails, so an in-project
dangling symlink was classified as `invalid` instead of `missing` — failing
test_status_treats_dangling_symlink_as_missing and the windows-style variant
on the Windows CI runners.
Centralize the containment check in _is_within_project() and strip the
\\?\ / \\?\UNC\ prefix from both sides before relative_to(). Add portable
regression tests for the prefix-stripping helper and the containment contract.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* test(integration): restore top-level pytest import after rebase
A three-way merge / rebase onto main silently dropped the module-level
`import pytest` from test_integration_subcommand.py: main reorganized the
import block without it (using only a local `import pytest as _pytest`),
while this branch added top-level fixtures and `pytest.skip`/`pytest.raises`
usage. The overlapping import-hunk edits resolved by dropping the import,
breaking collection with `NameError: name 'pytest' is not defined` on every
runner. Re-add the import in the third-party group.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(integration): fix Windows UNC path assertion in status helper test
`test_strip_extended_length_prefix_normalizes_windows_paths` compared the
str() form of the helper's output against a hand-built string. On Windows,
pathlib renders a UNC root with a trailing separator (`\\server\share\`),
so the exact string match failed there (`\\server\share\` != `\\server\share`)
even though `_strip_extended_length_prefix` behaves correctly — the trailing
separator is irrelevant to the `relative_to` containment check it feeds.
Compare Path objects (semantic equality) instead of exact strings so the
assertion holds on both POSIX and Windows. No production code change needed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(integration): make shared-manifest remediation specify --integration
The fallback `_manifest_suggestion` for the shared `speckit` manifest (used
when no usable default integration is recorded) suggested
`specify init --here --force`, which can trigger interactive integration
selection. For CI/agent consumers of `integration status`, surface an
explicit `--integration <key>` placeholder, matching the file's existing
`<key>` suggestion style.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* feat(init)!: make git extension opt-in and remove --no-git at v0.10.0
- Remove --no-git parameter from specify init command
- Remove git extension auto-installation from init flow
- Git repository initialization (git init) still runs when git is available
- Remove --no-git from all test invocations across the test suite
- Update docs to reflect opt-in git extension behavior
- Replace TestGitExtensionAutoInstall with TestGitExtensionOptIn tests
BREAKING CHANGE: specify init no longer auto-installs the git extension.
Use `specify extension add git` to install it explicitly.
The --no-git flag has been removed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor(scripts): remove git operations from core scripts
Git functionality is now entirely managed by the git extension.
Core scripts only handle directory-based feature creation and numbering.
- Remove has_git(), check_feature_branch(), git branch creation from core
- Simplify number detection to use only spec directory scanning
- Remove HAS_GIT output from get_feature_paths()
- Remove git remote fetching and branch querying
- Keep BRANCH_NAME output key for backward compatibility
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor: remove all git operations from core
- Remove is_git_repo() and init_git_repo() dead code from _utils.py
- Remove --branch-numbering from init command
- Remove git from 'specify check' (now extension-only)
- Update docs: git is optional prerequisite, check command description
- Fix tests to reflect no-git-in-core reality (fallback to main)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor(scripts): remove directory scanning and branch fallback from core
Core scripts now resolve feature context exclusively from:
1. SPECIFY_FEATURE env var (set by git extension)
2. .specify/feature.json (persisted by specify command)
Removed find_feature_dir_by_prefix() and directory scanning heuristics —
these are the git extension's responsibility. Scripts error clearly when
no feature context is available.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: introduce feature_numbering, deprecate branch_numbering in init-options
- specify command template now reads feature_numbering (preferred) with
fallback to branch_numbering (deprecated) from init-options.json
- Git extension reads git-config.yml > feature_numbering > branch_numbering
- init now writes feature_numbering: sequential to init-options.json
- Deprecation warning emitted when branch_numbering is used as fallback
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: remove trailing whitespace in common.ps1
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(scripts): persist SPECIFY_FEATURE_DIRECTORY env var to feature.json
When SPECIFY_FEATURE_DIRECTORY is set, get_feature_paths() now writes the
value to .specify/feature.json so future sessions without the env var can
still resolve the feature directory. The write is idempotent — it skips
when the file already contains the same value.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: address review feedback — error messages and docs
- Update error messages in common.sh and common.ps1 to reference
SPECIFY_FEATURE_DIRECTORY instead of SPECIFY_FEATURE (which no longer
resolves feature directories)
- Fix get_current_branch comment (returns empty string, not error)
- Update upgrade.md to reference SPECIFY_FEATURE_DIRECTORY with correct
example paths
- Update local-development.md troubleshooting: replace stale 'Git step
skipped' row with actionable git extension guidance
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(scripts): harden feature.json persistence
- Use json_escape in printf fallback when jq is unavailable (common.sh)
- Replace utf8NoBOM encoding with UTF8Encoding($false) for PowerShell
5.1 compatibility (common.ps1)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor(scripts): remove dead feature_json_matches_feature_dir functions
These guards are no longer needed since the branch-name validation they
protected against has been removed from check-prerequisites.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor(git-ext): rename create-new-feature to create-new-feature-branch
The git extension's script only creates the git branch — rename it to
reflect that responsibility. The core create-new-feature.sh/.ps1 handles
feature directory creation and feature.json persistence.
Also includes fixes from review feedback:
- common.sh: _persist_feature_json uses json_escape fallback
- common.ps1: Save-FeatureJson uses UTF8Encoding for PS 5.1 compat
- common.ps1: case-sensitive path stripping on non-Windows
- create-new-feature.sh/ps1: output both SPECIFY_FEATURE and
SPECIFY_FEATURE_DIRECTORY
- setup-tasks.sh: fix stale 'Validate branch' comment
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(tests): update references to renamed git extension scripts
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(tests): remove duplicate EXT_CREATE_FEATURE assignments
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Manfred Riem <mnriem@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Update preset-fiction-book-writing to community catalog
- Preset ID: fiction-book-writing
- Version: 1.5.0
- Author: Andreas Daumann
- Description: Spec-Driven Development for novel and long-form fiction. Replaces software engineering terminology with storytelling craft: specs become story briefs, plans become story structures, and tasks become scene-by-scene writing tasks. Supports 8 POV modes, all major plot structure frameworks, 5 humanized-AI prose profiles, and exports to DOCX/EPUB/LaTeX via pandoc. V1.5.0: Support interactive, audiobooks, series, workflow corrections
* Add fiction-book-writing preset to community catalog
- Preset ID: fiction-book-writing
- Version: 1.6.0
- Author: Andreas Daumann
- Description: Added support for 12 languages, export with templates, cover builder, bio builder, workflow fixes
* Update presets/catalog.community.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fixed update_at for fiction-book-writing preset
* Update README.md
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fixed description for fiction-book-writing
* Update Fiction Book Writing to community catalog
- Preset ID: fiction-book-writing
- Version: 1.9.0
- Author: Andreas Daumann
- Description: Update added illustration support
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* feat: add support for rovodev
* fixup! feat: add support for rovodev
* fixup! feat: add support for rovodev
* fixup! feat: add support for rovodev
* fixup! feat: add support for rovodev
* fixup! feat: add support for rovodev
* fixup! feat: add support for rovodev
* fixup! feat: add support for rovodev
* fixup! feat: add support for rovodev
* fixup! feat: add support for rovodev
* fixup! feat: add support for rovodev
* fixup! feat: add support for rovodev
* feat(workflows): add --json output to workflow run, resume, and status
Adds an opt-in `--json` flag to `workflow run`, `workflow resume`, and
`workflow status` that emits a single machine-readable object (run_id,
workflow_id, status, current step; status also reports per-step states
and a runs list) for automation and external orchestrators.
JSON is written via a small `_emit_workflow_json` helper using plain
stdout, so Rich markup, highlighting, and line-wrapping can never alter
the emitted object. Default human-readable output and exit codes are
unchanged when `--json` is omitted. Reference docs updated.
Closes#2811.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(workflows): keep --json stdout clean while steps write output
Suppressing the banner and the step-start callback was not enough to
guarantee a single parseable JSON object on stdout: individual steps still
write there while the engine runs. The gate step prints its prompt, and the
prompt step runs a CLI subprocess that inherits the process's stdout file
descriptor — either can corrupt the JSON stream for interactive runs or
integration-backed workflows.
Wrap engine.execute()/engine.resume() in a file-descriptor-level redirect
(dup2) when --json is set, so both Python-level writes and inherited-fd
subprocess output go to stderr while stdout carries only the emitted JSON.
Step progress stays visible on stderr. status does not run the engine, so
it is unaffected.
Tests cover both pollution channels (a Python print and a real subprocess)
via fd-level capture, and the inactive no-op path. Docs note the
stdout/stderr split.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(workflows): fix stray escape sequence in --json redirect comments
The redirect helper's docstring and its test comment wrote ``print``\s,
which renders as "print\s" rather than "prints". Replace with plain
"prints".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Initial plan
* feat: add --workflow option to init command for post-init workflow execution
* chore: remove unused import in test file
* refactor: allow workflow run without project when given a YAML file path
Instead of adding --workflow to init, make `specify workflow run ./file.yml`
work without requiring a .specify/ project directory. When the source is a
YAML file that exists on disk, cwd is used as the project root. When it's a
workflow ID, the .specify/ project requirement is preserved.
* Handle standalone workflow path edge cases
* Fix USERPROFILE env var portability and docs notation
* Fix workflow YAML path detection to require regular files
* Harden workflow run against unsafe .specify paths
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* feat(cli): implement specify self upgrade
* fix(cli): normalize self-upgrade prerelease tags
* fix(cli): tighten self-upgrade diagnostics
* fix(cli): harden self-upgrade verification parsing
* fix(cli): sanitize self-check fallback tags
* fix(cli): harden self-check release display
* fix(cli): validate resolved upgrade tags
* fix(cli): tolerate invalid install metadata
* test(cli): align upgrade network mocks
* fix(cli): respect relative installer paths
* fix(cli): tighten upgrade failure handling
* fix(cli): align installer path diagnostics
* fix(cli): validate release and version output
* fix(cli): clarify source checkout guidance
* fix(cli): harden upgrade detection helpers
* fix(cli): avoid echoing invalid release tags
* fix(cli): tolerate argv path resolve failures
* chore: remove self-upgrade formatting-only diffs
* fix: address self-upgrade review feedback
* fix: address self-upgrade review followups
* fix: address self-upgrade review edge cases
* fix: address self-upgrade review docs
* fix: refine self-upgrade review followups
* fix: address self-upgrade review cleanup
* fix: handle self-upgrade review edge cases
* fix: address self-upgrade review nits
* fix: address follow-up self-upgrade review
* fix: resolve self-upgrade review and Windows CI failures
- README: promote "Optional Commands" to ### so it is a sibling of
"Core Commands" under "Available Slash Commands" (consistent heading
levels; avoids the h2->h4 jump a revert would create).
- _version: allow --tag prerelease/dev and build-metadata suffixes to
compose (e.g. v1.0.0-rc1+build.42), matching PEP 440 / semver; the
Version() check still enforces canonical validity.
- tests: compare resolved argv0 as Path objects instead of POSIX strings
so the assertion holds on Windows; skip the relative-installer-path
executable-bit tests on Windows via a new requires_posix marker (they
rely on chmod/X_OK semantics and chdir-into-tmp teardown that do not
hold there). Add a combined prerelease+build-metadata tag test.
* fix: address second self-upgrade review round
- self_check: clarify that the "up to date" branch is reached only for
parseable latest tags (the unparseable case returns earlier), so the
InvalidVersion fallback assumption is not reintroduced.
- self_upgrade: compare target/current as Version instances directly
instead of re-parsing the canonical strings through _is_newer; the
empty-current case stays explicit via the not-None guard.
- tests: document the intentional broad GH_/GITHUB_ env scrub with a test
asserting non-credential context vars (GH_HOST, GITHUB_REPOSITORY, …) are
stripped from the installer subprocess env — a deliberate fail-safe that
also catches credential-adjacent names without a recognized suffix.
* fix: address third self-upgrade review round
- self_upgrade: unify the no-op short-circuits on packaging Version
equality instead of canonical-string equality. Version("1.0") equals
Version("1.0.0") but their str() forms differ, so the old check could
misreport an equal install as "already on latest release or newer".
Both the unpinned and pinned branches now use Version comparison.
- self_upgrade: compare the verified version as a parsed Version against
the target so a non-version verifier result is a mismatch (exit 2)
rather than a coincidental canonical-string match.
- resolver: map HTTP 429 (Too Many Requests / secondary rate limit) to
the rate-limited category so users get the same actionable token hint
as 403.
- _is_github_credential_env_key: document the precise (intentionally
broad) scrub matching contract in the docstring.
- tests: add a trailing-zero Version-equality regression test and a
parametrized HTTP-status categorization test (429 -> rate limited;
404/502 -> verbatim).
* fix: address fourth self-upgrade review round
- self_upgrade: label a pinned target older than the installed version as
"Downgrading" rather than "Upgrading" so `--tag <older>` is not mistaken
for a forward upgrade.
- resolver: drop the unused `typing.Optional` import and annotate the
`--tag` option as `str | None`, consistent with the rest of the module
(verified Typer resolves it on the supported Python versions).
- _is_github_credential_env_key: add `_PASSWORD` and `_CREDENTIALS` to the
recognized credential suffixes and document that only these shapes are
scrubbed (not blanket coverage).
- tests: assert the precise exit code (1) for the re-raised transient
OSError path; skip the InvalidMetadataError test on Pythons where the
real exception is absent instead of fabricating it; update the pinned
downgrade test to expect the "Downgrading" label.
* fix: accept uppercase V prefix in --tag
Fold a leading uppercase `V` (a common paste) to the canonical lowercase
`v` before validating `--tag`. The remainder of the tag stays
case-sensitive on purpose: the validated value is used verbatim as a git
ref, which is case-sensitive on GitHub, so rewriting label/build-metadata
casing could point at a tag that does not exist. Adds a normalization test.
`workflow resume` now accepts `--input key=value` (the same flag and
parsing as `workflow run`, via a shared `_parse_input_values` helper).
Supplied values are merged over the run's persisted inputs and
re-resolved through the existing typed-validation path
(`_resolve_inputs`), so a resumed/re-run step sees the updated inputs
and ill-typed values fail fast. Keys not supplied keep their persisted
values; resuming without `--input` is unchanged. Reference docs updated.
Distinct from #2405 (file-reference inputs at run time): this is about
supplying inputs at resume time, reusing the existing input model.
Closes#2812.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Hermes Agent integration ships in the CLI (src/specify_cli/integrations/hermes/)
and is registered in the catalog, but the supported-agents table in the
integrations reference omitted it. Add the row so the docs match the shipped
integration.
* Add spec-kit-linear extension to community catalog
Add linear extension submitted by @ashbrener to:\n- extensions/catalog.community.json\n- docs/community/extensions.md\n\nCloses #2778
* Address PR review feedback for spec-kit-linear entry
- Use Unicode arrow (→) in catalog/docs description\n- Move docs row to alphabetical Spec section
* Address follow-up review naming/order feedback
- Use human-friendly display name: Linear Integration\n- Move docs row to alphabetical L section
* Add Workflow Preset to community catalog
Add workflow-preset submitted by @bigsmartben to:
- presets/catalog.community.json (alphabetical order)
- docs/community/presets.md community presets table
Closes#2618
* Fix Requires column: use — for no required extensions
The Requires column lists required extensions, not the Spec Kit
version. This preset has no extension dependencies.