Skip to content
| Marketplace
Sign in
Visual Studio Code>AI>Ticket SidekickNew to Visual Studio Code? Get it now.
Ticket Sidekick

Ticket Sidekick

Robert Breunung

|
8 installs
| (0) | Free
Manage Jira tickets with GitHub Copilot Chat
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Ticket Sidekick

CI

Two independent GitHub Copilot Chat participants — use one or both:

  • @jira — manage Jira tickets in natural language (create, read, update, comment, bulk transitions, create from email)
  • @bitbucket — review Bitbucket pull requests with structured AI analysis and multi-turn follow-ups

Neither participant requires the other to be configured.


@jira — Jira

Prerequisites

  • VS Code 1.90 or later with GitHub Copilot extension
  • Jira Data Center (v8+) or any Jira Cloud instance

Setup

1. Set the Jira base URL

Open VS Code settings (Ctrl+, / Cmd+,) and add:

"ticketSidekick.jira.baseUrl": "https://jira.mycompany.com"

For Jira Cloud: "https://your-org.atlassian.net"

2. Set your auth type (Cloud only)

"ticketSidekick.jira.authType": "cloud"

Omit this setting for Data Center (default).

3. Store your credentials

Data Center: Open the Command Palette (Ctrl+Shift+P) → Ticket Sidekick: Set Jira Personal Access Token

Cloud: Open the Command Palette → Ticket Sidekick: Configure Jira Cloud Credentials (You will need your Atlassian email and an API token from id.atlassian.com)

Core commands

Open GitHub Copilot Chat and use @jira:

What you type What happens
@jira show PROJ-123 Full ticket: all non-null fields in a metadata table, formatted description, one-line comment summaries
@jira load PROJ-123 Download full ticket context into .jira-context/PROJ-123/ — ticket.md, comments.md, and attachments — so the AI can reason over them alongside your code
@jira show fields on PROJ-123 Table of every field: name, ID, and current value — use to discover IDs for additionalDisplayFields
@jira summarize PROJ-123 Same fields as show, but description + comments replaced by a one-paragraph AI synthesis
@jira show comments Full formatted comment bodies numbered — use when you want to read the actual text
@jira what do the comments say about the login bug? LLM synthesis filtered to a topic
@jira create a bug: login times out Resolves template and type, then shows a preview — reply "create it" to confirm
@jira create Story in VSJI: add dark mode Creates a ticket with project and type from the prompt — shows preview before creating
@jira set priority to High Updates any field by name (exact or fuzzy-matched) on the current branch ticket
@jira set labels to backend, urgent Replaces entire array field (comma-separated)
@jira add frontend to labels Appends to an array field, deduplicates
@jira remove backend from labels Removes items from an array field
@jira set sprint to Sprint 4 Sets sprint field — fuzzy-matched by name, resolved to sprint ID
@jira set customfield_10500 to ASL QRF Updates any custom field by ID
@jira assign this to jane.doe Assigns ticket (searches Jira by display name)
@jira assign to me Assigns ticket to the currently logged-in user
@jira update the description based on our conversation Generates a new description from context — shows preview before posting
@jira comment that the fix is in PR [#42](https://github.com/rbreunung/ticket-sidekick/issues/42) Adds a comment
@jira move to Done Transitions the current ticket to a target status
@jira move to Cancelled with resolution "Not a Bug" Transitions and sets a resolution in one step
@jira find open bugs assigned to me Runs JQL search
@jira check required fields on PROJ-123 Validates required fields
@jira check Validates the base URL, tests the connection, and shows active configuration
@jira create from email Create a Jira ticket from an imported .eml file

Reading tickets

Show vs summarize

There are two distinct ways to read a ticket:

Command What you get
@jira show PROJ-123 All non-null fields in a metadata table, multi-line fields (description, rich-text custom fields) in their own sections, numbered one-line comment summaries, linked issues, and web links
@jira summarize PROJ-123 Same fields, but description and comments replaced by a one-paragraph AI synthesis

The ticket key in the heading is a clickable link to the ticket in your browser. Search results (@jira find …) also produce clickable keys in the results table.

@jira show appends two additional sections when data is present:

  • Linked Issues — every issue link (blocks, is blocked by, relates to, etc.) with linked ticket key, summary, and status
  • Web Links — remote links attached to the ticket (Confluence pages, external documents, etc.)

And two ways to read comments:

Command What you get
@jira show comments Full comment bodies numbered — Markdown-rendered, separated by dividers
@jira what do comments say about X? AI synthesis filtered to the topic you named

After seeing numbered comments you can always ask to view one in full:

3
show comment 2
comment 4

If a ticket has more than 20 comments the response ends with an offer to load the rest:

… 5 older comment(s) not shown. Reply "load all" to include them.

Reply load all to fetch up to 100 comments. For show comments the full bodies are rendered; for synthesised views the summary is regenerated over all comments.

Loading ticket context

@jira load PROJ-123 downloads the complete ticket into .jira-context/PROJ-123/ in your workspace root:

.jira-context/
  PROJ-123/
    ticket.md       ← all fields in the same layout as @jira show, plus linked issues, web links, and attachment index
    comments.md     ← every comment in full, chronological order
    attachments/
      screenshot.png
      error.log
      report.pdf

Once loaded, your AI assistant (GitHub Copilot, Cursor, etc.) can read these files directly during coding sessions — no additional prompting required.

File type Criterion Action
Text / source text/* MIME type or known text extension Downloaded
Images image/* MIME type Downloaded
Documents .pdf, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .odt, .ods, .odp, .rtf, .csv Downloaded
Archives .zip, .tar, .gz, .tgz, .bz2, .7z, .rar, .jar, .war, .ear Downloaded
Oversized File larger than 100 MB Skipped — listed in ticket.md with size
Unknown binary Any other MIME type not covered above Skipped — listed in ticket.md with size

Up to three attachments are downloaded in parallel.

When a load completes with skipped attachments, the response shows a numbered list. To download on demand:

1              ← download attachment [#1](https://github.com/rbreunung/ticket-sidekick/issues/1)
download 1     ← same
1 2 3          ← download attachments [#1](https://github.com/rbreunung/ticket-sidekick/issues/1), [#2](https://github.com/rbreunung/ticket-sidekick/issues/2), and [#3](https://github.com/rbreunung/ticket-sidekick/issues/3) in one reply
download 1 3   ← same, with keyword prefix

.jira-context/ is automatically added to .gitignore at your workspace root the first time you run @jira load.

Ticket detection

If you don't name a ticket, the plugin resolves it in this order:

  1. Explicit key in your prompt (PROJ-123)
  2. Current git branch — feature/PROJ-123-my-work → PROJ-123
  3. Last ticket referenced earlier in the chat session
  4. Input box — the plugin asks you

This means you can @jira show PROJ-123, then immediately follow up with @jira add a comment: done without repeating the key.

Descriptions and comments — rich formatting

Descriptions and comments are rendered as Markdown. Jira wiki markup (bold, italic, monospace, code blocks, bullet lists) and legacy ADF content are both converted automatically — no configuration required.

Creating tickets

Running @jira create starts a guided flow:

  1. Template — if .jira-templates.json is present, a numbered list is shown in chat. Pick by number, name, or reply n for no template. Reply c to cancel.
  2. Summary — extracted from your prompt if provided; otherwise the plugin asks in chat. Providing the summary upfront is usually faster.
  3. Issue type — taken from the template or your prompt. If neither provides one, the plugin shows a numbered list of issue types for the project.
  4. Description sections — if the chosen template defines descriptionSections, the plugin asks each question in sequence, building the description incrementally.
  5. Preview — a full ticket card is shown: summary, issue type, project, template (if any), and description. Reply "create it" (or yes, ok, confirm) to create the ticket. Reply with a refinement instruction to adjust the description and see a new preview. Reply c to cancel.

Examples:

@jira create a bug

→ Template list shown. After picking a template, the plugin asks "What should the summary be?"

@jira create a bug: stale loans not returning after grace period

→ Template list shown. Summary is extracted from the prompt — no additional question.

@jira create Story in VSJI: dark mode — assign to jane.doe, components Backend

→ Project key VSJI, issue type Story, summary, assignee, and components all parsed from the prompt.

You can include these directly in the create prompt and the plugin will extract them without asking:

In your prompt What it sets
assign to me / assign to <name> Assignee (resolved via Jira user search)
components Backend, API Components field

Field updates

@jira set <field> to <value> works for any editable Jira field — built-in fields, custom fields, and sprint.

Field name matching is fuzzy: the plugin tries an exact match first, then prefix, then substring. If multiple fields match, a numbered disambiguation list is shown. Use field IDs (e.g. customfield_10500) for an exact, unambiguous match.

Array operations let you add to or remove from multi-value fields without overwriting existing entries:

What you type Effect
@jira set labels to backend, urgent Replace entire labels array
@jira add frontend to labels Append frontend, deduplicate
@jira remove backend from labels Remove backend from the array

Sprint fields are resolved by fuzzy name match against active and future sprints in the project. If multiple sprints match, a numbered list is shown.

Preview before writing: every field update streams a confirm screen before writing. Reply ok to apply, (c) to cancel, or give an adjustment instruction.

Scope: if your last search returned multiple tickets, the plugin asks whether to apply to the current ticket or all N results from the search.

Spell check on demand: run @jira spell check PROJ-123 to check and correct spelling and grammar on a ticket's description. The corrected version is shown as a preview before applying.

Content generation and preview

When you ask @jira to write content — for a new ticket, a comment, or a description update — the plugin shows a preview before posting:

@jira create a bug: login times out after entering password
@jira write a comment summarizing what we agreed on
@jira update the description based on our conversation
@jira draft a comment from the last few messages

The draft is streamed to chat. You then reply:

  • post it (or yes, looks good) — posts the content immediately
  • Any refinement instruction — regenerates with your feedback applied, shows a new preview
  • cancel (or never mind) — discards the draft without posting

If you provide explicit literal text the preview is skipped and the comment is posted directly:

@jira comment: ready for QA, all tests passing
@jira add comment "approved"

The plugin infers which mode to use from your phrasing — "write", "draft", "summarize", "based on our discussion", and similar phrases trigger generation. Quoted text or direct statements post literally.

Transitions and bulk cleanup

Transitioning a single ticket

Move a ticket to a target status by name:

@jira move to Done
@jira close this
@jira transition PROJ-123 to In Review
@jira move to Cancelled with resolution "Not a Bug"

The plugin resolves the ticket from context (current prompt, git branch, or last referenced key). It then fetches the ticket's available transitions and finds the one whose destination matches the target name (case-insensitive).

If the target state requires multiple hops (e.g. Open → In Review → Done), the plugin falls back to the workflow cache automatically — no extra steps needed as long as you have run @jira discover workflow at least once for that project and issue type.

If no path is found, the response lists the directly reachable states from the current status.

Resolution — include with resolution "<name>" to set the resolution field on the final transition in one command.

Workflow discovery (required for bulk transitions)

Before running cleanup rules or bulk status transitions, teach the plugin your Jira workflow:

@jira discover workflow BILLING Bug

This samples tickets across all statuses, queries their available transitions, and saves a workflow graph to .jira-workflow-cache.json at your workspace root. Re-run whenever your Jira workflow changes.

The plugin uses this graph to find the shortest transition path from each ticket's current status to the target state — for both single-ticket move commands and bulk cleanup runs.

Tip: Commit .jira-workflow-cache.json to share it with your team so everyone benefits from a single discovery run.

Bulk cleanup

Run a named cleanup rule to transition a batch of tickets to a target state:

@jira run cleanup "Close released bugs"

Or target a specific fix version ad-hoc:

@jira close BILLING bugs in "Release 3.2"

More examples:

@jira close BILLING bugs with resolution Fixed
@jira run cleanup "Close released bugs" with resolution "Won't Fix"
@jira run cleanup "Close released bugs" in released
@jira run cleanup "Close released bugs" in "Release*"

The plugin:

  1. Builds the effective JQL and shows it as a scope preview (including ticket count) before executing
  2. Searches for tickets matching the scope — tickets that already have a resolution set are automatically excluded
  3. If closeSubtasks is true, fetches all open subtasks in a single query (also excluding pre-resolved ones)
  4. Asks for a resolution once if neither the rule nor your prompt provides one and the target state is a closed state
  5. Shows a review screen listing every ticket and subtask, the transition path each will follow, and the resolution that will be applied

On the review screen, reply:

  • ok — execute all transitions
  • (c) or cancel — abort the entire run
  • ticket number(s) — skip those tickets (e.g. 123 or 123 456); skipping a subtask also skips its parent; skipping a parent also skips all its subtasks

Execution streams one confirmation line per ticket. Failures are reported at the end without stopping the rest of the batch.

Create Jira ticket from email (.eml)

Download the email from OWA using More actions → Download message to save a .eml file, then:

  1. Run Command Palette → Ticket Sidekick: Create Jira ticket from email (.eml)
  2. Select the .eml file from your Downloads folder
  3. A preview appears in the @jira chat with subject, sender, date, body, and attachments
  4. Reply with a template number, an issue type number, or post it to create the ticket

You can also trigger the import from the chat directly:

@jira create ticket from mail
@jira import email

A file picker opens, the preview appears, and you proceed as above.

Inline images are uploaded as Jira attachments and embedded as thumbnails at their position in the description. File attachments are uploaded to the ticket. Individual attachments larger than 25 MB are rejected with a clear message rather than failing mid-upload.

Add an email as a comment to an existing ticket

Log a customer follow-up, escalation, or partner communication on a ticket that already exists — without leaving VS Code.

From the chat (fastest):

@jira add email to PROJ-42
@jira add comment from mail to PROJ-42

A file picker opens. Select the .eml file. The email is posted as a comment on PROJ-42 with all attachments uploaded.

Via preview (to review before posting):

@jira add email

The email preview appears. Reply with a ticket key (e.g. PROJ-42) to add as a comment, or select a template / issue type to create a new ticket instead.

Via command palette: Use Command Palette → Ticket Sidekick: Create Jira ticket from email (.eml), then reply with a ticket key in the preview.

The comment includes the sender name and received date as a header, followed by the full email body in Jira markup. All attachments are uploaded to the ticket.

Settings:

Setting Default Description
ticketSidekick.email.deleteEmlAfterImport false Delete the .eml file automatically after the ticket is created
ticketSidekick.jira.defaultProject — Project key used when creating tickets (required for new ticket flow)

Templates and cleanup rules

Create a .jira-templates.json file in your workspace root to define per-application templates with default fields and guided description collection, plus named cleanup rules for bulk status transitions.

Template examples

Minimal — pre-populated fields:

{
  "templates": [
    {
      "name": "Billing Bug",
      "issueType": "Bug",
      "defaultFields": {
        "priority": { "name": "High" },
        "labels": ["billing"],
        "components": [{ "name": "Backend" }]
      }
    }
  ]
}

With resolved fields and guided description sections:

{
  "templates": [
    {
      "name": "Billing Bug",
      "issueType": "Bug",
      "defaultFields": {
        "priority": { "name": "High" },
        "labels": ["billing"]
      },
      "resolveFields": {
        "assignee": { "type": "user", "name": "Jane Smith" },
        "customfield_10020": { "type": "sprint", "name": "Sprint 42" },
        "customfield_10050": [{ "type": "team", "id": "billing-team-id" }]
      },
      "descriptionSections": [
        "Steps to reproduce",
        "Expected behavior",
        "Actual behavior"
      ]
    }
  ]
}

Cleanup rule examples

Basic — close a ticket type to a target state:

{
  "cleanupRules": [
    {
      "name": "Close billing bugs",
      "project": "BILLING",
      "issueType": "Bug",
      "targetState": "Done",
      "resolution": "Fixed"
    }
  ]
}

With subtasks and version filter:

{
  "cleanupRules": [
    {
      "name": "Close released bugs",
      "project": "BILLING",
      "issueType": "Bug",
      "targetState": "Done",
      "resolution": "Fixed",
      "closeSubtasks": true,
      "subtaskTargetState": "Closed",
      "subtaskResolution": "Fixed",
      "fixVersionFilter": "released"
    }
  ]
}

With a wildcard version pattern and extra JQL filter:

{
  "cleanupRules": [
    {
      "name": "Close Release-series bugs",
      "project": "BILLING",
      "issueType": "Bug",
      "targetState": "Done",
      "resolution": "Fixed",
      "fixVersionPattern": "Release*",
      "jql": "assignee is not EMPTY"
    }
  ]
}

Cleanup rule fields

Field Required Default Description
name yes — Rule identifier — used in @jira run cleanup "name"
project yes — Jira project key — always anchors the search query and workflow graph lookup
issueType yes — Issue type — always anchors the query; use the exact Jira name (e.g. Bug, Story)
targetState yes — Destination Jira status name (e.g. Done, Closed)
resolution no — Resolution applied to parent ticket transitions (e.g. Fixed, Won't Fix)
subtaskResolution no same as resolution Resolution applied to subtask transitions — falls back to resolution if omitted
subtaskTargetState no same as targetState Destination status for subtask transitions — falls back to targetState if omitted
closeSubtasks no false When true, open subtasks are transitioned before their parent
jql no — Extra JQL filter ANDed onto the base query — write only the additional conditions; project, issueType, and status are always included
fixVersionFilter no — "released" or "unreleased" — adds fixVersion in releasedVersions() / fixVersion in unreleasedVersions() to the query
fixVersionPattern no — Glob-style pattern (e.g. "Release*") — adds fixVersion ~ "pattern" to the query (requires Jira 11+ / modern Data Center)

Note: project and issueType are always prepended to the effective JQL even when jql is set — they are never replaced. The jql field adds extra conditions such as sprint in openSprints().

fixVersionFilter and fixVersionPattern are mutually exclusive in a rule — fixVersionFilter takes precedence if both are set. A prompt override (in "v1.2", in released, or in "Release*") always wins over the rule setting.

Version filter examples

{ "fixVersionFilter": "released" }

→ AND fixVersion in releasedVersions()

{ "fixVersionPattern": "Release*" }

→ AND fixVersion ~ "Release*"

You can also specify a version filter in the prompt without touching the rule:

@jira run cleanup "Close released bugs" in released
@jira run cleanup "Close released bugs" in "Release*"
@jira run cleanup "Close released bugs" in "Release 3.2"
@jira run cleanup "Close released bugs" in "released"

The last example (quoted "released") targets a Jira version literally named "released" — it does not trigger releasedVersions(). Only the unquoted form does.

Interaction model

Prompt JQL used Resolution
@jira run cleanup "Name" base + rule.jql if set rule.resolution, or prompted if absent
@jira run cleanup "Name" in "v1.2" base + fixVersion = "v1.2" + rule.jql same
@jira run cleanup "Name" in released base + fixVersion in releasedVersions() same
@jira run cleanup "Name" in unreleased base + fixVersion in unreleasedVersions() same
@jira run cleanup "Name" in "Release*" base + fixVersion ~ "Release*" same
@jira run cleanup "Name" with resolution "Won't Fix" same JQL prompt value overrides rule
@jira close PROJ Bug auto-built (matches rule by project + type if available) prompted if closing to a closed state
@jira close PROJ bugs in "v1.2" with resolution Released auto-built + fixVersion prompt value — no dialog

The base query always includes AND resolution is EMPTY — tickets that were previously resolved (even if since reopened) are automatically excluded.

When you run @jira create, the plugin shows a numbered list of your templates. Choosing one:

  • Pre-populates custom fields from defaultFields and resolved resolveFields entries
  • Guides you through each descriptionSections entry with a follow-up question per turn, building the description incrementally
  • Resumes automatically if the conversation is interrupted — session state is preserved in the chat history

resolveFields entries support two forms:

  • { "type": "sprint", "name": "Sprint 42" } — resolves by name via the Jira Agile API
  • { "type": "team", "id": "abc123" } — passes the id through directly (no API call)
  • { "type": "user", "name": "Jane Smith" } — resolves to { accountId } via user search

Wrap a single entry in an array when the Jira field expects an array value.

Setting assignee in a template:

"resolveFields": {
  "assignee": { "type": "user", "name": "Jane Smith" }
}

Or with a known accountId directly in defaultFields:

"defaultFields": {
  "assignee": { "accountId": "5b10a2844c20165700ede21g" }
}

Setting components in a template:

"defaultFields": {
  "components": [{ "name": "Backend" }, { "name": "API" }]
}

Setting group-picker custom fields (e.g. Team Names) in a template:

"defaultFields": {
  "customfield_18501": [{ "name": "ASL QRF" }]
}

Group-picker fields use { "name": "..." } — no API lookup is needed since the group name is a known string. Put these directly in defaultFields rather than resolveFields.

You can choose No template to create a plain ticket without any template applied.

Settings reference

Setting Key Default
Base URL ticketSidekick.jira.baseUrl (required)
Auth type ticketSidekick.jira.authType "datacenter"
Default project ticketSidekick.jira.defaultProject (empty)
Sprint board ID ticketSidekick.jira.sprintBoardId (auto)
Required fields ticketSidekick.jira.requiredFields []
Always-show fields ticketSidekick.jira.additionalDisplayFields []
Search result columns ticketSidekick.jira.searchFields []
Hidden fields ticketSidekick.jira.hiddenDisplayFields (see below)
Connection info banner ticketSidekick.jira.showConnectionInfo false
Delete .eml after import ticketSidekick.email.deleteEmlAfterImport false

Optional: default project

"ticketSidekick.jira.defaultProject": "PROJ"

When set, the create command skips the project input box and uses this key automatically. You can still override it by including a project key in your prompt.

Optional: sprint board ID

"ticketSidekick.jira.sprintBoardId": 12345

Sprint lookups automatically search all Scrum boards for the project, skipping Kanban boards. Set this only if your project has multiple Scrum boards and the wrong one is selected. Find the board ID in the URL:

  • Modern Jira: .../jira/software/projects/PROJ/boards/12345
  • Data Center RapidBoard: .../jira/secure/RapidBoard.jspa?rapidView=12345 (use the rapidView value)

Optional: required fields

"ticketSidekick.jira.requiredFields": ["assignee", "priority", "fixVersions"]

Used by the check required fields command.

Optional: always-show fields

By default @jira show omits fields that are null. Add field IDs to additionalDisplayFields to always show them (as _Not set_ when empty). Run @jira show fields on PROJ-123 to discover available field IDs.

"ticketSidekick.jira.additionalDisplayFields": ["customfield_10020", "customfield_10500"]

Optional: search result columns

By default @jira find … shows Key, Summary, Status, and Assignee. Add field IDs to searchFields to append them as extra columns in the results table:

"ticketSidekick.jira.searchFields": ["priority", "customfield_10020"]

Run @jira show fields on PROJ-123 to discover field IDs. Values render the same way as in @jira show.

Optional: hidden fields

By default @jira show already omits several noisy system fields (e.g. statusCategory, watches, votes). To suppress additional fields, add their IDs to hiddenDisplayFields. Fields listed in additionalDisplayFields always override this list.

"ticketSidekick.jira.hiddenDisplayFields": ["customfield_10900", "workratio"]

Optional: Jira connection info banner

"ticketSidekick.jira.showConnectionInfo": true

When enabled, every @jira response starts with an italic line showing the active base URL, API version, and auth type. Useful during initial setup or when switching between instances. Off by default.


@bitbucket — Bitbucket PR Reviews

Prerequisites

  • VS Code 1.90 or later with GitHub Copilot extension
  • Bitbucket Data Center or Bitbucket Cloud

Setup

1. Set the auth type

Open VS Code settings (Ctrl+, / Cmd+,) and add:

"ticketSidekick.bitbucket.authType": "datacenter"

Use "cloud" for Bitbucket Cloud. Default is "datacenter".

2. Set the base URL (Data Center only)

"ticketSidekick.bitbucket.baseUrl": "https://bitbucket.mycompany.com"

Leave this unset for Bitbucket Cloud — the plugin connects to api.bitbucket.org automatically.

3. Store your Bitbucket credentials

Data Center: Command Palette (Ctrl+Shift+P) → Ticket Sidekick: Set Bitbucket Personal Access Token

Generate a Personal Access Token in Bitbucket Data Center at Profile → Manage account → Personal access tokens. Grant at minimum Repositories: Read and Pull requests: Read (add Pull requests: Write if you want to post findings as PR comments).

Cloud: Command Palette → Ticket Sidekick: Configure Bitbucket Cloud Credentials

You will be prompted for your Bitbucket username and an App Password. Create an App Password at bitbucket.org → Personal settings → App passwords with at minimum:

Scope Required for
Repositories: Read Fetching file contents for review context
Pull requests: Read PR metadata and diff
Pull requests: Write Posting findings as PR comments (add to review)
Account: Read (optional) shows your username in @bitbucket check

Note: Bitbucket App Passwords use Authorization: Basic — they are not the same as Atlassian API tokens (used for Jira Cloud). Using an Atlassian API token here will fail with 401.

Run @bitbucket check after setup to confirm the connection and see which account is active.

Core commands

What you type What happens
@bitbucket check Test connection and show active configuration
@bitbucket <pr-url> Full structured review of the PR
@bitbucket review quick <pr-url> Review using diffs only — no second-pass file fetch (fewer tokens)
@bitbucket review deep <pr-url> Force standard two-pass review regardless of default setting
@bitbucket [#2](https://github.com/rbreunung/ticket-sidekick/issues/2) Explain finding #2 in detail
@bitbucket [#2](https://github.com/rbreunung/ticket-sidekick/issues/2) is this always a problem? Ask a follow-up question about a specific finding
@bitbucket is the change backwards-compatible? Ask any general question about the PR — no finding reference needed
@bitbucket [#1](https://github.com/rbreunung/ticket-sidekick/issues/1) [#3](https://github.com/rbreunung/ticket-sidekick/issues/3) add to review Preview findings #1 and #3 as comments — reply "post it" to confirm, "(c)" to cancel, or refine
@bitbucket add [#1](https://github.com/rbreunung/ticket-sidekick/issues/1) [#2](https://github.com/rbreunung/ticket-sidekick/issues/2) [#3](https://github.com/rbreunung/ticket-sidekick/issues/3) to review Same — numbers can appear anywhere relative to the keywords
@bitbucket add all to review Preview all findings as PR comments at once
@bitbucket [#2](https://github.com/rbreunung/ticket-sidekick/issues/2) add to review blocking merge Preview with reviewer note "blocking merge" appended — confirm before posting
@bitbucket c Exit the current review session

PR review

Paste any pull request URL into the chat:

@bitbucket https://bitbucket.mycompany.com/projects/PROJ/repos/myrepo/pull-requests/42
@bitbucket https://bitbucket.org/myworkspace/myrepo/pull-requests/7

Trailing segments like /overview, /diff, or /commits are stripped automatically.

The plugin:

  1. Fetches PR metadata and the full unified diff
  2. Applies any configured reviewExcludePatterns to skip files before analysis
  3. Splits the changed files into chunks sized to fill the model's actual context window — a 140-file PR on Claude Sonnet typically needs only 2 LLM calls
  4. For each chunk: sends a structured diff-only prompt and, if the LLM requests additional context files, fetches up to 5 and re-analyses (two-pass review); the second pass is skipped in quick mode
  5. Merges all findings across chunks and streams a single structured report ordered by file, with numbered findings and severity badges

Deleted files are reviewed — removing a validation or error-handling block can be just as risky as adding code. Files with no textual diff (binary, pure renames, or mode-only changes) are skipped and reported in the chat.

Very large files that exceed the per-call budget on their own are split along diff-hunk boundaries and reviewed across several calls, rather than failing or being truncated.

For token-saving options (quick mode, file exclusion, context tuning) see Reducing token usage on large PRs.

Example output:

## PR [#42](https://github.com/rbreunung/ticket-sidekick/issues/42) — Add OAuth login flow
_by Jane Smith → main · 3 files changed_

2 🔴 critical · 1 🟡 warning · 3 🔵 suggestions

---

**📄 src/auth/login.ts**
**#1** 🔴 `L42` SQL injection — user input concatenated into query string
→ Use parameterised queries or a query builder instead.

Follow-ups and posting comments

After a review, the session stays active for multi-turn follow-ups. Reference a finding by number, describe it in natural language, or ask any general question about the PR:

@bitbucket [#2](https://github.com/rbreunung/ticket-sidekick/issues/2) is this always a problem or only if the site has third-party scripts?
@bitbucket can the localStorage finding be downgraded if we enforce a strict CSP?
@bitbucket explain the SQL injection issue and show a fixed version
@bitbucket is this change backwards-compatible with the v2 API?
@bitbucket are there missing test cases for the new endpoints?

Questions without a #N reference automatically answer at the PR level using the title and all findings as context.

Each AI response ends with a _~N estimated tokens_ line (using a chars/4 heuristic — VS Code's LM API does not expose exact counts).

To exit the review session, reply c or cancel:

c

Push selected findings back to Bitbucket as PR comments:

@bitbucket [#2](https://github.com/rbreunung/ticket-sidekick/issues/2) [#3](https://github.com/rbreunung/ticket-sidekick/issues/3), [#5](https://github.com/rbreunung/ticket-sidekick/issues/5) add to review
@bitbucket add [#1](https://github.com/rbreunung/ticket-sidekick/issues/1) [#2](https://github.com/rbreunung/ticket-sidekick/issues/2) [#3](https://github.com/rbreunung/ticket-sidekick/issues/3) to review
@bitbucket add all to review
@bitbucket [#1](https://github.com/rbreunung/ticket-sidekick/issues/1) add to review this is blocking merge

The numbers and add to review keywords can appear in any order. add all to review selects every finding at once. Any extra text (after stripping the command keywords) becomes a brief reviewer note appended to each comment.

Before posting, the plugin shows a preview of each comment's exact text along with where it will land:

  • 📌 Inline comment on line 42 of src/auth.ts — the comment will be anchored to that diff line
  • ⚠️ Line 42 could not be located in the diff — will fall back to activity feed comment — the line was reported by the AI but isn't in the diff; you can cancel and investigate, or confirm to post as a general comment

Reply "post it" to post, (c) to cancel, or give a refinement instruction to adjust the comment text before posting. For example:

make it more concise
focus on the security impact only
add that this affects all authenticated endpoints

Note (Bitbucket Cloud): Posting comments requires the Pull requests: Write scope on your App Password. See the setup section above.

Settings reference

Setting Key Default
Auth type ticketSidekick.bitbucket.authType "datacenter"
Base URL (DC only) ticketSidekick.bitbucket.baseUrl (empty)
Connection info banner ticketSidekick.bitbucket.showConnectionInfo false
Review instructions ticketSidekick.bitbucket.reviewInstructions (empty)
Model context tokens ticketSidekick.bitbucket.modelContextTokens (auto-detected)
Context budget ratio ticketSidekick.bitbucket.contextBudgetRatio 0.7
Review mode ticketSidekick.bitbucket.reviewMode "standard"
Review exclude patterns ticketSidekick.bitbucket.reviewExcludePatterns []

Optional: Bitbucket connection info banner

"ticketSidekick.bitbucket.showConnectionInfo": true

When enabled, every @bitbucket response (except check) starts with an italic line showing the active base URL, API version, and auth type. Off by default.

Optional: custom review instructions

"ticketSidekick.bitbucket.reviewInstructions": "This project follows Google Style Guide. Focus on security issues and ignore minor style suggestions."

Additional instructions appended to the built-in PR review prompt. Use this to add project-specific guidance the model should apply on every review.

Using a local model: @bitbucket works with any model available in GitHub Copilot Chat, including local models via Ollama. Use a model with at least 16k context (32k+ recommended for large PRs).

Reducing token usage on large PRs

The reviewer automatically packs as many files as possible into each LLM call based on the model's actual context window. On Claude Sonnet (200k tokens) a 140-file PR typically needs only 2 LLM calls instead of 14.

Quick mode — skips the second LLM pass (diffs only, no additional file context):

@bitbucket review quick https://bitbucket.company.com/...

Set ticketSidekick.bitbucket.reviewMode to "quick" to make this the default. Use @bitbucket review deep <url> to force standard mode for a single review.

Excluding files — skip files that don't need review (migrations, snapshots, generated code):

"ticketSidekick.bitbucket.reviewExcludePatterns": [
  "**/migrations/**",
  "**/*.snap",
  "**/*.generated.ts"
]

Patterns use glob syntax. Both *.snap and **/*.snap work (bare filename patterns match at any depth).

Manual context override — if the model's context size isn't auto-detected, set it explicitly:

"ticketSidekick.bitbucket.modelContextTokens": 128000

Releasing

Releases are cut by a manually-triggered GitHub Actions workflow (.github/workflows/release.yml) — you no longer hand-edit package.json. Go to Actions → Release → Run workflow and fill in the form:

  • channel — release or preview.
  • bump — patch / minor / major. The workflow runs npm version <bump> to compute the new version.
  • version — optional explicit version (e.g. 0.4.0) that overrides the bump when set.

Both channels do the same thing with that version — they just differ by the pre-release flag:

  • The workflow commits the version bump back to the branch (commit titled with the bare version, matching the existing convention), creates the GitHub Release + bare tag X.Y.Z (auto-generated notes, .vsix attached), and publishes to the VS Code Marketplace.
  • release publishes a normal release; preview publishes with --pre-release (and marks the GitHub Release as a pre-release) for sideloading/dogfooding.

Because every run advances and commits the version, the published version line is strictly increasing — a version is never reused, so the Marketplace's "no duplicate version" rule can never bite and you never have to bump by hand. (The Marketplace versions must be plain x.y.z; the --pre-release flag — not a -preview suffix — is what marks a pre-release.) The workflow runs npm ci → compile → test first and will not publish a red build.

Branch protection: every run pushes the bump commit to the target branch (usually main) using the built-in GITHUB_TOKEN. If main is protected against direct pushes, either allow the Actions bot to bypass it or run the workflow from a release branch.

Prerequisite: add a repository secret VSCE_PAT — an Azure DevOps Personal Access Token for the RobertBreunung publisher with Marketplace → Manage scope (Settings → Secrets and variables → Actions). Without it the Marketplace step fails; the .vsix is still attached to the GitHub Release.

Getting a free Jira Cloud test instance

  1. Create a free account at atlassian.com
  2. Generate an API token at id.atlassian.com/manage-profile/security/api-tokens
  3. Set ticketSidekick.jira.baseUrl to https://<you>.atlassian.net and ticketSidekick.jira.authType to "cloud"
  4. Run Ticket Sidekick: Configure Jira Cloud Credentials
  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft