Files
github-spec-kit/extensions
Manfred Riem 60302fefec feat(extensions): add bundled bug triage workflow extension (#2871)
* feat(extensions): add bundled bug triage workflow extension (#2870)

Add a bundled 'bug' extension providing a three-stage bug triage workflow:

- speckit.bug.assess: triage a bug report (pasted text or URL), locate
  suspected code paths, and propose a remediation
- speckit.bug.fix: apply the proposed remediation and record what changed
- speckit.bug.test: validate the fix and record the verification result

Each bug gets its own directory under .specify/bugs/<slug>/ with one
Markdown report per stage (assessment.md, fix.md, test.md). The slug is
the only handle the three commands share; existing bug directories are
never overwritten.

Mirrors the layout of the existing bundled extensions (git, agent-context):

- extensions/bug/extension.yml, README.md, commands/
- extensions/catalog.json: register 'bug' (alphabetical, between
  agent-context and git)
- pyproject.toml: add wheel mapping to specify_cli/core_pack/extensions/bug

Closes #2870

* address Copilot review on #2871

- speckit.bug.assess.md: drop POSIX-specific 'mkdir -p' example;
  reword the prerequisite to describe the requirement (ensure BUG_DIR
  exists) without assuming a specific shell.
- speckit.bug.fix.md: fix the slug-resolution fallback wording. It
  listed '.specify/bugs/*/assessment.md' but then keyed off whether
  'exactly one bug directory' existed; now it correctly keys off whether
  exactly one matching 'assessment.md' was found and uses the slug from
  its parent directory.
- tests/extensions/bug/test_bug_extension.py: add a smoke test analogous
  to the agent-context extension's coverage. Validates the bundled
  layout, catalog registration, '_locate_bundled_extension("bug")'
  resolution, and that 'ExtensionManager.install_from_directory' installs
  the three commands.

All 333 tests in tests/extensions/, tests/test_extensions.py, and
tests/test_extension_registration.py pass.

* address Copilot review on #2871 (round 2)

- Import _locate_bundled_extension from the public 'specify_cli'
  package (it is re-exported in __init__.py) instead of the private
  'specify_cli._assets' module, so the test does not depend on internal
  module layout.
- Clarify module docstring: install_from_directory is called with
  register_commands=False, so commands are copied and recorded in the
  installed manifest but not registered with AI agents. Wording updated
  to avoid implying otherwise.

* address Copilot review on #2871 (round 3)

- tests/extensions/bug/test_bug_extension.py: read extension.yml as
  UTF-8 explicitly to avoid platform-dependent default encoding (notably
  on Windows). Matches how the README is read in the same module.
- extensions/bug/commands/speckit.bug.assess.md: add a 'Safety When
  Fetching URLs' section. Instructs the agent to treat fetched page
  content as untrusted input (no obeying embedded prompt-injection
  directives), forbids supplying credentials/secrets that a page asks
  for, scopes the fetch to the URL the user provided (no following
  redirects to other resources), and requires suspicious content to be
  quoted verbatim under an 'Unverified' heading rather than acted on.
- extensions/catalog.json: bump 'updated_at' to today (2026-06-05) so
  consumers that cache by this field invalidate when 'bug' is added.
- extensions/bug/README.md: minor grammar fix ('a reproduction that was
  not actually performed').

All 251 tests in tests/extensions/bug/, tests/test_extensions.py, and
tests/test_extension_registration.py pass.

* speckit.bug.assess: add URL Trust Policy for fetched bug-report URLs

Builds on the 'Safety When Fetching URLs' section by adding a tiered
classification rule the agent applies before any fetch:

1. Refuse outright (no fetch, no prompt) for non-http(s) schemes,
   loopback, link-local, RFC1918 private space, and known cloud
   instance-metadata endpoints (169.254.169.254, metadata.google.internal,
   100.100.100.200, metadata.azure.com). This closes the SSRF /
   internal-recon vector opened by 'paste any URL'.
2. Fetch silently for an explicit allowlist of widely-used public
   bug-report sources (github, gitlab, bitbucket, atlassian.net, linear,
   stackoverflow/stackexchange, sentry). This preserves the paste-a-URL
   ergonomics the workflow is built for.
3. Otherwise prompt once in interactive mode (default 'no', naming the
   resolved host explicitly); in automated mode skip the fetch and
   record '[UNVERIFIED - fetch skipped: host not on safe list: <host>]'
   in assessment.md so a human can decide later.

In every case, assessment.md records the verbatim URL, the resolved host,
and which branch of the policy was taken (allowlisted /
confirmed-by-user / auto-refused: <reason>) so the per-bug directory's
audit trail is complete. Preflight HEAD probes are explicitly forbidden
since the probe itself is the request the policy gates.

Execution step 1 now defers to the policy before fetching.

* speckit.bug.assess: remove 'post-redirect-resolution' inconsistency

The URL Trust Policy explicitly forbids following redirects, but the
audit-trail bullet asked the agent to record the host
'post-redirect-resolution', which contradicted that rule and could lead
agents to follow redirects unintentionally to determine what to log.

Reword both call sites to refer to the host parsed from the URL the user
supplied (no resolution implied):

- Tier-3 interactive prompt: '...naming the host parsed from the URL
  explicitly...'
- Recorded fields: 'The host parsed from that URL (no redirect following
  - see the rule above).'

No behavior change; clarification only.
2026-06-05 12:37:25 -05:00
..

Spec Kit Extensions

Extension system for Spec Kit - add new functionality without bloating the core framework.

Extension Catalogs

Spec Kit provides two catalog files with different purposes:

Your Catalog (catalog.json)

  • Purpose: Default upstream catalog of extensions used by the Spec Kit CLI
  • Default State: Empty by design in the upstream project - you or your organization populate a fork/copy with extensions you trust
  • Location (upstream): extensions/catalog.json in the GitHub-hosted spec-kit repo
  • CLI Default: The specify extension commands use the upstream catalog URL by default, unless overridden
  • Org Catalog: Point SPECKIT_CATALOG_URL at your organization's fork or hosted catalog JSON to use it instead of the upstream default
  • Customization: Copy entries from the community catalog into your org catalog, or add your own extensions directly

Example override:

# Override the default upstream catalog with your organization's catalog
export SPECKIT_CATALOG_URL="https://your-org.com/spec-kit/catalog.json"
specify extension search  # Now uses your organization's catalog instead of the upstream default

Community Reference Catalog (catalog.community.json)

Note

Community extensions are independently created and maintained by their respective authors. Maintainers only verify that catalog entries are complete and correctly formatted — they do not review, audit, endorse, or support the extension code itself. Review extension source code before installation and use at your own discretion.

  • Purpose: Browse available community-contributed extensions
  • Status: Active - contains extensions submitted by the community
  • Location: extensions/catalog.community.json
  • Usage: Reference catalog for discovering available extensions
  • Submission: Open to community contributions via issue template

How It Works:

Making Extensions Available

You control which extensions your team can discover and install:

Populate your catalog.json with approved extensions:

  1. Discover extensions from various sources:
    • Browse catalog.community.json for community extensions
    • Find private/internal extensions in your organization's repos
    • Discover extensions from trusted third parties
  2. Review extensions and choose which ones you want to make available
  3. Add those extension entries to your own catalog.json
  4. Team members can now discover and install them:
    • specify extension search shows your curated catalog
    • specify extension add <name> installs from your catalog

Benefits: Full control over available extensions, team consistency, organizational approval workflow

Example: Copy an entry from catalog.community.json to your catalog.json, then your team can discover and install it by name.

Option 2: Direct URLs (For Ad-hoc Use)

Skip catalog curation - team members install directly using URLs:

specify extension add <extension-name> --from https://github.com/org/spec-kit-ext/archive/refs/tags/v1.0.0.zip

Benefits: Quick for one-off testing or private extensions

Tradeoff: Extensions installed this way won't appear in specify extension search for other team members unless you also add them to your catalog.json.

Available Community Extensions

Note

Community extensions are independently created and maintained by their respective authors. Maintainers only verify that catalog entries are complete and correctly formatted — they do not review, audit, endorse, or support the extension code itself. The Community Extensions website is also a third-party resource. Review extension source code before installation and use at your own discretion.

🔍 Browse and search community extensions on the Community Extensions website.

See the Community Extensions page for the full list of available community-contributed extensions.

For the raw catalog data, see catalog.community.json.

Adding Your Extension

Submission Process

To add your extension to the community catalog:

  1. Prepare your extension following the Extension Development Guide
  2. Create a GitHub release for your extension
  3. File an issue using the Extension Submission template with all required metadata
  4. Wait for review — a maintainer will review the submission, update the catalog, and close the issue

See the Extension Publishing Guide for detailed step-by-step instructions.

Submission Checklist

Before submitting, ensure:

  • Valid extension.yml manifest
  • Complete README with installation and usage instructions
  • LICENSE file included
  • GitHub release created with semantic version (e.g., v1.0.0)
  • Extension tested on a real project
  • All commands working as documented

Installing Extensions

Once extensions are available (either in your catalog or via direct URL), install them:

# From your curated catalog (by name)
specify extension search                  # See what's in your catalog
specify extension add <extension-name>    # Install by name

# Direct from URL (bypasses catalog)
specify extension add <extension-name> --from https://github.com/<org>/<repo>/archive/refs/tags/<version>.zip

# List installed extensions
specify extension list

For more information, see the Extension User Guide.