Skip to content

feat(bug): add issue, PR, and fetch commands plus branch isolation - #4281

Open
arrrrny wants to merge 2 commits into
github:mainfrom
arrrrny:feat/bug-triage-issue-pr-fetch
Open

feat(bug): add issue, PR, and fetch commands plus branch isolation#4281
arrrrny wants to merge 2 commits into
github:mainfrom
arrrrny:feat/bug-triage-issue-pr-fetch

Conversation

@arrrrny

@arrrrny arrrrny commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Extend the bundled Bug Triage Workflow extension:

  • speckit.bug.issue: file a GitHub issue from an assessment (the "report" phase) and record the issue link, degrading to issue-draft.md offline.
  • speckit.bug.pr: open a PR from the fix branch, linking the tracked issue, degrading to pr-draft.md offline.
  • speckit.bug.fetch: load an existing GitHub issue by number/URL/owner#n via gh, record issue.md, and seed an assessment.md draft so fix/test can run.
  • speckit.bug.assess: auto-trigger the issue via --issue or the auto_create_issue config, and clarify that assess != report.
  • speckit.bug.fix: --branch/--worktree isolation mirroring specify spec.

Also updates extension.yml (new commands + gh tool), config-template.yml, README, catalog.json, and the extension test (EXPECTED_COMMANDS -> 6).

Assisted-by: Kimi Code (autonomous)

Description

Testing

  • Tested locally with uv run specify --help
  • Ran existing tests with uv sync && uv run pytest
  • Tested with a sample project (if applicable)

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (describe below)

Extend the bundled Bug Triage Workflow extension:

- speckit.bug.issue: file a GitHub issue from an assessment (the "report"
  phase) and record the issue link, degrading to issue-draft.md offline.
- speckit.bug.pr: open a PR from the fix branch, linking the tracked issue,
  degrading to pr-draft.md offline.
- speckit.bug.fetch: load an existing GitHub issue by number/URL/owner#n via
  gh, record issue.md, and seed an assessment.md draft so fix/test can run.
- speckit.bug.assess: auto-trigger the issue via --issue or the
  auto_create_issue config, and clarify that assess != report.
- speckit.bug.fix: --branch/--worktree isolation mirroring `specify spec`.

Also updates extension.yml (new commands + gh tool), config-template.yml,
README, catalog.json, and the extension test (EXPECTED_COMMANDS -> 6).

Assisted-by: Kimi Code (autonomous)
Copilot AI balanced review requested due to automatic review settings August 22, 2026 14:59
@arrrrny
arrrrny requested a review from mnriem as a code owner August 22, 2026 14:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Extends the bundled bug workflow with GitHub issue/PR operations, issue fetching, configuration, and branch isolation.

Changes:

  • Adds issue, fetch, and PR commands.
  • Adds configurable issue creation and branch isolation.
  • Updates documentation, manifest, catalog, and tests.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
extensions/bug/commands/speckit.bug.assess.md Adds optional issue reporting.
extensions/bug/commands/speckit.bug.fetch.md Adds existing-issue ingestion.
extensions/bug/commands/speckit.bug.fix.md Adds branch/worktree isolation.
extensions/bug/commands/speckit.bug.issue.md Adds GitHub issue creation.
extensions/bug/commands/speckit.bug.pr.md Adds pull-request creation.
extensions/bug/config-template.yml Defines workflow defaults.
extensions/bug/extension.yml Registers commands, configuration, and gh.
extensions/bug/README.md Documents the expanded workflow.
extensions/catalog.json Updates the bundled extension description.
tests/extensions/bug/test_bug_extension.py Updates command and configuration checks.
Suppressed comments (2)

extensions/bug/commands/speckit.bug.fetch.md:37

  • A URL or owner/repo#n already supplies the repository, but this prerequisite still refuses a live fetch unless the current directory has a GitHub origin. That unnecessarily degrades valid cross-repository fetches (and fetches outside a Git worktree) to a draft; require the remote only for bare issue numbers.
- Detect GitHub context (same as `__SPECKIT_COMMAND_BUG_ISSUE__`):
  - `git rev-parse --is-inside-work-tree 2>/dev/null` to confirm a repository.
  - `git config --get remote.origin.url` to read the remote; parse `owner`/`repo` (HTTPS `https://github.com/<owner>/<repo>.git` or SSH `git@github.com:<owner>/<repo>.git`). Only proceed with a live fetch when the remote points to `github.com`.
  - `command -v gh >/dev/null 2>&1` and `gh auth status` to confirm the CLI and auth. If `gh`/GitHub remote/auth is unavailable, skip the live fetch and write a draft (see Graceful Degradation).

extensions/bug/README.md:115

  • This again states that assess “never touches GitHub,” which is false when --issue or auto_create_issue is enabled. Describe the local-only behavior as the default and disclose that opt-in reporting delegates to bug.issue.
- **Assess** means *triage a report into a local `assessment.md`* — it never touches GitHub. Use it for a bug described in pasted text or a URL.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +57 to +63
3. **Open the PR (live path)**
- Determine the base branch: prefer the repository default (usually `main`/`master`); allow the user to override with `base=<branch>` in `$ARGUMENTS`.
- Run:
```bash
gh pr create --base <base> --title "<title>" --body-file BUG_DIR/pr-body.md --json number,url,title
```
- Capture the JSON. If the push of the current branch fails, run `git push -u origin <current-branch>` and retry.
Comment on lines +62 to +66
- Run:
```bash
gh issue create --title "<title>" --body-file BUG_DIR/issue-body.md --label "bug" --label "severity:<level>" --json number,url,title
```
- Capture the JSON. **If a label is rejected** (the repo does not have it), retry without the `severity:<level>` label, then without any labels — a tracked issue is better than none. Record the final outcome either way.
Comment on lines +54 to +55
- **Branch mode** (`--branch`): run `git checkout -b <prefix>/<BUG_SLUG>` from the current branch (assumed clean or committed).
- **Worktree mode** (`--worktree`): run `git worktree add ../<repo>-<BUG_SLUG> -b <prefix>/<BUG_SLUG>` so the fix lives in a separate working directory; then continue operations there.

## Slug Resolution

Each bug gets its own directory under `.specify/bugs/<slug>/`. If the user passed a slug, use it verbatim after normalization (lowercase, hyphen-separated, no spaces, no special characters other than `-` and digits). Otherwise derive a 2–4 word kebab-case slug from the issue **title**. Ensure the directory is unique — if `.specify/bugs/<slug>/` already exists, append the shortest disambiguating suffix (`-2`, `-3`, …) or `-<issue-number>`. Never overwrite an existing bug directory.
Comment on lines +135 to +136
- `__SPECKIT_COMMAND_BUG_ASSESS__ slug=<BUG_SLUG>` (refine the triage draft into a full assessment) — optional.
- `__SPECKIT_COMMAND_BUG_FIX__ slug=<BUG_SLUG>` (apply the fix; add `--branch` or `--worktree` to isolate).
- Parse the user input for `branch` / `--branch` / `worktree` / `--worktree` (or `branch=true` / `worktree=true`). These are mutually exclusive; prefer `--branch` unless the user explicitly asks for a worktree.
- Determine the branch name `<prefix>/<BUG_SLUG>`, where `<prefix>` comes from `.specify/extensions/bug/bug-config.yml` (`branch_prefix`, default `fix`). Example: `fix/login-timeout`. If a branch with that name already exists, stop and ask the user how to proceed (reuse it, choose another name, or skip isolation).
- **Branch mode** (`--branch`): run `git checkout -b <prefix>/<BUG_SLUG>` from the current branch (assumed clean or committed).
- **Worktree mode** (`--worktree`): run `git worktree add ../<repo>-<BUG_SLUG> -b <prefix>/<BUG_SLUG>` so the fix lives in a separate working directory; then continue operations there.
Comment on lines +167 to +168
- **Explicit opt-in**: if the user passed a truthy `issue` / `--issue` flag, file the issue now.
- **Config opt-in**: if `.specify/extensions/bug/bug-config.yml` exists and sets `auto_create_issue: true`, file the issue now.
Comment on lines +38 to +39
- `BUG_DIR/fix.md` MUST exist. If it does not, stop and instruct the user to run `__SPECKIT_COMMAND_BUG_FIX__` first.
- Confirm the current branch is the fix branch (created by `bug.fix --branch`, or whatever branch holds the change). If the working tree is on `main`/`master` with uncommitted changes, warn the user and ask which branch to open the PR from before continuing.
Comment thread extensions/bug/README.md
1. **Assess** — read a bug report (pasted text or a URL), judge whether it is a real bug, locate suspected code paths, and propose a remediation.
2. **Fix** — apply the proposed remediation and record exactly what changed.
3. **Test** — re-run the reproduction and any added tests, then record the verification result.
1. **Assess** — read a bug report (pasted text or a URL), judge whether it is a real bug, locate suspected code paths, and propose a remediation. `assess` writes a *local* assessment only; it does **not** file a GitHub issue.
Comment thread extensions/bug/README.md
Comment on lines +12 to +14
3. **Fix** — apply the proposed remediation and record exactly what changed. Pass `--branch` (or `--worktree`) to isolate the fix on its own git branch.
4. **Open PR** (optional) — `speckit.bug.pr` opens a pull request from the fix branch, linking the issue.
5. **Test** — re-run the reproduction and any added tests, then record the verification result.
- bug.issue / bug.pr: stop using `gh ... create --json`, which older gh
  versions reject ("unknown flag: --json"). Capture the issue/PR URL from
  stdout instead and parse the number from it.
- bug.fetch: same treatment — use plain `gh issue view` and read the
  rendered output rather than `--json`.
- bug.assess: make the auto_create_issue config check explicit and
  mandatory (read bug-config.yml; if auto_create_issue is true, file the
  issue without further confirmation) so the opt-in actually fires.

Assisted-by: Kimi Code (autonomous)
Copilot AI review requested due to automatic review settings August 22, 2026 15:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Suppressed comments (11)

Previously missed (9) — in code that hasn't changed since the last review.

extensions/bug/extension.yml:7

  • The extension still reports version 1.0.0, so specify extension update will consider existing 1.0.0 installations up to date (_commands.py:1660-1671) and they will never receive these new commands. Bump the manifest and catalog entry together (for example to 1.1.0) and refresh the catalog timestamp.
  description: "Assess, load or report (GitHub issue), fix, and validate bug reports against the codebase, with optional branch isolation and PR creation; per-bug reports stored under .specify/bugs/<slug>/"

extensions/bug/extension.yml:16

  • The new branch/worktree and PR paths invoke Git, but the manifest declares only gh. Add optional git metadata as the bundled Git extension does at extensions/git/extension.yml:14-16, otherwise prerequisite/tool reporting omits a tool required by these features.
  tools:
    - name: gh
      required: false

extensions/bug/commands/speckit.bug.fetch.md:37

  • Live fetches by URL or owner/repo#n are unnecessarily blocked unless the current directory is a Git repository with a GitHub origin. Those input forms already supply the repository, so only a bare issue number should depend on the current remote.
- Detect GitHub context (same as `__SPECKIT_COMMAND_BUG_ISSUE__`):
  - `git rev-parse --is-inside-work-tree 2>/dev/null` to confirm a repository.
  - `git config --get remote.origin.url` to read the remote; parse `owner`/`repo` (HTTPS `https://github.com/<owner>/<repo>.git` or SSH `git@github.com:<owner>/<repo>.git`). Only proceed with a live fetch when the remote points to `github.com`.
  - `command -v gh >/dev/null 2>&1` and `gh auth status` to confirm the CLI and auth. If `gh`/GitHub remote/auth is unavailable, skip the live fetch and write a draft (see Graceful Degradation).

extensions/bug/commands/speckit.bug.pr.md:39

  • bug.fix only edits files and never commits them, but gh pr create cannot include uncommitted changes. Require the intended fix to be committed (and the working tree clean) before creating the PR, or explicitly obtain consent to create a commit here; pushing an unchanged branch and retrying will not solve this failure.
- `BUG_DIR/fix.md` MUST exist. If it does not, stop and instruct the user to run `__SPECKIT_COMMAND_BUG_FIX__` first.
- Confirm the current branch is the fix branch (created by `bug.fix --branch`, or whatever branch holds the change). If the working tree is on `main`/`master` with uncommitted changes, warn the user and ask which branch to open the PR from before continuing.

extensions/bug/commands/speckit.bug.fix.md:54

  • Creating the branch without checking the working tree carries all pre-existing edits onto the fix branch, so the advertised isolation can mix unrelated work into the eventual commit/PR. Inspect Git status first and ask the user to commit, stash, or cancel when changes predate this fix.
- **Branch mode** (`--branch`): run `git checkout -b <prefix>/<BUG_SLUG>` from the current branch (assumed clean or committed).

extensions/bug/README.md:9

  • The overview says assess does not file an issue, but two lines later documents its --issue/config auto-create behavior. Qualify this as the default behavior so the workflow description is internally consistent.

This issue also appears on line 115 of the same file.

1. **Assess** — read a bug report (pasted text or a URL), judge whether it is a real bug, locate suspected code paths, and propose a remediation. `assess` writes a *local* assessment only; it does **not** file a GitHub issue.

extensions/bug/README.md:14

  • The ordered workflow repeats step 3 and leaves the final stage numbered 5 even though six stages are listed. Renumber these entries to preserve the documented sequence.
3. **Fix** — apply the proposed remediation and record exactly what changed. Pass `--branch` (or `--worktree`) to isolate the fix on its own git branch.
4. **Open PR** (optional) — `speckit.bug.pr` opens a pull request from the fix branch, linking the issue.
5. **Test** — re-run the reproduction and any added tests, then record the verification result.

extensions/bug/README.md:98

  • Without an explicit slug, fetch derives one from the issue title, so it is not guaranteed to be callback-token. Using that hard-coded slug in the next commands can target a different bug or fail; tell users to reuse the slug reported by fetch.
# Then proceed straight to the fix on its own branch
/speckit.bug.fix slug=callback-token --branch
/speckit.bug.pr slug=callback-token

tests/extensions/bug/test_bug_extension.py:64

  • This only proves the source template exists; it does not verify the new manifest entry or the promised deployment to .specify/extensions/bug/bug-config.yml. Extend the install test to invoke config scaffolding and assert the deployed file/content, so a broken provides.config declaration is caught.
    def test_config_template_exists(self):
        assert (EXT_DIR / "config-template.yml").is_file()

extensions/bug/commands/speckit.bug.fetch.md:28

  • Slug resolution requires the fetched issue title before the fetch occurs, and when gh is unavailable there is no title at all, so the promised offline issue-draft.md path cannot determine BUG_DIR. Parse the reference and fetch first, then derive the title-based slug; define a fallback such as issue-<number> for degraded fetches.
Each bug gets its own directory under `.specify/bugs/<slug>/`. If the user passed a slug, use it verbatim after normalization (lowercase, hyphen-separated, no spaces, no special characters other than `-` and digits). Otherwise derive a 2–4 word kebab-case slug from the issue **title**. Ensure the directory is unique — if `.specify/bugs/<slug>/` already exists, append the shortest disambiguating suffix (`-2`, `-3`, …) or `-<issue-number>`. Never overwrite an existing bug directory.

After resolution, set `BUG_SLUG` and `BUG_DIR = .specify/bugs/<BUG_SLUG>`.

extensions/bug/README.md:115

  • This absolute statement conflicts with the documented --issue and auto_create_issue modes, where assess does touch GitHub. State that assess is local-only by default and identify those explicit exceptions.
- **Assess** means *triage a report into a local `assessment.md`* — it never touches GitHub. Use it for a bug described in pasted text or a URL.

Comment on lines +167 to +169
1. **Explicit opt-in**: if the user passed a truthy `issue` / `--issue` flag (or `issue=true`), file the issue now.
2. **Config opt-in**: read `.specify/extensions/bug/bug-config.yml` (scaffolded at install). If it exists and `auto_create_issue` is `true` (or `1` / `yes` / `on`), file the issue now — the user enabled this explicitly, so no further confirmation is required.
3. **Otherwise**: do not file it; only **suggest** the issue step in the report-back below.
2. **Fetch the issue (live path)**
- Run (no `--json` — it is unsupported on older `gh`; read the rendered output instead):
```bash
gh issue view <number> --repo <owner>/<repo>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants