* docs: add core commands reference and simplify README CLI section
- New docs/reference/core.md: reference for init (active options only,
copilot as main example), check, and version commands
- docs/toc.yml: add Core Commands under Reference
- README.md: replace verbose CLI Reference section (init options table,
30+ per-agent examples, deprecated flags, env vars) with links to
reference docs; use copilot as main example throughout
* docs: add CLI reference overview page
- New docs/reference/overview.md: explains each CLI surface area
(core, integrations, extensions, presets, workflows) with key
commands and links to detailed reference pages
- docs/toc.yml: add Overview as first item under Reference
- README.md: simplify CLI Reference to single link to overview page
* docs: remove command references from overview, keep paragraphs only
* docs: add workflows reference, reorganize into docs/reference/, and add --version flag
- Move integrations.md, extensions.md, presets.md into docs/reference/
- New docs/reference/workflows.md: command reference for all workflow
commands, built-in SDD Cycle workflow with Mermaid diagram, step types,
expressions, input types, state/resume, and FAQ
- Rename workflow input feature_name to spec with prompt 'Describe what
you want to build' to match speckit.specify command terminology
- Add --version / -V flag to root specify command with tests
- Update docs/toc.yml, README.md links, and docs/upgrade.md cross-reference
to use reference/ paths
- Add workflow command to README CLI reference table
* docs: update speckit_version requirement to >=0.7.2 in workflow example
- New docs/presets.md: command reference for all 9 specify preset commands
and 3 specify preset catalog commands, file resolution stack with Mermaid
diagrams, catalog resolution order, and FAQ
- src/specify_cli/__init__.py: rename pack_id to preset_id across all preset
CLI commands so --help shows PRESET_ID matching the docs
- docs/toc.yml: add Presets under Reference section
- README.md: update presets link to published docs site
- New docs/extensions.md: command reference for all 9 specify extension
commands and 3 specify extension catalog commands, plus catalog
resolution order, extension configuration, and FAQ
- docs/integrations.md: add FAQ section covering single-integration limit,
file preservation, key discovery, CLI vs IDE requirements, upgrade vs switch
- docs/toc.yml: add Extensions under Reference section
- README.md: update integration and extension links to published docs site
- New docs/integrations.md: canonical reference for supported agents table
(with keys), list/install/uninstall/switch/upgrade commands, file
preservation behavior, and integration-specific options
- README.md: replace inline agents table with summary + link to new page;
normalize heading to 'Supported AI Coding Agent Integrations'
- docs/toc.yml: add top-level 'Reference' section with Integrations page
- docs/upgrade.md: fix broken cross-reference, update terminology
- CONTRIBUTING.md: update anchor link to new heading
* Initial plan
* feat: add integration catalog system with catalog files, IntegrationCatalog class, list --catalog flag, upgrade command, integration.yml descriptor, and tests
Agent-Logs-Url: https://github.com/github/spec-kit/sessions/bbcd44e8-c69c-4735-adc1-bdf1ce109184
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
* fix: address PR review feedback
- Replace empty except with cache cleanup in _fetch_single_catalog
- Log teardown failure warning instead of silent pass in upgrade
- Validate catalog_data and integrations are dicts before use
- Catch OSError/UnicodeError in IntegrationDescriptor._load
- Add isinstance checks for integration/requires/provides/commands
- Enforce semver (X.Y.Z) instead of PEP 440 for descriptor versions
- Fix docstring and CONTRIBUTING.md to match actual block-on-modified behavior
- Restore old manifest on upgrade failure for transactional safety
* refactor: address second round of PR review feedback
- Remove dead cache_file/cache_metadata_file attributes from IntegrationCatalog
- Deduplicate non-default catalog warning (show once per process)
- Anchor version regex to reject partial matches like 1.0.0beta
- Fix 'Preserved modified' message to 'Skipped' for accuracy
- Make upgrade transactional: install new files first, then remove stale
old-only files, so a failed setup leaves old integration intact
- Update CONTRIBUTING.md: speckit_version validates presence only
* Potential fix for pull request finding 'Empty except'
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
* fix: address third round of PR review feedback
- Fix CONTRIBUTING.md JSON examples to show full catalog structure with
schema_version and integrations wrapper
- Wrap cache writes in try/except OSError for read-only project dirs
- Validate _load_catalog_config YAML root is a dict
- Skip non-dict integ_data entries in merged catalog
- Normalize tags to list-of-strings before filtering/searching
- Add path traversal containment check for stale file deletion
- Clarify docstring: lower numeric priority = higher precedence
* fix: address fourth round of PR review feedback
- Remove unused _write_catalog helper from test file
- Fix comment: tests use monkeypatched urlopen, not file:// URLs
- Wrap cache unlink calls in OSError handler
- Add explicit encoding='utf-8' to all cache read_text/write_text calls
- Restore packaging.version.Version for descriptor version validation
to align with extension/preset validators
- Add missing goose entry to integrations/catalog.json
* fix: remove unused Path import, add comment to empty except
* fix: validate descriptor root is dict, add shared infra to upgrade
- Add isinstance(self.data, dict) check at start of _validate() so
non-mapping YAML roots raise IntegrationDescriptorError
- Run _install_shared_infra() and ensure_executable_scripts() in
upgrade command to match install/switch behavior
* fix: address sixth round of PR review feedback
- Validate integration.id/name/version/description are strings
- Catch TypeError in pkg_version.Version() for non-string versions
- Swap validation order: check catalogs type before emptiness
- Isolate TestActiveCatalogs from user ~/.specify/ via monkeypatch
* fix: address seventh round of PR review feedback
- Update docs: version field uses PEP 440, not semver
- Harden search() against non-string author/name/description fields
- Validate requires.speckit_version is a non-empty string
- Validate command name/file are non-empty strings, file is safe relative path
- Handle stale symlinks in upgrade cleanup
- Document catalog configuration stack in README.md
* fix: validate script entries, remove destructive teardown from upgrade rollback
- Validate provides.scripts entries are non-empty strings with safe relative paths
- Remove teardown from upgrade rollback since setup overwrites in-place —
teardown would delete files that were working before the upgrade
* fix: use consistent resolved root for stale-file cleanup paths
* fix: validate redirect URL and reject drive-qualified paths
- Validate final URL after redirects with _validate_catalog_url()
- Reject paths with Path.drive or Path.anchor for Windows safety
- Update FakeResponse mocks with geturl() method
* fix: fix docstring backticks, assert file modification in upgrade tests
* docs: clarify directory naming convention for hyphenated integration keys
* fix: correct key type hint, isolate all catalog tests from env
- Fix key parameter type to str | None (defaults to None)
- Add HOME/USERPROFILE monkeypatch and clear SPECKIT_INTEGRATION_CATALOG_URL
in all TestCatalogFetch tests for full environment isolation
* fix: neutralize catalog table title, handle non-dict cache metadata
* fix: validate requires.tools entries in descriptor
* fix: show discovery-only status, clear metadata files in clear_cache
* fix: catch OSError/UnicodeError in cache read path
* refactor: reuse IntegrationManifest.uninstall for stale-file cleanup
* fix: normalize null tools to empty list in descriptor accessor
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
- Adds catalog-ci entry to catalog.community.json (between canon and ci-guard)
- Adds Catalog CI row to community extensions table in README.md
- Bumps top-level updated_at
* chore: bump version to 0.7.1
* chore: begin 0.7.2.dev0 development
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* ci: add windows-latest to test matrix
Add windows-latest to the pytest job OS matrix so tests run on both
Ubuntu and Windows for all Python versions.
Closes#2232
* test: skip bash-specific tests on Windows
Add sys.platform skip markers to all test classes and methods that
execute bash scripts via subprocess, so they are skipped on Windows
where bash is not available. Mixed classes with both bash and pwsh
tests have markers on individual bash methods only.
* test: fix 3 Windows-specific test failures
- test_manifest: use platform-appropriate absolute path (C:\ on Windows
vs /tmp on POSIX) since /tmp is not absolute on Windows
- test_extensions: add agent_scripts.ps entry and platform-conditional
assertions for codex skill fallback variant test
- test_timestamp_branches: use json.dumps() instead of f-string to
properly escape Windows backslash paths in feature.json
* test: extract requires_bash marker and fix PS test skip
Address PR review feedback:
- Define a reusable requires_bash marker in conftest.py and use it
across all 3 test files instead of repeating the skipif inline
- Move test_powershell_scanner_uses_long_tryparse_for_large_prefixes
into its own TestSequentialBranchPowerShell class so it is not
incorrectly skipped on Windows by the class-level bash marker
* test: use runtime bash check instead of platform check
Replace sys.platform == 'win32' with an actual bash invocation test
to handle environments where bash exists but is non-functional (e.g.,
WSL stub on Windows without an installed distro).
* test: reject WSL bash, accept only MSYS/MINGW on Windows
On Windows, verify uname -s reports MSYS, MINGW, or CYGWIN so the WSL
launcher (System32\bash.exe) is rejected — it cannot handle native
Windows paths used by test fixtures. Add SPECKIT_TEST_BASH=1 env var
escape hatch to force-enable bash tests in non-standard setups.
* ci: add comment explaining Windows bash test behavior
* test: early-reject WSL launcher, fix remaining f-string JSON
- Check resolved bash path for System32 before spawning any subprocess
to avoid WSL init prompts and timeout during test collection
- Convert remaining feature_json f-string writes to json.dumps() so
paths with backslashes produce valid JSON on Windows
* test: use bare 'bash' for detection to match test invocation
On Windows, subprocess.run(['bash', ...]) uses CreateProcess which
searches System32 before PATH — finding WSL bash even when
shutil.which('bash') returns Git-for-Windows. Probe with bare 'bash'
(same as test helpers) so the detection matches actual test behavior.
* fix: allow Claude to chain skills for hook execution (#2178)
- Set disable-model-invocation to false so Claude can invoke extension
skills (e.g. speckit-git-feature) from within workflow skills
- Inject dot-to-hyphen normalization note into Claude SKILL.md hook
sections so the model maps extension.yml command names to skill names
- Replace Unicode checkmark with ASCII [OK] in auto-commit scripts to
fix PowerShell encoding errors on Windows
- Move Claude-specific frontmatter injection to ClaudeIntegration via
post_process_skill_content() hook on SkillsIntegration, wired through
presets and extensions managers
- Add positive and negative tests for all changes
Fixes#2178
* refactor: address PR review feedback
- Preserve line-ending style (CRLF/LF) in _inject_hook_command_note
instead of always inserting \n, matching the convention used by other
injection helpers in the same module.
- Extract duplicated _post_process_skill() from extensions.py and
presets.py into a shared post_process_skill() function in agents.py.
Both modules now import and call the shared helper.
* fix: match full hook instruction line in regex
The regex in _inject_hook_command_note only matched lines ending
immediately after 'output the following', but the actual template
lines continue with 'based on its `optional` flag:'. Use [^\r\n]*
to capture the rest of the line before the EOL.
* refactor: use integration object directly for post_process_skill_content
Instead of a free function in agents.py that re-resolves the
integration by key, callers in extensions.py and presets.py now
resolve the integration once via get_integration() and call
integration.post_process_skill_content() directly. The base
identity method lives on SkillsIntegration.
* docs: warn about unofficial PyPI packages and recommend version verification (#1982)
Clarify that only packages from github/spec-kit are official, and add
`specify version` as a post-install verification step to help users
catch accidental installation of an unrelated package with the same name.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(extensions): auto-correct legacy command names instead of hard-failing (#2017)
Community extensions that predate the strict naming requirement use two
common legacy formats ('speckit.command' and 'extension.command').
Instead of rejecting them outright, auto-correct to the required
'speckit.{extension}.{command}' pattern and emit a compatibility warning
so authors know they need to update their manifest. Names that cannot be
safely corrected (e.g. single-segment names) still raise ValidationError.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(tests): isolate preset catalog search test from community catalog network calls
test_search_with_cached_data asserted exactly 2 results but was getting 4
because _get_merged_packs() queries the full built-in catalog stack
(default + community). The community catalog had no local cache and hit
the network, returning real presets. Writing a project-level
preset-catalogs.yml that pins the test to the default URL only makes
the count assertions deterministic.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(extensions): extend auto-correction to aliases (#2017)
The upstream #1994 added alias validation in _collect_manifest_command_names,
which also rejected legacy 2-part alias names (e.g. 'speckit.verify').
Extend the same auto-correction logic from _validate() to cover aliases,
so both 'speckit.command' and 'extension.command' alias formats are
corrected to 'speckit.{ext_id}.{command}' with a compatibility warning
instead of hard-failing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(extensions): address PR review feedback (#2017)
- _try_correct_command_name: only correct 'X.Y' to 'speckit.ext_id.Y'
when X matches ext_id, preventing misleading warnings followed by
install failure due to namespace mismatch
- _validate: add aliases type/string guards matching _collect_manifest
_command_names defensive checks
- _validate: track command renames and rewrite any hook.*.command
references that pointed at a renamed command, emitting a warning
- test: fix test_command_name_autocorrect_no_speckit_prefix to use
ext_id matching the legacy namespace; add namespace-mismatch test
- test: replace redundant preset-catalogs.yml isolation with
monkeypatch.delenv("SPECKIT_PRESET_CATALOG_URL") so the env var
cannot bypass catalog restriction in CI environments
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Update docs/installation.md
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix(extensions): warn when hook command refs are silently canonicalized; fix grammar
- Hook rewrites (alias-form or rename-map) now always emit a warning so
extension authors know to update their manifests. Previously only
rename-map rewrites produced a warning; pure alias-form lifts were
silent.
- Pluralize "command/commands" in the uninstall confirmation message so
single-command extensions no longer print "1 commands".
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(extensions): raise ValidationError for non-dict hook entries
Silently skipping non-dict hook entries left them in manifest.hooks,
causing HookExecutor.register_hooks() to crash with AttributeError
when it called hook_config.get() on a non-mapping value.
Also updates PR description to accurately reflect the implementation
(no separate _try_correct_alias_name helper; aliases use the same
_try_correct_command_name path).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(extensions): derive remove cmd_count from registry, fix wording
Previously cmd_count used len(ext_manifest.commands) which only counted
primary commands and missed aliases. The registry's registered_commands
already tracks every command name (primaries + aliases) per agent, so
max(len(v) for v in registered_commands.values()) gives the correct
total.
Also changes "from AI agent" → "across AI agents" since remove()
unregisters commands from all detected agents.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(extensions): distinguish missing vs empty registered_commands in remove prompt
Using get() without a default lets us tell apart:
- key missing (legacy registry entry) → fall back to manifest count
- key present but empty dict (installed with no agent dirs) → show 0
Previously the truthiness check `if registered_commands and ...` treated
both cases the same, so an empty dict fell back to len(manifest.commands)
and overcounted commands that would actually be removed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(extensions): clarify removal prompt wording to 'per agent'
'across AI agents' implied a total count, but cmd_count uses max()
across agents (per-agent count). Using sum() would double-count since
users think in logical commands, not per-agent files. 'per agent'
accurately describes what the number represents.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(extensions): clarify cmd_count comment — per-agent max, not total
The comment said 'covers all agents' implying a total, but cmd_count uses
max() across agents (per-agent count). Updated comment to explain the
max() choice and why sum() would double-count.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(extensions): add CLI tests for remove confirmation pluralization
Adds TestExtensionRemoveCLI with two CliRunner tests:
- singular: 1 registered command → '1 command per agent'
- plural: 2 registered commands → '2 commands per agent'
These prevent regressions on the cmd_count pluralization logic
and the 'per agent' wording introduced in this PR.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(agents): remove orphaned SKILL.md parent dirs on unregister
For SKILL.md-based agents (codex, kimi), each command lives in its own
subdirectory (e.g. .agents/skills/speckit-ext-cmd/SKILL.md). The previous
unregister_commands() only unlinked the file, leaving an empty parent dir.
Now attempts rmdir() on the parent when it differs from the agent commands
dir. OSError is silenced so non-empty dirs (e.g. user files) are safely left.
Adds test_unregister_skill_removes_parent_directory to cover this.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(extensions): drop alias pattern enforcement from _validate()
Aliases are intentionally free-form to preserve community extension
compatibility (e.g. 'speckit.verify' short aliases used by spec-kit-verify
and other existing extensions). This aligns _validate() with the intent of
upstream commit 4deb90f (fix: restore alias compatibility, #2110/#2125).
Only type and None-normalization checks remain for aliases. Pattern
enforcement continues for primary command names only.
Updated tests to verify free-form aliases pass through unchanged with
no warnings instead of being auto-corrected.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(extensions): guard against non-dict command entries in _validate()
If provides.commands contains a non-mapping entry (e.g. an int or string),
'name' not in cmd raises TypeError instead of a user-facing ValidationError.
Added isinstance(cmd, dict) check at the top of the loop.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: iamaeroplane <michal.bachorik@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* chore: deprecate --ai flag in favor of --integration on specify init
- Adds deprecation warning when --ai is used
- Shows equivalent --integration command replacement
- Handles generic integration with --commands-dir mapping
- Adds comprehensive test coverage for deprecation behavior
- Warning displays as prominent red panel above Next Steps
- --ai flag continues to function (non-breaking change)
Fixes#2169
* Address PR review feedback for issue #2169
- Use existing strip_ansi helper from conftest instead of duplicating ANSI escape pattern
- Properly escape ai_commands_dir with shlex.quote() to handle paths with spaces
- Add shlex import to support proper command-line argument escaping
* chore: bump version to 0.7.0
* chore: begin 0.7.1.dev0 development
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* feat: add claude-ask-questions preset for AskUserQuestion rendering
Delivers the /speckit.clarify and /speckit.checklist AskUserQuestion
integration as a stackable preset under presets/claude-ask-questions/
instead of modifying core templates or ClaudeIntegration.
- presets/claude-ask-questions/preset.yml registers command overrides
for speckit.clarify and speckit.checklist following the same pattern
as the bundled lean preset.
- Override commands replace the Markdown-table question-rendering
blocks with AskUserQuestion instructions. Option | Description maps
to {label, description} for clarify; Option | Candidate | Why It
Matters maps to {label: Candidate, description: Why It Matters} for
checklist. Recommended option is placed first with a
"Recommended — <reasoning>" prefix; a final "Custom"/"Short" option
preserves the free-form ≤5-word escape hatch.
- Registered in presets/catalog.json as a bundled preset.
Core templates, ClaudeIntegration, and the existing test suite are
left untouched, so non-Claude agents and users who do not install
this preset see no behavior change.
Closes github/spec-kit#2181
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: move claude-ask-questions preset to external repo
Per maintainer feedback on #2191, presets should be hosted on the
author's own GitHub repository and registered in catalog.community.json
rather than bundled in spec-kit. Removes the bundled preset directory
and its entry from the official catalog, and adds a community catalog
entry pointing at the external repository and release archive.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs(catalog): sync claude-ask-questions description with upstream preset
* revert: keep presets/catalog.json updated_at unchanged
No entries in the official catalog changed in this PR, so the timestamp
bump was spurious. Addresses Copilot review feedback on #2191.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* chore: bump version to 0.6.2
* chore: begin 0.6.3.dev0 development
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* feat: Update catalog.community.json for preset-fiction-book-writing
* Add fiction-book-writing preset to community catalog
- Preset ID: fiction-book-writing
- Version: 1.3.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.
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* doc: added fiction-book-writing preset link in README.md
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Manfred Riem <15701806+mnriem@users.noreply.github.com>
* feat(integrations): add YamlIntegration base class for YAML recipe agents
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* feat(integrations): add Goose integration subpackage with YAML recipe support
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* feat(integrations): register GooseIntegration in the integration registry
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* feat(agents): add YAML format support to CommandRegistrar for extension/preset commands
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* feat(scripts): add goose agent type to bash update-agent-context script
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* feat(scripts): add goose agent type to PowerShell update-agent-context script
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* docs(agents): add Goose to supported agents table and integration notes
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* docs(readme): add Goose to supported agents table
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* test(integrations): add YamlIntegrationTests base mixin for YAML agent testing
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* test(integrations): add Goose integration tests
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* test(consistency): add Goose consistency checks for config, registrar, and scripts
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* docs(agents): move Goose to YAML Format section in Command File Formats
Goose uses YAML recipes, not Markdown. Remove it from the Markdown Format
list and add a dedicated YAML Format subsection with a representative
recipe example showing prompt: | and {{args}} placeholders.
* refactor(agents): delegate render_yaml_command to YamlIntegration
Remove the duplicate header dict, yaml.safe_dump call, body indentation,
and _human_title logic from CommandRegistrar.render_yaml_command(). Delegate
to YamlIntegration._render_yaml() and _human_title() so YAML recipe output
stays consistent across the init-time generation and command-registration
code paths.
* fix(agents): guard alias output path against directory traversal
Validate that alias_file resolves within commands_dir before writing.
Uses the same resolve().relative_to() pattern already established in
extensions.py for ZIP path containment checks.
* docs(agents): add Goose to Multi-Agent Support comment list in update-agent-context.sh
* fix(agents): add goose to print_summary Usage line in bash context script
The print_summary() function listed all supported agents in its Usage
output but omitted goose, making it inconsistent with the header docs
and the error message in update_specific_agent().
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* fix(agents): add goose to Print-Summary Usage line in PowerShell context script
The Print-Summary function listed all supported agents in its Usage
output but omitted goose, making it inconsistent with the ValidateSet
and the header documentation.
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* fix(agents): normalize description and title types in YamlIntegration.setup()
YAML frontmatter can contain non-string types (null, list, int).
Add isinstance checks matching TomlIntegration._extract_description()
to ensure Goose recipes always receive valid string fields.
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* fix(agents): validate shared script exists before exec in Goose bash wrapper
Add Forge-style check that the shared update-agent-context.sh is
present and executable, producing a clear error instead of a cryptic
shell exec failure when the shared script is missing.
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* fix(agents): validate shared script exists before invoke in Goose PowerShell wrapper
Add Forge-style Test-Path check that the shared update-agent-context.ps1
exists, producing a clear error instead of a cryptic PowerShell failure
when the shared script is missing.
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* fix(agents): normalize title and description types in render_yaml_command()
Extension/preset frontmatter can contain non-string types. Add
isinstance checks matching the normalization in YamlIntegration.setup()
so both code paths produce valid Goose recipe fields.
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* fix(agents): replace $ARGUMENTS with arg_placeholder in process_template()
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* test(agents): assert $ARGUMENTS absent from generated YAML recipes
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* test(agents): assert $ARGUMENTS absent from generated TOML commands
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* fix(tests): rewrite docstring to avoid embedded triple-quote in TOML test
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
---------
Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
* chore: bump version to 0.6.1
* chore: begin 0.6.2.dev0 development
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* feat: add bundled lean preset with minimal workflow commands
Add a lean preset that overrides the 5 core workflow commands (specify,
plan, tasks, implement, constitution) with minimal prompts that produce
exactly one artifact each — no extension hooks, no scripts, no git
branching, no templates.
Bundled preset infrastructure:
- Add _locate_bundled_preset() mirroring _locate_bundled_extension()
- Update 'specify init --preset' to try bundled -> catalog fallback
- Update 'specify preset add' to try bundled -> catalog fallback
- Add bundled guard in download_pack() for presets without download URLs
- Add lean to presets/catalog.json with 'bundled: true' marker
- Add lean to pyproject.toml force-include for wheel packaging
- Align error messages with bundled extension error pattern
Tests: 15 new tests (TestLeanPreset + TestBundledPresetLocator)
* refactor: address review — clean up unused imports, strengthen test assertions
- Remove unused MagicMock import and cache_dir setup in download test
- Assert 'bundled' and 'reinstall' in CLI error output (not just exit code)
- Mock catalog in missing-locally test for deterministic bundled error path
- Fix test versions to satisfy updated speckit_version >=0.6.0 requirement
* refactor: address review — fix constitution paths, add REINSTALL_COMMAND to presets.py
- Fix constitution path to .specify/memory/constitution.md in plan, tasks,
implement commands (matching core command convention)
- Include REINSTALL_COMMAND in download_pack() bundled guard for consistent
recovery instructions across bundled extensions and presets
* refactor: address review — explicit feature_directory paths, ZIP cleanup in finally
- Prefix spec.md/plan.md/tasks.md with <feature_directory>/ in plan, tasks,
and implement commands so the agent doesn't operate on repo root by mistake
- Move ZIP unlink into finally block in init --preset path so cleanup runs
even when install_from_zip raises (matching preset_add pattern)
* refactor: address review — replace Unicode em dashes with ASCII, fix grammar
- Replace all Unicode em dashes with ASCII hyphens in preset.yml and
catalog.json to avoid decode errors on non-UTF-8 environments
- Fix grammar: 'store it in tasks.md' -> 'store them in tasks.md'
* refactor: address review - align task format between tasks and implement
- Remove undefined [P] marker from implement (lean uses sequential execution)
- Clarify checkbox update: 'change - [ ] to - [x]' instead of ambiguous '[X]'
- Simplify implement to execute tasks in order without parallel complexity
* refactor: address review - parse frontmatter instead of raw substring search
- Use CommandRegistrar.parse_frontmatter() to check for scripts/agent_scripts
keys in YAML frontmatter instead of brittle 'scripts:' substring search
* Add SpecTest extension to community catalog
Adds spec-kit-spectest: auto-generate test scaffolds from spec criteria.
4 commands:
- /speckit.test.generate — generate framework-native test scaffolds
- /speckit.test.coverage — map spec requirements to test coverage
- /speckit.test.gaps — find untested requirements with suggestions
- /speckit.test.plan — generate structured test plan documents
1 hook: after_implement (gap detection)
Bridges the spec-to-test gap in the SDD workflow.
* Update extensions/catalog.community.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Fix spectest created_at/updated_at to use current timestamp per Copilot review
Set both to 2026-04-10T16:00:00Z instead of midnight.
---------
Co-authored-by: Manfred Riem <15701806+mnriem@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: bundled extensions should not have download URLs (#2151)
- Remove selftest from default catalog (not a published extension)
- Replace download_url with 'bundled: true' flag for git extension
- Add bundled check in extension add flow with clear error message
when bundled extension is missing from installed package
- Add bundled check in download_extension() with specific error
- Direct users to reinstall via uv with full GitHub URL
- Add 3 regression tests for bundled extension handling
* refactor: address review - move bundled check up-front, extract reinstall constant
- Move bundled check before download_url inspection in download_extension()
so bundled extensions can never be downloaded even with a URL present
- Extract REINSTALL_COMMAND constant to avoid duplicated install strings
* fix: allow bundled extensions with download_url to be updated
Bundled extensions should only be blocked from download when they have
no download_url. If a newer version is published to the catalog with a
URL, users should be able to install it to get bug fixes.
Add test for bundled-with-URL download path.
* chore: bump version to 0.6.0
* chore: begin 0.6.1.dev0 development
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* Add Bugfix Workflow community extension to catalog and README
Adds the spec-kit-bugfix extension (3 commands, 1 hook) that provides a
structured bugfix workflow — capture bugs, trace to spec artifacts, and
surgically patch specs without regenerating from scratch.
Addresses community request in issue #619 (25+ upvotes, maintainer-approved).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Bump catalog updated_at to 2026-04-09 to match new entry date
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* Rewrite AGENTS.md for integration subpackage architecture
Replaces the old AGENT_CONFIG dict-based 7-step process with documentation
reflecting the integration subpackage architecture shipped in #1924.
Removed: Supported Agents table, old step-by-step guide referencing
AGENT_CONFIG/release scripts/case statements, Agent Categories lists,
Directory Conventions section, Important Design Decisions section.
Kept: About Spec Kit and Specify, Command File Formats, Argument Patterns,
Devcontainer section.
Added: Architecture overview, decision tree for base class selection,
configure/register/scripts/test/override steps with real code examples
from existing integrations (Windsurf, Gemini, Codex, Copilot).
Agent-Logs-Url: https://github.com/github/spec-kit/sessions/71b25c53-7d0c-492a-9503-f40a437d5ece
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
* Fix JSONC comment syntax in devcontainer example
Agent-Logs-Url: https://github.com/github/spec-kit/sessions/71b25c53-7d0c-492a-9503-f40a437d5ece
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
* docs(AGENTS.md): address Copilot PR review comments
- Clarify that integrations are registered by _register_builtins() in
__init__.py, not self-registered at import time
- Scope the key-must-match-executable rule to CLI-based integrations
(requires_cli: True); IDE-based integrations use canonical identifiers
- Replace <commands_dir> placeholder in test snippet with a concrete
example path (.windsurf/workflows/)
- Document that hyphens in keys become underscores in test filenames
(e.g. cursor-agent -> test_integration_cursor_agent.py)
- Note that the argument placeholder is integration-specific
(registrar_config["args"]); add Forge's {{parameters}} as an example
- Apply consistency fixes to Required fields table, Key design rule
callout, and Common Pitfalls #1
* docs(AGENTS.md): clarify scripts path uses Python-safe package_dir not key
The scripts step previously referenced src/specify_cli/integrations/<key>/scripts/
but for hyphenated keys the actual directory is underscored (e.g. kiro-cli -> kiro_cli/).
Rename the placeholder to <package_dir> and add a note explaining:
- <package_dir> matches <key> for non-hyphenated keys
- <package_dir> uses underscores for hyphenated keys (e.g. kiro-cli -> kiro_cli/)
- IntegrationBase.key always retains the original hyphenated value
Addresses: https://github.com/github/spec-kit/pull/2119#discussion_r3054946896
* docs(AGENTS.md): use <key_with_underscores> in pytest example command
The pytest command previously used <key> as a placeholder, but test
filenames always use underscores even for hyphenated keys. This was
internally inconsistent since the preceding sentence already explained
the hyphen→underscore mapping. Switch to <key_with_underscores> to
match the actual filename on disk.
Addresses: https://github.com/github/spec-kit/pull/2119#discussion_r3054962863
* docs(AGENTS.md): use <package_dir> in step 2 subpackage path
The path src/specify_cli/integrations/<key>/__init__.py was inaccurate
for hyphenated keys (e.g. kiro-cli lives in kiro_cli/, not kiro-cli/).
Rename the placeholder to <package_dir>, define it inline (hyphens
become underscores), and note that IntegrationBase.key always retains
the original hyphenated value.
Addresses: https://github.com/github/spec-kit/pull/2119#discussion_r3058050583
* docs(AGENTS.md): qualify 'single source of truth' to Python metadata only
The registry is only authoritative for Python integration metadata.
Context-update dispatcher scripts (bash + PowerShell) still require
explicit per-agent cases and maintain their own supported-agent lists
until they are migrated to registry-based dispatch. Tighten the claim
to avoid misleading contributors into skipping the script updates.
Addresses: https://github.com/github/spec-kit/pull/2119#pullrequestreview-4083090261
* docs(AGENTS.md): mention ValidateSet update in PowerShell dispatcher step
The update-agent-context.ps1 script has a [ValidateSet(...)] on the
AgentType parameter. Without adding the new key to that list, the script
rejects the argument before reaching Update-SpecificAgent. Add this as
an explicit step alongside the switch case and Update-AllExistingAgents.
Addresses: https://github.com/github/spec-kit/pull/2119#pullrequestreview-4083217694
* fix(integrations): sort codebuddy before codex in _register_builtins()
Both the import list and the _register() call list had codex before
codebuddy, violating the alphabetical ordering that AGENTS.md documents.
Swap them so the file matches the documented convention.
Addresses: https://github.com/github/spec-kit/pull/2119#pullrequestreview-4083341590
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>