feat(extensions): add bundled bug triage workflow extension#2871
Merged
Conversation
) 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 github#2870
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new bundled bug extension to Spec Kit that defines a three-stage bug triage workflow (assess → fix → test) with standardized per-bug Markdown reports written under .specify/bugs/<slug>/. This fits the existing bundled-extension model (manifest + command markdowns) and registers the extension in the bundled catalog and wheel packaging.
Changes:
- Register bundled
bugextension inextensions/catalog.json. - Add the
bugextension manifest + command markdowns + README underextensions/bug/. - Include
extensions/bugin wheelforce-includemappings inpyproject.toml.
Show a summary per file
| File | Description |
|---|---|
| pyproject.toml | Bundles the extensions/bug directory into the wheel. |
| extensions/catalog.json | Registers the new bundled bug extension metadata and tags. |
| extensions/bug/README.md | Documents the workflow, commands, slug conventions, and guardrails. |
| extensions/bug/extension.yml | Declares the extension manifest + the three provided commands. |
| extensions/bug/commands/speckit.bug.assess.md | Defines the assess-stage workflow and report contract. |
| extensions/bug/commands/speckit.bug.fix.md | Defines the fix-stage workflow and report contract. |
| extensions/bug/commands/speckit.bug.test.md | Defines the test-stage workflow and report contract. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 7/7 changed files
- Comments generated: 3
- 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.
- 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.
- 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.
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.
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2870
Summary
Adds a bundled
bugextension that provides a three-stage bug triage workflow any AI coding agent can drive:speckit.bug.assess— read a bug report (pasted text or URL), judge whether it is a real bug, locate suspected code paths, and propose a remediation.speckit.bug.fix— apply the proposed remediation and record exactly what changed.speckit.bug.test— re-run the reproduction and any added tests, then record the verification result.Each stage writes a Markdown report into a per-bug directory:
Design
Slug
A slug is the per-bug directory name and the only handle the three commands share.
login-timeout,cve-2026-001). No timestamps or numbers appended automatically.speckit.bug.assessasks for a slug when none is supplied, suggesting a kebab-case default derived from the bug summary.-2,-3, …) or short date (-20260605) when needed. Existing directories are never overwritten.Guardrails
speckit.bug.assessandspeckit.bug.testnever modify source code; they read the repository and write only inside.specify/bugs/<slug>/.speckit.bug.fixis the only command that edits source code, scoped to the files listed in the assessment unless new evidence requires expanding scope (logged under Deviations from Assessment infix.md).partialornot-run, neververified.Changes
extensions/bug/extension.yml— manifest (id, version, three commands)extensions/bug/commands/speckit.bug.{assess,fix,test}.mdextensions/bug/README.mdextensions/catalog.json— registerbug(alphabetical, betweenagent-contextandgit)pyproject.toml— wheel mapping tospecify_cli/core_pack/extensions/bugMirrors the layout of the existing bundled extensions (
extensions/git/,extensions/agent-context/). Uses the existing extension registration / skills pipeline — no new CLI commands or core machinery.Validation
extension.ymlandextensions/catalog.json.tests/test_extensions.pyandtests/test_extension_registration.py.Posted on behalf of @mnriem by GitHub Copilot (model: Claude Opus 4.7).