Commit Graph

157 Commits

Author SHA1 Message Date
Si Zengyu
1add20341d fix(extensions,presets,workflows): resolve private GHES release assets via /api/v3 (#3157)
* feat(auth): add github_provider_hosts() to enumerate GHES hosts from auth.json

Assisted-by: Claude Code (model: claude-sonnet-4-6, autonomous)

* fix(extensions): resolve GHES release assets via /api/v3

Generalizes resolve_github_release_asset_api_url to GitHub Enterprise
Server hosts (gated by auth.json github hosts), fixing private GHES
extension/preset downloads. github/spec-kit#3147

Assisted-by: Claude Code (model: claude-sonnet-4-6, autonomous)

* fix(extensions,presets): pass auth.json github hosts into release resolver

Assisted-by: Claude Code (model: claude-sonnet-4-6, autonomous)

* docs(auth): document GHES private catalog + release-asset auth

Assisted-by: Claude Code (model: claude-sonnet-4-6, autonomous)

* fix(presets,workflows): pass auth.json github hosts into remaining release resolvers

Wires preset add --from and workflow add through github_provider_hosts()
so private GHES release assets resolve via /api/v3 there too. github/spec-kit#3147

Assisted-by: Claude Code (model: claude-sonnet-4-6, autonomous)

* test(presets): use module-level io.BytesIO in GHES preset test

Addresses Copilot review on PR #3157: drop unnecessary __import__("io")
in test_preset_add_from_ghes_release_url_resolves_via_api_v3 since io is
already imported at module level.

* fix(github-http): pass through GHES asset API URLs by path shape

Addresses Copilot review on PR #3157. A direct GHES /api/v3 release asset
URL was only returned as already-resolved when its host was in the
allowlist; otherwise the resolver returned None and the caller downloaded
the same URL without 'Accept: application/octet-stream', fetching JSON
metadata instead of the binary.

Gate the passthrough on path shape alone, mirroring the github.com case.
This is safe: passthrough returns the input URL unchanged and the caller
fetches it either way, so no new request to an arbitrary host is induced;
the token stays independently gated by auth.json in open_url. The
allowlist remains the anti-SSRF gate on the tag-lookup resolving path.

Add test_passthrough_for_unlisted_ghes_api_asset_url.
2026-06-25 10:44:30 -05:00
WOLIKIMCHENG
7624dd6582 Update preset composition strategy reference (#3143)
* docs: update preset composition strategy reference

* docs: clarify preset command composition timing

* docs: clarify preset command reconciliation timing

* docs: clarify preset file resolution behavior

* docs: clarify preset command reconciliation wording

---------

Co-authored-by: root <kinsonnee@gmail.com>
2026-06-25 10:13:14 -05:00
Rafael Sales
05cf078ea4 docs: add SpecKit Assistant npm package to Community Friends (#3142)
* docs: add SpecKit Assistant npm package to Community Friends

Adds SpecKit Assistant (https://www.npmjs.com/package/speckit-assistant)
to the Community Friends list. It is a visual interface for the specify
CLI that orchestrates Spec-Driven Development (SDD) — connecting local
specification, planning, and task checklists with AI agents (Claude,
Gemini, Copilot). No installation required; run it via npx speckit-assistant.

As the author of both the VS Code Spec Kit Assistant extension and the
SpecKit Assistant npm package, I maintain these community tools that
provide a visual interface on top of the specify CLI.

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* docs: clarify SpecKit Assistant requires no global installation

Address Copilot review: 'No installation required' was misleading for an
npx-run package since npx still downloads it. Clarify that no global
installation is required.

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-24 17:37:28 -05:00
github-actions[bot]
0cde6be41b Add Spec Roadmap extension to community catalog (#3153)
Add roadmap extension submitted by @srobroek to:
- extensions/catalog.community.json (alphabetical order)
- docs/community/extensions.md community extensions table

Closes #3150

Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-24 15:32:04 -05:00
meymchen
dc840f07d0 feat(integration): update Kimi integration for Kimi Code CLI (#2979)
* feat(integration): update Kimi integration for Kimi Code CLI

Update the Kimi integration to target the new Kimi Code CLI
(MoonshotAI/kimi-code) layout:

- Change skills directory from .kimi/skills/ to .kimi-code/skills/
- Change context file from KIMI.md to AGENTS.md
- Extend --migrate-legacy to move old .kimi/skills/ installs and
  migrate KIMI.md user content to AGENTS.md
- Clean up leftover legacy .kimi/skills/ directories on teardown
- Update devcontainer installer to @moonshot-ai/kimi-code
- Update docs and tests

Relates to #1532

* fix(integration): align Kimi dispatch and harden legacy migration

- Override build_command_invocation to emit /skill:speckit-<stem>
  so dispatched commands match Kimi Code CLI's native slash syntax.
- Skip symlinked .kimi/skills directories during legacy migration
  and teardown to avoid operating on files outside the project.
- Remove kimi from the multi-install-safe integrations table.
- Add tests for command invocation and symlink safety.

* fix(integration): resolve custom context markers in Kimi legacy migration

Use IntegrationBase._resolve_context_markers() when migrating legacy
KIMI.md content so that projects with customized context_markers in
.specify/extensions/agent-context/agent-context-config.yml have the
managed section stripped with the correct markers instead of the
hard-coded defaults.

Adds a test verifying custom markers are respected during
--migrate-legacy.

* fix(integration): harden Kimi legacy migration against symlinked paths

* fix(kimi): guard symlinked SKILL.md during migration and teardown

* docs(kimi): mention KIMI.md→AGENTS.md migration in --migrate-legacy help

The --migrate-legacy help text listed only the skills directory move and
dotted→hyphenated renaming, but the flag also migrates KIMI.md user content
into AGENTS.md. Align the help with the actual behavior, docs, and tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(kimi): validate legacy migration destination; clarify docstrings

Address Copilot review feedback on PR #2979:

- setup(): gate skills migration on _is_safe_legacy_dir(new_skills_dir)
  as well as the source. base setup() already rejects a destination that
  escapes the project root, but an in-tree symlinked .kimi-code/skills
  (e.g. -> .) could still misdirect the move; this gives the destination
  the same symlink-component protection as the source.
- _migrate_legacy_kimi_dotted_skills: rewrite docstring as a compatibility
  shim describing same-path delegation to _migrate_legacy_kimi_skills_dir.
- test_presets: clarify that the dotted-skill test exercises legacy naming
  under the current .kimi-code/ base, not the legacy .kimi/ location.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(kimi): harden legacy KIMI.md→AGENTS.md context migration

- Skip context-file migration when the agent-context extension is
  disabled, matching upsert/remove_context_section opt-out behavior so
  an opted-out project's KIMI.md/AGENTS.md are left untouched.
- Safely skip (instead of raising) on filesystem edge cases: unreadable
  or non-UTF-8 KIMI.md, and AGENTS.md existing as a non-file/unwritable.
- Refuse to migrate a corrupted managed section (single marker, or end
  before start) so a partial managed block is never copied into
  AGENTS.md; KIMI.md is preserved for manual repair.

Add regression tests for all three cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Approve fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* chore(kimi): revert CHANGELOG.md edit (auto-generated)

The CHANGELOG is generated from merged PR titles, so a hand-written entry
is redundant; it was also placed under the already-released 0.10.2 section,
which would make those release notes historically inaccurate. Revert to
match main per maintainer feedback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test(kimi): skip symlink-safety tests when symlinks are unavailable

The Kimi legacy-migration safety tests create symlinks to assert that
migration/teardown never follow them out of the project. Symlink creation
fails on Windows without the create-symlink privilege and in some restricted
CI sandboxes, so these tests errored during setup instead of skipping.

Wrap every symlink_to() call in a shared _symlink_or_skip() helper that
pytest.skip()s on OSError/NotImplementedError, matching the guard pattern
already used by one of these tests. Verified on Windows: the 6 symlink tests
now skip cleanly (51 passed, 6 skipped) instead of erroring.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(kimi): reject symlinked skills destination before install

Add a destination symlink pre-check in KimiIntegration.setup() before
super().setup() writes any SKILL.md. The base class only rejects a
destination that escapes project_root after resolve(), so an in-tree
symlinked .kimi-code/.kimi-code/skills (e.g. `-> .`) would still
misdirect writes into an unintended in-tree location (./skills/).

Extract the symlink-component walk into a shared _has_symlinked_component()
helper and reuse it from _is_safe_legacy_dir(). Add a regression test.

Also clarify that --migrate-legacy only migrates KIMI.md -> AGENTS.md when
the agent-context extension is enabled, in the CLI help text and the
integration docs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Refactor formatting and simplify logic in Kimi integration

* fix(kimi): reject symlinked target dir during legacy skills migration

When the migration destination already exists, guard against a symlinked
(or non-directory) target_dir before comparing SKILL.md bytes, so the
comparison never follows a link outside the project root. Also skip a
missing/non-file target SKILL.md explicitly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-24 15:22:08 -05:00
github-actions[bot]
e12beda5f9 [extension] Add Golden Demo extension to community catalog (#3151)
* Add Golden Demo extension to community catalog

Add golden-demo extension submitted by @jasstt to:
- extensions/catalog.community.json (alphabetical order)
- docs/community/extensions.md community extensions table

Closes #3127

Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove empty changelog field from golden-demo catalog entry

Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@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>
2026-06-24 15:17:04 -05:00
Ali jawwad
5404f7ee1c docs: run /speckit.checklist after /speckit.plan in quickstart (#3108)
* docs: run /speckit.checklist after /speckit.plan in quickstart

The quickstart workflow showed /speckit.checklist before /speckit.plan,
contradicting the CLI next-steps text (commands/init.py), which lists the
checklist as running after the plan. Per the maintainer on #2816 — "the
docs were actually wrong here ... checklists are meant for after plan" —
align the docs to the CLI: move /speckit.checklist after /speckit.plan in
the workflow diagram, the prose, and both walkthrough step sequences.

Docs-only; no behavior change.

Closes #2606

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: reword checklist as generating quality checklists, not validating directly

Address review: /speckit.checklist generates quality checklists (which then validate the requirements) rather than validating directly, matching the CLI/README phrasing. Preserves the after-plan ordering.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: align checklist wording with CLI next-steps phrasing

Address review: state the checklist's purpose (validate requirements completeness, clarity, and consistency) and anchor it to /speckit.plan as the CLI does, use the plural 'quality checklists', and reword the Taskify step so the spec is validated using the generated checklists.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 15:16:36 -05:00
Zied Jlassi
f846d6526c fix(workflows): validate requires keys and reject phantom permissions gate (#3079)
* fix(workflows): validate requires keys and reject phantom permissions gate

A workflow's `requires` block was parsed but its keys were never
validated, so a typo or an unsupported key was silently ignored. Most
importantly, authors could write `requires.permissions.shell: true`
expecting a runtime capability gate — but no such gate exists: a `shell`
step always runs with the user's privileges. The declaration gave a
false sense of sandboxing.

`validate_workflow` now accepts only the recognised keys
(`speckit_version`, `integrations`, `tools`, `mcp`) and rejects anything
else, with an explicit error for `requires.permissions` pointing authors
to `gate` steps for approval. Docs and the model comment are updated to
state that `requires` is advisory, not a security boundary.

- Reject non-mapping `requires`, unknown keys, and `requires.permissions`
- Clarify workflows reference + PUBLISHING.md shell-step guidance
- Tests for valid keys, non-mapping, unknown key, and permissions

Signed-off-by: Zied Jlassi <6190550+zied-jlassi@users.noreply.github.com>
Assisted-by: AI

* fix(workflows): address review feedback on requires validation

Follow-up to the review on #3079:

- Guard `requires` validation on `is not None` instead of truthiness so a
  falsy non-mapping value (e.g. `requires: []` or `requires: ''`) is
  reported as an error instead of being silently skipped; `requires:`
  (YAML null) is still treated as an omitted block. Add a regression test.
- Reword the workflows security note so `requires.permissions` is shown
  as rejected/unsupported rather than as a valid example of `requires`.
- Standardize on US spelling (`_RECOGNIZED_REQUIRES_KEYS`, "recognized")
  to match the surrounding code and ease searching.
- Tighten the permissions-rejection test to assert on specific message
  markers (`requires.permissions` and the `gate` guidance) so it fails if
  the validation path or wording drifts.

Assisted-by: AI
Signed-off-by: Zied Jlassi (Architect AI) <6190550+zied-jlassi@users.noreply.github.com>

* fix(workflows): scope requires validation to workflow keys (drop tools/mcp)

tools and mcp belong to the bundle manifest requires schema (bundler/models/manifest.py, resolved in bundler/services/resolver.py), not the workflow requires validated here. Drop them from _RECOGNIZED_REQUIRES_KEYS and revert the PUBLISHING.md claim that this PR had introduced, so workflow requires only recognizes speckit_version and integrations.

This keeps the existing docs accurate and resolves the inline doc-consistency review comments.

Signed-off-by: Zied Jlassi <6190550+zied-jlassi@users.noreply.github.com>

* refactor(workflows): type WorkflowDefinition.requires as Any pre-validation

self.requires holds the raw parsed value, which before validate_workflow()
runs may be a non-mapping (None for a bare 'requires:', a list for
'requires: []', etc.). Annotating it dict[str, Any] was misleading for
editors/type-checkers; use Any and document that validate_workflow() enforces
the mapping shape.

Addresses Copilot review feedback on engine.py.

Signed-off-by: Zied Jlassi <6190550+zied-jlassi@users.noreply.github.com>

* fix(workflows): reject YAML-null requires: as a non-mapping

Address Copilot review: validate requires the same way as inputs. A
bare requires: parses as YAML null and was previously treated as an
omitted block, which is inconsistent with inputs and lets a stray
requires: line be silently ignored.

Drop the is-not-None guard and check isinstance(..., dict) directly: an
omitted block still defaults to {} (valid), but a present-but-non-mapping
value -- YAML null, [] or '' -- is now an authoring error that surfaces.

Tests: add YAML-null rejection + an omitted-is-still-valid guard test.
Signed-off-by: Zied Jlassi <6190550+zied-jlassi@users.noreply.github.com>

---------

Signed-off-by: Zied Jlassi <6190550+zied-jlassi@users.noreply.github.com>
Signed-off-by: Zied Jlassi (Architect AI) <6190550+zied-jlassi@users.noreply.github.com>
2026-06-24 14:49:43 -05:00
Omar
44ef11aa18 feat(integrations): add omp support (#3107)
* feat(integrations): add omp support

* Update updated_at timestamp

* refactor(integrations): delegate omp build_exec_args to base, register in issue templates

Inherit MarkdownIntegration.build_exec_args so omp picks up shared CLI
contract changes (requires_cli gating, extra-args ordering, --model
handling) automatically; only specialize the --mode json flag.

Also add Oh My Pi / omp to the issue-template agent lists so
test_issue_template_agent_lists_match_runtime_integrations passes.

* fix(integrations): use --print + positional prompt for omp argv

OMP's CLI parser treats `-p`/`--print` as a boolean (one-shot mode)
and consumes the prompt as a positional message; the previous
inherited `-p <prompt>` shape worked by accident only because `-p`
ignores its next token. Build the argv explicitly with flags first
and the prompt as a trailing positional, matching upstream args.ts.
2026-06-24 13:44:34 -05:00
Pascal THUET
b6b74d4ccf docs: add monorepo guide (#3084)
* docs: add monorepo guide

Adds docs/guides/monorepo.md covering per-project .specify/, targeting a member project from the repo root with SPECIFY_INIT_DIR, agent env propagation, the git extension scoping limitation (#3081), and per-project constitutions. Wires it into docs/toc.yml under Development.

* docs: correct monorepo Git guidance

* docs: drop open-issue reference and polish monorepo guide prose

* docs: fix SPECIFY_INIT_DIR error example (absolute path, non-project dir)

* docs: address Copilot wording nits in monorepo guide

* docs: clarify monorepo constitution sharing

Assisted-by: Codex (model: GPT-5, autonomous)
2026-06-23 14:20:28 -05:00
github-actions[bot]
45423d6bc6 [extension] Update Spec Kit Preview extension to v1.1.0 and sync Firebender agent lists (#3116)
* Update Spec Kit Preview extension to v1.1.0

Update preview extension submitted by @bigsmartben to:
- extensions/catalog.community.json (version, name, description, download_url, commands, tags, updated_at)
- docs/community/extensions.md community extensions table (name, description, alphabetical order)

Closes #3109

Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Sync issue templates with firebender integration

Assisted-by: GitHub Copilot (model: GPT-5, autonomous)

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@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>
Co-authored-by: Manfred Riem <15701806+mnriem@users.noreply.github.com>
2026-06-23 09:32:16 -05:00
github-actions[bot]
a86ee0e8b6 Add Spec Kit Discovery Extension to community catalog (#3119)
Add discovery extension submitted by @bigsmartben to:
- extensions/catalog.community.json (alphabetical order)
- docs/community/extensions.md community extensions table

Closes #3113

Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-23 08:30:21 -05:00
github-actions[bot]
8c85919f0f Update Architecture Workflow extension to v1.2.1 (#3118)
Update arch extension submitted by @bigsmartben to:
- extensions/catalog.community.json (version, download_url, description, provides.commands)
- docs/community/extensions.md community extensions table

Closes #3111

Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-23 08:30:01 -05:00
github-actions[bot]
2344eafdd9 Add Intake extension to community catalog (#3117)
Add intake extension submitted by @bigsmartben to:
- extensions/catalog.community.json (alphabetical order)
- docs/community/extensions.md community extensions table

Closes #3110

Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-23 08:16:15 -05:00
Ali jawwad
0a126256e0 feat: add Firebender integration (Android Studio / IntelliJ) (#3077)
* feat: add Firebender integration (Android Studio / IntelliJ)

Firebender (https://firebender.com/) is an AI coding agent for Android
Studio and IntelliJ. It reads project-local custom slash commands from
.firebender/commands/*.mdc and project rules from .firebender/rules/*.mdc.

Add a FirebenderIntegration (MarkdownIntegration) that installs the
speckit command templates as .mdc command files and writes the managed
context section into .firebender/rules/specify-rules.mdc. command_filename
is overridden so init-time commands also use the .mdc extension Firebender
requires. Register it in the integration registry, add the catalog entry
and docs row, and add an integration test covering the .mdc command output.

Closes #1548

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: address review - bump catalog updated_at and list firebender as multi-install safe

Bump the catalog top-level updated_at to reflect the new entry, and add firebender (with its .firebender/commands + .firebender/rules/specify-rules.mdc isolation paths) to the 'currently declared multi-install safe integrations' table in the docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 08:01:00 -05:00
github-actions[bot]
afe7657d2c Add SicarioSpec Core preset to community catalog (#3102)
Add sicario-core preset submitted by @SiCar10mw to:
- presets/catalog.community.json (alphabetical order)
- docs/community/presets.md community presets table

Closes #3101

Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-22 17:10:00 -05:00
github-actions[bot]
5224f33d7d Update Game Narrative Writing preset to v1.1.0 (#3099)
Update game-narrative-writing preset submitted by @adaumann:
- presets/catalog.community.json (version, download_url, description, provides, tags, updated_at)
- docs/community/presets.md community presets table

Closes #3096

Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-22 16:15:28 -05:00
meymchen
6a3ee9b64e feat: add ZCode (Z.AI) integration (#3063)
* feat: add ZCode (Z.AI) integration

Add a skills-based integration for ZCode, Z.AI's Claude-Code-style
agent. ZCode uses the same SKILL.md layout as Claude Code, so spec-kit
installs workflows into .zcode/skills/speckit-<name>/SKILL.md, invoked
in chat as $speckit-<name>.

- ZcodeIntegration(SkillsIntegration) with .zcode/ folder and --skills option
- Register in INTEGRATION_REGISTRY
- Catalog entry (tags: cli, skills, z-ai)
- Tests via SkillsIntegrationTests mixin
- Document in integrations reference and README

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix: render $speckit-* invocations for ZCode skills

ZCode is documented as a skills agent invoked with $speckit-<command>,
but the central invocation rendering only special-cased codex, so
specify init Next Steps and extension hooks rendered the dotted
/speckit.<command> form instead.

Centralize the $speckit-* decision in a DOLLAR_SKILLS_AGENTS set with an
is_dollar_skills_agent() helper, and route both init Next Steps and
HookExecutor._render_hook_invocation through it. Add ZCode invocation
regression tests mirroring the existing Codex/Kimi coverage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 12:14:18 -05:00
github-actions[bot]
85d59d2d70 [extension] Add Tasks to GitHub Project extension to community catalog (#3090)
* Add Tasks to GitHub Project extension to community catalog

Add tasks-to-project extension submitted by @mancioshell to:
- extensions/catalog.community.json (alphabetical order)
- docs/community/extensions.md community extensions table

Closes #3082

Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Revert catalog re-serialization churn and drop git tool requirement

Restore extensions/catalog.community.json to upstream content and add only
the tasks-to-project entry, removing the unrelated Unicode-escape and
tool-object expansion churn across the catalog. Drop the git tool from the
entry's requirements to match the published extension.yml (gh + python3).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Manfred Riem <15701806+mnriem@users.noreply.github.com>
2026-06-22 11:10:53 -05:00
Manfred Riem
487af97864 feat: add specify bundle command (#3070)
* docs: dogfood Spec Kit — bundler SDD artifacts + constitution

Scaffold Spec Kit (--integration copilot) and run the full SDD workflow
against the `specify bundle` subcommand feature:

- spec.md (4 user stories, 31 FRs, 8 success criteria) + clarifications
- plan.md, research.md, data-model.md, contracts/, quickstart.md
- tasks.md (43 dependency-ordered tasks, organized by user story)
- Spec Kit Constitution v1.0.0 (code quality, testing, UX, performance,
  dependency/security principles) derived from deep codebase analysis
- plan Constitution Check + tasks grounded against the ratified principles

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(bundler): add `specify bundle` subcommand for role-based setups

Implements the Spec Kit Bundler as a `specify bundle ...` subcommand group
that calls existing primitive machinery in-process with zero new dependencies,
per the v1.0.0 constitution (Principles I-V).

Adds the `specify_cli.bundler` package (models, services, lib helpers) and the
`commands/bundle` Typer group wiring search, info, list, install, update,
remove, validate, build, init, and catalog list/add/remove (with --json and
--offline). Includes manifest/catalog schemas, version + integration-clash
gating, discovery-only refusal, idempotent install with atomic rollback,
non-collateral removal, and offline-first catalog resolution.

Ships an 82-test suite (contract/unit/integration), four sample role bundles
(product-manager, business-analyst, security-researcher, developer), README
"Bundles" docs, and an AGENTS.md pitfall on the test-venv gotcha. Marks
tasks T001-T043 complete and records follow-ups T044 (live in-process
primitive dispatch) and T045 (install from a local artifact path).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(contributing): document running the full test suite via project .venv

Add a "Running the full test suite" subsection under Automated checks covering
`uv pip install -e ".[test]"` + `.venv/bin/python -m pytest`, with the
shared/global editable-install contamination caveat that mirrors the AGENTS.md
pitfall.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(bundler): wire real in-process primitive install + local-artifact install

Closes the two follow-ups left after the initial bundler landing.

T044 — DefaultPrimitiveInstaller now performs real installs through existing
machinery instead of raising "use the primitive command" errors:
- presets/extensions install via their reusable managers
  (install_from_directory / install_from_zip); bundled assets install fully
  offline, catalog assets are fetched only when the network is allowed.
- workflows/steps delegate to the existing `workflow add` / `workflow step add`
  command callables in-process (project root as cwd), avoiding any duplicated
  download/validation logic (Principle I).
- `--offline` is threaded through DefaultPrimitiveInstaller(allow_network=…) so
  network-only kinds refuse with an actionable message rather than silently
  reaching out.

T045 — `specify bundle install` now accepts a local path (a built .zip
artifact, a bundle directory, or a bundle.yml) and installs directly without
consulting the catalog stack; bundle-ids still resolve via the stack.

Adds 13 tests (routing, offline gating, local-source resolution, and an
end-to-end offline build → install → list → remove of the bundled
agent-context extension). Bundler suite: 95 passing; ruff clean. Marks T044
and T045 complete in tasks.md.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(bundler): append Phase 8 convergence tasks from converge assessment

Ran the converge command: assessed the codebase against spec.md, plan.md,
tasks.md, and the v1.0.0 constitution. Appended 7 traceable gap-closure tasks
(T046–T052) as a new "Phase 8: Convergence" section. Append-only — no existing
tasks were modified and no application code was changed.

Findings: 1 CRITICAL (Constitution III — bundle group undocumented under
docs/reference/), 3 HIGH (FR-005/SC-007 validate references; FR-009/SC-002 info
expansion; FR-012 install-time init), 3 MEDIUM (FR-013 integration precedence;
FR-020 surface overlaps; FR-028 update refresh).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Implement Phase 8 convergence tasks (T046–T052)

Close the gaps the converge command found between the bundler spec/plan/
constitution and the code:

- T046: add docs/reference/bundles.md documenting the full `specify bundle`
  command group; link it from docs/reference/overview.md (Constitution III).
- T047: wire a reference checker into `bundle validate` (services/references.py);
  online runs fail and name unresolved component references, offline runs warn.
- T048: expand `bundle info` to enumerate the full component set (versions,
  preset priority/strategy) plus the bundle integration — info == install.
- T049/T050: `bundle install`/`bundle init` now scaffold an uninitialized
  project via the existing `specify init` machinery, choosing the integration by
  precedence (override → bundle-declared → Copilot + OS default script type).
- T051: surface foreseeable component overlaps during info and install.
- T052: `bundle update` refreshes already-installed components via a new
  refresh path in install_bundle, preserving primitive-level overrides.

Adds unit/contract/integration coverage (107 tests pass).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* converge: append Phase 9 (T053) — surface bundle trust indicator

Re-run of converge after Phase 8. The seven Phase 8 tasks are verified closed.
One residual partial gap remains: the `verified`/trust indicator (FR-010,
FR-027) is exposed only in `bundle info --json`, absent from `bundle search`
(the primary discovery surface) and `bundle info` text. Appended as a single
new task for implement to complete. Append-only; no code changed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Implement T053 — surface bundle trust indicator in discovery

`bundle search` (text + JSON) and `bundle info` (text + JSON) now expose each
catalog entry's verification/trust level (verified vs community), so users can
judge a bundle's trust before installing, per FR-010 / FR-027. Previously
`verified` was only present in `bundle info --json`.

Adds contract coverage; 108 tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: dogfood Spec Kit — bundler SDD artifacts + constitution

Scaffold Spec Kit (--integration copilot) and run the full SDD workflow
against the `specify bundle` subcommand feature:

- spec.md (4 user stories, 31 FRs, 8 success criteria) + clarifications
- plan.md, research.md, data-model.md, contracts/, quickstart.md
- tasks.md (43 dependency-ordered tasks, organized by user story)
- Spec Kit Constitution v1.0.0 (code quality, testing, UX, performance,
  dependency/security principles) derived from deep codebase analysis
- plan Constitution Check + tasks grounded against the ratified principles

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(bundler): add `specify bundle` subcommand for role-based setups

Implements the Spec Kit Bundler as a `specify bundle ...` subcommand group
that calls existing primitive machinery in-process with zero new dependencies,
per the v1.0.0 constitution (Principles I-V).

Adds the `specify_cli.bundler` package (models, services, lib helpers) and the
`commands/bundle` Typer group wiring search, info, list, install, update,
remove, validate, build, init, and catalog list/add/remove (with --json and
--offline). Includes manifest/catalog schemas, version + integration-clash
gating, discovery-only refusal, idempotent install with atomic rollback,
non-collateral removal, and offline-first catalog resolution.

Ships an 82-test suite (contract/unit/integration), four sample role bundles
(product-manager, business-analyst, security-researcher, developer), README
"Bundles" docs, and an AGENTS.md pitfall on the test-venv gotcha. Marks
tasks T001-T043 complete and records follow-ups T044 (live in-process
primitive dispatch) and T045 (install from a local artifact path).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(contributing): document running the full test suite via project .venv

Add a "Running the full test suite" subsection under Automated checks covering
`uv pip install -e ".[test]"` + `.venv/bin/python -m pytest`, with the
shared/global editable-install contamination caveat that mirrors the AGENTS.md
pitfall.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(bundler): wire real in-process primitive install + local-artifact install

Closes the two follow-ups left after the initial bundler landing.

T044 — DefaultPrimitiveInstaller now performs real installs through existing
machinery instead of raising "use the primitive command" errors:
- presets/extensions install via their reusable managers
  (install_from_directory / install_from_zip); bundled assets install fully
  offline, catalog assets are fetched only when the network is allowed.
- workflows/steps delegate to the existing `workflow add` / `workflow step add`
  command callables in-process (project root as cwd), avoiding any duplicated
  download/validation logic (Principle I).
- `--offline` is threaded through DefaultPrimitiveInstaller(allow_network=…) so
  network-only kinds refuse with an actionable message rather than silently
  reaching out.

T045 — `specify bundle install` now accepts a local path (a built .zip
artifact, a bundle directory, or a bundle.yml) and installs directly without
consulting the catalog stack; bundle-ids still resolve via the stack.

Adds 13 tests (routing, offline gating, local-source resolution, and an
end-to-end offline build → install → list → remove of the bundled
agent-context extension). Bundler suite: 95 passing; ruff clean. Marks T044
and T045 complete in tasks.md.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(bundler): append Phase 8 convergence tasks from converge assessment

Ran the converge command: assessed the codebase against spec.md, plan.md,
tasks.md, and the v1.0.0 constitution. Appended 7 traceable gap-closure tasks
(T046–T052) as a new "Phase 8: Convergence" section. Append-only — no existing
tasks were modified and no application code was changed.

Findings: 1 CRITICAL (Constitution III — bundle group undocumented under
docs/reference/), 3 HIGH (FR-005/SC-007 validate references; FR-009/SC-002 info
expansion; FR-012 install-time init), 3 MEDIUM (FR-013 integration precedence;
FR-020 surface overlaps; FR-028 update refresh).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Implement Phase 8 convergence tasks (T046–T052)

Close the gaps the converge command found between the bundler spec/plan/
constitution and the code:

- T046: add docs/reference/bundles.md documenting the full `specify bundle`
  command group; link it from docs/reference/overview.md (Constitution III).
- T047: wire a reference checker into `bundle validate` (services/references.py);
  online runs fail and name unresolved component references, offline runs warn.
- T048: expand `bundle info` to enumerate the full component set (versions,
  preset priority/strategy) plus the bundle integration — info == install.
- T049/T050: `bundle install`/`bundle init` now scaffold an uninitialized
  project via the existing `specify init` machinery, choosing the integration by
  precedence (override → bundle-declared → Copilot + OS default script type).
- T051: surface foreseeable component overlaps during info and install.
- T052: `bundle update` refreshes already-installed components via a new
  refresh path in install_bundle, preserving primitive-level overrides.

Adds unit/contract/integration coverage (107 tests pass).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* converge: append Phase 9 (T053) — surface bundle trust indicator

Re-run of converge after Phase 8. The seven Phase 8 tasks are verified closed.
One residual partial gap remains: the `verified`/trust indicator (FR-010,
FR-027) is exposed only in `bundle info --json`, absent from `bundle search`
(the primary discovery surface) and `bundle info` text. Appended as a single
new task for implement to complete. Append-only; no code changed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Implement T053 — surface bundle trust indicator in discovery

`bundle search` (text + JSON) and `bundle info` (text + JSON) now expose each
catalog entry's verification/trust level (verified vs community), so users can
judge a bundle's trust before installing, per FR-010 / FR-027. Previously
`verified` was only present in `bundle info --json`.

Adds contract coverage; 108 tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): address PR review — annotations, Windows paths, HTTPS, errors, reproducible builds

Resolves automated review feedback on github/spec-kit#3070:

- validator: drop redundant string-quoting on ReferenceChecker's
  `str | None` return so the annotation evaluates as a real union under
  `from __future__ import annotations`.
- adapters: normalize Windows drive-letter paths (e.g. C:\...) to the
  local-file branch so offline file catalogs resolve on Windows.
- adapters: enforce HTTPS (HTTP only for localhost) and require a host on
  remote catalog URLs before any network call, mirroring
  specify_cli.catalogs URL validation (MITM/downgrade protection).
- adapters: pass `origin` to loads_json for local files and HTTP payloads
  so JSON parse errors name the real source instead of <string>.
- manifest: parse component `priority` defensively, raising an actionable
  BundlerError on non-integer values instead of a raw ValueError.
- packager: write zip members with a fixed timestamp + permissions so
  identical inputs yield byte-for-byte identical artifacts (genuinely
  reproducible builds), and strengthen the determinism test accordingly.

Adds regression tests for priority validation, plain-HTTP/host rejection,
and byte-level artifact reproducibility (111 bundler tests pass; ruff clean).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): address PR review round 2 — nested output dir + file:// URLs

- packager: when --output points inside the bundle directory, exclude the
  whole output subtree from collection so previously-built artifacts are
  never re-packaged (prevents broken reproducibility and unbounded growth).
- adapters: resolve file:// catalog URLs via url2pathname and preserve
  netloc, so Windows file URLs (file:///C:/...) and UNC shares
  (file://server/share) resolve correctly instead of dropping the host or
  producing /C:/x.

Adds regression tests for nested-output exclusion and file:// resolution
(113 bundler tests pass; ruff clean).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): address PR review round 3 — discovery UX + hardening

- bundle search/info: fall back to the built-in/user catalog stack instead of
  requiring a Spec Kit project, so discovery works in a fresh directory (and
  the README/quickstart examples now match actual behavior). install still
  auto-initializes a project as before.
- packager: traverse with os.walk(followlinks=False) and prune symlinked
  directories before descending, so a symlink-to-dir can no longer pull in
  out-of-tree files (which previously turned "skip symlinks" into a hard
  ensure_within() failure and did extra filesystem work).
- records: parse contributed-component priority defensively, raising an
  actionable BundlerError on a corrupt records file instead of leaking a raw
  ValueError/traceback.
- installer: give install_bundle's manifest parameter an explicit
  BundleManifest | None type for a clearer, safer service API.

Adds regression tests for project-less search/info, symlinked-dir pruning,
and corrupt-priority records (117 bundler tests pass; ruff clean).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): address PR review round 4 + markdownlint exclusions

Review fixes:
- bundle info: expand the manifest regardless of install policy so
  discovery-only bundles remain inspectable (only install is refused).
- _download_manifest: handle local .zip download_url by extracting bundle.yml
  (via _local_manifest_source), and add a real remote HTTPS fetch path using
  the shared authenticated, redirect-validated open_url client (HTTPS enforced
  on the initial URL and every redirect; offline still refuses).
- _run_init: thread the --offline flag through to the init callback so
  `bundle install/init --offline` never performs network init.
- conflict.ConflictReport: use field(default_factory=list) and drop the
  None + __post_init__ workaround.
- CatalogSource.from_dict: parse priority defensively, raising an actionable
  BundlerError naming the source + offending value instead of a raw ValueError.

markdownlint:
- Exclude .specify/, .github/, and specs/ (and their subdirectories) from
  markdownlint so the in-flight dogfooding scaffolding doesn't trip the linter.

Adds regression tests for discovery-only info, local-zip download_url, and
non-integer catalog priority (120 bundler tests pass; ruff clean; the PR's own
markdown lints clean).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): address PR review round 5 + ignore generated files in whitespace check

Review fixes:
- packager: exclude any prior build artifact for this bundle (matching
  <id>-*.zip), not just the current output path, so older artifacts next to
  bundle.yml are never re-packaged.
- docs(bundles): correct the note — `search` and `info` work without a project
  (they fall back to the built-in/user catalog stack); only list/update/remove/
  catalog require an initialized project.

CI / generated files:
- .gitattributes: mark the generated dogfooding scaffolding (.specify/**, the
  speckit .github agent/prompt files, copilot-instructions.md, specs/**) with
  -whitespace so `git diff --check` (the Lint workflow's whitespace gate) stops
  flagging emitted trailing whitespace. These files are produced by
  `specify init` and are scrubbed before merge.

Adds a regression test for prior-artifact exclusion (121 bundler tests pass;
ruff clean).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): collision-resistant catalog ids, canonical local paths, explicit uninstalled result

Addresses review round 6 (PR #3070):
- catalog_config._derive_id now combines host label with the URL path stem so
  multiple catalogs from the same host get distinct, stable default ids.
- add_source canonicalizes local file paths to absolute before persisting, so
  project config no longer depends on the caller's cwd.
- InstallResult gains a dedicated `uninstalled` list; remove_bundle no longer
  overloads `installed` for removals, and the CLI prints from `uninstalled`.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): confine config writes, guard indeterminate integration, fix validate docs

Addresses review round 7 (PR #3070):
- save_records and catalog_config._write now pass within=project_root to
  dump_json/dump_yaml, refusing symlinked .specify paths that escape the
  project (defense-in-depth, matching the rest of the codebase).
- resolve_install_plan now fails when a bundle pins an integration but the
  project's active integration cannot be determined and no explicit
  --integration override was given, instead of silently adopting the bundle's
  required integration (FR-019 guard). CLI passes integration_explicit.
- docs/reference/bundles.md: corrected the validate semantics to describe the
  actual best-effort online behavior (unreachable catalogs warn, not fail).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): Windows path handling + review round 8 hardening

Fix Windows CI failures:
- is_safe_relpath now rejects POSIX-absolute (/abs) and Windows drive-absolute
  (C:\x, UNC) paths on every OS, instead of passing them through on Windows
  where os.path.isabs('/abs') is False and Path('/abs').parts yields '\\'.
- _download_manifest treats a Windows drive-letter download_url (C:\bundle.yml,
  which urlparse reads as scheme 'c') as a local file, fixing the empty
  component set in `bundle info` on Windows.

Address review round 8 (PR #3070):
- Bundled workflows now install under --offline (locate via
  _locate_bundled_workflow) instead of being refused unconditionally.
- bundle update preserves the original installed_at timestamp on refresh
  (import find_record; reuse the existing record's timestamp).
- _derive_id lowercases the host label so 'Example.com' and 'example.com'
  produce the same deterministic id.
- CatalogEntry.from_dict validates 'tags' is a list and 'verified' is a real
  boolean, raising BundlerError on invalid untrusted shapes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): normalize SemVer prerelease spellings before version parsing

Addresses review round 9 (PR #3070): parse_version and is_semver now apply the
same prerelease normalization (mirroring specify_cli._version._normalize_tag)
so SemVer spellings like 1.2.3-rc1 / 1.2.3-alpha1 validate and compare
consistently across is_semver, parse_version, and satisfies. Leading 'v' is
also stripped. Keeps the manifest validator and constraint checks in agreement.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): no collateral removal + enforce manifest-pinned versions

Addresses review round 10 (PR #3070):
- install_bundle records only the components this bundle actually contributed:
  freshly-installed components, plus pre-existing ones already owned by this
  bundle (refresh) or a sibling bundle (shared/refcounted). A component that is
  installed on disk but tracked by no bundle was installed independently and is
  no longer attributed, so `bundle remove` won't uninstall it (FR-022).
- preset/extension/workflow install paths now verify the active catalog's
  advertised version matches the manifest-pinned component.version before
  downloading/installing, raising BundlerError on mismatch so bundles stay
  reproducible. When a catalog advertises no version the pin can't be enforced
  and installation proceeds.

Added regression tests: independent pre-existing component survives removal;
version-mismatch refusal (helper + workflow path).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(scripts): add SPECIFY_INIT_DIR to target a member project from the repo root (#2892)

* feat(scripts): add SPECIFY_INIT_DIR to target a member project from the repo root

Resolve an explicit SPECIFY_INIT_DIR project override once in the core
get_repo_root / Get-RepoRoot, so a non-interactive / CI caller can target a
member project (the directory containing .specify/) from a monorepo root
without cd. Strict by design: the path must exist and contain .specify/,
otherwise it hard-errors with no silent fallback.

- Single resolver in core; the git feature-branch script inherits it by
  sourcing core, with no per-extension copies.
- PS resolver verifies the resolved path is a directory (Resolve-Path also
  succeeds for files) so a file value errors as "not an existing directory".
- get_feature_paths splits decl/assignment so a SPECIFY_INIT_DIR failure
  propagates instead of being masked by `local`.
- create-new-feature-branch: when core is absent (only git-common loaded) and
  SPECIFY_INIT_DIR is set, hard-error rather than silently using the git root.
- Document SPECIFY_INIT_DIR and SPECIFY_FEATURE_DIRECTORY in the core reference.
- Tests for valid/relative/trailing-slash/file/missing/no-.specify targets,
  feature-axis composition, the no-core guard, and a PowerShell mirror.

* fix: guard SPECIFY_INIT_DIR with stale core scripts

* docs: clarify SPECIFY_FEATURE_DIRECTORY precedence wording

* fix: normalize trailing slash in PowerShell SPECIFY_INIT_DIR resolver

Resolve-Path preserves a trailing separator from its input, so a
SPECIFY_INIT_DIR ending in a slash returned a root that didn't match the
bash resolver (whose `cd && pwd` strips it). That broke
test_ps_trailing_slash_tolerated on the CI runners, which do have pwsh.
Trim it with TrimEndingDirectorySeparator (no-op on a bare root or a path
with no trailing separator).

Also fix the misleading test comment: the PowerShell mirror runs on the
CI ubuntu/windows runners (they ship pwsh), it is not skipped there.

* test: normalize bash path expectations on Windows

* docs: clarify SPECIFY_INIT_DIR root helpers

* chore: sync dogfooded .specify core scripts with SPECIFY_INIT_DIR

Mirror the SPECIFY_INIT_DIR resolver (resolve_specify_init_dir in
common.sh) into the committed dogfooding .specify/scripts/bash copies so
the git extension's create-new-feature-branch.sh finds an up-to-date
common.sh instead of failing with "requires updated Spec Kit core
scripts". Fixes the test_init_dir.py CI failures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): harden remote catalog fetch and config parsing

- adapters: route catalog HTTP fetches through the shared authenticated
  client (authentication.http.open_url) so auth.json tokens apply and the
  Authorization header is stripped on cross-host/downgrade redirects.
  Reject any redirect that leaves HTTPS via a redirect_validator and
  re-validate the final URL after redirects, closing the urlopen
  auto-redirect MITM/downgrade gap.
- catalog_config._read: raise an actionable BundlerError when the config
  top level is not a mapping, 'catalogs' is not a list, or an entry is
  not a mapping, instead of letting list(<str>) produce a downstream
  AttributeError.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): tighten record read confinement, policy gate, and precedence

Addresses review 4534504799:

- records.load_records: confine the read via ensure_within(project_root,
  ...) so a symlinked/traversal-escaping .specify cannot read arbitrary
  files outside the project (matches the write path's within= guard).
- catalog_config._slug: lowercase so derived catalog ids are
  deterministic across platforms and case-variant duplicates can't slip
  past the case-sensitive dup check.
- installer.install_bundle: reword the docstring's misleading "atomic on
  failure" claim to describe the real scoped guarantee (record written
  only on full success; rollback limited to newly-installed components).
- bundle update: enforce the source install_policy like install, refusing
  to update from a discovery-only source (FR-025).
- catalog source precedence: the CLI now passes ~/.specify as the user
  config dir so project > user > built-in precedence is actually
  reachable (previously the user scope was silently ignored).
- .gitattributes: scope the specs whitespace exemption to the generated
  dogfooding feature dir (specs/001-spec-kit-bundler/**) instead of all
  of specs/**.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): no collateral refresh, catalog id integrity, loud info

Addresses review 4534571362:

- installer: in refresh mode (bundle update) only re-apply already-
  installed components that this bundle (or a sibling) owns. Components
  installed independently and tracked by no bundle are now skipped, never
  refreshed, so update cannot make collateral changes (FR-022).
- catalog.load_catalog_payload: validate each entry's own id is present
  and matches its enclosing bundles key, rejecting catalogs that would
  otherwise list a spoofed or unresolvable id.
- bundle info: stop swallowing manifest download failures. If the
  manifest can't be resolved (e.g. --offline against an https download_url
  or a download failure), surface the error and exit non-zero instead of
  silently degrading to catalog `provides` counts, preserving the "info
  == what install applies" guarantee.

Added regressions: refresh leaves independently-installed components
untouched, catalog id key/field mismatch + missing id rejection, and
info exits non-zero when the manifest is unresolvable offline.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): confine catalog-config and integration-marker reads

Addresses review 4534716790: two more state reads bypassed the
symlink/path-escape confinement that records and the write paths already
enforce.

- catalog_config._read: validate the config path with
  ensure_within(project_root, ...) before exists()/read, so a symlinked
  .specify resolving outside project_root is rejected instead of read.
- lib.project.active_integration: confine the .specify/integration.json
  read the same way; an out-of-tree escape is treated as "not
  determinable" (returns None) rather than followed.

Added regressions covering both via a symlinked .specify pointing
outside the project root.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): validate manifest tags, disambiguate derived ids by full host

Addresses review 4534768419:

- manifest.from_dict: reject a non-list `tags` (e.g. a bare string) instead
  of splitting it character-by-character, matching the catalog parser and
  the schema contract (tags = list of strings).
- catalog_config._derive_id: derive ids from the full host (TLD included)
  so example.com and example.net no longer collide on the same id. Updated
  the affected id assertions.
- CHANGELOG: call out the new `specify bundle` command group in the
  unreleased section (the PR's headline user-facing feature).
- .gitattributes: clarify the specs whitespace exemption — the dogfooding
  feature dir is scrubbed before merge (not retained), so it doesn't weaken
  checks for kept docs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore(gitattributes): retain whitespace exemption for constitution.md

The project constitution (.specify/memory/constitution.md) is the one
dogfooding artifact carried forward past the pre-merge scrub. Give it its
own standalone whitespace exemption so it survives removal of the broader
.specify/** generated-scaffolding exemption.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): accurate uninstall count, confine catalog read, safe bundle id

Addresses review 4534812056:

- installer.remove_bundle: only count a component as uninstalled when
  installer.remove() actually ran; components already absent on disk are
  reported as skipped, keeping the uninstalled count accurate.
- catalog.load_source_stack: confine the project-scoped .specify config read
  with ensure_within, so a symlinked .specify/ resolving outside the project
  root is refused (consistent with the bundler's other guarded reads).
- manifest: enforce a filesystem-safe slug for bundle.id in structural
  validation; packager.build_bundle adds an ensure_within defense-in-depth
  check so a crafted id can never push the artifact outside the output dir.

Also reverts the CHANGELOG entry (the changelog is updated separately).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): validate requires/provides shapes in manifest and catalog

Addresses review 4534855443:

- manifest: validate requires.tools and requires.mcp as list-of-strings via
  a shared _parse_str_list helper (also reused for tags), so a bare string
  like `tools: docker` is rejected with an actionable BundlerError instead of
  being split character-by-character.
- catalog.CatalogEntry.from_dict: validate that `requires` and `provides` are
  mappings before accessing them, so an untrusted catalog payload with
  `requires: "..."` raises a named BundlerError rather than escaping as a raw
  AttributeError traceback.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): require README.md when building a bundle artifact

Addresses review 4534938014: build_bundle now fails early with an
actionable error when README.md is missing, matching the documented
artifact contract (manifest + README) instead of silently producing a
bundle with no human-facing description.

Also reverts CHANGELOG.md to the upstream/main copy.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): validate record shapes; drop stale install --refresh claim

Addresses review 4534969692:

- records.InstalledBundleRecord.from_dict: hard-error when
  contributed_components is not a list, instead of iterating a corrupt
  bare string character-by-character.
- records.load_records: validate the top-level 'bundles' field is a list and
  fail with a clear BundlerError when a corrupt file makes it a mapping/string.
- PR description: remove the inaccurate "supports --refresh" note from
  `bundle install` (refresh is the `bundle update` path); docs already omit it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): refuse symlinked .specify, reject bad url schemes, IPv6 ids

Addresses review 4534997724:

- lib.project.find_project_root: a symlinked .specify is no longer accepted
  as a project root (is_dir() follows symlinks), matching the confinement the
  rest of the CLI applies and avoiding confusing downstream failures.
- catalog_config.add_source: reject unsupported url schemes (ssh://, ftp://,
  ...) up front instead of silently treating them as local paths; local paths
  containing ':' but not '://' are still allowed.
- catalog_config._derive_id: derive the host via urlparse().hostname so IPv6
  literals, credentials, and ports no longer corrupt the derived id.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): strict semver, narrow artifact skip, preserve priority 0

Addresses review 4535084048:

- versioning.is_semver: enforce a full MAJOR.MINOR.PATCH SemVer (with optional
  pre-release/build) via a dedicated regex, instead of accepting any
  packaging.version.Version-parseable string (e.g. "1", "1.0"). This makes
  BundleManifest.structural_errors() reject non-semver versions.
- packager: narrow the prior-artifact skip pattern to semver-named zips
  (<id>-<x.y.z>.zip) so legitimate assets like <id>-assets.zip are still
  packaged.
- primitives (preset + extension install): use an explicit `is None` check so
  an intentional priority of 0 is preserved instead of being replaced by the
  default.

Adds regressions: non-semver rejection ("1"/"1.0"/"1.2.3.4"), asset-not-
excluded vs semver-artifact-excluded, and priority-0 pass-through.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): artifact regex for prerelease+build; clarify integration/priority docs

Addresses review 4535132279:

- packager: the prior-artifact skip regex now matches semver names carrying
  both a prerelease and build-metadata segment (e.g. 1.0.0-rc1+build5), so such
  an existing artifact is excluded rather than re-packaged — keeping builds
  bounded/deterministic, consistent with is_semver().
- docs/reference/bundles.md: correct the install integration wording.
  --integration selects the integration when initializing a new project and
  confirms the target when a pinned bundle's active integration can't be
  determined; it does NOT override a bundle that targets a specific integration
  (a mismatch aborts with no changes).
- examples/security-researcher README: reword the preset priority note in terms
  of the numeric comparison (ascending priority order) to avoid inverting the
  meaning.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): --integration can't bypass clash guard; honest rollback docs

Addresses review 4535159341:

- bundle install: for an already-initialized project, the project's recorded
  active integration is now authoritative. --integration no longer overrides it
  (which let a copilot project install a claude-pinned bundle via
  `--integration claude`, bypassing the FR-019 clash guard). The override still
  selects the integration at init time and confirms the target only when the
  active integration cannot be determined.
- docs/reference/bundles.md: reword the install guarantee to match the
  implementation — no provenance record is written unless the install fully
  succeeds, and rollback of this run's components is best-effort (removal errors
  are swallowed, so partial on-disk state may remain). Dropped the inaccurate
  "atomic / rolls back everything" claim.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): validate component kind/id when loading records

Addresses review 4535194606: _component_from_dict now rejects a contributed
component whose 'kind' is not a supported component kind or whose 'id' is
empty, raising a BundlerError that explicitly flags the records file as
corrupt. Previously such a record loaded successfully and only failed later
(e.g. in primitive_manager() during bundle remove/update) with a less
actionable error.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): address review 4535234003 (7 findings)

- versioning: tolerate an uppercase `V` prefix in `_normalize_semver` and
  `is_semver`, mirroring specify_cli._version tag normalization (V -> v) so
  `V1.2.3` parses and validates consistently.
- validator: import BundlerError and narrow the speckit_version constraint
  except clause to `BundlerError` only, so programming errors are no longer
  masked behind an "invalid constraint" message.
- bundle update: accept `--integration` and thread it through
  resolve_install_plan the same way `bundle install` does (override used only
  when the active integration can't be auto-detected), so integration-pinned
  bundles can be updated where `.specify/integration.json` is missing/unreadable.
- bundle validate: fold reference warnings into `report.warnings` so the
  ValidationReport is the single warning channel at the CLI layer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* test(bundler): make update --integration help assertion ANSI-safe

Rich can split the "--integration" option label with ANSI escape codes
between the two leading dashes, so the literal substring check failed under
CI's terminal settings. Match the un-split option word instead, mirroring how
test_bundle_help_lists_all_commands checks bare command names.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): preserve exec bits in artifacts; document install-time pins

Addresses review 4535280786:

- packager.build_bundle: no longer forces every ZIP member to 0644, which
  stripped the executable bit from bundled scripts (e.g. extension hook
  scripts) and could break them after extraction. Permissions are now
  normalized reproducibly to 0755 when the source file has any execute bit
  set, otherwise 0644 — identical inputs still yield byte-for-byte identical
  artifacts.
- installer.install_bundle + docs/reference/bundles.md: document that version
  pins are enforced install-time only. Because primitive is_installed checks
  are id-based (not version-aware), an already-present component is skipped
  during install without comparing its on-disk version to the manifest pin;
  pins are guaranteed applied only on a real install or `bundle update` refresh.

Added a regression asserting executable sources map to 0755 and plain files to
0644 in the built artifact.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* test(bundler): skip exec-bit packager test on Windows

Windows filesystems do not carry Unix execute bits, so chmod(0o755) is a no-op
and the source file reports no execute bit — the packager then correctly stores
the member as 0644. The assertion that an executable source maps to 0755 is only
meaningful on POSIX, so skip it on nt rather than asserting platform-specific
behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): normalize prerelease spellings inside version constraints

Addresses review 4535327154: parse_version() normalized SemVer prerelease
spellings (e.g. 1.2.3-rc1 -> 1.2.3rc1) but parse_constraint() passed the
constraint to packaging.SpecifierSet unmodified, so ">=1.2.3-rc1" raised
InvalidSpecifier even though the same spelling is accepted for installed
versions. parse_constraint() now normalizes the version portion of each
comma-separated clause via the shared _normalize_semver helper, so prerelease
handling is consistent across versions and constraints.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(bundler): validate schema versions and required record identity fields

Addresses review 4535351596:

- records.load_records: validate the on-disk 'schema_version' (required;
  forward-compatible across same-major minor bumps) and fail fast with an
  actionable error on a missing/unknown version, rather than silently parsing a
  possibly-incompatible format and risking incorrect bundle attribution/removal.
- records.InstalledBundleRecord.from_dict: treat missing 'bundle_id' or
  'version' as corruption and raise BundlerError, instead of coercing them to
  empty strings that let later list/remove/update operations behave
  unpredictably.
- catalog_config._read: validate 'schema_version' when present (same-major
  compatibility) and fail fast on an unsupported version so an incompatible
  future config shape can't be mis-parsed into a wrong effective catalog stack.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore(bundler): scrub generated dogfooding scaffold before merge

The bundler feature was developed by dogfooding Spec Kit on itself. Now that
the work is complete, remove all generated scaffolding so it does not land in
the repository on merge:

- specs/001-spec-kit-bundler/** (spec, plan, research, data-model, contracts,
  quickstart, tasks, checklists)
- .specify/** (extensions, integrations, scripts, templates, workflows,
  feature/init/integration metadata)
- .github/agents/speckit.*.agent.md, .github/prompts/speckit.*.prompt.md, and
  .github/copilot-instructions.md (Copilot integration scaffold)

Retained: .specify/memory/constitution.md — the single dogfooding artifact
carried forward — with its whitespace exemption in .gitattributes.

.gitattributes and .markdownlint-cli2.jsonc are reverted to the upstream
baseline (plus the constitution whitespace exemption), dropping the now-moot
exemptions for the removed scaffold.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Pascal THUET <pascal.thuet@arte.tv>
2026-06-19 17:07:20 -05:00
Pascal THUET
a17a658bbd feat(scripts): add SPECIFY_INIT_DIR to target a member project from the repo root (#2892)
* feat(scripts): add SPECIFY_INIT_DIR to target a member project from the repo root

Resolve an explicit SPECIFY_INIT_DIR project override once in the core
get_repo_root / Get-RepoRoot, so a non-interactive / CI caller can target a
member project (the directory containing .specify/) from a monorepo root
without cd. Strict by design: the path must exist and contain .specify/,
otherwise it hard-errors with no silent fallback.

- Single resolver in core; the git feature-branch script inherits it by
  sourcing core, with no per-extension copies.
- PS resolver verifies the resolved path is a directory (Resolve-Path also
  succeeds for files) so a file value errors as "not an existing directory".
- get_feature_paths splits decl/assignment so a SPECIFY_INIT_DIR failure
  propagates instead of being masked by `local`.
- create-new-feature-branch: when core is absent (only git-common loaded) and
  SPECIFY_INIT_DIR is set, hard-error rather than silently using the git root.
- Document SPECIFY_INIT_DIR and SPECIFY_FEATURE_DIRECTORY in the core reference.
- Tests for valid/relative/trailing-slash/file/missing/no-.specify targets,
  feature-axis composition, the no-core guard, and a PowerShell mirror.

* fix: guard SPECIFY_INIT_DIR with stale core scripts

* docs: clarify SPECIFY_FEATURE_DIRECTORY precedence wording

* fix: normalize trailing slash in PowerShell SPECIFY_INIT_DIR resolver

Resolve-Path preserves a trailing separator from its input, so a
SPECIFY_INIT_DIR ending in a slash returned a root that didn't match the
bash resolver (whose `cd && pwd` strips it). That broke
test_ps_trailing_slash_tolerated on the CI runners, which do have pwsh.
Trim it with TrimEndingDirectorySeparator (no-op on a bare root or a path
with no trailing separator).

Also fix the misleading test comment: the PowerShell mirror runs on the
CI ubuntu/windows runners (they ship pwsh), it is not skipped there.

* test: normalize bash path expectations on Windows

* docs: clarify SPECIFY_INIT_DIR root helpers
2026-06-19 12:05:42 -05:00
github-actions[bot]
afff4eba15 Add Token Economy extension to community catalog (#3049)
Add token-economy extension submitted by @formin to:
- extensions/catalog.community.json (alphabetical order)
- docs/community/extensions.md community extensions table

Closes #3048

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-18 08:29:16 -05:00
Huy Do
affbf5ead5 feat(workflows): add from_json expression filter (#2961)
* feat(workflows): add from_json expression filter

Step outputs captured as strings could never become typed values in
templates - the filter set was default/join/map/contains only, so e.g.
a fan-out items: could never consume a step's JSON stdout. Add an
arg-less from_json pipe filter with parse-or-raise semantics: invalid
JSON or non-string input raises a clear ValueError rather than passing
through silently.

Fixes #2960

* fix(expressions): make from_json strict — reject any arguments

Address review (#2961): from_json('x') and from_json() previously fell through to a silent passthrough of the unparsed value. Reject any parenthesized form with a clear error so mis-wired templates fail loudly. Rename test to ...parses_object (JSON under test is an object) and add coverage for the strict no-arguments behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(workflows): document the from_json expression filter

Address Copilot review: the user-facing filter references omitted the
newly added `from_json` filter. Add it to the ARCHITECTURE.md filter table
(with the `{{ steps.emit.output.stdout | from_json }}` example) and to the
filter enumerations in workflows/README.md and docs/reference/workflows.md
so the docs match the evaluator's capabilities.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(workflows): make from_json strictness reject trailing tokens; fix docstring

Address Copilot review:
- Strictness only rejected parenthesized forms, so typos like
  `| from_json)` or `| from_json extra` still fell through to the
  unknown-filter path and silently returned the unparsed value. Match on
  the leading filter token and require the whole filter to be exactly
  `from_json`, so every mis-wired form raises. Extend the rejection test to
  cover the trailing-token cases.
- The module docstring claimed "no imports", which is misleading now that
  the module imports `json`. Reword to state the actual sandbox guarantee:
  templates cannot do file I/O, import modules, or run arbitrary code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-17 13:43:26 -05:00
Jiandong
cedbf484d7 docs: clarify Taskify specify command (#3016) 2026-06-17 08:30:23 -05:00
WOLIKIMCHENG
75df458c37 docs: document evolving specs in existing projects (#2902)
* docs: document evolving specs in existing projects

* docs: reframe evolving specs guide around persistence models

* docs: address evolving specs guide feedback

* docs: address evolving specs review feedback

* docs: require explicit integration in evolving specs update command

---------

Co-authored-by: root <kinsonnee@gmail.com>
2026-06-17 08:17:01 -05:00
Thorsten Hindermann
ae23a84677 Update a11y-governance preset to v0.4.0 (#2981) 2026-06-17 06:44:32 -05:00
Pascal THUET
9cd20c6c25 feat(dev): add integration scaffolder (#2685)
* 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>
2026-06-16 17:48:40 -05:00
Maksim Kudriavtsev
497ca074ed Add Command Density preset to community catalog (#3006) 2026-06-16 17:40:20 -05:00
Ahmet TOK
1150d32aee Add Zed integration (#2780)
* 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>
2026-06-16 17:29:08 -05:00
Thorsten Hindermann
0fad994e86 Update architecture-governance preset to v0.5.0 (#2929)
* Update architecture-governance preset to v0.3.0

* Update architecture-governance preset to v0.4.0

* Update architecture-governance preset to v0.5.0

* Address Copilot wording feedback for architecture preset
2026-06-16 17:20:28 -05:00
Thorsten Hindermann
79b3f6733a Update isaqb-architecture-governance preset to v0.2.0 (#2984)
* Update isaqb-architecture-governance preset to v0.2.0

* Address Copilot wording feedback for isaqb preset
2026-06-16 16:42:43 -05:00
Thorsten Hindermann
6c098ce1e0 Update security-governance preset to v0.6.0 (#2932)
* Update security-governance preset to v0.5.0

* Update security-governance preset to v0.6.0
2026-06-16 16:10:27 -05:00
Thorsten Hindermann
3b6c4e7419 Update agent-parity-governance preset to v0.3.0 (#2982) 2026-06-16 14:04:55 -05:00
Thorsten Hindermann
04c74eef49 Update cross-platform-governance preset to v0.2.0 (#2983)
* Update cross-platform-governance preset to v0.2.0

* Address Copilot wording feedback for cross-platform preset
2026-06-16 13:58:02 -05:00
Manfred Riem
194fd08bd8 Add Data Model Diagram extension to community catalog (#2922)
* Add Data Model Diagram extension to community catalog

Add data-model-diagram extension submitted by @benizzio to:
- extensions/catalog.community.json (alphabetical order)
- docs/community/extensions.md community extensions table

Closes #2920

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix author field to match extension.yml manifest

Use the full author name from extension.yml rather than GitHub username.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Align entry timestamps with catalog updated_at date

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>
2026-06-16 13:44:52 -05:00
Manfred Riem
b22834bd4a Add Spec Kit TLDR extension to community catalog (#3007)
Add tldr extension submitted by @qurore to:
- extensions/catalog.community.json (alphabetical order)
- docs/community/extensions.md community extensions table

Closes #2987

Co-authored-by: Manfred Riem <mnriem@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-16 13:30:03 -05:00
Manfred Riem
860a49edb1 docs: add guide for handling complex features (#3004)
* 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>
2026-06-16 13:20:36 -05:00
Manfred Riem
7a3710242c Add Loop Engineering extension to community catalog (#3002)
Add loop extension submitted by @formin to:
- extensions/catalog.community.json (alphabetical order)
- docs/community/extensions.md community extensions table

Closes #2977

Co-authored-by: Manfred Riem <mnriem@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-16 10:10:03 -05:00
Manfred Riem
97d5376fc7 Update MemoryLint extension to v1.5.1 (#3000)
Update memorylint extension submitted by @RbBtSn0w:
- extensions/catalog.community.json (version, download_url, description, provides)
- docs/community/extensions.md community extensions table

Closes #2974

Co-authored-by: Manfred Riem <mnriem@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-16 09:56:48 -05:00
Manfred Riem
33fefde268 Update Superpowers Bridge extension to v1.6.0 (#2998)
* Update Superpowers Bridge extension to v1.6.0

Update superb extension submitted by @RbBtSn0w:
- extensions/catalog.community.json (version, download_url, description, provides, updated_at)
- docs/community/extensions.md community extensions table

Closes #2973

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Align superb catalog author and tags with v1.6.0 manifest

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>
2026-06-16 09:34:35 -05:00
Manfred Riem
70f9242be9 Add Improve Extension to community catalog (#2997)
Add improve extension submitted by @d0whc3r to:
- extensions/catalog.community.json (alphabetical order)
- docs/community/extensions.md community extensions table

Closes #2972

Co-authored-by: Manfred Riem <mnriem@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-16 09:16:56 -05:00
Manfred Riem
7c1d4212db Update Product Forge extension to v1.7.0 (#2996)
Update product-forge extension submitted by @VaiYav:
- extensions/catalog.community.json (version, download_url, description, tags, documentation, updated_at)
- docs/community/extensions.md community extensions table

Closes #2967

Co-authored-by: Manfred Riem <mnriem@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-16 09:03:35 -05:00
Manfred Riem
4384338ec1 Add SpecKit Companion extension to community catalog (#2937)
* Add SpecKit Companion extension to community catalog

Add companion extension submitted by @alfredoperez to:
- extensions/catalog.community.json (alphabetical order)
- docs/community/extensions.md community extensions table

Closes #2926

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address review: multi-line tools format, add vscode tag

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>
2026-06-11 08:16:10 -05:00
Manfred Riem
77af08ba22 Add Research Harness extension to community catalog (#2935)
Add harness extension submitted by @formin to:
- extensions/catalog.community.json (alphabetical order)
- docs/community/extensions.md community extensions table

Closes #2925

Co-authored-by: Manfred Riem <mnriem@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-11 07:53:59 -05:00
Manfred Riem
f5d47720b9 Add Coding Standards Drift Control extension to community catalog (#2934)
Add coding-standards-drift-control extension submitted by @benizzio to:
- extensions/catalog.community.json (alphabetical order)
- docs/community/extensions.md community extensions table

Closes #2923

Co-authored-by: Manfred Riem <mnriem@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-11 07:44:07 -05:00
Quratulain-bilal
4e899d3002 Add Spec Trace extension to community catalog (#2527)
* 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.
2026-06-11 07:34:36 -05:00
Manfred Riem
40e48ed22c feat: add category and effect as first-class fields in extension schema (#2899)
* 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>
2026-06-10 07:44:27 -05:00
Ash Brener
45b88f62be chore(catalog): add Jira Integration (Sync Engine) extension (#2895)
* 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>
2026-06-10 07:43:12 -05:00
Thorsten Hindermann
fa93572e27 Update a11y-governance preset to v0.3.0 (#2867)
* Update a11y-governance preset to v0.3.0

* Fix a11y-governance catalog updated_at
2026-06-09 16:28:45 -05:00
Wondr
0b82a1ddf1 docs: document spec persistence models (#2856) 2026-06-09 15:52:59 -05:00