This is the full developer documentation for Bitbucket CLI # Bitbucket CLI > Clone repositories, manage pull requests, and automate workflows from your terminal. If you know GitHub's gh, you'll feel right at home. ## Install [Section titled “Install”](#install) Requires [Bun](https://bun.sh) 1.0+ runtime. * npm ```bash npm install -g @pilatos/bitbucket-cli ``` * pnpm ```bash pnpm add -g @pilatos/bitbucket-cli ``` * Bun ```bash bun install -g @pilatos/bitbucket-cli ``` ```bash bb auth login # authenticate bb repo clone myworkspace/myrepo # clone a repository bb pr create -t "My awesome feature" # create a PR bb pr list # list open PRs ``` *** ## What can you do? [Section titled “What can you do?”](#what-can-you-do) Repository management Clone, create, list, view, and delete repositories. ```bash bb repo clone workspace/repo bb repo create my-new-project bb repo list -w myworkspace ``` Pull requests Full PR lifecycle — create, review, approve, merge. ```bash bb pr create -t "Add feature" bb pr approve 42 bb pr merge 42 --strategy squash ``` Code review View diffs, checkout PR branches, inspect checks. ```bash bb pr diff 42 bb pr checkout 42 bb pr checks 42 ``` CI/CD pipelines Trigger, inspect, and stop Bitbucket Pipelines. ```bash bb pipeline run --branch main bb pipeline list --status FAILED bb pipeline logs 42 ``` Workspaces and projects Find the workspaces you belong to and the projects inside them. ```bash bb workspace list bb project list bb project view PROJ ``` Issues, snippets, and commits Track issues, share snippets, read history, and publish build statuses. ```bash bb issue list --state open bb snippet create -t notes -f a.txt bb commit list --limit 10 bb status set abc1234 --key BB-DEPLOY --state SUCCESSFUL ``` See [Issue commands](/commands/issue/) and [Snippet commands](/commands/snippet/). Jump to the web UI Open Bitbucket pages — PRs, files, commits, settings — in your browser. ```bash bb browse 42 bb browse src/cli.ts:20 bb browse --pipelines ``` Scripting and automation Every command speaks JSON. `--json` projects to a field list, `--jq` filters in-process — no external `jq` binary, no shell pipe. ```bash bb pr list --json id,title,author.display_name bb pipeline run --branch main --json --jq '.build_number' ``` A field list returns a flat array of objects; dotted paths keep their full name as the key. See the [Scripting guide](/guides/scripting/). Raw API access Reach any Bitbucket 2.0 endpoint not yet wrapped by a typed command. ```bash bb api /user bb api /repositories/{workspace}/{repo}/pullrequests --paginate bb api POST /repositories/ws/repo/issues -f title=Bug ``` *** ## PR workflows [Section titled “PR workflows”](#pr-workflows) [Create, edit, and view](/commands/pr/create-and-edit/)Open a PR, change its title or description, list PRs, inspect one. [Review and merge](/commands/pr/review-and-merge/)Approve, decline, mark drafts ready, and merge with explicit strategy control. [Diff and checkout](/commands/pr/diff-and-checkout/)Review patch output, fetch PR branches locally, and open browser diffs. [Activity and checks](/commands/pr/activity-and-checks/)Inspect activity history and CI/build status before approving or merging. [Review comments](/commands/pr/comments/)List, add, view, edit, reply to, resolve, unresolve, and delete general or inline review comments. [Reviewers](/commands/pr/reviewers/)Add and remove reviewers. Adding someone already assigned is a no-op, as is removing someone who is not. [All PR commands](/commands/pr/) *** ## Explore [Section titled “Explore”](#explore) [Scripting guide](/guides/scripting/)JSON output, exit codes, shell patterns. [CI/CD integration](/guides/cicd/)GitHub Actions, GitLab CI, Jenkins, and more. [Recipes](/recipes/)Auto-merge on green CI, bulk reviewer assignment, fork sync, reporting, retry wrappers. [AI agent integration](/guides/ai-agents/)Wire the CLI into coding agents and tool-calling loops. [Troubleshooting](/help/troubleshooting/)Common issues and solutions. *** ## Community [Section titled “Community”](#community) This is an **unofficial**, community-maintained CLI. Not affiliated with Atlassian. * [GitHub Repository](https://github.com/0pilatos0/bitbucket-cli) * [Report Issues](https://github.com/0pilatos0/bitbucket-cli/issues) * [Contribute](https://github.com/0pilatos0/bitbucket-cli/blob/main/CONTRIBUTING.md) # API Command — Raw Authenticated Bitbucket API Access > Call any Bitbucket Cloud 2.0 API endpoint through the CLI's authenticated stack — the escape hatch for endpoints not yet wrapped by a typed command. Mirrors gh api. `bb api` sends an authenticated request to any Bitbucket Cloud 2.0 endpoint through the same stack as every other command: Basic/Bearer auth, automatic OAuth token refresh, rate-limit and transient-error retries, and secret redaction. Same shape as `gh api`. Every global flag is inherited — see [Global Flags](/reference/global-flags/). The ones that matter here are `--json [fields]`, `--jq `, `-w/--workspace`, `-r/--repo`, and `--no-color`/`--no-unicode`, which style the error and `--paginate` warning lines. `--no-truncate` and `--locale` change nothing: `bb api` prints no tables and no dates. ## `bb api` [Section titled “bb api”](#bb-api) ```bash bb api [options] [method] ``` ### Arguments [Section titled “Arguments”](#arguments) | Argument | Description | | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `method` | Optional HTTP verb (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS`), case-insensitive. When omitted, defaults to `GET`, or `POST` when fields/body are present. Both `bb api GET /user` and `bb api /user` work. | | `endpoint` | The API path, relative to `https://api.bitbucket.org/2.0` (a leading `/` is optional). A redundant leading `/2.0` is stripped, so paths copied straight out of the Bitbucket REST docs (`/2.0/user`) work unchanged. `{workspace}` and `{repo}` placeholders are substituted from `--workspace`/`--repo` or the current repository. | ### Options [Section titled “Options”](#options) | Option | Description | | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `-X, --method ` | HTTP method. Overrides a positional verb. | | `-f, --raw-field ` | Add a string parameter. Query param on `GET`/`HEAD`, JSON body field otherwise. Repeatable. | | `-F, --field ` | Add a typed parameter: `true`/`false`/`null` and numbers are converted; `@file` reads a file and `@-` reads stdin. Repeatable. | | `--input ` | Read the raw request body from a file, or `-` for stdin. Sent as `application/json` (override with `-H 'Content-Type: ...'`). Mutually exclusive with `-f`/`-F`. | | `-H, --header ` | Add a request header. Repeatable. `Authorization` is managed automatically and cannot be set here. | | `-i, --include` | Print the HTTP status line and response headers before the body (text mode only — suppressed under `--json`). | | `--paginate` | Follow the cursor (`next`) across pages and merge every page into a single `{ "values": [...] }` result (`GET`/`HEAD` only). | ### Argument errors [Section titled “Argument errors”](#argument-errors) Positionals are strict: at most two, and with two the first must be an HTTP verb. Every case below exits `1` without sending a request. ```text $ bb api ✗ An endpoint path is required (e.g. /user). Run `bb api --help` for usage. $ bb api GET ✗ An endpoint path is required after the method (e.g. bb api GET /user). Run `bb api --help` for usage. $ bb api GTE /user ✗ 'GTE' is not a valid HTTP method. Expected one of: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS. Run `bb api --help` for usage. (Did you mean GET?) $ bb api -X GTE /user ✗ --method must be one of: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS (Did you mean GET?) $ bb api GET /user /extra error: too many arguments for 'api'. Expected 2 arguments but got 3: GET, /user, /extra. ``` ### Examples [Section titled “Examples”](#examples) ```bash # Current user bb api /user # Explicit method (equivalent to the above) bb api GET /user # List every pull request, following pagination, using the current repository bb api /repositories/{workspace}/{repo}/pullrequests --paginate # Create an issue (method inferred as POST because fields are present) bb api /repositories/my-ws/my-repo/issues -f title=Bug -f priority=major # -F applies gh-style magic typing: true/false/null and numbers become JSON literals bb api PUT /repositories/my-ws/my-repo -F is_private=true # Send a JSON body from a file bb api PUT /repositories/my-ws/my-repo/pullrequests/42 --input body.json # Pipe a body in from stdin cat body.json | bb api POST /repositories/my-ws/my-repo/pullrequests/42/comments --input - # Force a GET with query parameters (fields normally infer POST) bb api GET /repositories/my-ws/my-repo/pullrequests -f state=MERGED # Filter the response with jq (no --json needed — bb api output is already JSON) bb api /repositories/my-ws --jq '.values[].name' # Inspect the status line and response headers bb api -i /user ``` ### How fields are sent [Section titled “How fields are sent”](#how-fields-are-sent) * **`GET` / `HEAD`** — `-f`/`-F` are appended as a URL query string (`?key=value&...`). * **Every other method** — `-f`/`-F` are assembled into a JSON request body. * Repeating the same key turns it into an array, matching `gh`. ### Placeholders [Section titled “Placeholders”](#placeholders) `{workspace}` and `{repo}` are resolved only when they actually appear in the path, so `bb api /user` works outside a checkout. ```bash # Inside a Bitbucket checkout, these resolve automatically: bb api /repositories/{workspace}/{repo}/commits # Or override explicitly: bb api -w my-ws -r my-repo /repositories/{workspace}/{repo}/commits ``` ### Output [Section titled “Output”](#output) The response body is printed to stdout. JSON responses are pretty-printed and respect the global `--json [fields]` projection and `--jq` filtering. Non-JSON responses (e.g. raw diffs) are printed verbatim, and `--json`/`--jq` are inert on them. An empty response body (e.g. a `HEAD` or `204`) prints nothing in text mode, and `{}` under `--json`, so a downstream `jq` never sees zero bytes. ```bash bb api /user ``` ```json { "type": "user", "username": "my-user", "display_name": "My User", "account_id": "557058:..." } ``` `bb api` is the only command where `--jq` works without `--json`; everywhere else a bare `--jq` fails with `✗ --jq requires --json`. On a paginated endpoint, `--json ` unwraps the `values` array and drops the envelope (`pagelen`, `size`, `next`), returning a bare array of projected objects. Projection runs before `--jq`, so once you pass `--json ` the expression sees that flat array — use `.[]`, not `.values[]`. ```bash # Envelope intact bb api /repositories/my-ws --jq '.values[].name' # Projected and unwrapped bb api /repositories/my-ws --json name --jq '.[].name' ``` ### Notes [Section titled “Notes”](#notes) * **Authentication is automatic.** The same credentials as the rest of the CLI are attached to every request; you cannot (and need not) set `Authorization` yourself. * **Only the Bitbucket API host is allowed.** Absolute URLs are accepted only when they point at `api.bitbucket.org`. This prevents the CLI from sending your token to a foreign host. Pagination cursors (which are absolute `api.bitbucket.org` URLs) are followed safely. * **`--paginate` degrades instead of erroring.** On a non-`GET`/`HEAD` request it prints `--paginate only applies to GET/HEAD requests; ignoring it.` on stderr and sends the request unpaginated. If the first response has no `values` array — a single resource rather than a collection — it prints `--paginate: response has no "values" array; returning the first page only.` and returns page 1. Both warnings are suppressed under `--json`. Combined with `-i`, the status line and headers printed are the first page’s. * **Errors surface the API response.** On a non-2xx status, the API’s error body is printed and the command exits non-zero. With `--json`, the error payload (including `statusCode` and `response`) is emitted as structured JSON. A `401` or `403` also carries a `hint` with the next step to take. The generic `404` hint is deliberately suppressed here — you supplied the URL yourself, so advice about `--workspace`/`--repo` would not apply. Note the API error body prints to **stdout** while the error line and its hint go to **stderr**, so in a terminal the hint appears after the body. * **Retries and redaction are inherited** from the shared API client — rate limits (`429`) and the transient gateway errors `502`/`503`/`504` are retried with backoff, and sensitive values are redacted from `DEBUG` logs. ### Related [Section titled “Related”](#related) * [Scripting & Automation](/guides/scripting/) — combine `bb api` with `--jq` to build pipelines over endpoints without a typed command. * [JSON Output](/reference/json-output/) — how `--json` projection and `--jq` filtering work across the CLI. * [Authentication](/getting-started/authentication/) — the auth methods that `bb api` reuses. # Auth Commands > Authentication commands reference Manage authentication with Bitbucket. Global options available on all auth commands: `--json [fields]`, `--jq `, `--no-color`, `--no-unicode`, `--locale `. See [Global flags](/reference/global-flags/) for the full list. ## `bb auth login` [Section titled “bb auth login”](#bb-auth-login) Authenticate with Bitbucket using OAuth (default) or an API token. ```bash bb auth login [options] ``` ### Options [Section titled “Options”](#options) | Option | Description | | -------------------------------- | ----------------------------------------------------------------------------------------------------------- | | `-u, --username ` | Bitbucket username (implies API token auth) | | `-p, --password ` | Bitbucket API token (implies API token auth) | | `--with-token` | Read the API token from stdin so it never appears in shell history or process args (implies API token auth) | | `--app-password` | Use API token authentication instead of OAuth (see the note below) | | `--client-id ` | Custom OAuth consumer client ID | | `--client-secret ` | Custom OAuth consumer client secret | ### Examples [Section titled “Examples”](#examples) ```bash # Login with OAuth (opens browser) bb auth login # Login with a custom OAuth consumer bb auth login --client-id YOUR_KEY --client-secret YOUR_SECRET # Login with API token bb auth login -u myuser -p your-api-token # Login by piping the token via stdin (keeps it out of shell history and `ps`) echo "$BB_API_TOKEN" | bb auth login -u myuser --with-token # Login using environment variables (API token) export BB_USERNAME=myuser export BB_API_TOKEN=your-api-token bb auth login ``` Tip `--with-token` is the safest way to pass a token. Unlike `-p`, the token is read from stdin, so it never lands in your shell history or in process-listing tools like `ps`. It pairs well with secret managers, e.g. `my-secret-tool get bb-token | bb auth login -u myuser --with-token`. Two rules: `--with-token` cannot be combined with `-p/--password` (hard error, `VALIDATION_INVALID`), and it reads all of stdin and trims it, so an empty stdin fails instead of prompting — `bb auth login -u me --with-token < /dev/null` errors with `No API token found on stdin.` ### How it works [Section titled “How it works”](#how-it-works) OAuth is used unless any of `--app-password`, `--with-token`, `-u`, `-p`, or the `BB_API_TOKEN` environment variable is present. **OAuth flow (default):** 1. The CLI starts a local callback server and opens your browser 2. You authorize the CLI on Bitbucket’s consent screen 3. Bitbucket redirects back to the CLI with an authorization code 4. The CLI exchanges the code for access and refresh tokens 5. Tokens are stored in your config file 6. Access tokens expire after 2 hours and are refreshed automatically Note The OAuth flow needs a browser that can reach a loopback callback server on `http://localhost:19872/callback`. There is **no device-code flow**, so on headless hosts (SSH sessions, containers, CI) use API token auth — ideally `--with-token` — instead. **API token flow:** 1. You provide your Bitbucket username and API token (token via `-p`, piped to stdin with `--with-token`, or the `BB_API_TOKEN` environment variable) 2. The CLI stores the credentials in your config file 3. The CLI verifies the credentials by fetching your user information 4. If verification fails, credentials are not saved Note The `--app-password` flag is a legacy name. It triggers API token authentication, not Bitbucket app passwords (which are deprecated). Prefer `-u`/`-p`, `--with-token`, or the environment variables. ### Required scopes (API token) [Section titled “Required scopes (API token)”](#required-scopes-api-token) `bb auth login` and `bb auth status` need `read:user:bitbucket` to verify your identity, and so does `bb pr list --mine` (it resolves your account UUID). Repository and pull request commands need `read:repository:bitbucket` and `read:pullrequest:bitbucket`, plus the matching `write:` scopes to create, edit, merge, approve, or decline. Creating a repository needs the admin scope (legacy `repository:admin`) and deleting one needs the delete scope (legacy `repository:delete`); Atlassian publishes these as `admin:repository:bitbucket` and `delete:repository:bitbucket`. Everything else — pipelines, issues, snippets, projects — needs its own scope. See [Token scopes](/reference/token-scopes/) for the per-command table. OAuth logins request a fixed scope set: `account repository repository:admin pullrequest pullrequest:write`. Commands outside repositories and pull requests (`bb pipeline`, `bb issue`, `bb snippet`, `bb project`) are not covered, and neither is `bb repo delete`. Use an API token with the matching scopes for those. See the [Authentication guide](/getting-started/authentication/) for setup instructions. *** ## `bb auth logout` [Section titled “bb auth logout”](#bb-auth-logout) Log out of Bitbucket and remove stored credentials. ```bash bb auth logout [options] ``` ### Examples [Section titled “Examples”](#examples-1) ```bash bb auth logout # Machine-readable result bb auth logout --json ``` ### What gets removed [Section titled “What gets removed”](#what-gets-removed) * **OAuth**: Revokes the token on Bitbucket’s side, then removes `oauthAccessToken`, `oauthRefreshToken`, `oauthExpiresAt`, `authMethod`, and custom OAuth consumer credentials from the config file. * **API Token**: Removes `username` and `apiToken` from the config file. Other settings like `defaultWorkspace`, `skipVersionCheck`, and `versionCheckInterval` are preserved. If revocation fails, the CLI still clears local credentials and warns you to revoke the token manually (`revokeFailed: true` in `--json`). *** ## `bb auth status` [Section titled “bb auth status”](#bb-auth-status) Show current authentication status and account information. ```bash bb auth status [options] ``` ### Examples [Section titled “Examples”](#examples-2) ```bash # Check authentication status bb auth status # Get status as JSON bb auth status --json ``` ### Output [Section titled “Output”](#output) When authenticated with OAuth: ```plaintext ✓ Logged in to Bitbucket Authentication: OAuth Username: myuser Display name: My Name Account ID: 712020:3cfed7e0-0ed6-49fc-bb35-410a00ccee6f Token expires: in 1h 42m Default workspace: myworkspace ``` When authenticated with API token: ```plaintext ✓ Logged in to Bitbucket Authentication: API Token Username: myuser Display name: My Name Account ID: 712020:3cfed7e0-0ed6-49fc-bb35-410a00ccee6f Default workspace: myworkspace ``` The `Default workspace:` line appears only when `defaultWorkspace` is set. On an OAuth login with a stale token, `Token expires:` reads `expired (will refresh automatically)`. When not authenticated: ```plaintext ℹ Not logged in Run bb auth login to authenticate. ``` Caution `bb auth status --json` reports `method: "basic"` for API-token logins, while `bb auth login --json` reports `method: "api_token"` for the same credentials. In scripts, match on `!== "oauth"` rather than on either literal. See [JSON output](/reference/json-output/) for the full payloads. *** ## `bb auth token` [Section titled “bb auth token”](#bb-auth-token) Print the current access token. ```bash bb auth token [options] ``` ### Examples [Section titled “Examples”](#examples-3) ```bash # Print the token bb auth token # Copy it to the clipboard bb auth token | pbcopy # Use it against the raw API (OAuth login — bearer token) curl -H "Authorization: Bearer $(bb auth token)" https://api.bitbucket.org/2.0/user # Use it against the raw API (API token login — base64 basic credentials) curl -H "Authorization: Basic $(bb auth token)" https://api.bitbucket.org/2.0/user # Get token as JSON bb auth token --json ``` ### Output [Section titled “Output”](#output-1) * **OAuth**: Prints the bearer access token (automatically refreshes if expired). `--json` reports `type: "bearer"`. * **API Token**: Prints a base64-encoded `username:apiToken` string suitable for HTTP Basic auth headers. `--json` reports `type: "basic"`. Caution Anyone holding this token has your Bitbucket access, within the scopes you granted. Don’t paste it into logs, CI output, or issue reports. # Browse Command — Open Bitbucket Pages from the Terminal > Open Bitbucket Cloud web pages — repo home, files, branches, commits, pull requests, pipelines, settings — directly from the CLI, or print the URL for scripts. `bb browse` opens Bitbucket Cloud web pages — repository home, files, branches, commits, pull requests, pipelines, settings, and more — in your default browser. Mirrors `gh browse`. It also doubles as a script-friendly URL builder: pass `--no-browser` to print the URL instead, or `--json url` for machine-readable output. It accepts the [global flags](/reference/global-flags/), including `--json [fields]`, `--jq `, `-w, --workspace`, and `-r, --repo`. ## `bb browse` [Section titled “bb browse”](#bb-browse) ```bash bb browse [target] [options] ``` ### Arguments [Section titled “Arguments”](#arguments) | Argument | Description | | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `target` | Optional positional. Resolved by shape: pure digits → PR id, 7–40 hex chars → commit SHA, anything else → file/dir path. Append `:` to a path for a line anchor (e.g. `src/cli.ts:42`). | ### Resource flags [Section titled “Resource flags”](#resource-flags) Resource flags are mutually exclusive — pick at most one. They cannot be combined with a positional `target` (except `--branch`, which is a modifier that pairs with a path target). | Option | Opens | | ----------------- | --------------------------------------------------------------------- | | `--pr ` | A specific pull request | | `--prs` | The pull-requests list | | `--pull-requests` | Alias for `--prs` | | `--branch ` | The branch source tree (or, with ``, that path on the branch) | | `--branches` | The branches list | | `--commit [sha]` | A specific commit (defaults to current HEAD when no SHA is given) | | `--commits` | The commits list | | `--pipelines` | The pipelines page | | `--pipeline ` | A specific pipeline run | | `--downloads` | The downloads page | | `--issue ` | A specific issue | | `--issues` | The issue tracker | | `--wiki` | The wiki | | `--settings` | Repository admin / settings | ### Behavior flags [Section titled “Behavior flags”](#behavior-flags) | Option | Description | | ------------------ | --------------------------------------------------- | | `-n, --no-browser` | Print the URL to stdout instead of opening it | | `--json [fields]` | Emit `{ "url": "..." }` (does not open the browser) | ### Examples [Section titled “Examples”](#examples) ```bash # Repo home bb browse # A file at the current branch bb browse src/cli.ts # A file at a specific line bb browse src/cli.ts:42 # A file on a specific branch bb browse --branch release/2.0 src/cli.ts # Just the branch tree bb browse --branch release/2.0 # Pull request #217 (positional shorthand) bb browse 217 # Pull request #217 (explicit) bb browse --pr 217 # Pull-request list bb browse --prs # A commit by SHA bb browse abc1234 # Current HEAD commit bb browse --commit # Pipelines tab bb browse --pipelines # Repo settings bb browse --settings # Print the URL only — useful in scripts and pipes bb browse --pr 217 --no-browser # Script-friendly URL retrieval bb browse --pr 217 --json url ``` ### Notes [Section titled “Notes”](#notes) * **Positional disambiguation.** A bare `` is treated as a pull request id (the most common case). Use `--issue ` to open an issue with the same number. * **Branch defaulting.** When you give a path target without `--branch`, the CLI uses your current git branch (`git rev-parse --abbrev-ref HEAD`). Outside a git checkout (when using `--workspace`/`--repo` overrides), it falls back to the literal `HEAD` segment, which Bitbucket resolves server-side to the repository’s default branch. * **URL encoding.** Workspace and repository slugs, branch names, and path segments are URL-encoded individually, so branches with slashes (`feature/foo`) and paths or names with spaces still produce valid URLs. Path separators (`/` between segments) are preserved. * **No API calls.** `bb browse` never talks to the Bitbucket API — it only builds URLs. It does shell out to git: to resolve workspace and repository from your remote (skipped only when you pass both `-w` and `-r`), and to resolve a ref — `git rev-parse --abbrev-ref HEAD` for a path target without `--branch`, `git rev-parse HEAD` for `--commit` with no SHA. `--branch `, an explicit SHA, and the resource flags need no extra git call. * **`--json` does not open the browser.** Either output mode (JSON or `--no-browser`) suppresses the open action, so scripts can capture the URL deterministically. ### Output [Section titled “Output”](#output) In default mode, `bb browse` prints a short status line and shells out to the [`open`](https://www.npmjs.com/package/open) helper to launch the URL. With `--no-browser`: ```text https://bitbucket.org/myworkspace/myrepo/pull-requests/217 ``` With `--json`: ```json { "url": "https://bitbucket.org/myworkspace/myrepo/pull-requests/217" } ``` `--jq` output is JSON-quoted (the embedded jq has no `-r`), so for a bare, pipe-ready URL use `--no-browser` as shown above. Reach for `--jq` when you are feeding a JSON consumer: ```bash bb browse --pr 217 --json url --jq '.url' ``` ### Related [Section titled “Related”](#related) * [`bb pr diff --web`](/commands/pr/diff-and-checkout/) — open the PR diff page directly in the browser. * [Repository Context](/guides/repository-context/) — how the CLI infers workspace and repository from your current directory. * [Scripting & Automation](/guides/scripting/) — capture URLs from `bb browse` to feed other tools. # Commit Commands - Inspect Repository History > Reference for Bitbucket CLI commit commands. List commit history for a branch, tag, or revision and view full commit details from the command line. Inspect commits in a Bitbucket repository — list the history of a branch, tag, or revision, and view the full details of a single commit. Commit commands operate at **repository** scope. Run them inside a cloned Bitbucket repository, or pass `-w, --workspace ` and `-r, --repo ` explicitly. Global options available on all commit commands: `--json [fields]`, `--jq `, `--no-color`, `--no-unicode`, `--no-truncate`, `--locale `, `-w, --workspace`, `-r, --repo`. A `` is a full 40-character hash or any abbreviated prefix (`abc1234`). `--json` output is wrapped in an envelope keyed by `workspace` and `repoSlug`; the `# →` comments below show each shape. *** ## `bb commit list` [Section titled “bb commit list”](#bb-commit-list) List commits, newest first. ```bash bb commit list [options] ``` ### Options [Section titled “Options”](#options) | Option | Description | | ------------------ | ---------------------------------------------------------------------------- | | `--ref ` | Branch, tag, or commit SHA to list history for (default: current git branch) | | `--limit ` | Maximum number of commits (default: 25) | | `--all` | List all commits (overrides `--limit`) | ### Examples [Section titled “Examples”](#examples) ```bash # Inside a git repository: history of the current branch bb commit list bb commit list --ref main bb commit list --ref v1.0.0 --limit 50 # → { workspace, repoSlug, [ref], count, commits } bb commit list --json # Hashes only, via built-in --jq bb commit list --json --jq '.commits[].hash' ``` ### Notes [Section titled “Notes”](#notes) * **Default ref:** with no `--ref`, the CLI uses the current git branch when run inside a git repository. When branch detection fails (outside a git repository, detached HEAD), it falls back to the repository’s default commit listing instead of erroring. * Columns: short hash (7 characters), first line of the commit message (truncated to 60 characters; disable with `--no-truncate`), author (Bitbucket display name, or the name parsed from the raw git author), and commit date. * `--limit` is enforced across paginated responses. When results are capped the CLI prints `Showing 25 commits. Use --limit or --all to see more.` (suppressed with `--json`). * An unknown `--ref` returns `Ref 'no-such-branch' not found in acme/api. Pass --ref to choose a different ref.` *** ## `bb commit view` [Section titled “bb commit view”](#bb-commit-view) View the full details of a single commit. `` is a full or abbreviated hash. ```bash bb commit view [options] ``` ### Examples [Section titled “Examples”](#examples-1) ```bash bb commit view abc1234 # → { workspace, repoSlug, commit } bb commit view abc1234 --json # Raw author string of the commit bb commit view abc1234 --json --jq '.commit.author.raw' ``` ### Notes [Section titled “Notes”](#notes-1) * The human view shows the full hash, author (raw `Name ` when available), date, parent commits (short hashes), and the complete commit message including the body. * In `--json` mode, `commit` is the raw commit resource as returned by the Bitbucket API (hash, author, parents, message, links, …). * An unknown sha returns `Commit abc1234 not found in acme/api.` *** ## See also [Section titled “See also”](#see-also) * [Status Commands](/commands/status/) — read and report build statuses on commits. * [Scripting & Automation](/guides/scripting/) — JSON envelopes, `--jq`, exit codes. # Completion Commands > Install or remove bb tab completion for bash, zsh, and fish, and see exactly what the completer suggests. Tab completion for bash, zsh, and fish. Global options: every global flag is accepted here (see [Global Flags](/reference/global-flags/)). Only `--json`, `--no-color` and `--no-unicode` change anything — `--jq` needs `--json`, and `--no-truncate`/`--locale`/`-w`/`-r` have no output to affect. ## `bb completion install` [Section titled “bb completion install”](#bb-completion-install) ```bash bb completion install [options] ``` This command is interactive. It asks two questions: 1. **“Which Shell do you use ?”** — pick `bash`, `zsh`, or `fish`. The default is `bash`; the prompt does **not** preselect your current shell. 2. **“We will install completion to ``, is it ok ?”** — confirm, or decline and supply an absolute path of your own. It then appends a source line to that file and writes the completion script under `~/.config/tabtab/`. | Shell | Config file offered | | ----- | ---------------------------- | | bash | `~/.bashrc` | | zsh | `~/.zshrc` | | fish | `~/.config/fish/config.fish` | Because it prompts, `bb completion install` is not scriptable. It blocks on the shell question in CI, `--json` included. A failure throws error code `9001` ([`COMPLETION_INSTALL_FAILED`](/reference/error-codes/)) with the message `Failed to install completions: `, and the command exits `1`. ### After installing [Section titled “After installing”](#after-installing) Restart your shell, or source the file you chose: ```bash source ~/.bashrc # bash source ~/.zshrc # zsh source ~/.config/fish/config.fish # fish ``` Then check it works: ```bash bb # every top-level command (the root flags are offered too) bb repo # clone, create, list, view, delete, default-reviewers ``` ### JSON output [Section titled “JSON output”](#json-output) `--json` replaces both the success line and the “Restart your shell…” follow-up with a single object: ```json { "success": true, "shellCompletion": { "command": "bb", "installed": true } } ``` ## `bb completion uninstall` [Section titled “bb completion uninstall”](#bb-completion-uninstall) ```bash bb completion uninstall [options] ``` No prompt. It deletes `~/.config/tabtab/bb.`, removes the `bb` lines from `~/.config/tabtab/__tabtab.`, and drops the source line from your shell config once no other package is left in that file. Both `` and that config file come from `$SHELL` — your login shell, not the shell you happen to be typing in, and not the shell you picked at the install prompt. If they disagree, the source line is left behind and you have to delete it by hand. On success it prints `✓ Shell completions uninstalled successfully!`; with `--json` you get the same envelope as install, with `"installed": false`. Most uninstall failures are swallowed by tabtab: it prints `ERROR while uninstalling ` and resolves anyway, so the command still reports success and exits `0`. Error code `9002` ([`COMPLETION_UNINSTALL_FAILED`](/reference/error-codes/)) only fires for failures thrown outside that handler. ## What gets completed [Section titled “What gets completed”](#what-gets-completed) Completions are generated from the live command tree, so they always match the commands and flags the CLI actually ships. * **Commands and subcommands** — every command in the tree, at every depth. * **Options** — every flag on the command plus the inherited globals (`--json`, `--jq`, `--no-color`, `--no-unicode`, `--no-truncate`, `--locale`, `--workspace`, `--repo`, `--help`), plus `--version` on the bare `bb`. Only long forms are suggested; short aliases like `-w` still work but are never offered. * **Flag values** for options with a fixed set of choices. Commands and flags carry their help text as a completion description. zsh and fish display it alongside the name; bash shows bare names. Enum **values** never carry a description, so they are bare in every shell. ### Flag-value completion [Section titled “Flag-value completion”](#flag-value-completion) Completing right after a flag that takes a fixed set of values suggests those values, and nothing else: ```bash $ bb pr merge 42 --strategy merge_commit squash fast_forward squash_fast_forward rebase_fast_forward rebase_merge $ bb pr list --state OPEN MERGED DECLINED SUPERSEDED $ bb snippet list --role owner contributor member $ bb pr diff --color auto always never $ bb api -X GET POST PUT PATCH HEAD OPTIONS DELETE ``` ### Example session [Section titled “Example session”](#example-session) ```bash $ bb pr pr $ bb pr activity approve checks checkout comments create decline diff edit list merge ready reviewers view $ bb pr create -- # the command's own flags, plus inherited global flags: --title --body --source --destination --close-source-branch --draft --reviewer --default-reviewers --no-default-reviewers --json --jq --no-color --no-unicode --no-truncate --locale --workspace --repo --help ``` ### Related [Section titled “Related”](#related) * [Global Flags](/reference/global-flags/) — the flags the completer offers on every command. * [Error Codes](/reference/error-codes/) — `9001` and `9002` in context. * [Scripting & Automation](/guides/scripting/) — `--json` envelopes and exit codes for the non-interactive commands. # Config Commands > Configuration commands reference Manage CLI configuration settings. Global options available on all config commands: `--json [fields]`, `--jq `, `--no-color`, `--no-unicode`, `--locale `. See [Global flags](/reference/global-flags/) for the full list. ## Configuration file [Section titled “Configuration file”](#configuration-file) Configuration is stored in a JSON file at: * **Linux/macOS**: `~/.config/bb/config.json` (fixed path — `XDG_CONFIG_HOME` is not read) * **Windows**: `%APPDATA%\bb\config.json`, falling back to `%USERPROFILE%\AppData\Roaming\bb\config.json` On Linux and macOS the CLI creates the directory `0700` and the file `0600`, and refuses to run if either grants group or other access. See [Configuration file](/reference/configuration/) for the permission rules and how to fix them. ## Available settings [Section titled “Available settings”](#available-settings) | Key | `bb config get` | `bb config set` | Description | | --------------------------------- | ------------------------ | ------------------------ | ------------------------------------------------------------------------------------------------------------------ | | `defaultWorkspace` | yes | yes | Default workspace for commands | | `skipVersionCheck` | yes | yes | Disable update notifications (default: false) | | `versionCheckInterval` | yes | yes | Days between update checks (default: 1) | | `prCreateIncludeDefaultReviewers` | yes | yes | Auto-add the repository’s default reviewers on `bb pr create` (default: false) | | `username` | yes | no — use `bb auth login` | Bitbucket username | | `apiToken` | no — use `bb auth token` | no — use `bb auth login` | Bitbucket API token (masked in `bb config list`) | | `lastVersionCheck` | no | no | Timestamp of the last update check. Auto-managed; `bb config get lastVersionCheck` fails with `Unknown config key` | `bb auth login` also writes `authMethod` — `basic` for API tokens, `oauth` for OAuth — and, after an OAuth login, the `oauth*` keys (`oauthAccessToken`, `oauthRefreshToken`, `oauthExpiresAt`, and custom consumer credentials). Only `bb auth login` and `bb auth logout` touch those keys; see [Configuration file](/reference/configuration/) for the full schema. ### Configuration file format [Section titled “Configuration file format”](#configuration-file-format) ```json { "authMethod": "basic", "username": "myuser", "apiToken": "ATBB_xxxxxxxxxxxxxxxxxxxx", "defaultWorkspace": "myworkspace", "skipVersionCheck": false, "versionCheckInterval": 1, "prCreateIncludeDefaultReviewers": false } ``` Don’t edit this file by hand. Use `bb config set` for settings and `bb auth login` for credentials. ## `bb config get` [Section titled “bb config get”](#bb-config-get) Print a configuration value. ```bash bb config get ``` Readable keys: `username`, `defaultWorkspace`, `skipVersionCheck`, `versionCheckInterval`, `prCreateIncludeDefaultReviewers`. Any other key exits `1` with `Unknown config key ''`, except `apiToken`, which points you at `bb auth token`. ### Examples [Section titled “Examples”](#examples) ```bash # Get default workspace bb config get defaultWorkspace # Get username bb config get username # Get output as JSON bb config get defaultWorkspace --json ``` *** ## `bb config set` [Section titled “bb config set”](#bb-config-set) Set a configuration value. ```bash bb config set ``` Settable keys, and the values each accepts: | Key | Accepted values | Stored type | | --------------------------------- | ---------------------------------- | ----------- | | `defaultWorkspace` | Any string | string | | `skipVersionCheck` | `true` or `false` | boolean | | `versionCheckInterval` | Positive integer (`>= 1`), in days | number | | `prCreateIncludeDefaultReviewers` | `true` or `false` | boolean | ### Examples [Section titled “Examples”](#examples-1) ```bash # Set default workspace bb config set defaultWorkspace myworkspace # Disable update notifications bb config set skipVersionCheck true # Check for updates weekly instead of daily bb config set versionCheckInterval 7 # Get output as JSON bb config set defaultWorkspace myworkspace --json ``` Values that don’t match the key’s type are rejected and exit `1`: ```bash bb config set skipVersionCheck maybe ``` ```plaintext ✗ Invalid value for 'skipVersionCheck'. Expected 'true' or 'false'. ``` JSON output for typed keys: ```json { "success": true, "key": "skipVersionCheck", "value": true } ``` Caution `bb config set username …` and `bb config set apiToken …` are rejected outright: ```plaintext ✗ Cannot set 'username' directly. Use 'bb auth login' to configure authentication. ``` Use `bb auth login` for credentials. *** ## `bb config list` [Section titled “bb config list”](#bb-config-list) List all configuration values. ```bash bb config list [options] ``` ### Examples [Section titled “Examples”](#examples-2) ```bash # List all config bb config list # List as JSON for scripting bb config list --json # Read one value out of the JSON bb config list --json --jq '.config.defaultWorkspace' ``` ### Output [Section titled “Output”](#output) ```plaintext Config file: /Users/you/.config/bb/config.json KEY VALUE ---------------- ----------- username myuser defaultWorkspace myworkspace apiToken ******** skipVersionCheck false Settable keys: defaultWorkspace, skipVersionCheck, versionCheckInterval, prCreateIncludeDefaultReviewers. Run 'bb config set --help' for details. ``` With an empty config file the table is replaced by `ℹ No configuration set`; the `Config file:` line and the `Settable keys:` footer still print. `apiToken` is always masked. OAuth credentials are omitted from `bb config list` entirely — after an OAuth login the listing shows no auth rows at all. # Issue Commands - Manage the Bitbucket Issue Tracker > Reference for Bitbucket CLI issue commands. List, view, create, edit, close, and comment on Bitbucket Cloud issues from the command line, mirroring gh issue. Manage issues in a repository’s built-in issue tracker — list, view, create, edit, close, and comment, mirroring the ergonomics of `gh issue`. Issue commands operate at **repository** scope. Run them inside a cloned Bitbucket repository, or pass `-w, --workspace ` and `-r, --repo ` explicitly. Global options available on all issue commands: `--json [fields]`, `--jq `, `--no-color`, `--no-unicode`, `--no-truncate`, `--locale `, `-w, --workspace`, `-r, --repo`. See [Global flags](/reference/global-flags/) for the full list. The per-command tables below list only command-specific options. Caution Bitbucket’s issue tracker is **opt-in per repository** and disabled by default. When it is off, every issues endpoint answers `404` and `bb issue list` / `bb issue create` report: *“This repository’s issue tracker is disabled (or the repo was not found). Enable it under Repository settings → Issue tracker on Bitbucket, or check `--workspace`/`--repo`. Many teams use Jira instead — see the docs.”* *** ## `bb issue list` [Section titled “bb issue list”](#bb-issue-list) List issues. By default only “open-ish” issues are shown (states `new` and `open`), sorted most recently updated first. ```bash bb issue list [options] ``` ### Options [Section titled “Options”](#options) | Option | Description | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------ | | `--state ` | Filter by exact state: `submitted`, `new`, `open`, `resolved`, `on-hold`, `invalid`, `duplicate`, `wontfix`, or `closed` | | `--kind ` | Filter by kind: `bug`, `enhancement`, `proposal`, or `task` | | `--assignee ` | Filter by assignee username | | `--reporter ` | Filter by reporter username | | `--query ` | Raw Bitbucket `q` filter expression (escape hatch) | | `--limit ` | Maximum number of issues (default: 25) | | `--all` | List all issues (overrides `--limit`) | ### Examples [Section titled “Examples”](#examples) ```bash bb issue list bb issue list --state resolved bb issue list --kind bug --assignee some.user bb issue list --limit 50 # Raw q escape hatch (replaces the default state filter) bb issue list --query 'priority="blocker" AND state!="closed"' # Project to specific fields (returns a flat array) bb issue list --json id,title,state # Filter with built-in --jq — ids of critical issues bb issue list --json --jq '.issues[] | select(.priority == "critical") | .id' ``` ### Notes [Section titled “Notes”](#notes) * **Filter composition:** without `--state` or `--query` the command filters on `(state="new" OR state="open")`. An explicit `--state` matches exactly (the CLI’s `on-hold` maps to the API’s `"on hold"`). `--kind`, `--assignee`, and `--reporter` clauses are AND-ed on. * **`--query` grouping:** the expression replaces the default state filter. It is wrapped in parentheses and placed first in the AND-ed clause list, so a top-level `OR` inside it stays correctly grouped against `--kind`/`--assignee`/`--reporter`. The composed expression comes back as `filters.q` in `--json` output. * **JSON envelope:** `{ workspace, repoSlug, filters, count, issues }`, where `filters` echoes the active flags plus the effective `q` expression. * TITLE is truncated to 50 characters in the table; pass the global `--no-truncate` for full titles (`--json` always carries the full value). UPDATED is formatted with `--locale`/`BB_LOCALE`, falling back to the system locale and then `en-US`. * `--limit` is enforced across paginated responses; a hint shows when results were capped (suppressed with `--json`). *** ## `bb issue view` [Section titled “bb issue view”](#bb-issue-view) View the full details of a single issue. ```bash bb issue view [options] ``` ### Arguments [Section titled “Arguments”](#arguments) | Argument | Description | | -------- | -------------------- | | `id` | Issue ID (e.g. `42`) | ### Examples [Section titled “Examples”](#examples-1) ```bash bb issue view 42 # Print just the state, for a CI guard bb issue view 42 --json --jq '.issue.state' ``` ### Notes [Section titled “Notes”](#notes-1) * Human output shows the id, title, state, kind, priority, reporter, assignee, created/updated dates, votes, the issue body, and the web URL. * **JSON envelope:** `{ workspace, repoSlug, issue }`. * A `404` is reported as `Issue # not found in /.`, with a reminder that a disabled issue tracker 404s identically. *** ## `bb issue create` [Section titled “bb issue create”](#bb-issue-create) Create an issue. ```bash bb issue create --title [options] ``` ### Options [Section titled “Options”](#options-1) | Option | Description | | ------------------------ | ------------------------------------------------------------------- | | `-t, --title <title>` | Issue title (**required**) | | `-b, --body <text>` | Issue description (Markdown) | | `-F, --body-file <file>` | Read the description from a file (mutually exclusive with `--body`) | | `--kind <kind>` | `bug`, `enhancement`, `proposal`, or `task` | | `--priority <priority>` | `trivial`, `minor`, `major`, `critical`, or `blocker` | | `--assignee <username>` | Assign the issue to a user | ### Examples [Section titled “Examples”](#examples-2) ```bash bb issue create --title "Crash on login" bb issue create --title "Crash on login" --kind bug --priority major --assignee some.user bb issue create --title "RFC: new API" --body-file ./rfc.md # Capture the new issue id in a script bb issue create --title "Crash on login" --json --jq '.issue.id' ``` ### Notes [Section titled “Notes”](#notes-2) * On success the new issue number and its web URL are printed. * **JSON envelope:** `{ workspace, repoSlug, issue }` with the created issue. * A `404` here means the issue tracker is disabled (see the note at the top of this page). *** ## `bb issue edit` [Section titled “bb issue edit”](#bb-issue-edit) Edit an issue. At least one change flag is required. ```bash bb issue edit <id> [options] ``` ### Arguments [Section titled “Arguments”](#arguments-1) | Argument | Description | | -------- | -------------------- | | `id` | Issue ID (e.g. `42`) | ### Options [Section titled “Options”](#options-2) | Option | Description | | ----------------------- | ----------------------------------------------- | | `-t, --title <title>` | New title | | `-b, --body <text>` | New description (replaces the existing body) | | `--kind <kind>` | New kind | | `--priority <priority>` | New priority | | `--assignee <username>` | Reassign to a user | | `--state <state>` | New state (`on-hold` for the API’s `"on hold"`) | ### Examples [Section titled “Examples”](#examples-3) ```bash bb issue edit 42 --title "Crash on login (Safari only)" bb issue edit 42 --state on-hold --priority critical # Confirm the reassignment landed bb issue edit 42 --assignee some.user --json --jq '.issue.assignee.display_name' ``` ### Notes [Section titled “Notes”](#notes-3) * Only the flags you pass are changed; everything else is left untouched. * **JSON envelope:** `{ workspace, repoSlug, issue }` with the updated issue. *** ## `bb issue close` [Section titled “bb issue close”](#bb-issue-close) Close an issue — sugar for `bb issue edit <id> --state closed`, optionally posting a comment first. ```bash bb issue close <id> [options] ``` ### Arguments [Section titled “Arguments”](#arguments-2) | Argument | Description | | -------- | -------------------- | | `id` | Issue ID (e.g. `42`) | ### Options [Section titled “Options”](#options-3) | Option | Description | | ---------------------- | -------------------------------- | | `-c, --comment <text>` | Post this comment before closing | ### Examples [Section titled “Examples”](#examples-4) ```bash bb issue close 42 bb issue close 42 --comment "Fixed in 1.4.2" # Verify the new state bb issue close 42 --json --jq '.issue.state' ``` ### Notes [Section titled “Notes”](#notes-4) * With `--comment`, the comment is posted **before** the state change so it lands while the issue is still open. * **JSON envelope:** `{ workspace, repoSlug, issue }` with the closed issue. *** ## `bb issue comment` [Section titled “bb issue comment”](#bb-issue-comment) Add a comment to an issue. ```bash bb issue comment <id> --body <text> ``` ### Arguments [Section titled “Arguments”](#arguments-3) | Argument | Description | | -------- | -------------------- | | `id` | Issue ID (e.g. `42`) | ### Options [Section titled “Options”](#options-4) | Option | Description | | ------------------- | --------------------------------------- | | `-b, --body <text>` | Comment text in Markdown (**required**) | ### Examples [Section titled “Examples”](#examples-5) ```bash bb issue comment 42 --body "Reproduced on main" # Capture the new comment id bb issue comment 42 --body "Reproduced on main" --json --jq '.comment.id' ``` ### Notes [Section titled “Notes”](#notes-5) * **JSON envelope:** `{ workspace, repoSlug, comment }` with the created comment. # Pipeline Commands - Run and Inspect Bitbucket Pipelines > Reference for Bitbucket CLI pipeline commands. List, view, trigger, stop, and read logs of Bitbucket Pipelines builds from the command line. Manage Bitbucket Pipelines (CI/CD) — list runs, inspect a run and its steps, trigger and stop runs, and read step logs. Pipeline commands operate at **repository** scope. Run them inside a cloned Bitbucket repository, or pass `-w, --workspace <workspace>` and `-r, --repo <repo>` explicitly. Global options available on all pipeline commands: `--json [fields]`, `--jq <expression>`, `--no-color`, `--no-unicode`, `--no-truncate`, `--locale <locale>`, `-w, --workspace`, `-r, --repo`. An `<id>` is either the build number from the UI (`42`) or the pipeline UUID with braces (`{a1b2c3d4-...}`). `--json` output is wrapped in an envelope keyed by `workspace` and `repoSlug`; the `# →` comments below show each shape. *** ## `bb pipeline list` [Section titled “bb pipeline list”](#bb-pipeline-list) List pipeline runs, newest first. ```bash bb pipeline list [options] ``` ### Options [Section titled “Options”](#options) | Option | Description | | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | `--status <status>` | Filter by status: `PARSING`, `PENDING`, `PAUSED`, `HALTED`, `BUILDING`, `ERROR`, `PASSED`, `FAILED`, `STOPPED`, `UNKNOWN` (case-insensitive) | | `--branch <branch>` | Filter by target branch | | `--sort <attribute>` | Sort attribute: `created_on`, `run_creation_date`, `creator.uuid`; prefix with `-` for descending (default: `-created_on`) | | `--limit <number>` | Maximum number of runs (default: 25) | | `--all` | List all runs (overrides `--limit`) | ### Examples [Section titled “Examples”](#examples) ```bash bb pipeline list bb pipeline list --status FAILED bb pipeline list --branch main --limit 50 # → { workspace, repoSlug, [status], [branch], sort, count, pipelines } bb pipeline list --json # Build numbers of recent failures, via built-in --jq bb pipeline list --status FAILED --json --jq '.pipelines[].build_number' ``` ### Notes [Section titled “Notes”](#notes) * Columns: build number, status (colored), ref (truncated to 40 characters; disable with `--no-truncate`), trigger, created date, and duration for completed runs. * `--limit` is enforced across paginated responses. When results are capped the CLI prints `Showing 25 pipelines. Use --limit <n> or --all to see more.` (suppressed with `--json`). * `--status` is upper-cased before validation, so `failed` and `FAILED` both work. `--sort` is matched case-sensitively. * An invalid value lists the allowed ones and, when the input is close to a valid one, suggests it: ```text --status must be one of: PARSING, PENDING, PAUSED, HALTED, BUILDING, ERROR, PASSED, FAILED, STOPPED, UNKNOWN (Did you mean FAILED?) ``` A `--sort` value that differs only in case gets `(Values are case-sensitive — use created_on.)` instead of a suggestion. *** ## `bb pipeline view` [Section titled “bb pipeline view”](#bb-pipeline-view) View run details and a per-step summary. `<id>` is a build number or UUID. ```bash bb pipeline view <id> [options] ``` ### Examples [Section titled “Examples”](#examples-1) ```bash bb pipeline view 42 bb pipeline view {a1b2c3d4-0000-0000-0000-000000000000} # → { workspace, repoSlug, pipeline, steps } bb pipeline view 42 --json # Status name of the run bb pipeline view 42 --json --jq '.pipeline.state.result.name // .pipeline.state.name' ``` ### Notes [Section titled “Notes”](#notes-1) * The human view shows number, UUID, status, ref, the custom pipeline selector when the run used one (`Pipeline:`), trigger, creator, created/completed timestamps, duration, and a step table (index, name, status, duration). * The step index is the value you pass to `bb pipeline logs --step`. * The step table and the JSON `steps` array are complete even on large runs — the CLI follows the steps endpoint’s pagination. * An unknown id returns `Pipeline 42 not found in acme/api.` *** ## `bb pipeline run` [Section titled “bb pipeline run”](#bb-pipeline-run) Trigger a pipeline run on a branch. ```bash bb pipeline run [options] ``` ### Options [Section titled “Options”](#options-1) | Option | Description | | ----------------------- | --------------------------------------------------------- | | `-b, --branch <branch>` | Branch to run on (default: current git branch) | | `--commit <hash>` | Run against a specific commit on the branch | | `-p, --pipeline <name>` | Custom pipeline definition from `bitbucket-pipelines.yml` | | `--var <key=value...>` | Pipeline variable; repeatable, value may contain `=` | ### Examples [Section titled “Examples”](#examples-2) ```bash # Run the default pipeline for the current branch bb pipeline run bb pipeline run --branch main bb pipeline run --pipeline deploy-prod --var ENV=prod --var DRY_RUN=false bb pipeline run --branch main --commit abc123def456 # → { workspace, repoSlug, pipeline }; grab the build number bb pipeline run --branch main --json --jq '.pipeline.build_number' ``` ### Notes [Section titled “Notes”](#notes-2) * Outside a git repository, `--branch` is required (the error tells you so). * `--pipeline <name>` selects a `custom:` pipeline defined in `bitbucket-pipelines.yml`. * Variables are sent unsecured; secured variables must be configured in repository settings. * On success the CLI prints the build number plus ready-to-paste `bb pipeline view` / `bb pipeline logs` commands. *** ## `bb pipeline stop` [Section titled “bb pipeline stop”](#bb-pipeline-stop) Stop a running pipeline. `<id>` is a build number or UUID. ```bash bb pipeline stop <id> [options] ``` ### Examples [Section titled “Examples”](#examples-3) ```bash bb pipeline stop 42 # → { workspace, repoSlug, pipelineId, stopped } bb pipeline stop 42 --json --jq '.stopped' ``` ### Notes [Section titled “Notes”](#notes-3) * No `--yes` confirmation is required: stopping CI is reversible — rerun with `bb pipeline run`. *** ## `bb pipeline logs` [Section titled “bb pipeline logs”](#bb-pipeline-logs) Print the raw log of a pipeline step. `<id>` is a build number or UUID. ```bash bb pipeline logs <id> [options] ``` ### Options [Section titled “Options”](#options-2) | Option | Description | | ---------------------------- | --------------------------------------------------------------- | | `-s, --step <uuid-or-index>` | Step to fetch: a step UUID (braces optional) or a 1-based index | ### Examples [Section titled “Examples”](#examples-4) ```bash # Single-step runs need no --step bb pipeline logs 42 bb pipeline logs 42 --step 2 bb pipeline logs 42 --step {a1b2c3d4-0000-0000-0000-000000000000} bb pipeline logs 42 --step a1b2c3d4-0000-0000-0000-000000000000 # → { workspace, repoSlug, pipelineId, stepUuid, log } bb pipeline logs 42 --json --jq '.log' ``` ### Notes [Section titled “Notes”](#notes-4) * With exactly one step, it is selected automatically. * With several steps and no `--step`, the CLI lists the steps (index, name, status, UUID) instead of guessing. With `--json` it returns `{ workspace, repoSlug, pipelineId, count, steps }` so scripts and agents can pick a step UUID and call again. * Every step is selectable even on large runs — the CLI follows the steps endpoint’s pagination, so indexes and UUIDs beyond the API’s default page size of 10 work. * The log is printed verbatim to stdout, so it pipes cleanly into `grep`, `less`, or a file. * Four failure modes — a queued run with no steps yet, an out-of-range `--step` index, a `--step` UUID that matches nothing, and a step that has produced no log yet — each get their own message, in that order: ```text Pipeline 42 has no steps yet. It may still be queued — check with `bb pipeline view 42`. --step index 9 is out of range; the pipeline has 3 steps. No step matching 'abc' found. Available steps: 1 ({uuid-1}), 2 ({uuid-2}). No log found for step {uuid-2} of pipeline 42. The step may not have started yet. ``` *** ## See also [Section titled “See also”](#see-also) * [Scripting & Automation](/guides/scripting/) — JSON envelopes, `--jq`, exit codes. * [CI/CD Integration](/guides/cicd/) — using `bb` inside pipelines. # PR Commands > Task-based reference for creating, reviewing, and merging pull requests Manage pull requests (PRs) in Bitbucket repositories. New here? Start with [Create, edit, and view](/commands/pr/create-and-edit/). Global options work on every PR command: `--json [fields]`, `--jq <expression>`, `--no-color`, `--no-unicode`, `--no-truncate`, `--locale <locale>`, `-w, --workspace`, `-r, --repo` — see [Global Flags](/reference/global-flags/). ## Command groups [Section titled “Command groups”](#command-groups) [Create, edit, and view](/commands/pr/create-and-edit/)Open a PR, change its title or description, list PRs, inspect one. [Activity and checks](/commands/pr/activity-and-checks/)Read the activity timeline and CI build statuses before approving or merging. [Diff and checkout](/commands/pr/diff-and-checkout/)Print the patch or diffstat, fetch the PR branch locally, open the diff in a browser. [Review and merge](/commands/pr/review-and-merge/)Approve, decline, mark a draft ready, and merge with an explicit strategy. [Comments](/commands/pr/comments/)List, add, view, edit, reply to, resolve, unresolve, and delete general or inline review comments. [Reviewers](/commands/pr/reviewers/)Add and remove reviewers. Adding someone already assigned is a no-op, as is removing someone who is not. ## Most-used commands [Section titled “Most-used commands”](#most-used-commands) | Task | Command | | --------------------------------------------------- | --------------------------------------------------- | | Create a PR | `bb pr create -t "Add feature"` | | Create a PR with the repository’s default reviewers | `bb pr create -t "Add feature" --default-reviewers` | | List open PRs | `bb pr list` | | List all PRs (ignore the default limit) | `bb pr list --all` | | List PRs where you are a reviewer | `bb pr list --mine` | | View PR details | `bb pr view 42` | | View checks | `bb pr checks 42` | | Review diff | `bb pr diff 42 --stat` | | Checkout PR locally | `bb pr checkout 42` | | Approve PR | `bb pr approve 42` | | Merge PR | `bb pr merge 42 --strategy squash` | ## JSON for automation [Section titled “JSON for automation”](#json-for-automation) List commands wrap their results in an envelope. Bare `bb pr list --json` returns `{workspace, repoSlug, state, filters, count, pullRequests}`, so a `--jq` filter starts at `.pullRequests[]`. Adding a field list (`--json id,title`) drops the envelope and returns a flat array, so the filter starts at `.[]` instead. Single-PR commands like `bb pr view` return the PR object itself, with no envelope. ```bash # Project to specific fields (returns a flat array) bb pr list --json id,title,author.display_name # Filter with built-in --jq bb pr list --json --jq '.pullRequests[] | select(.state == "OPEN") | .title' # Combine projection + filter (jq runs after projection) bb pr list --json id,title,state --jq '.[] | select(.state == "OPEN") | .title' # Grab a PR URL from view output bb pr view 42 --json --jq '.links.html.href' # Capture diffstat totals bb pr diff 42 --stat --json --jq '{filesChanged, totalAdditions, totalDeletions}' ``` `--json <fields>` misfires on `bb pr create`, `bb pr edit` and `bb pr view` — see [Create, Edit, and View PRs](/commands/pr/create-and-edit/) for why, and [JSON Output](/reference/json-output/) for the full reference. # Activity and Checks > Inspect pull request activity history and CI/CD check status Inspect pull request activity and build checks. Global options available on all PR commands: `--json [fields]`, `--jq <expression>`, `--no-color`, `-w, --workspace`, `-r, --repo`. ## `bb pr activity` [Section titled “bb pr activity”](#bb-pr-activity) Show a pull request activity log. ```bash bb pr activity <id> [options] ``` ### Arguments [Section titled “Arguments”](#arguments) | Argument | Description | | -------- | --------------- | | `id` | Pull request ID | ### Options [Section titled “Options”](#options) | Option | Description | Default | | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------- | | `--limit <number>` | Maximum number of activity entries | `25` | | `--all` | Show all activity entries (overrides `--limit`) | | | `--type <types>` | Filter by activity type (comma-separated): `comment`, `approval`, `changes_requested`, `merge`, `decline`, `commit`, `update` | | | `--no-truncate` | Global flag. Show full details without truncation | | | `-w, --workspace <workspace>` | Workspace | | | `-r, --repo <repo>` | Repository | | | `--json` | Output as JSON | | ### Examples [Section titled “Examples”](#examples) ```bash # View activity for PR #42 bb pr activity 42 # Filter to comment and approval events bb pr activity 42 --type comment,approval # Limit results bb pr activity 42 --limit 10 # Show the full activity history bb pr activity 42 --all # Get activity as JSON bb pr activity 42 --json ``` Output: ```text TYPE ACTOR DATE DETAILS -------- -------- ------------------------ -------------------------------- UPDATE Sam Ali Jul 29, 2026 at 01:20 PM state: OPEN COMMENT Jane Doe Jul 29, 2026 at 10:41 AM #486513002 Why was this removed? APPROVAL Lee Park Jul 28, 2026 at 06:05 PM approved COMMIT Sam Ali Jul 28, 2026 at 05:58 PM commit a1b2c3d ``` ### Notes [Section titled “Notes”](#notes) * Comment snippets and change-request reasons are truncated to 80 characters, and `title:` change details to 60. Use `--no-truncate` for the full text * An unrecognized `--type` token fails with `--type must be one of: comment, approval, changes_requested, merge, decline, commit, update`. Each bad token that is close to a valid one adds a `(Did you mean ...?)` line; tokens with no close match add nothing * `--limit` is enforced across paginated activity responses * When the result is capped by `--limit`, a hint shows how many were listed; use a higher `--limit` or `--all` to see the rest (suppressed with `--json`) *** ## `bb pr checks` [Section titled “bb pr checks”](#bb-pr-checks) Show CI/CD checks and build status for a pull request. ```bash bb pr checks <id> [options] ``` ### Arguments [Section titled “Arguments”](#arguments-1) | Argument | Description | | -------- | --------------- | | `id` | Pull request ID | ### Options [Section titled “Options”](#options-1) | Option | Description | | ----------------------------- | ------------------------------------------------------------ | | `--no-truncate` | Global flag. Show full check descriptions without truncation | | `-w, --workspace <workspace>` | Workspace | | `-r, --repo <repo>` | Repository | | `--json` | Output as JSON | ### Examples [Section titled “Examples”](#examples-1) ```bash # View checks for PR #42 bb pr checks 42 # View checks in a specific repository bb pr checks 42 -w myworkspace -r myrepo # Get checks as JSON bb pr checks 42 --json ``` Output: ```text Pull Request #42 - 3 checks ──────────────────────────────────────────────────────────── STATUS NAME DESCRIPTION UPDATED ----------- -------------- ----------------------------- ------------------------ OK passed build Build succeeded in 2m 11s Jul 29, 2026 at 01:31 PM FAIL failed unit-tests 3 of 412 tests failed Jul 29, 2026 at 01:34 PM RUN running deploy-preview Deploying preview environment Jul 29, 2026 at 01:36 PM OK 1 successful, FAIL 1 failed, RUN 1 pending ``` ### Notes [Section titled “Notes”](#notes-1) * The `STATUS` cell is an icon plus a label: `OK passed`, `FAIL failed`, `RUN running`, `STOP stopped`, or `?` plus the raw state for anything else * The summary line counts only successful, failed, and running checks, so it can total fewer than the header count * Check descriptions are truncated to 40 characters in the table view. Use `--no-truncate` for the full text * `bb pr checks` is not paginated — it makes a single request and has no `--limit` or `--all` * `--json` returns `{ pullRequestId, workspace, repoSlug, summary, statuses }`. Unlike list commands, there is no `count` key — use the length of `statuses` * With no checks, the command prints `No CI/CD checks found for this pull request`; with `--json` it returns an empty `statuses` array # Comments > List, add, view, edit, reply to, resolve, unresolve, and delete pull request comments Manage pull request comments. Global options available on all PR commands: `--json [fields]`, `--jq <expression>`, `--no-color`, `-w, --workspace`, `-r, --repo`. Every `bb pr comments` subcommand accepts those globals. They work the same everywhere, so the per-command examples below leave them out: ```bash # Target a repository other than the one you are standing in bb pr comments list 42 -w myworkspace -r myrepo # Machine-readable output bb pr comments list 42 --json ``` `view`, `edit`, `reply`, `resolve`, and `unresolve` have no options of their own — only the globals. ## `bb pr comments` [Section titled “bb pr comments”](#bb-pr-comments) ### Subcommands [Section titled “Subcommands”](#subcommands) | Subcommand | Description | | -------------------------------------- | -------------------------------------------------- | | `list <id>` | List comments on a pull request | | `add <id> <message>` | Add a comment to a pull request | | `view <pr-id> <comment-id>` | View a single comment on a pull request | | `edit <pr-id> <comment-id> <message>` | Edit a comment on a pull request | | `reply <pr-id> <comment-id> <message>` | Reply to a comment on a pull request | | `resolve <pr-id> <comment-id>` | Resolve a comment thread on a pull request | | `unresolve <pr-id> <comment-id>` | Reopen a resolved comment thread on a pull request | | `delete <pr-id> <comment-id>` | Delete a comment on a pull request | *** ## `bb pr comments list` [Section titled “bb pr comments list”](#bb-pr-comments-list) List comments on a pull request. ```bash bb pr comments list <id> [options] ``` ### Arguments [Section titled “Arguments”](#arguments) | Argument | Description | | -------- | --------------- | | `id` | Pull request ID | ### Options [Section titled “Options”](#options) | Option | Description | Default | | ------------------ | --------------------------------------------------------- | ------- | | `--limit <number>` | Maximum number of comments | `25` | | `--all` | List all comments (overrides `--limit`) | | | `--resolved` | Only show resolved comments | | | `--unresolved` | Only show unresolved comments | | | `--no-truncate` | Global flag. Show full comment content without truncation | | ### Examples [Section titled “Examples”](#examples) ```bash # List comments on PR #42 bb pr comments list 42 # Only comments that still need attention bb pr comments list 42 --unresolved # List more comments bb pr comments list 42 --limit 50 # List every comment bb pr comments list 42 --all # Show full comment content (not truncated) bb pr comments list 42 --no-truncate ``` Output: ```text ID Author Content Status Date --------- -------- ------------------------------- -------- ------------------------ 486512301 Jane Doe Consider renaming this variable resolved Jul 28, 2026 at 11:14 AM 486512477 Sam Ali Good catch, fixed. open Jul 28, 2026 at 12:02 PM 486513002 Jane Doe Why was this removed? open Jul 29, 2026 at 10:41 AM ``` ### Notes [Section titled “Notes”](#notes) * Comment content is truncated to 60 characters in the table view. Use `--no-truncate` for the full text * The `Status` column shows `resolved`, `pending`, or `open`. Bitbucket records resolution on the comment that was resolved, so a reply inside a resolved thread shows `open` (or `pending` if it is an unpublished draft) * `--resolved` and `--unresolved` filter on the same resolution state and cannot be combined * With `--resolved`/`--unresolved` the filter is applied client-side after each page is fetched, so `--limit` counts comments that survive the filter — `--unresolved --limit 25` keeps fetching pages until 25 unresolved comments are found or the list is exhausted * When the result is capped by `--limit`, a hint shows how many were listed; use a higher `--limit` or `--all` to see the rest (suppressed with `--json`) *** ## `bb pr comments add` [Section titled “bb pr comments add”](#bb-pr-comments-add) Add a general comment, or an inline comment anchored to a file line. ```bash bb pr comments add <id> <message> [options] ``` ### Arguments [Section titled “Arguments”](#arguments-1) | Argument | Description | | --------- | --------------- | | `id` | Pull request ID | | `message` | Comment message | ### Options [Section titled “Options”](#options-1) | Option | Description | | ---------------------- | --------------------------------------------------------------------------- | | `--file <path>` | File path for an inline comment (requires `--line-to` and/or `--line-from`) | | `--line-to <number>` | Line number in the new version of the file (requires `--file`) | | `--line-from <number>` | Line number in the old version of the file (requires `--file`) | ### Examples [Section titled “Examples”](#examples-1) ```bash # Add a general comment to PR #42 bb pr comments add 42 "LGTM! This looks great." # Inline comment on a line in the new file bb pr comments add 42 "Consider renaming this variable" --file src/index.ts --line-to 15 # Inline comment on a line in the old (removed) version of the file bb pr comments add 42 "Why was this removed?" --file src/utils.ts --line-from 10 # Inline comment spanning old and new lines bb pr comments add 42 "This logic changed" --file src/app.ts --line-from 5 --line-to 8 ``` ### Notes [Section titled “Notes”](#notes-1) * `--file` is required when using `--line-to` or `--line-from` * At least one of `--line-to` or `--line-from` is required when using `--file` * Line numbers must be positive integers *** ## `bb pr comments view` [Section titled “bb pr comments view”](#bb-pr-comments-view) View a single comment, including whether it is resolved. ```bash bb pr comments view <pr-id> <comment-id> ``` ### Arguments [Section titled “Arguments”](#arguments-2) | Argument | Description | | ------------ | --------------- | | `pr-id` | Pull request ID | | `comment-id` | Comment ID | ### Examples [Section titled “Examples”](#examples-2) ```bash # View comment #486512301 on PR #42 bb pr comments view 42 486512301 ``` ### Notes [Section titled “Notes”](#notes-2) * The header shows `[resolved]` or `[unresolved]` for that specific comment. Bitbucket records the resolution on the comment that was resolved, so a reply inside a resolved thread still shows `[unresolved]` * Unpublished draft review comments show `[pending]` instead * Deleted comments render their content as `[deleted]` * `--json` prints the raw comment object returned by the API *** ## `bb pr comments edit` [Section titled “bb pr comments edit”](#bb-pr-comments-edit) Edit a comment on a pull request. ```bash bb pr comments edit <pr-id> <comment-id> <message> ``` ### Arguments [Section titled “Arguments”](#arguments-3) | Argument | Description | | ------------ | ------------------- | | `pr-id` | Pull request ID | | `comment-id` | Comment ID | | `message` | New comment message | ### Examples [Section titled “Examples”](#examples-3) ```bash # Replace the body of comment #486512301 on PR #42 bb pr comments edit 42 486512301 "Updated: I noticed something else..." ``` *** ## `bb pr comments reply` [Section titled “bb pr comments reply”](#bb-pr-comments-reply) Reply to an existing comment. The reply is attached to the parent comment, so it lands in the same thread. ```bash bb pr comments reply <pr-id> <comment-id> <message> ``` ### Arguments [Section titled “Arguments”](#arguments-4) | Argument | Description | | ------------ | ----------------------------- | | `pr-id` | Pull request ID | | `comment-id` | ID of the comment to reply to | | `message` | Reply message | ### Examples [Section titled “Examples”](#examples-4) ```bash # Reply to comment #486512301 on PR #42 bb pr comments reply 42 486512301 "Good catch, fixed." ``` ### Notes [Section titled “Notes”](#notes-3) * Use `bb pr comments list <id>` to find the comment ID to reply to * How Bitbucket anchors a reply to an inline comment is decided server-side *** ## `bb pr comments resolve` [Section titled “bb pr comments resolve”](#bb-pr-comments-resolve) Resolve a comment thread on a pull request. ```bash bb pr comments resolve <pr-id> <comment-id> ``` ### Arguments [Section titled “Arguments”](#arguments-5) | Argument | Description | | ------------ | --------------- | | `pr-id` | Pull request ID | | `comment-id` | Comment ID | ### Examples [Section titled “Examples”](#examples-5) ```bash # Resolve comment thread #486512301 on PR #42 bb pr comments resolve 42 486512301 ``` ### Notes [Section titled “Notes”](#notes-4) * Resolving is reversible with `bb pr comments unresolve` * `--json` returns `{ success, pullRequestId, commentId, resolution }`; the API returns the resolution record, not the full comment — use `bb pr comments view` to read the comment back *** ## `bb pr comments unresolve` [Section titled “bb pr comments unresolve”](#bb-pr-comments-unresolve) Reopen a resolved comment thread on a pull request. ```bash bb pr comments unresolve <pr-id> <comment-id> ``` ### Arguments [Section titled “Arguments”](#arguments-6) | Argument | Description | | ------------ | --------------- | | `pr-id` | Pull request ID | | `comment-id` | Comment ID | ### Examples [Section titled “Examples”](#examples-6) ```bash # Reopen comment thread #486512301 on PR #42 bb pr comments unresolve 42 486512301 ``` ### Notes [Section titled “Notes”](#notes-5) * The API returns no body, so `--json` reports only `{ success, pullRequestId, commentId }` *** ## `bb pr comments delete` [Section titled “bb pr comments delete”](#bb-pr-comments-delete) Delete a comment from a pull request. `--yes` is required. ```bash bb pr comments delete <pr-id> <comment-id> [options] ``` ### Arguments [Section titled “Arguments”](#arguments-7) | Argument | Description | | ------------ | --------------- | | `pr-id` | Pull request ID | | `comment-id` | Comment ID | ### Options [Section titled “Options”](#options-2) | Option | Description | | ----------- | --------------------------- | | `-y, --yes` | Confirm deletion (required) | ### Examples [Section titled “Examples”](#examples-7) ```bash # Delete comment #486512301 from PR #42 bb pr comments delete 42 486512301 --yes ``` ### Notes [Section titled “Notes”](#notes-6) * `bb pr comments delete` never prompts. Without `--yes` it exits with a validation error ending in `Use --yes to confirm.` * Deleting a comment is permanent and cannot be undone # Create, Edit, and View PRs > Create pull requests, edit metadata, and inspect PR details Create and inspect pull requests (PRs). Global options work on every PR command: `--json [fields]`, `--jq <expression>`, `--no-color`, `--no-unicode`, `--no-truncate`, `--locale <locale>`, `-w, --workspace`, `-r, --repo` — see [Global Flags](/reference/global-flags/). Field projection (`--json id,title`) works on list commands such as `bb pr list`. It does not work on `bb pr create`, `bb pr edit` or `bb pr view`. The payload there is a single PR carrying a `reviewers` array, and the projector unwraps that array instead — you get the reviewers back, or `[]` when there are none. Use `--json --jq '{...}'` on those three. ## `bb pr create` [Section titled “bb pr create”](#bb-pr-create) Create a pull request. ```bash bb pr create [options] ``` ### Options [Section titled “Options”](#options) | Option | Description | | ---------------------------- | ------------------------------------------------------------ | | `-t, --title <title>` | PR title (required) | | `-b, --body <body>` | PR description | | `-s, --source <branch>` | Source branch (default: current branch) | | `-d, --destination <branch>` | Destination branch (default: main) | | `--close-source-branch` | Close source branch after merge | | `--draft` | Create the PR as draft | | `--reviewer <user>` | Add a reviewer by account ID or `{uuid}` (repeatable) | | `--default-reviewers` | Include the repository’s default reviewers (opt-in) | | `--no-default-reviewers` | Skip default reviewers even when the config key enables them | ### Examples [Section titled “Examples”](#examples) ```bash # Create a PR from current branch to main bb pr create -t "Add new feature" # Create a PR with full details bb pr create -t "Add login page" -b "Implements user login functionality" -d develop # Create a PR that will close the source branch after merging bb pr create -t "Hotfix: Critical bug" --close-source-branch # Create a draft PR bb pr create -t "WIP: Add feature" --draft # Auto-add the repository's default reviewers (matches the Bitbucket web UI) bb pr create -t "Add new feature" --default-reviewers # Add specific reviewers (repeatable; accepts account ID or {uuid}) bb pr create -t "Add new feature" \ --reviewer "712020:3cfed7e0-0ed6-49fc-bb35-410a00ccee6f" \ --reviewer "{c1cb1bb5-2e32-456e-a373-43978dc12aa1}" # Combine defaults + explicit additions (duplicates are de-duped) bb pr create -t "Add new feature" --default-reviewers \ --reviewer "712020:3cfed7e0-0ed6-49fc-bb35-410a00ccee6f" # Capture the new PR's URL from JSON output for scripting bb pr create -t "Add new feature" --json --jq '.links.html.href' ``` ### Reviewers [Section titled “Reviewers”](#reviewers) By default `bb pr create` does **not** attach reviewers to the PR — this differs from the Bitbucket web UI, which auto-populates the repository’s default reviewers. * `--default-reviewers` opts in per-invocation. The command fetches the repository’s *effective* default reviewers (repo-level + project-inherited) and attaches them. * `--reviewer <user>` adds specific reviewers regardless of the defaults and can be passed multiple times. Accepts an **account ID** (e.g. `712020:3cfed7e0-...`) or a **UUID** in curly braces (e.g. `{c1cb1bb5-...}`). Bitbucket Cloud’s GDPR changes retired username lookups, so nicknames are not accepted. * The PR author is automatically excluded from the reviewer list — Bitbucket rejects PRs that list the author as a reviewer. * To make `--default-reviewers` the default behavior, set the config key: ```bash bb config set prCreateIncludeDefaultReviewers true ``` Pass `--no-default-reviewers` to skip defaults for a single invocation when this is enabled. * If the default-reviewer fetch fails (network error, permission issue, etc.) the CLI prints `Could not fetch default reviewers: … Continuing without them.` and creates the PR anyway. Only the *defaults* are dropped — reviewers you passed with `--reviewer` are still attached. A failed `--reviewer` lookup, by contrast, aborts the create. See [`bb repo default-reviewers`](/commands/repo/#bb-repo-default-reviewers) to inspect or manage the underlying default reviewer list. *** ## `bb pr edit` [Section titled “bb pr edit”](#bb-pr-edit) Edit an existing pull request’s title or description. ```bash bb pr edit [id] [options] ``` `[id]` is the PR number. Omit it to auto-detect the open PR whose source branch matches your current git branch. ### Options [Section titled “Options”](#options-1) | Option | Description | | ------------------------ | -------------------------- | | `-t, --title <title>` | New PR title | | `-b, --body <body>` | New PR description | | `-F, --body-file <file>` | Read description from file | ### Examples [Section titled “Examples”](#examples-1) ```bash # Edit the title by ID bb pr edit 42 -t "Updated: Add new feature" # Edit the description bb pr edit 42 -b "This PR implements the new login flow" # Edit both title and description bb pr edit 42 -t "New title" -b "New description" # Auto-detect the PR from the current branch and update the title bb pr edit -t "Updated title" # Read the description from a file bb pr edit 42 -F description.md # Get the updated PR as JSON bb pr edit 42 -t "New title" --json ``` ### Notes [Section titled “Notes”](#notes) * When no ID is provided, the command searches for an open PR where the source branch matches your current git branch * At least one of `--title`, `--body`, or `--body-file` must be provided * If both `-b/--body` and `-F/--body-file` are given, the file wins and no error is raised. This differs from `bb issue create`, which rejects the combination * An unreadable path fails with `Failed to read file '<path>': <reason>` *** ## `bb pr list` [Section titled “bb pr list”](#bb-pr-list) List pull requests. ```bash bb pr list [options] ``` ### Options [Section titled “Options”](#options-2) | Option | Description | | --------------------- | ------------------------------------------------------------------- | | `-s, --state <state>` | Filter by state: OPEN, MERGED, DECLINED, SUPERSEDED (default: OPEN) | | `--limit <number>` | Maximum number of PRs (default: 25) | | `--all` | List all PRs (overrides `--limit`) | | `--mine` | Show only PRs where you are a reviewer | ### Examples [Section titled “Examples”](#examples-2) ```bash # List open PRs in current repository bb pr list # List merged PRs bb pr list -s MERGED # List declined PRs bb pr list -s DECLINED # List PRs in specific repository bb pr list -w myworkspace -r myrepo # List with JSON output for scripting bb pr list --json # Project to specific fields (returns a flat array) bb pr list --json id,title,author.display_name # Filter with built-in --jq (no external jq binary needed) bb pr list --json --jq '.pullRequests[] | select(.state == "OPEN") | .title' # List more results bb pr list --limit 50 # Fetch every open PR, ignoring the default limit of 25 bb pr list --all # Show only PRs assigned to you for review bb pr list --mine ``` ### Notes [Section titled “Notes”](#notes-1) * Draft PRs are shown with a `[DRAFT]` prefix in the title * `--limit` is enforced across paginated API responses * The TITLE column is truncated to 50 characters, and the `[DRAFT] `prefix counts against that budget. Pass `--no-truncate` for full titles; `--json` output is never truncated `--mine` does not mean “my PRs” `--mine` filters PRs where you are assigned as a **reviewer**, not PRs you authored. It uses the Bitbucket API’s `reviewers.uuid` filter. To find PRs you created, filter the JSON yourself: ```bash bb pr list --json --jq '.pullRequests[] | select((.author.nickname // .author.display_name) == "your-username")' ``` *** ## `bb pr view` [Section titled “bb pr view”](#bb-pr-view) View pull request details. ```bash bb pr view <id> [options] ``` `<id>` is the PR number. ### Examples [Section titled “Examples”](#examples-3) ```bash # View PR #42 in current repository bb pr view 42 # View PR in specific repository bb pr view 42 -w myworkspace -r myrepo # Get PR details as JSON bb pr view 42 --json # Pick out fields with built-in --jq bb pr view 42 --json --jq '{id, title, state, author: .author.display_name}' # Extract just the web URL bb pr view 42 --json --jq '.links.html.href' ``` # Diff and Checkout > Checkout pull request branches locally and inspect diff output Review pull request changes with local checkout and diff tooling. Global options available on all PR commands: `--json [fields]`, `--jq <expression>`, `--no-color`, `-w, --workspace`, `-r, --repo`. ## `bb pr checkout` [Section titled “bb pr checkout”](#bb-pr-checkout) Check out a pull request’s source branch locally. ```bash bb pr checkout <id> [options] ``` ### Arguments [Section titled “Arguments”](#arguments) | Argument | Description | | -------- | --------------- | | `id` | Pull request ID | ### Options [Section titled “Options”](#options) | Option | Description | | ----------------------------- | -------------- | | `-w, --workspace <workspace>` | Workspace | | `-r, --repo <repo>` | Repository | | `--json` | Output as JSON | ### Examples [Section titled “Examples”](#examples) ```bash # Checkout PR #42 to review locally bb pr checkout 42 # Checkout PR from specific repository bb pr checkout 42 -w myworkspace -r myrepo ``` ### Notes [Section titled “Notes”](#notes) The command, in order: 1. Fetches the latest changes from the remote 2. Checks out the pull request’s source branch 3. If that checkout fails, creates a local branch `pr-<id>` tracking `origin/<source-branch>` `--json` returns `{ success, pullRequestId, branch, pullRequest }`, where `branch` is whichever of the two names was checked out. *** ## `bb pr diff` [Section titled “bb pr diff”](#bb-pr-diff) View the diff of a pull request in unified diff format. ```bash bb pr diff [id] [options] ``` ### Arguments [Section titled “Arguments”](#arguments-1) | Argument | Description | | -------- | ------------------------------------------------------------- | | `id` | Pull request ID (optional - auto-detects from current branch) | ### Options [Section titled “Options”](#options-1) | Option | Description | | ----------------------------- | ---------------------------------------------------------- | | `-w, --workspace <workspace>` | Workspace | | `-r, --repo <repo>` | Repository | | `--color <when>` | Colorize output: `auto`, `always`, `never` (default: auto) | | `--name-only` | Show only names of changed files | | `--stat` | Show diffstat (files changed, insertions, deletions) | | `--web` | Open diff in web browser | | `--json` | Output as JSON | ### Examples [Section titled “Examples”](#examples-1) ```bash # View diff for PR #42 bb pr diff 42 # Auto-detect PR from current branch bb pr diff # Show only changed file names bb pr diff 42 --name-only # Show statistics (like git diff --stat) bb pr diff 42 --stat # Open diff in browser bb pr diff 42 --web # Return browser URL as JSON bb pr diff 42 --web --json # Disable colors for piping to file or other commands bb pr diff 42 --color never > pr-42.patch # Get diffstat as JSON for scripting bb pr diff 42 --stat --json ``` `--stat` output: ```text src/index.ts | +12 -3 src/utils.ts | +4 docs/README.md | -8 3 files changed, 16 insertions(+), 11 deletions(-) ``` ### Notes [Section titled “Notes”](#notes-1) * When no ID is provided, the command searches for an open pull request whose source branch matches your current git branch * `--color auto` colors the diff only when stdout is a terminal: green for additions, red for deletions, cyan for hunk headers. Whole lines are colored by their leading marker — there is no language-aware highlighting * `--color never` forces plain text, which is what you want when redirecting to a file or piping into another command. The global `--no-color` flag does the same for every command * The value is validated before the request. A typo fails with `--color must be one of: auto, always, never` plus a `(Did you mean never?)` suggestion, rather than silently falling back * Passing `--color <when>` at all turns the *global* color setting on, because the CLI resolves color by scanning raw argv for a `--color` token. `bb pr diff 42 --color never` still leaves the diff body uncolored, but it overrides `--no-color` and `NO_COLOR` for everything else that invocation prints. See [Global Flags → Precedence summary](/reference/global-flags/#precedence-summary) * `-w` is the global short alias for `--workspace`. To open the diff in a browser you must spell out `--web` * For opening other Bitbucket pages (PR detail, files, commits, pipelines, settings) in the browser, see [`bb browse`](/commands/browse/) # Review and Merge > Approve, decline, mark ready, and merge pull requests The four commands that change a pull request’s state: `bb pr approve`, `bb pr decline`, `bb pr ready`, `bb pr merge`. Global options work on every PR command: `--json [fields]`, `--jq <expression>`, `--no-color`, `--no-unicode`, `--no-truncate`, `--locale <locale>`, `-w, --workspace`, `-r, --repo` — see [Global Flags](/reference/global-flags/). `--json` accepts an optional comma-separated field list and `--jq` filters the JSON in-process — see [JSON Output](/reference/json-output/) for the full reference. On these four commands the field list is matched against the result envelope shown under [JSON output](#json-output), not against the PR, so `--json title` returns `{"title": null}`. Use a dotted path (`--json pullRequest.state`) or `--jq` instead. ## `bb pr merge` [Section titled “bb pr merge”](#bb-pr-merge) ```bash bb pr merge <id> [options] ``` `<id>` is the pull request ID. ### Options [Section titled “Options”](#options) | Option | Description | | ------------------------- | -------------------------------------- | | `-m, --message <message>` | Merge commit message | | `--close-source-branch` | Delete the source branch after merging | | `--strategy <strategy>` | Merge strategy (see below) | ### Merge strategies [Section titled “Merge strategies”](#merge-strategies) | Strategy | Description | | --------------------- | ---------------------------------------------------------------- | | `merge_commit` | Create a merge commit | | `squash` | Squash all commits into a single commit | | `fast_forward` | Fast-forward if possible, fail otherwise | | `squash_fast_forward` | Squash commits and fast-forward | | `rebase_fast_forward` | Rebase source commits onto destination and fast-forward | | `rebase_merge` | Rebase source commits onto destination and create a merge commit | Omitting `--strategy` uses the repository’s configured merge strategy (typically `merge_commit`), not a CLI default. The CLI sends no strategy at all unless you pass one. Strategy names are checked when the command runs, not by the argument parser. An unknown value fails with [`5002` VALIDATION\_INVALID](/reference/error-codes/#5002---validation_invalid) and the message `--strategy must be one of: merge_commit, squash, …`. A wrong-case value such as `SQUASH` gets a case-sensitivity note; a typo such as `sqush` gets a “did you mean” suggestion. Under `--json` that failure comes back as a JSON error envelope. ### Examples [Section titled “Examples”](#examples) ```bash # Merge PR #42 using the repository's configured strategy bb pr merge 42 # Squash and delete the source branch bb pr merge 42 --strategy squash --close-source-branch # Merge with a custom commit message bb pr merge 42 -m "Merge feature: Add user authentication" # Rebase and fast-forward bb pr merge 42 --strategy rebase_fast_forward # Capture the merge commit hash (--jq prints JSON-quoted strings, so strip them) bb pr merge 42 --json --jq '.pullRequest.merge_commit.hash' | tr -d '"' ``` *** ## `bb pr approve`, `bb pr decline`, `bb pr ready` [Section titled “bb pr approve, bb pr decline, bb pr ready”](#bb-pr-approve-bb-pr-decline-bb-pr-ready) Each takes a pull request ID and nothing else — no command-specific options, only the global ones. ```bash bb pr approve 42 # Approve bb pr decline 42 # Decline bb pr ready 42 # Clear the draft flag, marking the PR ready for review # Any of them against an explicit repository bb pr approve 42 -w myworkspace -r myrepo ``` `bb pr ready` is a pull request update that sets `draft: false`. It sends no other fields. ## JSON output [Section titled “JSON output”](#json-output) The four commands on this page do not return the same shape. `bb pr approve` returns only the identifiers: ```json { "success": true, "pullRequestId": 42 } ``` `bb pr decline`, `bb pr ready`, and `bb pr merge` add the pull request exactly as the API returned it, so `state` reflects the command you ran — `DECLINED`, `OPEN`, and `MERGED` respectively. Abridged, for `bb pr merge`: ```json { "success": true, "pullRequestId": 42, "pullRequest": { "id": 42, "title": "Add user authentication", "state": "MERGED" } } ``` A script that reads `.pullRequest` after `bb pr approve --json` gets `null`. Fetch the PR separately with `bb pr view 42 --json` if you need its fields after approving. # Reviewers > List, add, and remove pull request reviewers Manage pull request (PR) reviewers. Global options work on every PR command: `--json [fields]`, `--jq <expression>`, `--no-color`, `--no-unicode`, `--no-truncate`, `--locale <locale>`, `-w, --workspace`, `-r, --repo` — see [Global Flags](/reference/global-flags/). Looking for repo-level defaults? This page covers reviewers on **existing** pull requests. To manage the repository’s **default reviewers** — the list Bitbucket auto-suggests when someone opens a PR — see [`bb repo default-reviewers`](/commands/repo/#bb-repo-default-reviewers). `bb pr create` can also auto-apply them via `--default-reviewers` or the `prCreateIncludeDefaultReviewers` config key. ## Identifying users [Section titled “Identifying users”](#identifying-users) Bitbucket Cloud no longer accepts the legacy `username` (login name) when modifying reviewers. The `<user>` positional accepts either: * An **account ID**, e.g. `712020:3cfed7e0-0ed6-49fc-bb35-410a00ccee6f` * A **UUID** wrapped in braces, e.g. `{c1cb1bb5-2e32-456e-a373-43978dc12aa1}` Both forms come back from `bb pr reviewers list --json`, as the `account_id` and `uuid` fields: ```bash # One object per reviewer: [{"account_id": "712020:3cfed..."}, …] bb pr reviewers list 42 --json account_id # Copy every reviewer from PR #42 onto PR #43 for u in $(bb pr reviewers list 42 --json --jq '.reviewers[].account_id' | tr -d '"'); do bb pr reviewers add 43 "$u" done ``` Two things to watch in scripts. `--json <fields>` projects across the `reviewers` array and drops the surrounding `{workspace, repoSlug, pullRequestId, count}` envelope, so you get a bare array of objects — not bare IDs. And the built-in jq runs without `-r`, so strings arrive JSON-quoted; strip the quotes with `tr -d '"'` or interpolate inside jq. See [`bb pr create`](/commands/pr/create-and-edit/#bb-pr-create) for matching `--reviewer` examples. ## `bb pr reviewers` [Section titled “bb pr reviewers”](#bb-pr-reviewers) | Subcommand | Description | | -------------------- | ------------------------------------- | | `list <id>` | List reviewers on a pull request | | `add <id> <user>` | Add a reviewer to a pull request | | `remove <id> <user>` | Remove a reviewer from a pull request | None of the three take command-specific options — only the global ones. `<id>` is the pull request ID; `<user>` is an account ID or a braced UUID. *** ## `bb pr reviewers list` [Section titled “bb pr reviewers list”](#bb-pr-reviewers-list) ```bash bb pr reviewers list <id> ``` ```bash # List reviewers on PR #42 bb pr reviewers list 42 # List reviewers in a specific repository bb pr reviewers list 42 -w myworkspace -r myrepo ``` Human output is a two-column table of display name and account ID. If the pull request has no reviewers, the command prints `No reviewers assigned to this pull request`. The deprecated `username` field is never shown — Bitbucket Cloud stopped returning it for GDPR reasons. `--json` returns the full envelope: ```json { "workspace": "myworkspace", "repoSlug": "myrepo", "pullRequestId": 42, "count": 1, "reviewers": [ { "display_name": "Jane Doe", "account_id": "712020:3cfed7e0-0ed6-49fc-bb35-410a00ccee6f", "uuid": "{c1cb1bb5-2e32-456e-a373-43978dc12aa1}" } ] } ``` *** ## `bb pr reviewers add` [Section titled “bb pr reviewers add”](#bb-pr-reviewers-add) Add a reviewer by account ID or UUID. The legacy `username` (login name) is not accepted by Bitbucket Cloud — see [Identifying users](#identifying-users). ```bash bb pr reviewers add <id> <user> ``` ```bash # By account ID bb pr reviewers add 42 "712020:3cfed7e0-0ed6-49fc-bb35-410a00ccee6f" # By UUID (keep the braces, and quote the argument so the shell leaves them alone) bb pr reviewers add 42 "{c1cb1bb5-2e32-456e-a373-43978dc12aa1}" ``` Adding someone who is already a reviewer succeeds and changes nothing. *** ## `bb pr reviewers remove` [Section titled “bb pr reviewers remove”](#bb-pr-reviewers-remove) Remove a reviewer by account ID or UUID. Same `<user>` rules as `add`. ```bash bb pr reviewers remove <id> <user> ``` ```bash # By account ID bb pr reviewers remove 42 "712020:3cfed7e0-0ed6-49fc-bb35-410a00ccee6f" # By UUID bb pr reviewers remove 42 "{c1cb1bb5-2e32-456e-a373-43978dc12aa1}" ``` Removing someone who is not a reviewer succeeds and changes nothing. ## JSON output for `add` and `remove` [Section titled “JSON output for add and remove”](#json-output-for-add-and-remove) Both commands emit the same envelope. `reviewer.username` echoes the `<user>` value you passed, whatever form it was in; `reviewer.uuid` is the resolved UUID. ```json { "success": true, "pullRequestId": 42, "reviewer": { "username": "712020:3cfed7e0-0ed6-49fc-bb35-410a00ccee6f", "uuid": "{c1cb1bb5-2e32-456e-a373-43978dc12aa1}" }, "pullRequest": { "id": 42, "title": "Add user authentication" } } ``` ## When the user lookup fails [Section titled “When the user lookup fails”](#when-the-user-lookup-fails) Both commands resolve `<user>` through Bitbucket’s user endpoint before touching the pull request. A bad account ID or UUID fails there with a 404, carrying whatever message Bitbucket returns. The CLI appends its generic 404 hint, which mentions `--workspace` and `--repo` — but for these two commands the wrong value is almost always the `<user>` argument, not the repository. # Project Commands - Manage Bitbucket Projects > Reference for Bitbucket CLI project commands. List, view, and create Bitbucket Cloud projects to organize repositories from the command line. Projects are the grouping layer for repositories inside a workspace. Use these commands to discover the project keys you pass to `bb repo create -p <KEY>`. Project commands run at **workspace** scope; no repository context is required. Unlike `bb workspace view` and the repo-scoped commands, they never infer the workspace from your git remote. Resolution is `-w/--workspace` → `BB_WORKSPACE` → `defaultWorkspace`. With none of those set, `bb project list` fails with `No workspace specified.` even inside a Bitbucket checkout — see [Repository Context](/guides/repository-context/). All three subcommands are non-interactive and accept the [global flags](/reference/global-flags/), including `--json [fields]` and `--jq <expression>`. *** ## `bb project list` [Section titled “bb project list”](#bb-project-list) List projects in a workspace. ```bash bb project list [options] ``` ### Options [Section titled “Options”](#options) | Option | Description | | ----------------------------- | ---------------------------------------- | | `-w, --workspace <workspace>` | Workspace | | `--limit <number>` | Maximum number of projects (default: 25) | | `--all` | List all projects (overrides `--limit`) | | `--json` | Output as JSON | ### Examples [Section titled “Examples”](#examples) ```bash bb project list bb project list -w my-workspace bb project list --all # Just key and name — a flat array, not the envelope bb project list --json key,name # Keys, one per line (JSON-quoted — the embedded jq has no -r) bb project list --json --jq '.projects[].key' # Unquoted keys for a shell loop — needs the jq binary bb project list --json | jq -r '.projects[].key' ``` ### Output [Section titled “Output”](#output) ```text KEY NAME PRIVACY DESCRIPTION UPDATED -------- ----------------- ------- --------------------------------- ------------------------ PLATFORM Platform Services private Shared infrastructure and tooling Jul 30, 2026 at 09:12 AM WEB Web Apps private Customer-facing web frontends Jul 24, 2026 at 04:38 PM ``` An empty workspace prints `No projects found in workspace <workspace>`. ### JSON output [Section titled “JSON output”](#json-output) The envelope is `{ workspace, count, projects }`, where `projects` is the array of project objects. ### Notes [Section titled “Notes”](#notes) * The `DESCRIPTION` column is truncated to 50 characters. Pass the global `--no-truncate` for the full text; `--json` always carries the full values. * When more results exist than `--limit` returned, the table is followed by `Showing 25 projects. Use --limit <n> or --all to see more.` This footer is never printed under `--json`. *** ## `bb project view` [Section titled “bb project view”](#bb-project-view) View project details. ```bash bb project view <key> [options] ``` ### Arguments [Section titled “Arguments”](#arguments) | Argument | Description | | -------- | --------------------------------------------------------------------------------------------------------------------- | | `key` | Project key (e.g. `PROJ`; lowercase input is uppercased automatically, so `proj` and `PROJ` resolve the same project) | ### Options [Section titled “Options”](#options-1) | Option | Description | | ----------------------------- | -------------- | | `-w, --workspace <workspace>` | Workspace | | `--json` | Output as JSON | ### Examples [Section titled “Examples”](#examples-1) ```bash bb project view PROJ bb project view PROJ -w my-workspace # JSON is wrapped: { workspace, project } bb project view PROJ --json --jq '.project.name' ``` ### Notes [Section titled “Notes”](#notes-1) * An unknown key fails with `Project <KEY> not found in workspace <workspace>.` — exit code 1, and `--json` writes a structured error envelope to stderr. *** ## `bb project create` [Section titled “bb project create”](#bb-project-create) Create a new project in a workspace. ```bash bb project create [options] ``` ### Options [Section titled “Options”](#options-2) | Option | Description | | --------------------------------- | ------------------------------------------------------------- | | `-w, --workspace <workspace>` | Workspace | | `-k, --key <key>` | Project key, e.g. `PROJ` (required; uppercased automatically) | | `-n, --name <name>` | Project name (required) | | `-d, --description <description>` | Project description | | `--private` | Create a private project (default) | | `--public` | Create a public project | | `--json` | Output as JSON | ### Examples [Section titled “Examples”](#examples-2) ```bash bb project create --key PROJ --name "My Project" bb project create -k PROJ -n "My Project" -d "Team things" --public # Then create repositories inside it bb repo create my-repo -p PROJ # The response is wrapped: { workspace, project } bb project create -k PROJ -n "My Project" --json --jq '.project.key' ``` ### Notes [Section titled “Notes”](#notes-2) * Projects are private by default. `--private` and `--public` cannot both be set. A private project cannot contain public repositories. * Keys must start with a letter and contain only letters, digits, and underscores. Bitbucket requires uppercase keys, so lowercase input is uppercased automatically; the CLI prints a note when it does, except under `--json`. ### Related [Section titled “Related”](#related) * [Workspace Commands](/commands/workspace/) — find the workspace slug these commands need. * [Repository Context](/guides/repository-context/) — how the CLI resolves workspace and repository. # Repo Commands - Clone, Create & Manage Bitbucket Repositories > Complete reference for Bitbucket CLI repository commands. Learn to clone, create, list, view, and delete repositories from the command line with examples. Manage Bitbucket repositories. Global options available on all repo commands: `--json [fields]`, `--jq <expression>`, `--no-color`, `--no-unicode`, `--no-truncate`, `--locale <locale>`, `-w, --workspace`, `-r, --repo`. See [Global flags](/reference/global-flags/) for the full list. The per-command tables below list only command-specific options. One exception: `bb repo clone` ignores `-w, --workspace`. ## `bb repo clone` [Section titled “bb repo clone”](#bb-repo-clone) Clone a Bitbucket repository. ```bash bb repo clone <repository> [options] ``` ### Arguments [Section titled “Arguments”](#arguments) | Argument | Description | | ------------ | ------------------------------------------------------------- | | `repository` | `workspace/repo`, a bare repository name, or a full clone URL | For a bare name, the workspace comes from `BB_WORKSPACE`, then the `defaultWorkspace` config key. The global `-w` is **not** honoured by this command. ### Options [Section titled “Options”](#options) | Option | Description | | ----------------------- | ----------------------- | | `-d, --directory <dir>` | Directory to clone into | ### Examples [Section titled “Examples”](#examples) ```bash # Clone using workspace/repo format bb repo clone myworkspace/myrepo # Clone into a specific directory bb repo clone myworkspace/myrepo -d my-local-dir # Bare name — workspace comes from the environment BB_WORKSPACE=myworkspace bb repo clone myrepo # Clone using full URL bb repo clone git@bitbucket.org:myworkspace/myrepo.git ``` ### Notes [Section titled “Notes”](#notes) * For the `workspace/repo` and bare-name forms the CLI clones over SSH (`git@bitbucket.org:<workspace>/<repo>.git`). Pass a full HTTPS URL if you do not have SSH keys set up. * A path with more than one `/` fails with `Invalid repository format. Use workspace/repo or a full URL.` * `--json` emits `{ success, repository, path, cloneUrl }`. *** ## `bb repo create` [Section titled “bb repo create”](#bb-repo-create) Create a new repository. ```bash bb repo create <name> [options] ``` ### Arguments [Section titled “Arguments”](#arguments-1) | Argument | Description | | -------- | --------------------------- | | `name` | Name for the new repository | ### Options [Section titled “Options”](#options-1) | Option | Description | Default | | --------------------------------- | --------------------------- | ------- | | `-d, --description <description>` | Repository description | | | `--private` | Create a private repository | true | | `--public` | Create a public repository | | | `-p, --project <project>` | Project key | | ### Examples [Section titled “Examples”](#examples-1) ```bash # Create a private repository bb repo create my-new-repo -w myworkspace # Create a public repository with description bb repo create my-new-repo -w myworkspace --public -d "My awesome project" # Create in a specific project bb repo create my-new-repo -w myworkspace -p PROJ ``` ### Notes [Section titled “Notes”](#notes-1) * Visibility is private unless `--public` is passed. If both `--private` and `--public` are given, `--public` currently wins and no error is raised — unlike `bb snippet create` and `bb project create`, which reject the combination. * `--json` emits the raw Bitbucket repository object, with no envelope. *** ## `bb repo list` [Section titled “bb repo list”](#bb-repo-list) List repositories in a workspace. ```bash bb repo list [options] ``` ### Options [Section titled “Options”](#options-2) | Option | Description | Default | | ------------------ | ------------------------------------------- | ------- | | `--limit <number>` | Maximum number of repositories | 25 | | `--all` | List all repositories (overrides `--limit`) | | ### Examples [Section titled “Examples”](#examples-2) ```bash # List repositories in a workspace bb repo list -w myworkspace # List more repositories bb repo list -w myworkspace --limit 50 # List every repository in the workspace bb repo list -w myworkspace --all # List with JSON output for scripting bb repo list -w myworkspace --json # Project to specific fields (returns a flat array) bb repo list -w myworkspace --json full_name,is_private,language # Filter with built-in --jq — print just public repo names bb repo list -w myworkspace --json --jq '.repositories[] | select(.is_private == false) | .full_name' ``` ### JSON output [Section titled “JSON output”](#json-output) The `--json` envelope is `{ workspace, count, repositories }`, where `repositories` is the array of repository objects. `--json <fields>` drops the envelope and returns a flat array. ### Notes [Section titled “Notes”](#notes-2) * `--limit` caps how many repositories come back, not the page size. The CLI walks pages (at most 50 per request) until the cap is reached. A value below 1 fails with `--limit must be a positive integer`. * Long descriptions are truncated to 50 characters in the table (disable with the global `--no-truncate`); `--json` always carries the full values. * When the result is capped by `--limit`, a hint shows how many were listed; use a higher `--limit` or `--all` to see the rest (suppressed with `--json`). *** ## `bb repo view` [Section titled “bb repo view”](#bb-repo-view) View repository details. ```bash bb repo view [repository] [options] ``` ### Arguments [Section titled “Arguments”](#arguments-2) | Argument | Description | | ------------ | ----------------------------------------------------------------------------------------------------- | | `repository` | `workspace/repo`, or a bare repository name paired with `-w`. Optional inside a repository directory. | ### Examples [Section titled “Examples”](#examples-3) ```bash # View current repository (from within repo directory) bb repo view # View specific repository using workspace/repo format bb repo view myworkspace/myrepo # View with explicit workspace option bb repo view myrepo -w myworkspace # Get repository details as JSON bb repo view --json ``` ### Notes [Section titled “Notes”](#notes-3) * Resolution order: the positional argument wins, then the global `-w`/`-r` flags, then the git remote of the current directory. * `--json` emits the raw Bitbucket repository object, with no envelope. *** ## `bb repo delete` [Section titled “bb repo delete”](#bb-repo-delete) Delete a repository. ```bash bb repo delete <repository> [options] ``` ### Arguments [Section titled “Arguments”](#arguments-3) | Argument | Description | | ------------ | ----------------------------------------------------------------------------------------------------------------------------------- | | `repository` | `workspace/repo`, or a bare repository name when the workspace comes from `-w`, `BB_WORKSPACE` or the `defaultWorkspace` config key | ### Options [Section titled “Options”](#options-3) | Option | Description | | ----------- | --------------------------- | | `-y, --yes` | Confirm deletion (required) | ### Examples [Section titled “Examples”](#examples-4) ```bash # Delete a repository (--yes is required to confirm) bb repo delete myworkspace/myrepo --yes # Delete using explicit workspace option bb repo delete myrepo -w myworkspace --yes ``` `--json` emits `{ success, workspace, repoSlug }`. Danger Deletion is permanent. All repository data, including code, issues and pull requests, is destroyed. There is no interactive prompt — without `--yes` the command exits with `This will permanently delete <workspace>/<repo>.` followed by `Use --yes to confirm.` *** []() ## `bb repo default-reviewers` [Section titled “bb repo default-reviewers”](#bb-repo-default-reviewers) Default reviewers are auto-suggested when someone opens a pull request in Bitbucket’s web UI. This group reads and edits that list. ### `bb repo default-reviewers list` [Section titled “bb repo default-reviewers list”](#bb-repo-default-reviewers-list) ```bash bb repo default-reviewers list [options] ``` By default the **effective** reviewer list is shown: reviewers configured directly on the repository *and* reviewers inherited from the parent project, matching what Bitbucket’s web UI would auto-populate. | Option | Description | | ------------- | ---------------------------------------------------------------------------- | | `--repo-only` | Only show reviewers configured on the repository (exclude project-inherited) | ```bash # Effective list (repo + project-inherited) bb repo default-reviewers list # Only repo-level entries bb repo default-reviewers list --repo-only # JSON for scripting bb repo default-reviewers list --json ``` `--json` emits `{ workspace, repoSlug, mode, count, reviewers }`, where `mode` is `effective` or `direct`. ### `bb repo default-reviewers add` [Section titled “bb repo default-reviewers add”](#bb-repo-default-reviewers-add) ```bash bb repo default-reviewers add <user> ``` Adds a user as a default reviewer on the repository. Requires repository admin permission. The `<user>` argument accepts either an **account ID** (e.g. `712020:3cfed7e0-0ed6-49fc-bb35-410a00ccee6f`) or a **UUID** in curly braces (e.g. `{c1cb1bb5-2e32-456e-a373-43978dc12aa1}`). Bitbucket Cloud’s GDPR changes retired username lookups, so nicknames like `jdoe` are no longer accepted. You can find a user’s account ID from the Bitbucket web UI under their profile, or by running `bb pr reviewers list <pr-id> --json` on a pull request they have reviewed. ```bash bb repo default-reviewers add "712020:3cfed7e0-0ed6-49fc-bb35-410a00ccee6f" bb repo default-reviewers add "{c1cb1bb5-2e32-456e-a373-43978dc12aa1}" ``` ### `bb repo default-reviewers remove` [Section titled “bb repo default-reviewers remove”](#bb-repo-default-reviewers-remove) ```bash bb repo default-reviewers remove <user> --yes ``` Removes a user from the repository’s default reviewers. `--yes` is required to confirm. Requires repository admin permission. `<user>` accepts the same identifiers as `add` (account ID or `{uuid}`). ```bash bb repo default-reviewers remove "712020:3cfed7e0-0ed6-49fc-bb35-410a00ccee6f" --yes ``` ### Notes [Section titled “Notes”](#notes-4) * Project-inherited reviewers can only be removed by editing the parent project, not the repository. * Related: [`bb pr create --default-reviewers`](/commands/pr/create-and-edit/) applies these reviewers when opening a pull request. # Snippet Commands - Manage Bitbucket Snippets > Reference for Bitbucket CLI snippet commands. Create, view, edit, delete, watch, and comment on Bitbucket Cloud snippets from the command line. Manage Bitbucket Cloud snippets — workspace-scoped code/text pastes. Snippet commands operate at **workspace** scope (no repository context required). Use `-w, --workspace <workspace>` or set a default with `bb config set defaultWorkspace <workspace>`. Global options available on all snippet commands: `--json [fields]`, `--jq <expression>`, `--no-color`, `--no-unicode`, `--no-truncate`, `--locale <locale>`, `-w, --workspace`. See [Global flags](/reference/global-flags/) for the full list. The per-command tables below list only command-specific options. *** ## `bb snippet list` [Section titled “bb snippet list”](#bb-snippet-list) List snippets in a workspace. ```bash bb snippet list [options] ``` ### Options [Section titled “Options”](#options) | Option | Description | | ------------------ | ------------------------------------------------------------------------ | | `--role <role>` | Filter by authenticated user’s role: `owner`, `contributor`, or `member` | | `--limit <number>` | Maximum number of snippets (default: 25) | | `--all` | List all snippets (overrides `--limit`) | ### Examples [Section titled “Examples”](#examples) ```bash bb snippet list bb snippet list --role owner bb snippet list --limit 50 --json bb snippet list --all # Project to specific fields (returns a flat array) bb snippet list --json id,title,is_private # Filter with built-in --jq — public snippets only bb snippet list --json --jq '.snippets[] | select(.is_private == false) | .title' ``` ### Notes [Section titled “Notes”](#notes) * Table columns: ID, TITLE, VISIBILITY, CREATOR, UPDATED. * **JSON envelope:** `{ workspace, count, snippets }`. * `--limit` is enforced across paginated responses. * When the result is capped by `--limit`, a hint shows how many were listed; use a higher `--limit` or `--all` to see the rest (suppressed with `--json`). *** ## `bb snippet view` [Section titled “bb snippet view”](#bb-snippet-view) View snippet details. Optionally print file contents. ```bash bb snippet view <id> [options] ``` ### Arguments [Section titled “Arguments”](#arguments) | Argument | Description | | -------- | -------------------------------- | | `id` | Snippet encoded ID (e.g. `kypj`) | ### Options [Section titled “Options”](#options-1) | Option | Description | | ------------------- | ------------------------------------------------ | | `-f, --file <name>` | Print contents of a specific file in the snippet | | `--files` | Print contents of all files in the snippet | ### Examples [Section titled “Examples”](#examples-1) ```bash bb snippet view kypj bb snippet view kypj --json bb snippet view kypj --file config.yml bb snippet view kypj --files ``` ### Notes [Section titled “Notes”](#notes-1) * `--file` takes precedence over `--files`. Pass both and only the single file is printed. * An unknown file name fails with `File not found in snippet: <name>` (`5003 FILE_NOT_FOUND`, see [Error codes](/reference/error-codes/)). The error context carries `available` with the snippet’s actual file names. * `--files` prints the snippet header first, then each file under a bold `── <name> ──` heading. With the global `--no-unicode` the separator renders as `--`. * **JSON shapes** differ per flag: * no flag → the bare Bitbucket snippet object, no envelope * `--file <name>` → `{ file, content }` * `--files` → `{ snippet, files: { "<name>": "<content>" } }` *** ## `bb snippet create` [Section titled “bb snippet create”](#bb-snippet-create) Create a snippet. The files you pass are uploaded as `multipart/form-data` to Bitbucket — their contents are the snippet body. ```bash bb snippet create [options] ``` ### Options [Section titled “Options”](#options-2) | Option | Description | | ---------------------- | ------------------------------------------------------------------------------------ | | `-t, --title <title>` | Snippet title (required) | | `-f, --file <path...>` | File path(s) to include (required; variadic — pass several paths or repeat the flag) | | `--private` | Create a private snippet (default) | | `--public` | Create a public snippet | ### Examples [Section titled “Examples”](#examples-2) ```bash bb snippet create -t "My snippet" -f file.txt bb snippet create -t "Config files" -f config.yml -f setup.sh --public # Capture the new snippet id bb snippet create -t "My snippet" -f file.txt --json --jq '.id' ``` ### Notes [Section titled “Notes”](#notes-2) * Snippets are private by default. * `--private` and `--public` cannot both be set. * Each `--file` must exist on disk; missing files fail the command before any upload. * `--json` emits the bare Bitbucket snippet object, with no envelope. *** ## `bb snippet edit` [Section titled “bb snippet edit”](#bb-snippet-edit) Update a snippet’s title, visibility, or files. ```bash bb snippet edit <id> [options] ``` ### Arguments [Section titled “Arguments”](#arguments-1) | Argument | Description | | -------- | -------------------------------- | | `id` | Snippet encoded ID (e.g. `kypj`) | ### Options [Section titled “Options”](#options-3) | Option | Description | | ---------------------- | ----------------------------------------------------------- | | `-t, --title <title>` | New title | | `--private` | Make snippet private | | `--public` | Make snippet public | | `-f, --file <path...>` | Replace or add file(s); sends a multipart update (variadic) | ### Examples [Section titled “Examples”](#examples-3) ```bash bb snippet edit kypj -t "New title" bb snippet edit kypj --public bb snippet edit kypj -f updated.txt ``` ### Notes [Section titled “Notes”](#notes-3) * Metadata-only edits (title, visibility) send a JSON PUT. * Passing `--file` switches to a multipart PUT and uploads the given files. * At least one of `--title`, `--private`, `--public`, or `--file` is required. * `--json` emits the bare Bitbucket snippet object, with no envelope. *** ## `bb snippet delete` [Section titled “bb snippet delete”](#bb-snippet-delete) Delete a snippet. ```bash bb snippet delete <id> [options] ``` ### Arguments [Section titled “Arguments”](#arguments-2) | Argument | Description | | -------- | -------------------------------- | | `id` | Snippet encoded ID (e.g. `kypj`) | ### Options [Section titled “Options”](#options-4) | Option | Description | | ----------- | --------------------------- | | `-y, --yes` | Confirm deletion (required) | ### Examples [Section titled “Examples”](#examples-4) ```bash bb snippet delete kypj --yes ``` ### Notes [Section titled “Notes”](#notes-4) * **JSON envelope:** `{ success, snippetId, workspace }`. Danger Deletion is permanent and cannot be undone. There is no interactive prompt — without `--yes` the command exits with `This will permanently delete snippet <id>.` followed by `Use --yes to confirm.` *** ## `bb snippet watch` / `bb snippet unwatch` [Section titled “bb snippet watch / bb snippet unwatch”](#bb-snippet-watch--bb-snippet-unwatch) Subscribe or unsubscribe the authenticated user to/from a snippet. ```bash bb snippet watch <id> [options] bb snippet unwatch <id> [options] ``` ### Arguments [Section titled “Arguments”](#arguments-3) | Argument | Description | | -------- | -------------------------------- | | `id` | Snippet encoded ID (e.g. `kypj`) | ### Examples [Section titled “Examples”](#examples-5) ```bash bb snippet watch kypj bb snippet unwatch kypj ``` ### Notes [Section titled “Notes”](#notes-5) * **JSON envelope:** `{ success, snippetId, watching }` — `watching` is `true` for `watch` and `false` for `unwatch`. *** ## `bb snippet comments list` [Section titled “bb snippet comments list”](#bb-snippet-comments-list) List comments on a snippet. ```bash bb snippet comments list <id> [options] ``` ### Arguments [Section titled “Arguments”](#arguments-4) | Argument | Description | | -------- | -------------------------------- | | `id` | Snippet encoded ID (e.g. `kypj`) | ### Options [Section titled “Options”](#options-5) | Option | Description | | ------------------ | ---------------------------------------- | | `--limit <number>` | Maximum number of comments (default: 25) | | `--all` | List all comments (overrides `--limit`) | ### Examples [Section titled “Examples”](#examples-6) ```bash bb snippet comments list kypj bb snippet comments list kypj --all bb snippet comments list kypj --limit 50 --json ``` ### Notes [Section titled “Notes”](#notes-6) * Table columns: ID, AUTHOR, DATE, CONTENT. * CONTENT is truncated to 60 characters; pass the global `--no-truncate` for full comment bodies (`--json` always carries the full value). DATE is formatted with `--locale`/`BB_LOCALE`, falling back to the system locale and then `en-US`. * **JSON envelope:** `{ workspace, snippetId, count, comments }`. *** ## `bb snippet comments add` [Section titled “bb snippet comments add”](#bb-snippet-comments-add) Add a comment to a snippet. ```bash bb snippet comments add <id> [message] [options] ``` ### Arguments [Section titled “Arguments”](#arguments-5) | Argument | Description | | --------- | ----------------------------------------------------------------------------------------------------------------- | | `id` | Snippet encoded ID (e.g. `kypj`) | | `message` | Comment body. Alternative to `-m, --message`; one of the two is required. The positional wins if both are passed. | ### Options [Section titled “Options”](#options-6) | Option | Description | | ---------------------- | ------------------------------------------------------ | | `-m, --message <text>` | Comment body (alternative to the positional `message`) | ### Examples [Section titled “Examples”](#examples-7) ```bash bb snippet comments add kypj "Great snippet!" bb snippet comments add kypj -m "Great snippet!" bb snippet comments add kypj "Great snippet!" --json ``` ### Notes [Section titled “Notes”](#notes-7) * Omitting both forms fails with `Comment message is required. Use --message option.` * **JSON envelope:** `{ success, snippetId, comment }` with the created comment. *** ## `bb snippet comments edit` [Section titled “bb snippet comments edit”](#bb-snippet-comments-edit) Edit a comment on a snippet. ```bash bb snippet comments edit <snippet-id> <comment-id> <message> [options] ``` ### Arguments [Section titled “Arguments”](#arguments-6) | Argument | Description | | ------------ | ----------------------------------- | | `snippet-id` | Snippet encoded ID (e.g. `kypj`) | | `comment-id` | Numeric comment ID (e.g. `123`) | | `message` | Replacement comment body (Markdown) | ### Examples [Section titled “Examples”](#examples-8) ```bash bb snippet comments edit kypj 123 "Updated comment" bb snippet comments edit kypj 123 "Updated comment" --json ``` ### Notes [Section titled “Notes”](#notes-8) * The message replaces the existing body outright. * **JSON envelope:** `{ success, snippetId, comment }` with the updated comment. *** ## `bb snippet comments delete` [Section titled “bb snippet comments delete”](#bb-snippet-comments-delete) Delete a comment on a snippet. ```bash bb snippet comments delete <snippet-id> <comment-id> [options] ``` ### Arguments [Section titled “Arguments”](#arguments-7) | Argument | Description | | ------------ | -------------------------------- | | `snippet-id` | Snippet encoded ID (e.g. `kypj`) | | `comment-id` | Numeric comment ID (e.g. `123`) | ### Options [Section titled “Options”](#options-7) | Option | Description | | ----------- | --------------------------- | | `-y, --yes` | Confirm deletion (required) | ### Examples [Section titled “Examples”](#examples-9) ```bash bb snippet comments delete kypj 123 --yes ``` ### Notes [Section titled “Notes”](#notes-9) * There is no interactive prompt. Without `--yes` the command fails with `This will permanently delete comment #<comment-id> on snippet <snippet-id>.` * **JSON envelope:** `{ success, snippetId, commentId }`. # Status Commands - Commit Build Statuses > Reference for Bitbucket CLI status commands. List build statuses on a commit and report CI build results (INPROGRESS, SUCCESSFUL, FAILED) from scripts and pipelines. Manage build statuses on commits — the red/green/yellow indicators Bitbucket shows next to commits and pull requests. `bb status set` is built for CI scripts: it is non-interactive, idempotent per status key, and JSON-friendly. Status commands operate at **repository** scope. Run them inside a cloned Bitbucket repository, or pass `-w, --workspace <workspace>` and `-r, --repo <repo>` explicitly. Global options available on all status commands: `--json [fields]`, `--jq <expression>`, `--no-color`, `--no-unicode`, `--no-truncate`, `--locale <locale>`, `-w, --workspace`, `-r, --repo`. A `<sha>` is a full 40-character hash or any abbreviated prefix (`abc1234`). `--json` output is wrapped in an envelope keyed by `workspace` and `repoSlug`; the `# →` comments below show each shape. *** ## `bb status list` [Section titled “bb status list”](#bb-status-list) List the build statuses reported on a commit. ```bash bb status list <sha> [options] ``` ### Options [Section titled “Options”](#options) | Option | Description | | ------------------ | ---------------------------------------- | | `--limit <number>` | Maximum number of statuses (default: 25) | | `--all` | List all statuses (overrides `--limit`) | ### Examples [Section titled “Examples”](#examples) ```bash bb status list abc1234 bb status list abc1234 --all # → { workspace, repoSlug, commit, count, statuses } bb status list abc1234 --json # States only, via built-in --jq bb status list abc1234 --json --jq '.statuses[].state' ``` ### Notes [Section titled “Notes”](#notes) * Columns: status key, state (colored: green `SUCCESSFUL`, red `FAILED`, yellow `INPROGRESS`, gray `STOPPED`), name, description (truncated to 40 characters; disable with `--no-truncate`), and URL. * `bb pr checks` colors states the same way but renders a different table: `STATUS / NAME / DESCRIPTION / UPDATED`, with the state shown as `OK passed` / `FAIL failed` / `RUN running` / `STOP stopped` rather than the raw state string. * An unknown sha returns `Commit abc1234 not found in acme/api.` *** ## `bb status set` [Section titled “bb status set”](#bb-status-set) Create or update a build status on a commit. `<sha>` is a full or abbreviated hash. ```bash bb status set <sha> --key <key> --state <state> [options] ``` ### Options [Section titled “Options”](#options-1) | Option | Description | | ----------------------------- | ------------------------------------------------------------------------------------------------------------ | | `--key <key>` | **Required.** Unique status key, e.g. `BB-DEPLOY`. Re-running with the same key updates the existing status. | | `--state <state>` | **Required.** One of `FAILED`, `INPROGRESS`, `STOPPED`, `SUCCESSFUL` (case-insensitive) | | `--url <url>` | Link back to the build system | | `--name <name>` | Build identifier, e.g. `BB-DEPLOY-1` | | `--description <description>` | Short build description | | `--refname <refname>` | Ref the build ran on, e.g. a branch name | ### Examples [Section titled “Examples”](#examples-1) ```bash bb status set abc1234 --key CI --state INPROGRESS bb status set abc1234 --key CI --state SUCCESSFUL --url https://ci.example.com/builds/42 bb status set abc1234 --key LINT --state FAILED --description "ESLint found 3 errors" --refname main # → { workspace, repoSlug, commit, status } bb status set abc1234 --key CI --state SUCCESSFUL --json --jq '.status.state' ``` #### CI recipe: wrap a build in INPROGRESS → SUCCESSFUL/FAILED [Section titled “CI recipe: wrap a build in INPROGRESS → SUCCESSFUL/FAILED”](#ci-recipe-wrap-a-build-in-inprogress--successfulfailed) ```bash #!/usr/bin/env bash set -euo pipefail SHA="$(git rev-parse HEAD)" KEY="CI" URL="https://ci.example.com/builds/${BUILD_ID:-local}" # Mark the commit as building before the work starts bb status set "$SHA" --key "$KEY" --state INPROGRESS --url "$URL" \ --name "CI Build ${BUILD_ID:-local}" --refname "$(git branch --show-current)" # Run the build; report the result either way if ./run-build.sh; then bb status set "$SHA" --key "$KEY" --state SUCCESSFUL --url "$URL" else bb status set "$SHA" --key "$KEY" --state FAILED --url "$URL" \ --description "Build failed; see logs" exit 1 fi ``` ### Notes [Section titled “Notes”](#notes-1) * **Idempotent per status key:** the CLI first POSTs a new status. If the POST is rejected for anything other than an auth or not-found failure — most commonly because a status with that key already exists on the commit, the normal case on CI re-runs — it retries as a PUT against the existing key. Repeated `bb status set` calls with the same `--key` are therefore always safe. * `--state` is upper-cased before validation, so `successful` and `SUCCESSFUL` both work. An invalid value lists the allowed states and, when the input is close to a valid one, suggests it: ```text --state must be one of: FAILED, INPROGRESS, STOPPED, SUCCESSFUL (Did you mean SUCCESSFUL?) ``` * On success the CLI prints `✓ Status <key> set to <state> on <short-sha>`; with `--json` it returns the resulting status resource wrapped in `{ workspace, repoSlug, commit, status }`. * These statuses are what `bb pr checks` aggregates for a pull request. *** ## See also [Section titled “See also”](#see-also) * [Commit Commands](/commands/commit/) — list and inspect the commits themselves. * [CI/CD Integration](/guides/cicd/) — using `bb` inside pipelines. * [Scripting & Automation](/guides/scripting/) — JSON envelopes, `--jq`, exit codes. # Workspace Commands - Discover Bitbucket Workspaces > Reference for Bitbucket CLI workspace commands. List the workspaces you have access to and view workspace details from the command line. Find the workspace slugs you pass to `-w, --workspace`, to [`bb config set defaultWorkspace`](/reference/configuration/), and to `bb repo create`. Workspace commands run at **account** scope. `bb workspace list` needs no context at all — it lists your own workspaces. `bb workspace view` falls back to the resolved workspace context when you pass no slug. Both accept the [global flags](/reference/global-flags/), including `--json [fields]`, `--jq <expression>`, and `-w, --workspace`. *** ## `bb workspace list` [Section titled “bb workspace list”](#bb-workspace-list) List the workspaces the authenticated user has access to. ```bash bb workspace list [options] ``` ### Options [Section titled “Options”](#options) | Option | Description | | ------------------ | --------------------------------------------------------- | | `--role <role>` | Filter by your role: `owner`, `collaborator`, or `member` | | `--limit <number>` | Maximum number of workspaces (default: 25) | | `--all` | List all workspaces (overrides `--limit`) | | `--json` | Output as JSON | ### Examples [Section titled “Examples”](#examples) ```bash bb workspace list bb workspace list --role owner bb workspace list --all # Only the columns you need — a flat array, not the envelope bb workspace list --json slug,name # Slugs, one per line (JSON-quoted — the embedded jq has no -r) bb workspace list --json --jq '.workspaces[].slug' # Bare slugs for a shell loop, via the jq binary bb workspace list --json | jq -r '.workspaces[].slug' ``` ### Output [Section titled “Output”](#output) ```text SLUG NAME PRIVACY UUID ------------- ------------- ------- -------------------------------------- acme-corp Acme Corp private {6f1e8a2c-9d34-4b7e-8f21-0c5a7d3e1b90} side-projects Side Projects public {b2c9e740-15af-4d63-9a08-3e6f2c81d475} Use a slug with -w <slug> or set a default: bb config set defaultWorkspace <slug> ``` That last line prints after every non-JSON `bb workspace list`. ### JSON output [Section titled “JSON output”](#json-output) The envelope is `{ filters, count, workspaces }`. `workspaces` holds the workspace objects; `filters` echoes the active `--role` filter, and is an empty object when unfiltered. ### Notes [Section titled “Notes”](#notes) * Role semantics: `owner` = admin access, `collaborator` = write access to at least one repository, `member` = member of at least one group or repository. * When more results exist than `--limit` returned, the table is followed by `Showing 25 workspaces. Use --limit <n> or --all to see more.` This footer is never printed under `--json`. *** ## `bb workspace view` [Section titled “bb workspace view”](#bb-workspace-view) View workspace details. ```bash bb workspace view [slug] [options] ``` ### Arguments [Section titled “Arguments”](#arguments) | Argument | Description | | -------- | --------------------------------------------------------------------- | | `slug` | Workspace slug (optional; defaults to the resolved workspace context) | ### Options [Section titled “Options”](#options-1) | Option | Description | | ----------------------------- | -------------------------------------------------- | | `-w, --workspace <workspace>` | Workspace (used when no `slug` argument is passed) | | `--json` | Output as JSON | ### Examples [Section titled “Examples”](#examples-1) ```bash # Resolved workspace: -w, the current repository's remote, # BB_WORKSPACE, then defaultWorkspace bb workspace view bb workspace view my-workspace # JSON is wrapped: { workspace: { ... } } bb workspace view my-workspace --json --jq '.workspace.uuid' ``` ### Notes [Section titled “Notes”](#notes-1) * Without a `slug`, the workspace resolves in this order: the `-w` flag, the current repository’s Bitbucket remote, the `BB_WORKSPACE` environment variable, then the configured `defaultWorkspace`. * An unknown or inaccessible slug fails with `Workspace <slug> not found (or you do not have access to it).` — exit code 1, and `--json` writes a structured error envelope to stderr. Because that message already names the missing workspace, the generic 404 “check the slug” hint is suppressed. ### Related [Section titled “Related”](#related) * [Project Commands](/commands/project/) — list the projects inside a workspace. * [Repository Context](/guides/repository-context/) — how the CLI resolves workspace and repository. * [Configuration](/reference/configuration/) — set `defaultWorkspace` once. # Authentication > How to authenticate with Bitbucket The Bitbucket CLI supports two authentication methods: **OAuth** (recommended) and **API tokens**. ## OAuth (recommended) [Section titled “OAuth (recommended)”](#oauth-recommended) ```bash bb auth login ``` This opens your browser where you authorize the CLI with your Bitbucket account. No tokens to copy, no scopes to select manually. Tokens expire after 2 hours and are refreshed automatically. If `BB_API_TOKEN` is exported in your shell, `bb auth login` uses API-token auth instead of opening a browser. It is the variable being *set* that switches the flow, not its value — even `export BB_API_TOKEN=` does it. Run `unset BB_API_TOKEN` first if you want OAuth. Caution OAuth needs a browser that can reach a loopback callback server on `http://localhost:19872/callback`. There is **no device-code flow**, so if you’re on a headless host (SSH session, container, CI runner) where no browser is available, use an [API token](#api-token-for-cicd-and-headless-environments) instead. ### Using a custom OAuth consumer [Section titled “Using a custom OAuth consumer”](#using-a-custom-oauth-consumer) Organizations can use their own OAuth consumer instead of the built-in default: ```bash bb auth login --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET ``` To set up a custom OAuth consumer: 1. Go to **Workspace settings** > **Apps and features** > **OAuth consumers** 2. Click **Add consumer** 3. Set **Callback URL** to `http://localhost:19872/callback` 4. Grant permissions: Account (Read), Repositories (Read, Write, Admin), Pull requests (Read, Write) 5. Save and use the generated **Key** as `--client-id` and **Secret** as `--client-secret` Custom credentials are stored in your config file for subsequent logins. OAuth cannot reach every command The CLI requests a hardcoded OAuth scope set: `account repository repository:admin pullrequest pullrequest:write`. A custom consumer cannot widen it. `bb pipeline`, `bb issue`, `bb snippet`, `bb project` and `bb repo delete` are not covered — use an API token for those. See [Token Scopes](/reference/token-scopes/). *** ## API token (for CI/CD and headless environments) [Section titled “API token (for CI/CD and headless environments)”](#api-token-for-cicd-and-headless-environments) Use API tokens when a browser is not available (SSH sessions, Docker containers, CI/CD pipelines). 1. **Create an API token** 1. Log in to [Bitbucket](https://bitbucket.org) 2. Go to **Personal settings** (click your avatar in the bottom left) 3. Navigate to **API tokens** under “Access management” 4. Click **Create API token** 5. Give it a descriptive name (e.g., “Bitbucket CLI”) 6. Select the required scopes: * `read:user:bitbucket` — verify your identity * `read:repository:bitbucket` — list and view repositories, commits, build statuses * `write:repository:bitbucket` — set commit build statuses * `admin:repository:bitbucket` — create repositories, manage default reviewers * `delete:repository:bitbucket` — delete repositories (optional) * `read:pullrequest:bitbucket` — list and view pull requests * `write:pullrequest:bitbucket` — create, edit, merge, approve, decline pull requests See [Token Scopes](/reference/token-scopes/) for a per-command breakdown if you want to mint a token with the minimum scope set for your workflow. 7. Click **Create** 8. **Copy the generated token** — Bitbucket will not show it again. 2. **Authenticate** ```bash bb auth login -u your-username -p your-api-token ``` Or pipe the token via stdin so it never lands in your shell history or `ps` output (recommended): ```bash echo "$BB_API_TOKEN" | bb auth login -u your-username --with-token ``` `--with-token` reads all of stdin and trims it, so a trailing newline is fine. It cannot be combined with `-p` — that fails with error `5002` (“Cannot combine –password with –with-token”). If nothing is piped in, the login fails with `5001` (“No API token found on stdin”). Or using environment variables: ```bash export BB_USERNAME=your-username export BB_API_TOKEN=your-api-token bb auth login ``` Tip Prefer `--with-token` or `BB_API_TOKEN` over `-p` in scripts and CI. Passing a secret as a command-line argument leaves it visible in shell history and to anyone who can list processes (`ps`). See [Environment Variables Reference](/reference/environment-variables/) for more details on using environment variables in scripts and CI/CD. *** ## Check auth status [Section titled “Check auth status”](#check-auth-status) ```bash bb auth status ``` ```text ✓ Logged in to Bitbucket Authentication: OAuth Username: jdoe Display name: Jane Doe Account ID: 5f1a2b3c4d5e6f7a8b9c0d1e Token expires: in 1h 42m Default workspace: acme ``` `Token expires` only appears for OAuth logins. `Default workspace` only appears once one is configured. Add `--json` for a machine-readable version. ## Logout [Section titled “Logout”](#logout) ```bash bb auth logout ``` This removes stored credentials and revokes your OAuth token (if using OAuth). Non-auth settings are preserved. ## Configuration storage [Section titled “Configuration storage”](#configuration-storage) Credentials are stored in: * **Linux/macOS**: `~/.config/bb/config.json` * **Windows**: `%APPDATA%\bb\config.json` See [Configuration File Reference](/reference/configuration/) for details on the config file format. Caution Tokens are stored in plaintext JSON. On Linux and macOS the CLI writes the file with mode `600` and the directory with mode `700`, and refuses to read either if any group or other permission bit is set — you get error `4001` with the exact `chmod` to run. Windows skips the check. ## Next steps [Section titled “Next steps”](#next-steps) * [Quick Start Guide](/getting-started/quickstart/) - Get up and running in 60 seconds * [Repository Context](/guides/repository-context/) - How the CLI detects your workspace/repo * [Troubleshooting](/help/troubleshooting/) - Common authentication issues and solutions # Installation > Install the Bitbucket CLI with npm, pnpm, or Bun, or build it from source. Requires the Bun runtime. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) * [Bun](https://bun.sh) runtime 1.0 or higher — the CLI runs on Bun, not Node.js * Git Install Bun if `bun --version` fails: ```bash curl -fsSL https://bun.sh/install | bash ``` For other platforms and install methods, see [bun.sh](https://bun.sh). ## Install [Section titled “Install”](#install) Any package manager works. Bun is still required to run `bb`. * npm ```bash npm install -g @pilatos/bitbucket-cli ``` * pnpm ```bash pnpm add -g @pilatos/bitbucket-cli ``` * Bun ```bash bun install -g @pilatos/bitbucket-cli ``` ## Build from source [Section titled “Build from source”](#build-from-source) ```bash # Clone the repository git clone https://github.com/0pilatos0/bitbucket-cli.git cd bitbucket-cli # Install dependencies bun install # Build bun run build # Link globally bun link ``` ## Verify installation [Section titled “Verify installation”](#verify-installation) ```bash bb --version ``` ## Next steps [Section titled “Next steps”](#next-steps) [Authenticate](/getting-started/authentication/) with your Bitbucket account. Then install [shell completion](/commands/completion/) so your shell can complete `bb` subcommands and flags. # Quick Start > Get up and running with Bitbucket CLI in 60 seconds ## TL;DR [Section titled “TL;DR”](#tldr) ```bash npm install -g @pilatos/bitbucket-cli bb auth login bb repo clone myworkspace/myrepo bb pr create -t "My feature" ``` ## Prerequisites [Section titled “Prerequisites”](#prerequisites) * **[Bun](https://bun.sh) runtime 1.0+**. Installing via npm or pnpm does not install Bun. Without it, `bb` exits with `Error: This CLI requires the Bun runtime.` See [Installation](/getting-started/installation/). * A **Bitbucket Cloud** account. ## Step-by-step setup [Section titled “Step-by-step setup”](#step-by-step-setup) 1. **Install the CLI** ```bash npm install -g @pilatos/bitbucket-cli ``` Verify the installation: ```bash bb --version ``` 2. **Authenticate** ```bash bb auth login ``` This opens your browser to authorize the CLI with your Bitbucket account. No token setup needed. For CI/CD or headless environments, pipe an API token in on stdin: ```bash echo "$BB_API_TOKEN" | bb auth login -u your-username --with-token ``` If `BB_API_TOKEN` is set in your environment, a bare `bb auth login` uses API token auth instead of OAuth. Verify it worked: ```bash bb auth status ``` See the [Authentication guide](/getting-started/authentication/) for full details. 3. **Clone a repository** ```bash bb repo clone myworkspace/myrepo cd myrepo ``` 4. **Create your first pull request** ```bash git checkout -b feature/my-feature # Make some changes... git add . git commit -m "Add my feature" git push -u origin feature/my-feature bb pr create -t "Add my feature" ``` ## Common commands [Section titled “Common commands”](#common-commands) | Command | Description | | ------------------------- | ---------------------------------------------- | | `bb pr list` | List open pull requests | | `bb pr view 42` | View PR #42 details | | `bb pr activity 42` | View PR #42 activity log | | `bb pr create -t "Title"` | Create a new PR | | `bb pr merge 42` | Merge PR #42 | | `bb pr checkout 42` | Checkout PR #42 locally | | `bb pr diff 42` | View PR #42 diff | | `bb repo list` | List repositories | | `bb browse 42` | Open PR #42 in your browser | | `bb browse src/cli.ts:20` | Open a file at a specific line in your browser | | `bb api /user` | Call any Bitbucket API endpoint (escape hatch) | ## Set a default workspace [Section titled “Set a default workspace”](#set-a-default-workspace) Not sure what your workspace slug is? List the workspaces you have access to: ```bash bb workspace list ``` If you work primarily in one workspace, set it as default: ```bash bb config set defaultWorkspace myworkspace ``` Now commands will use this workspace automatically: ```bash bb repo list # Lists repositories in "myworkspace" bb pr list -r myrepo # Lists PRs in "myworkspace/myrepo" ``` ## Enable tab completion [Section titled “Enable tab completion”](#enable-tab-completion) ```bash bb completion install ``` Restart your shell, then try: ```bash bb <Tab> # Shows every top-level command bb pr <Tab> # Shows: activity, approve, checkout, checks, comments, create, decline, diff, edit, list, merge, ready, reviewers, view bb pr create -<Tab> # Shows available flags bb pr merge 42 --strategy <Tab> # Shows: merge_commit, squash, fast_forward, ... ``` ## Scripting with JSON [Section titled “Scripting with JSON”](#scripting-with-json) Every command accepts `--json` for machine-readable output. You can project to a comma-separated field list and filter results through a built-in `jq` engine — no external `jq` binary required: ```bash # Project to specific fields bb pr list --json id,title,state # Filter through built-in jq bb pr list --json --jq '.pullRequests[] | select(.state == "OPEN") | .title' ``` Tip See [JSON Output](/reference/json-output/) for the full shape reference and the [Scripting guide](/guides/scripting/) for end-to-end automation patterns. ## Update notifications [Section titled “Update notifications”](#update-notifications) When a newer version is available on npm, `bb` writes a one-time notice to stderr after the next command finishes: ```text ────────────────────────────────────────────────── A new version is available: 1.23.0 (you have 1.22.0) Run 'bun install -g @pilatos/bitbucket-cli' to update Or disable with 'bb config set skipVersionCheck true' ────────────────────────────────────────────────── ``` Under `--no-unicode` or `BB_NO_UNICODE`, the horizontal rules are drawn with `-` instead of `─`. The notice never appears with `--json`, when stderr is not a TTY, or in CI environments. The check itself runs at most once every `versionCheckInterval` days (default: 1). Disable it permanently with: ```bash bb config set skipVersionCheck true ``` See the [Configuration File reference](/reference/configuration/) for related settings. ## Next steps [Section titled “Next steps”](#next-steps) * **[Command Reference](/commands/auth/)** - Full documentation for all commands * **[Repository Context](/guides/repository-context/)** - How the CLI detects your workspace/repository * **[Scripting & Automation](/guides/scripting/)** - Use bb in scripts and CI/CD * **[JSON Output Reference](/reference/json-output/)** - Field projection, `--jq` filtering, output shapes * **[AI Agent Integration](/guides/ai-agents/)** - Wire the CLI into Claude Code, Cursor, or Windsurf * **[Changelog](/help/changelog/)** - What’s new in recent releases * **[Troubleshooting](/help/troubleshooting/)** - Common issues and solutions # AI Agent Integration - Claude Code, Cursor, Windsurf & More > Set up the Bitbucket CLI with Claude Code, opencode, Cursor, Windsurf, and other AI coding assistants. Skill files, quick-start guides, and real-world workflow examples. Drop a skill or rules file into your project and your coding assistant drives Bitbucket through `bb`. The templates below cover Claude Code, opencode, Cursor, and Windsurf. ## Quick start [Section titled “Quick start”](#quick-start) Pick your editor and paste the command: * Claude Code Run this in your project root: ```bash mkdir -p .claude/skills/bb-cli && cat > .claude/skills/bb-cli/SKILL.md << 'SKILL' --- name: bb-cli description: > Bitbucket Cloud CLI. Use when the user wants to create, list, review, merge, or manage pull requests, repositories, authentication, or configuration via the `bb` command. argument-hint: "[command or question]" allowed-tools: Bash(bb *), Read, Grep, Glob --- # Bitbucket CLI (`bb`) CLI for Bitbucket Cloud. Package: `@pilatos/bitbucket-cli`. ## Available commands !`bb --help` ## Key workflows **Create PR:** `bb pr create -t "title" -b "description"` **List PRs:** `bb pr list` (add `--mine` for your reviews, `--json` for scripts) **Review:** `bb pr checkout <id>` → `bb pr diff <id>` → `bb pr approve <id>` **Merge:** `bb pr merge <id> --strategy squash --close-source-branch` **Draft:** `bb pr create -t "WIP" --draft` → later `bb pr ready <id>` **Comments:** `bb pr comments list <id>` (add `--unresolved` to see open threads), `bb pr comments add <id> "text"`, `bb pr comments view <pr-id> <comment-id>` **Review threads:** `bb pr comments reply <pr-id> <comment-id> "text"` → `bb pr comments resolve <pr-id> <comment-id>` (`unresolve` reopens); `bb pr comments edit <pr-id> <comment-id> "text"`, `bb pr comments delete <pr-id> <comment-id>` **Repos:** `bb repo list`, `bb repo clone workspace/repo`, `bb repo view` **CI/CD:** `bb pipeline list`, `bb pipeline run --branch main`, `bb pipeline view/logs/stop <id>` **Commits:** `bb commit list`, `bb commit view <sha>`; build statuses: `bb status list <sha>`, `bb status set <sha> --key CI --state SUCCESSFUL` **Issues:** `bb issue list`, `bb issue view <id>`, `bb issue create -t "title"`, `bb issue edit/comment/close <id>` **Snippets:** `bb snippet list/view/create/edit/delete/watch/unwatch`, plus `bb snippet comments` **Workspaces & projects:** `bb workspace list/view`, `bb project list/view/create` **Browser URLs:** `bb browse --pr <id> -n` prints the URL instead of opening it (`--json` does the same and returns `{"url": …}`) **Raw API:** `bb api <endpoint>` — any Bitbucket 2.0 endpoint not covered above (e.g. `bb api /repositories/{workspace}/{repo}/branch-restrictions`; supports `--paginate` and `--jq`) ## Tips - Auto-detects workspace/repo from git remotes; override with `-w` / `-r` - All commands support `--json` for structured output - Merge strategies: `merge_commit`, `squash`, `fast_forward`, `squash_fast_forward`, `rebase_fast_forward`, `rebase_merge` SKILL echo "✓ Skill installed. Restart Claude Code to activate." ``` Restart Claude Code and try: **“List my open pull requests”** Tip This also registers `/bb-cli` as a slash command. For personal use across all projects, install to `~/.claude/skills/bb-cli/SKILL.md` instead. Commit the project-level file to git so your team gets it automatically. * opencode Add this to `AGENTS.md` in your project root (create the file if it doesn’t exist): ```markdown ## Bitbucket CLI (`bb`) Use `bb` (`@pilatos/bitbucket-cli`) for all Bitbucket operations. Requires Bun 1.0+ runtime. Install: `npm install -g @pilatos/bitbucket-cli` ### Commands **Pull Requests:** - `bb pr create -t "title" -b "body"` - Create PR from current branch - `bb pr create --default-reviewers` - Also attach the repo's default reviewers - `bb pr create --reviewer <uuid>` - Add a specific reviewer (repeatable) - `bb pr list` - List open PRs (`--mine` for your reviews, `--json` for scripts) - `bb pr view <id>` / `bb pr diff <id>` - Inspect a PR - `bb pr checkout <id>` - Check out PR locally - `bb pr approve <id>` / `bb pr decline <id>` - Review - `bb pr merge <id> --strategy squash --close-source-branch` - Merge - `bb pr ready <id>` - Mark draft as ready - `bb pr reviewers add <id> <uuid>` - Add reviewer to an existing PR **PR comments and review threads:** - `bb pr comments list <id>` - List comments (`--resolved` / `--unresolved` to filter) - `bb pr comments add <id> "text"` - Add a top-level comment - `bb pr comments view <pr-id> <comment-id>` - Read one comment - `bb pr comments reply <pr-id> <comment-id> "text"` - Reply in a thread - `bb pr comments resolve <pr-id> <comment-id>` / `unresolve <pr-id> <comment-id>` - Close or reopen a thread - `bb pr comments edit <pr-id> <comment-id> "text"` / `delete <pr-id> <comment-id>` - Edit or remove **Repositories:** - `bb repo list` / `bb repo view` / `bb repo clone workspace/repo` - `bb repo default-reviewers list` / `add <uuid>` / `remove <uuid> --yes` - Manage repo default reviewers **Pipelines (CI/CD):** - `bb pipeline list` / `bb pipeline view <id>` / `bb pipeline logs <id> --step <n>` - `bb pipeline run --branch main` / `bb pipeline stop <id>` **Commits & build statuses:** - `bb commit list` / `bb commit view <sha>` - `bb status list <sha>` / `bb status set <sha> --key CI --state SUCCESSFUL` **Issues:** - `bb issue list` / `bb issue view <id>` / `bb issue create -t "title"` - `bb issue edit <id>` / `bb issue comment <id> -b "text"` / `bb issue close <id>` **Workspaces & projects:** - `bb workspace list` / `bb workspace view [slug]` - `bb project list` / `bb project view <key>` / `bb project create` **Snippets:** - `bb snippet list` / `view` / `create` / `edit` / `delete` / `watch` / `unwatch` - `bb snippet comments list <id>` / `add <id> "text"` **Browser URLs:** - `bb browse --pr <id> -n` - Print the PR URL instead of opening a browser (`--json` returns `{"url": …}`) **Raw API access:** - `bb api <endpoint>` - Authenticated call to any Bitbucket 2.0 endpoint (escape hatch for anything without a typed command; e.g. `bb api /repositories/{workspace}/{repo}/branch-restrictions`; supports `--paginate` and `--jq`) **Configuration:** - `bb config set defaultWorkspace myworkspace` - `bb auth status` - Check authentication ### Tips - Auto-detects workspace/repo from git remotes; override with `-w` / `-r` - All commands support `--json` for machine-readable output - Run `bb --help` or `bb <command> --help` for full usage ``` Run opencode in your project and try: **“What PRs are open?”** Tip Keep `AGENTS.md` version-controlled so your team stays in sync. * Cursor Run this in your project root: ```bash mkdir -p .cursor/rules && cat > .cursor/rules/bb-cli.mdc << 'RULE' --- description: Bitbucket CLI - use `bb` for PR and repo operations globs: alwaysApply: true --- # Bitbucket CLI (`bb`) Use `bb` (`@pilatos/bitbucket-cli`) for Bitbucket operations. ## Key commands - `bb pr create -t "title" -b "body"` - Create PR - `bb pr list` - List open PRs (`--mine` for reviews, `--json` for scripts) - `bb pr view/diff/checkout <id>` - Inspect PR - `bb pr approve/decline/merge <id>` - Review and merge - `bb pr merge <id> --strategy squash --close-source-branch` - `bb pr ready <id>` - Mark draft as ready - `bb pr comments list <id>` - List comments (`--resolved`/`--unresolved` to filter) - `bb pr comments add <id> "text"` - Comment on PR - `bb pr comments reply/resolve/unresolve <pr-id> <comment-id>` - Work a review thread - `bb pr comments view/edit/delete <pr-id> <comment-id>` - Read, edit, remove a comment - `bb repo list/view/clone` - Repository operations - `bb pipeline list/view/run/stop/logs` - CI/CD pipelines - `bb commit list/view` + `bb status list/set <sha>` - Commits and build statuses - `bb issue list/view/create/edit/comment/close` - Issue tracker - `bb snippet list/view/create/edit/delete/watch/unwatch` + `bb snippet comments` - Snippets - `bb workspace list/view` + `bb project list/view/create` - Workspaces and projects - `bb browse --pr <id> -n` - Print a Bitbucket URL instead of opening a browser - `bb api <endpoint>` - Raw call to any Bitbucket 2.0 endpoint (escape hatch; `--paginate`, `--jq`) - `bb config set defaultWorkspace <ws>` - Set defaults ## Context Auto-detects workspace/repo from git remotes. Override with `-w`/`-r` flags. Use `--json` for machine-readable output. Run `bb --help` for full usage. RULE echo "✓ Rule created. Restart Cursor to activate." ``` * Windsurf Create `.windsurfrules` in your project root: ```markdown ## Bitbucket CLI (`bb`) Use `bb` (`@pilatos/bitbucket-cli`) for Bitbucket operations. **Key commands:** - `bb pr create -t "title" -b "body"` - Create PR - `bb pr list` - List open PRs (`--mine` for reviews, `--json` for scripts) - `bb pr view/diff/checkout <id>` - Inspect PR - `bb pr approve/decline/merge <id>` - Review and merge - `bb pr merge <id> --strategy squash --close-source-branch` - `bb pr ready <id>` - Mark draft as ready - `bb pr comments list <id>` - List comments (`--resolved`/`--unresolved` to filter) - `bb pr comments add <id> "text"` - Comment on PR - `bb pr comments reply/resolve/unresolve <pr-id> <comment-id>` - Work a review thread - `bb pr comments view/edit/delete <pr-id> <comment-id>` - Read, edit, remove a comment - `bb repo list/view/clone` - Repository operations - `bb pipeline list/view/run/stop/logs` - CI/CD pipelines - `bb commit list/view` + `bb status list/set <sha>` - Commits and build statuses - `bb issue list/view/create/edit/comment/close` - Issue tracker - `bb snippet list/view/create/edit/delete/watch/unwatch` + `bb snippet comments` - Snippets - `bb workspace list/view` + `bb project list/view/create` - Workspaces and projects - `bb browse --pr <id> -n` - Print a Bitbucket URL instead of opening a browser - `bb api <endpoint>` - Raw call to any Bitbucket 2.0 endpoint (escape hatch; `--paginate`, `--jq`) - `bb config set defaultWorkspace <ws>` - Set defaults **Context:** Auto-detects workspace/repo from git remotes. Use `-w`/`-r` to override. **Output:** Use `--json` for machine-readable output. **Help:** Run `bb --help` or `bb <command> --help` for full usage. ``` Tip **No setup at all?** Tell your AI assistant: *“Run `bb --help` to learn the Bitbucket CLI, then use it to list my open PRs.”* Most AI coding assistants can learn any CLI from its `--help` output on the fly. *** ## Example workflows [Section titled “Example workflows”](#example-workflows) ### Create and submit a PR [Section titled “Create and submit a PR”](#create-and-submit-a-pr) ```text You: Push my changes and create a PR titled "Add input validation" with a description of what changed AI: [Runs: git push -u origin feat/input-validation] [Runs: bb pr create -t "Add input validation" \ -b "Adds server-side validation for email and password fields. Includes unit tests and updates the API docs."] ✅ Created PR #47 https://bitbucket.org/acme/api/pull-requests/47 ``` ### Review multiple PRs at once [Section titled “Review multiple PRs at once”](#review-multiple-prs-at-once) ```text You: Show me all open PRs and summarize which ones are ready to merge AI: [Runs: bb pr list --json] [Runs: bb pr diff 42, bb pr diff 45, bb pr diff 46] 3 open PRs: • #42 "Fix login timeout" — 12 lines, 2 approvals, CI passing. Ready. • #45 "Refactor auth module" — 340 lines, no reviews, CI failing. Needs work. • #46 "Update README" — 3 lines, 1 approval. Ready. Want me to merge #42 and #46? ``` ### Full review-and-merge cycle [Section titled “Full review-and-merge cycle”](#full-review-and-merge-cycle) ```text You: Check out PR 42, review the diff, and if it looks good, approve and squash-merge it AI: [Runs: bb pr checkout 42] Checked out PR #42 on branch fix/login-timeout. [Runs: bb pr diff 42] Changes look clean — fixes the timeout by increasing the retry limit from 3 to 5, with a new test covering the edge case. [Runs: bb pr approve 42] ✅ Approved. [Runs: bb pr merge 42 --strategy squash --close-source-branch] ✅ Merged PR #42 with squash strategy. Source branch deleted. ``` ### Work an open review thread [Section titled “Work an open review thread”](#work-an-open-review-thread) ```text You: What review comments are still open on PR 45? AI: [Runs: bb pr comments list 45 --unresolved] 2 unresolved: • #109820 bob — "This retry loop has no upper bound." • #109834 bob — "Missing test for the 429 path." You: Fix both, then reply and resolve them AI: [Edits src/client.ts, adds tests] [Runs: bb pr comments reply 45 109820 "Capped at 3 attempts in a1b2c3d."] [Runs: bb pr comments resolve 45 109820] [Runs: bb pr comments reply 45 109834 "Added a 429 retry test in a1b2c3d."] [Runs: bb pr comments resolve 45 109834] ✅ Both threads replied to and resolved. ``` ### Draft PR workflow [Section titled “Draft PR workflow”](#draft-pr-workflow) ```text You: Create a draft PR for my work-in-progress AI: [Runs: bb pr create -t "WIP: New dashboard" --draft] ✅ Created draft PR #48 You: Mark PR 48 as ready and add Alice as reviewer AI: [Runs: bb pr ready 48] [Runs: bb pr reviewers add 48 {alice-uuid}] ✅ PR #48 is ready for review. Alice added as a reviewer. ``` *** ## Security [Section titled “Security”](#security) Caution Never commit API tokens to version control. Use environment variables or `bb auth login`. Your AI assistant never sees the raw token — it calls `bb` commands, and the CLI handles authentication internally. The `allowed-tools` field in the Claude Code skill restricts the AI to only running `bb` commands and reading files — no arbitrary shell access. For CI/CD or shared environments, use environment variables: ```bash export BB_USERNAME="your-username" export BB_API_TOKEN="your-api-token" bb auth login # Reads from env vars automatically ``` ### Required API token scopes [Section titled “Required API token scopes”](#required-api-token-scopes) These cover the command families the templates above teach. For the full command-to-scope map, see [Token Scopes](/reference/token-scopes/). | Scope | Required for | | ----------------------------- | ----------------------------------------------------------------------------------------------------------- | | `read:user:bitbucket` | Identity checks — `bb auth status`, plus resolving your own UUID for `bb pr create` and `bb pr list --mine` | | `read:repository:bitbucket` | `bb repo list`, `bb repo view`, `bb commit list/view`, `bb status list` — browse repos and commits | | `write:repository:bitbucket` | `bb status set` — set commit build statuses | | `admin:repository:bitbucket` | `bb repo create`, `bb repo default-reviewers add/remove` | | `delete:repository:bitbucket` | `bb repo delete` — delete repos (optional) | | `read:pullrequest:bitbucket` | `bb pr list`, `bb pr view`, `bb pr diff`, `bb pr comments list` — browse PRs | | `write:pullrequest:bitbucket` | `bb pr create`, `bb pr merge`, `bb pr approve`, `bb pr comments add/reply/resolve` — manage PRs | | `read:pipeline:bitbucket` | `bb pipeline list`, `bb pipeline view`, `bb pipeline logs` — inspect CI/CD | | `write:pipeline:bitbucket` | `bb pipeline run`, `bb pipeline stop` — control CI/CD | | `read:issue:bitbucket` | `bb issue list`, `bb issue view` — browse issues | | `write:issue:bitbucket` | `bb issue create`, `bb issue edit`, `bb issue close` — manage issues | | `read:workspace:bitbucket` | `bb workspace list`, `bb workspace view` — discover workspaces | | `read:project:bitbucket` | `bb project list`, `bb project view` — browse projects | | `admin:project:bitbucket` | `bb project create` — create projects | | `read:snippet:bitbucket` | `bb snippet list`, `bb snippet view` — browse snippets | | `write:snippet:bitbucket` | `bb snippet create/edit/delete/watch/unwatch` — manage snippets | For read-only agents (listing and viewing), the `read` scopes are enough. ### OAuth agents [Section titled “OAuth agents”](#oauth-agents) `bb auth login` defaults to OAuth, which requests a fixed scope set and never prompts you to choose: ```text account repository repository:admin pullrequest pullrequest:write ``` That covers repository and pull request work, including `bb repo create` and `bb repo default-reviewers`. It does **not** cover `bb pipeline`, `bb issue`, `bb project`, `bb snippet`, or `bb repo delete` — those return 403 under OAuth. Use an API token with the scopes above if your agent needs them. *** ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) | Issue | Solution | | ----------------------------- | ------------------------------------------------------------------------------------------------- | | “Not authenticated” | Run `bb auth login` or set `BB_USERNAME` + `BB_API_TOKEN` env vars | | Claude doesn’t use `bb` | Restart Claude Code after creating the skill file. Check `/bb-cli` shows in the slash menu | | “Could not determine repo” | Run from a git repo with a Bitbucket remote, or pass `-w`/`-r` flags explicitly | | Skill not auto-activating | Invoke manually with `/bb-cli`, or check the `description` field in SKILL.md | | Cursor rule not loading | Ensure the file is at `.cursor/rules/bb-cli.mdc` with valid frontmatter. Restart Cursor | | opencode ignoring AGENTS.md | Ensure the file is in the project root (not a subdirectory). Restart opencode | | `bb` command not found | Install with `npm install -g @pilatos/bitbucket-cli`. Requires [Bun 1.0+](https://bun.sh) runtime | | AI using wrong flags | Tell the AI to run `bb <command> --help` first | | Windsurf not picking up rules | Ensure `.windsurfrules` is in the project root. Restart Windsurf | *** ## `llms.txt` for IDE agents [Section titled “llms.txt for IDE agents”](#llmstxt-for-ide-agents) The docs site publishes the [`llms.txt`](https://llmstxt.org/) convention so agents that fetch documentation on demand (Cursor, Cline, Continue, Aider, and similar) can pull a clean markdown view of the full reference instead of scraping HTML: | URL | Contents | | --------------------------------------------------------------------------- | --------------------------------------------------------------------------- | | [`/llms.txt`](https://bitbucket-cli.paulvanderlei.com/llms.txt) | Index pointing to the two content files below | | [`/llms-full.txt`](https://bitbucket-cli.paulvanderlei.com/llms-full.txt) | Every doc page concatenated as markdown | | [`/llms-small.txt`](https://bitbucket-cli.paulvanderlei.com/llms-small.txt) | Abridged subset (excludes Help / FAQ / Changelog) for tight context windows | All three are generated at build time, so they always match the live docs. Tools that support `llms.txt` find them on their own. For everything else, paste the URL into the chat — in Cursor, `@https://bitbucket-cli.paulvanderlei.com/llms-full.txt`. *** ## Related guides [Section titled “Related guides”](#related-guides) * [Scripting & Automation](/guides/scripting/) — JSON output, exit codes, and shell scripting patterns * [CI/CD Integration](/guides/cicd/) — Use `bb` in GitHub Actions, GitLab CI, Jenkins, and more * [JSON Output Reference](/reference/json-output/) — Detailed JSON schemas for all commands * [Error Codes](/reference/error-codes/) — the numeric `code` values in `--json` error output (the process exit code is always 0 or 1) * [Command Reference](/commands/pr/) — Complete PR command documentation # CI/CD Integration - GitHub Actions, GitLab, Jenkins, CircleCI > Integrate Bitbucket CLI into your CI/CD pipelines. Step-by-step examples for GitHub Actions, GitLab CI, Jenkins, CircleCI, and generic pipelines with authentication and best practices. The Bitbucket CLI automates pull request (PR) workflows, reports build statuses back to commits, and triggers Bitbucket Pipelines from any CI system. ## Quick setup [Section titled “Quick setup”](#quick-setup) 1. **Store credentials as secrets** in your CI/CD platform. * `BB_USERNAME` — your Bitbucket username * `BB_API_TOKEN` — your Bitbucket API token 2. **Install Bun and the CLI.** The CLI is Bun-only; it exits immediately under Node.js. ```bash curl -fsSL https://bun.sh/install | bash export PATH="$HOME/.bun/bin:$PATH" bun install -g @pilatos/bitbucket-cli ``` On an image that already ships Bun (`oven/bun:latest`) skip the `curl` line and keep the other two — those images contain no Node.js and no npm. 3. **Authenticate.** With `BB_API_TOKEN` set in the environment, `bb auth login` takes the API-token path and stores the credentials. With no token set it opens a browser for OAuth and waits five minutes for a callback that never arrives in a headless runner. ```bash bb auth login ``` 4. **Run commands** with explicit workspace and repository flags. ```bash bb pr list -w myworkspace -r myrepo --json ``` ### Paging [Section titled “Paging”](#paging) List commands return 25 items by default. Pass `--limit <n>` to raise or lower that cap, or `--all` to fetch every page — `--all` overrides `--limit`. ```bash bb pr list -w myworkspace -r myrepo --all --json ``` See [Global Flags](/reference/global-flags/#list-command-flags). ### Reading JSON without an external jq [Section titled “Reading JSON without an external jq”](#reading-json-without-an-external-jq) `--json [fields]` and `--jq <expression>` are global flags. `--jq` runs an embedded jq, so it works on minimal CI images and on Windows agents that have no `jq` binary. `--jq` requires `--json`. ```bash # Project to a comma-separated field list bb pr list -w myworkspace -r myrepo --json id,title # Filter with the embedded jq bb pr list -w myworkspace -r myrepo --all --json --jq '.pullRequests[].id' ``` Projection runs before jq, and `--json <fields>` drops the envelope on list commands — `count` disappears once you project. See [Scripting & Automation](/guides/scripting/#field-selection-and---jq). *** ## Platform examples [Section titled “Platform examples”](#platform-examples) Each snippet shows the platform-specific part: how secrets reach the job, and how `~/.bun/bin` gets on `PATH`. The install and `bb auth login` steps are the same everywhere. ### GitHub Actions [Section titled “GitHub Actions”](#github-actions) ```yaml name: Bitbucket PR Check on: push: branches: [main] pull_request: jobs: check-bitbucket-prs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v1 with: bun-version: latest - name: Install Bitbucket CLI run: bun install -g @pilatos/bitbucket-cli - name: List open PRs env: BB_USERNAME: ${{ secrets.BB_USERNAME }} BB_API_TOKEN: ${{ secrets.BB_API_TOKEN }} run: | bb auth login bb pr list -w myworkspace -r myrepo --json --jq '.count' ``` `oven-sh/setup-bun` puts `bun` on `PATH` for you, including globally installed binaries. ### GitLab CI [Section titled “GitLab CI”](#gitlab-ci) ```yaml stages: - check variables: BB_WORKSPACE: myworkspace BB_REPO: myrepo check-prs: stage: check image: oven/bun:latest before_script: - bun install -g @pilatos/bitbucket-cli - export PATH="$HOME/.bun/bin:$PATH" - bb auth login script: - bb pr list -w $BB_WORKSPACE -r $BB_REPO --json - bb repo view -w $BB_WORKSPACE -r $BB_REPO ``` Define `BB_USERNAME` and `BB_API_TOKEN` under **Settings > CI/CD > Variables** (masked, protected). GitLab exports project variables into the job environment, so no `variables:` entry is needed for them. ### Bitbucket Pipelines [Section titled “Bitbucket Pipelines”](#bitbucket-pipelines) ```yaml image: oven/bun:latest pipelines: default: - step: name: Check PRs script: - bun install -g @pilatos/bitbucket-cli - export PATH="$HOME/.bun/bin:$PATH" - bb auth login - bb pr list -w $BITBUCKET_WORKSPACE -r $BITBUCKET_REPO_SLUG --json pull-requests: '**': - step: name: PR Info script: - bun install -g @pilatos/bitbucket-cli - export PATH="$HOME/.bun/bin:$PATH" - bb auth login - bb pr view $BITBUCKET_PR_ID -w $BITBUCKET_WORKSPACE -r $BITBUCKET_REPO_SLUG definitions: caches: bun: ~/.bun ``` Pipelines injects `BITBUCKET_WORKSPACE`, `BITBUCKET_REPO_SLUG`, and `BITBUCKET_PR_ID`, which the snippet above passes to `-w`, `-r`, and `bb pr view`. Caution Pipelines does **not** inject Bitbucket credentials, and the CLI never reads the `BITBUCKET_*` variables for auth. Add both `BB_USERNAME` and `BB_API_TOKEN` as secured repository or workspace variables. Without `BB_API_TOKEN`, `bb auth login` falls back to the OAuth browser flow and the step hangs until it times out. ### Jenkins [Section titled “Jenkins”](#jenkins) ```groovy pipeline { agent any environment { BB_USERNAME = credentials('bitbucket-username') BB_API_TOKEN = credentials('bitbucket-token') } stages { stage('Setup') { steps { sh 'curl -fsSL https://bun.sh/install | bash' sh 'export PATH="$HOME/.bun/bin:$PATH" && bun install -g @pilatos/bitbucket-cli' sh 'export PATH="$HOME/.bun/bin:$PATH" && bb auth login' } } stage('Check PRs') { steps { sh ''' export PATH="$HOME/.bun/bin:$PATH" bb pr list -w myworkspace -r myrepo --json --jq '.count' ''' } } } } ``` Each `sh` step is a fresh shell, so `PATH` has to be exported in every one. To merge approved PRs from Jenkins, run the script in [Merge approved PRs automatically](#merge-approved-prs-automatically) as a build step. ### Azure DevOps [Section titled “Azure DevOps”](#azure-devops) ```yaml trigger: - main pool: vmImage: 'ubuntu-latest' variables: - group: bitbucket-credentials # Variable group with BB_USERNAME, BB_API_TOKEN steps: - script: | curl -fsSL https://bun.sh/install | bash echo "##vso[task.prependpath]$HOME/.bun/bin" displayName: 'Install Bun' - script: bun install -g @pilatos/bitbucket-cli displayName: 'Install Bitbucket CLI' - script: | bb auth login bb pr list -w myworkspace -r myrepo --json displayName: 'List PRs' env: BB_USERNAME: $(BB_USERNAME) BB_API_TOKEN: $(BB_API_TOKEN) ``` `##vso[task.prependpath]` puts `~/.bun/bin` on `PATH` for every later step. *** ## Common use cases [Section titled “Common use cases”](#common-use-cases) ### Report build status back to Bitbucket [Section titled “Report build status back to Bitbucket”](#report-build-status-back-to-bitbucket) `bb status set <sha>` creates or updates a build status on a commit. It is idempotent per `--key`, so calling it again with the same key replaces the previous status instead of adding a second one. ```bash bb status set "$GITHUB_SHA" -w myworkspace -r myrepo \ --key CI --state INPROGRESS --url "$RUN_URL" # ... run the build ... bb status set "$GITHUB_SHA" -w myworkspace -r myrepo \ --key CI --state SUCCESSFUL --url "$RUN_URL" --description "All tests passed" ``` `--state` accepts `INPROGRESS`, `SUCCESSFUL`, `FAILED`, or `STOPPED`. `--name`, `--description`, and `--refname` are optional. Read statuses back with `bb status list <sha>`. ### Trigger a Bitbucket pipeline from another CI system [Section titled “Trigger a Bitbucket pipeline from another CI system”](#trigger-a-bitbucket-pipeline-from-another-ci-system) ```bash # Latest commit on a branch bb pipeline run -w myworkspace -r myrepo --branch main # A custom pipeline from bitbucket-pipelines.yml, with variables bb pipeline run -w myworkspace -r myrepo \ --pipeline deploy-prod --var ENV=prod --var DRY_RUN=false ``` `bb pipeline list --status FAILED`, `bb pipeline view <id>`, `bb pipeline logs <id> --step <n>`, and `bb pipeline stop <id>` cover the rest. See [bb pipeline](/commands/pipeline/). ### Create a PR from a branch [Section titled “Create a PR from a branch”](#create-a-pr-from-a-branch) Create the PR only if one does not already exist for the source branch. This works the same whether the branch came from a feature push or a scheduled dependency bump. ```bash BRANCH=${GITHUB_REF#refs/heads/} EXISTING=$(bb pr list -w myworkspace -r myrepo --all --json \ --jq "[.pullRequests[] | select(.source.branch.name == \"$BRANCH\")] | length") if [ "$EXISTING" -eq 0 ]; then bb pr create -w myworkspace -r myrepo \ -t "chore: $BRANCH" \ -b "Opened automatically by CI" \ -s "$BRANCH" \ -d main fi ``` ### Merge approved PRs automatically [Section titled “Merge approved PRs automatically”](#merge-approved-prs-automatically) This script merges as soon as any reviewer has approved. To wait for **all CI checks to pass** first — the more common production pattern — see [Auto-merge on green CI](/recipes/auto-merge-on-ci-green/). ```bash #!/bin/bash # auto-merge.sh - Run in CI on schedule set -e WORKSPACE="myworkspace" REPO="myrepo" # --all is required: without it only the first 25 open PRs are considered open_prs=$(bb pr list -w "$WORKSPACE" -r "$REPO" --all --json --jq '.pullRequests[].id') for pr_id in $open_prs; do is_approved=$(bb pr view "$pr_id" -w "$WORKSPACE" -r "$REPO" --json \ --jq '[.participants[] | select(.approved == true)] | length > 0') if [ "$is_approved" != "true" ]; then sleep 1 continue fi if bb pr merge "$pr_id" -w "$WORKSPACE" -r "$REPO" --strategy squash --close-source-branch; then echo "Merged PR #$pr_id" else echo "Could not merge PR #$pr_id (conflicts or failing checks)" fi sleep 2 done ``` ### Generate a changelog from merged PRs [Section titled “Generate a changelog from merged PRs”](#generate-a-changelog-from-merged-prs) generate-changelog.sh ```bash #!/bin/bash WORKSPACE="myworkspace" REPO="myrepo" SINCE_DATE=$(date -d '7 days ago' +%Y-%m-%d 2>/dev/null || \ date -v-7d +%Y-%m-%d) echo "# Changelog - Week of $(date +%Y-%m-%d)" echo "" # External jq here because the program needs --arg; --jq takes no variables bb pr list -w "$WORKSPACE" -r "$REPO" -s MERGED --all --json | jq -r --arg since "$SINCE_DATE" ' .pullRequests[] | select(.updated_on >= $since) | "- \(.title) (#\(.id)) by @\(.author.nickname // .author.display_name // "unknown")" ' ``` *** ## Exit codes and errors [Section titled “Exit codes and errors”](#exit-codes-and-errors) Every command exits `0` on success and `1` on any failure. There is no per-error exit code — the specific `ErrorCode` lives in the error payload. Under `--json`, the error envelope is written to **stderr** as one compact line while stdout stays byte-clean JSON: ```json {"name":"BBError","code":1001,"message":"Authentication required. Run 'bb auth login' or set BB_USERNAME and BB_API_TOKEN."} ``` 401, 403, and 404 failures carry an extra `hint` string. See [Scripting & Automation](/guides/scripting/#exit-codes) and [Error Codes](/reference/error-codes/). *** ## Security considerations [Section titled “Security considerations”](#security-considerations) ### Token scopes [Section titled “Token scopes”](#token-scopes) Create a dedicated CI/CD token with minimal permissions: | Use case | Required scopes | | -------------------------------------------- | ----------------------------------------------------------- | | Verify identity | `read:user:bitbucket` | | Read-only checks | + `read:repository:bitbucket`, `read:pullrequest:bitbucket` | | Create/merge PRs | + `write:pullrequest:bitbucket` | | Report build statuses, write repository data | + `write:repository:bitbucket` | | Create repositories | + `admin:repository:bitbucket` | | Delete repositories | + `delete:repository:bitbucket` | The `+` notation is cumulative for the read and write scopes only. `admin:repository:bitbucket` and `delete:repository:bitbucket` are separate scopes, not supersets of each other or of `write:repository:bitbucket` — grant each one you actually need. Full list: [Token Scopes](/reference/token-scopes/). ### Secrets management [Section titled “Secrets management”](#secrets-management) * GitHub Actions Store in **Settings > Secrets and variables > Actions** * GitLab Store in **Settings > CI/CD > Variables** (masked, protected) * Jenkins Use **Credentials** plugin with Secret text type * Bitbucket Pipelines Store as **secured** repository or workspace variables *** ## Troubleshooting CI/CD [Section titled “Troubleshooting CI/CD”](#troubleshooting-cicd) ### Authentication fails [Section titled “Authentication fails”](#authentication-fails) ```text ✗ Authentication required. Run 'bb auth login' or set BB_USERNAME and BB_API_TOKEN. ``` Under `--json` the same failure appears on stderr as `{"name":"BBError","code":1001,...}`. Check that both variables reach the job, and that the token has not expired: ```bash echo "Username set: $([ -n "$BB_USERNAME" ] && echo 'yes' || echo 'no')" echo "Token set: $([ -n "$BB_API_TOKEN" ] && echo 'yes' || echo 'no')" ``` ### The auth step hangs [Section titled “The auth step hangs”](#the-auth-step-hangs) `bb auth login` only uses the API-token path when `BB_API_TOKEN` is set (or when you pass `-u`/`-p`/`--with-token`). Otherwise it starts the OAuth browser flow on `http://localhost:19872/callback` and blocks for five minutes. Set `BB_API_TOKEN` in the step’s environment. ### Rate limiting in loops [Section titled “Rate limiting in loops”](#rate-limiting-in-loops) Add a delay between API calls: ```bash for pr_id in $pr_ids; do bb pr view "$pr_id" -w myworkspace -r myrepo --json sleep 2 done ``` ### `bb: command not found` [Section titled “bb: command not found”](#bb-command-not-found) `bun install -g` puts binaries in `~/.bun/bin`, which is not on `PATH` in a fresh shell. Export it before calling `bb`, in the same shell invocation: ```bash export PATH="$HOME/.bun/bin:$PATH" bb --version ``` # Understanding Repository Context > How the CLI determines which workspace and repository to use Most commands need a workspace and a repository. If you don’t pass `-w`/`-r`, the CLI works them out from your git remote, then `BB_WORKSPACE`, then your config file — in that order. ## Context resolution order [Section titled “Context resolution order”](#context-resolution-order) 1. **`-w/--workspace` and `-r/--repo`** on the command line 2. **The `origin` git remote** of the current repository 3. **The `BB_WORKSPACE` environment variable** 4. **`defaultWorkspace`** in the config file Sources 3 and 4 only supply a workspace. A repository still has to come from `-r` or the git remote. ### Typical local layout [Section titled “Typical local layout”](#typical-local-layout) * projects/ * myworkspace-tools/ * .git/ * … * src/ * commands/ * … * services/ * … * README.md When you run `bb` from `myworkspace-tools/`, the CLI reads the Bitbucket remote from `.git/` and uses that workspace and repository as context. ### Examples [Section titled “Examples”](#examples) #### Scenario 1: inside a git repository [Section titled “Scenario 1: inside a git repository”](#scenario-1-inside-a-git-repository) ```bash # /projects/myrepo has a Bitbucket origin remote cd /projects/myrepo bb pr list # workspace and repository come from the remote ``` The CLI reads your `.git/config` and extracts the workspace and repository from the remote URL. #### Scenario 2: using command-line flags [Section titled “Scenario 2: using command-line flags”](#scenario-2-using-command-line-flags) ```bash bb pr list -w myworkspace -r myrepo ``` Flags always win, and they work from anywhere — no git repository required. #### Scenario 3: using a default workspace [Section titled “Scenario 3: using a default workspace”](#scenario-3-using-a-default-workspace) ```bash # Environment variable — useful in CI export BB_WORKSPACE=myworkspace # Or persist it in the config file bb config set defaultWorkspace myworkspace bb repo list # workspace-only command, no repository needed ``` `BB_WORKSPACE` wins over `defaultWorkspace`, so a pipeline can override a developer’s persisted default without rewriting the config file. #### Scenario 4: mixed sources [Section titled “Scenario 4: mixed sources”](#scenario-4-mixed-sources) ```bash # Inside a clone of gitworkspace/gitrepo cd /projects/myrepo # Override just the workspace bb pr list -w anotherworkspace # anotherworkspace/gitrepo # Override just the repository bb pr list -r anotherrepo # gitworkspace/anotherrepo ``` ## Workspace-only vs repository-scoped commands [Section titled “Workspace-only vs repository-scoped commands”](#workspace-only-vs-repository-scoped-commands) The two classes fail differently when context is missing. | Class | Commands | Error when unresolved | | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | | Workspace-only | `bb repo list`, `bb repo create`, `bb repo clone`, `bb project *`, `bb snippet *`, `bb workspace view` | `6002 CONTEXT_WORKSPACE_NOT_FOUND` | | Repository-scoped | `bb pr *`, `bb pipeline *`, `bb issue *`, `bb commit *`, `bb status *`, `bb browse`, `bb repo view`, `bb repo delete`, `bb repo default-reviewers *` | `6001 CONTEXT_REPO_NOT_FOUND` | `bb api` falls in either class depending on the endpoint: it resolves a workspace only if the endpoint contains `{workspace}`, and a repository only if it contains `{repo}`. ```bash # Placeholders are filled from the same resolution chain bb api /repositories/{workspace}/{repo}/pullrequests ``` If a placeholder can’t be resolved you get `Endpoint uses {repo} but no repository could be resolved. Pass --repo or run inside a Bitbucket repo.` ## Repository argument formats [Section titled “Repository argument formats”](#repository-argument-formats) Commands that accept a repository argument support two formats. ### Full format: `workspace/repo` [Section titled “Full format: workspace/repo”](#full-format-workspacerepo) ```bash bb repo view myworkspace/myrepo bb repo delete myworkspace/myrepo --yes ``` ### Short format: `repo` only [Section titled “Short format: repo only”](#short-format-repo-only) ```bash bb repo view myrepo ``` The workspace is resolved in the usual order: 1. `-w/--workspace`, if you passed it 2. Otherwise the workspace from the current git remote 3. Otherwise `BB_WORKSPACE` 4. Otherwise `defaultWorkspace` from the config file 5. Otherwise error The git remote wins over your config. Running `bb repo view myrepo` inside a clone of `otherws/otherrepo` resolves to `otherws/myrepo`, even if `defaultWorkspace` is set to something else. ## Supported remote URL formats [Section titled “Supported remote URL formats”](#supported-remote-url-formats) ### SSH format [Section titled “SSH format”](#ssh-format) ```text git@bitbucket.org:workspace/repo.git git@bitbucket.org:workspace/repo ``` ### HTTPS format [Section titled “HTTPS format”](#https-format) ```text https://bitbucket.org/workspace/repo.git https://bitbucket.org/workspace/repo https://username@bitbucket.org/workspace/repo.git ``` ### Limitations [Section titled “Limitations”](#limitations) * Only the remote named `origin` is inspected. If your Bitbucket remote has another name, pass `-w`/`-r`. * Repository names containing a dot (`docs.example.com`, `my.repo`) are not parsed. * `ssh://git@bitbucket.org/workspace/repo.git` is not recognised — use the `git@bitbucket.org:workspace/repo` form. A dotted repository name or an `ssh://` URL fails with `Remote '<url>' is not a Bitbucket URL.` A differently-named remote fails with `Git repository has no remote configured.` ## Error messages [Section titled “Error messages”](#error-messages) ### Repository could not be resolved [Section titled “Repository could not be resolved”](#repository-could-not-be-resolved) Three distinct messages, all error code `6001 CONTEXT_REPO_NOT_FOUND`. Under `--json` each sets a different `context.reason`. The working directory is not a git repository — `reason: not_a_git_repo`: ```text ✗ Not in a git repository. Use --workspace and --repo options, or run this command from within a Bitbucket repository. ``` There is no `origin` remote — `reason: no_remote`: ```text ✗ Git repository has no remote configured. Add a Bitbucket remote with `git remote add origin <url>`, or use --workspace and --repo options, or run this command from within a Bitbucket repository. ``` `origin` points somewhere other than Bitbucket, or the repository name contains a dot — `reason: remote_not_bitbucket`: ```text ✗ Remote 'git@github.com:acme/tool.git' is not a Bitbucket URL. Use --workspace and --repo options, or run this command from within a Bitbucket repository. ``` Fix any of them with explicit flags: `bb pr list -w myworkspace -r myrepo`. ### No workspace specified [Section titled “No workspace specified”](#no-workspace-specified) ```text ✗ No workspace specified. Use --workspace option or set a default workspace with `bb config set defaultWorkspace <name>`. ``` Error code `6002 CONTEXT_WORKSPACE_NOT_FOUND`, thrown by workspace-only commands. Pass `-w`, export `BB_WORKSPACE`, or set `defaultWorkspace`. ### “Repository not found” [Section titled ““Repository not found””](#repository-not-found) The workspace and repository resolved, but the pair doesn’t exist or your token can’t see it. Check the spelling, your access, and that the repository lives in that workspace. See [Error Codes](/reference/error-codes/) for the full list. ## Which approach to use [Section titled “Which approach to use”](#which-approach-to-use) | Situation | Use | | --------------------------- | ------------------------------------------- | | Interactive work in a clone | Nothing — the git remote resolves it | | Scripts and automation | Explicit `-w`/`-r` on every command | | CI pipelines | `BB_WORKSPACE` plus `-r`, or explicit flags | | You live in one workspace | `bb config set defaultWorkspace <name>` | Don’t set `defaultWorkspace` if you work across several workspaces — a stale default silently sends commands to the wrong place when you’re outside a clone. ## Checking what got resolved [Section titled “Checking what got resolved”](#checking-what-got-resolved) ```bash bb repo view # the resolved workspace/repository bb workspace view # the resolved workspace ``` Both accept `--json`, which every command in the CLI supports — see [JSON Output](/reference/json-output/). For the full list of global flags including `-w`/`-r`, see [Global Flags](/reference/global-flags/). # Scripting & Automation - Bitbucket CLI for CI/CD Workflows > Learn how to use Bitbucket CLI in automation scripts and CI/CD pipelines. JSON output, exit codes, error handling, and practical examples for DevOps workflows. ## JSON output mode [Section titled “JSON output mode”](#json-output-mode) Add `--json` for machine-readable output: ```bash bb pr list --json bb repo list --json bb pr view 42 --json ``` Caution `--json` must come **after** the subcommand. Its field-list argument is optional, so `bb --json pr list` swallows `pr` as the field list, leaves `list` to be parsed as a top-level command, and exits 1 with error code 5002. Write `bb pr list --json`. If you need the flag before the subcommand, use the equals form: `bb --json=id,title pr list`. Paginated list commands return 25 rows by default. Pass `--all` to fetch every page, or `--limit <n>` for a specific cap — `--all` wins if you pass both. `--limit` must be a positive integer; anything else fails with `--limit must be a positive integer` (error code 5002). There is no `--page` flag; pagination is followed internally. ```bash bb pr list --json --all bb pr list --json --limit 100 ``` Twelve commands take `--limit` and `--all`: `repo list`, `pr list`, `pr activity`, `pr comments list`, `snippet list`, `snippet comments list`, `pipeline list`, `commit list`, `status list`, `issue list`, `workspace list`, `project list`. Other list-style commands return their full result set and accept neither flag — `bb pr reviewers list` and `bb repo default-reviewers list`, for example. ### Field selection and `--jq` [Section titled “Field selection and --jq”](#field-selection-and---jq) Two flags inspired by the [`gh` CLI](https://cli.github.com/manual/gh_help_formatting) slice and filter output without an external `jq` binary: ```bash # Project to a comma-separated field list bb pr list --json id,title,state # Filter through the embedded jq (requires --json) bb pr list --json --jq '.pullRequests[].title' # Combine both bb pr list --json id,title,state \ --jq '.[] | select(.state == "OPEN") | .title' ``` When `--json fields` is passed against a list-style command, the wrapper envelope is dropped and the field list is projected per-item — the result is a flat array. See [JSON Output reference](/reference/json-output/) for details. `--jq` matches the syntax of the standalone [jq](https://jqlang.github.io/jq/) binary, so existing expressions work either way. These two are equivalent: ```bash bb pr list --json --jq '.pullRequests[].title' bb pr list --json | jq '.pullRequests[].title' ``` ### jq patterns [Section titled “jq patterns”](#jq-patterns) ```bash # Open PR count (--state defaults to OPEN) bb pr list --json --all --jq '.count' # Merged PR count bb pr list -s MERGED --json --all --jq '.count' # Project specific fields bb pr list --json --all --jq '.pullRequests[] | {id, title, author: .author.display_name}' # Filter by author bb pr list --json --all --jq '.pullRequests[] | select((.author.nickname // .author.display_name) == "alice")' # PR web URLs bb pr list --json --all --jq '.pullRequests[].links.html.href' # Web diff URL for one PR bb pr diff 42 --web --json --jq '.url' # PRs updated in the last 7 days bb pr list --json --all | jq --arg date "$(date -d '7 days ago' -Iseconds 2>/dev/null || \ date -v-7d -Iseconds)" \ '.pullRequests[] | select(.updated_on > $date)' # PRs targeting main bb pr list --json --all | jq '.pullRequests[] | select(.destination.branch.name == "main")' # Group PRs by author bb pr list --json --all | jq '.pullRequests | group_by(.author.nickname // .author.display_name) | map({author: (.[0].author.nickname // .[0].author.display_name), count: length})' ``` *** ## Raw API access (escape hatch) [Section titled “Raw API access (escape hatch)”](#raw-api-access-escape-hatch) When no typed command covers what you need, [`bb api`](/commands/api/) calls any Bitbucket Cloud 2.0 endpoint through the same authenticated stack. Its output is already JSON, so `--jq` works without `--json`. ```bash # Any endpoint, authenticated bb api /user --jq '.username' # Fields become a query string on GET, a JSON body otherwise bb api /repositories/myworkspace/myrepo/pullrequests -X GET -f state=MERGED # Follow pagination and pull a single field across every page bb api /repositories/myworkspace/myrepo/pullrequests --paginate \ --jq '.values[].title' # Create resources that have no typed command yet bb api POST /repositories/myworkspace/myrepo/issues -f title="Bug report" ``` `{workspace}` and `{repo}` placeholders resolve from `-w`/`-r` or the current checkout. See the [API command reference](/commands/api/) for every flag. *** ## Exit codes [Section titled “Exit codes”](#exit-codes) | Code | Meaning | | ---- | ------------------------------------------------------------- | | 0 | Success | | 1 | Any failure (authentication, API, validation, network, jq, …) | There is **no `2`/`3`/etc. mapping** — every failure exits with `1`. To branch on the specific failure mode, read the `code` field of the JSON error envelope, which is one of the [error codes](/reference/error-codes/). *** ## Error handling [Section titled “Error handling”](#error-handling) In `--json` mode, success JSON goes to stdout and the error envelope goes to stderr. Redirect them separately: ```bash #!/bin/bash set -euo pipefail if ! bb pr view 999 -w myworkspace -r myrepo --json > out.json 2> err.json; then code=$(jq -r '.code' err.json) case "$code" in 1001|1002|1003) echo "auth problem";; 2002) echo "PR not found";; *) echo "other failure ($code): $(jq -r '.message' err.json)";; esac exit 1 fi ``` The error envelope carries: | Field | Notes | | ------------ | ------------------------------------------------------------------- | | `name` | Error class — `BBError`, `AuthError`, `APIError`, … | | `code` | Numeric [error code](/reference/error-codes/) | | `message` | Human-readable failure description | | `context` | Extra detail (ids, keys, args); omitted when the error carries none | | `statusCode` | HTTP status — `APIError` only | | `response` | Raw API response body — `APIError` only, when non-empty | | `hint` | Remediation advice; optional, see below | `hint` appears only on API errors with status 401, 403, or 404, and is skipped on 404 when the message already names the missing resource. Treat it as optional in scripts. Argument-parsing failures are the exception. An unknown option, a missing argument, or too many arguments prints a **plain text** usage error to stderr and exits 1 even under `--json`, so `jq` cannot parse it. The one parse failure that still emits an envelope is an unknown top-level command — `bb bogus --json` returns code 5002, while `bb pr bogus --json` prints `error: unknown command 'bogus'` as plain text. *** ## Environment variables [Section titled “Environment variables”](#environment-variables) For non-interactive scripts, use environment variables: ```bash export BB_USERNAME=myuser export BB_API_TOKEN=ATBB_token bb auth login # Uses env vars bb pr list -w workspace -r repo ``` See [Environment Variables Reference](/reference/environment-variables/) for details. *** ## Built-in resilience [Section titled “Built-in resilience”](#built-in-resilience) ### Automatic retry [Section titled “Automatic retry”](#automatic-retry) API requests that fail with HTTP 429, 502, 503, or 504 are retried up to 3 times with exponential backoff. Add your own retry loop only if you need more than 3 attempts. ### OAuth token refresh [Section titled “OAuth token refresh”](#oauth-token-refresh) OAuth access tokens expire after 2 hours. The CLI refreshes them automatically — proactively before expiry and reactively on 401 responses. Long-running OAuth scripts never need to re-authenticate manually. *** ## Scripting best practices [Section titled “Scripting best practices”](#scripting-best-practices) ### Always pass `-w` and `-r` [Section titled “Always pass -w and -r”](#always-pass--w-and--r) Workspace and repository detection reads the git remote of the current checkout. CI runners frequently check out with a non-Bitbucket remote, or no remote at all, so context detection fails there. ```bash # Good - explicit and reliable bb pr list -w myworkspace -r myrepo --json # Bad - fails when the checkout has no Bitbucket remote bb pr list --json ``` ### Add delays in loops [Section titled “Add delays in loops”](#add-delays-in-loops) When making many sequential API calls, add short delays to avoid hitting rate limits: ```bash #!/bin/bash set -euo pipefail WORKSPACE="myworkspace" REPO="myrepo" for pr_id in $(bb pr list -w "$WORKSPACE" -r "$REPO" --json --all | jq -r '.pullRequests[].id'); do bb pr view "$pr_id" -w "$WORKSPACE" -r "$REPO" --json sleep 1 done ``` *** ## Example scripts [Section titled “Example scripts”](#example-scripts) Looking for a recipe? For ready-to-copy workflows — auto-merge on green CI, bulk reviewer assignment, fork sync, jq analytics, and retry wrappers — see the [Recipes section](/recipes/). ### Batch pull request approval [Section titled “Batch pull request approval”](#batch-pull-request-approval) Approve all open pull requests (PRs) from a specific author: ```bash #!/bin/bash set -euo pipefail WORKSPACE="myworkspace" REPO="myrepo" AUTHOR="trusted-bot" echo "Finding PRs from $AUTHOR..." pr_ids=$(bb pr list -w "$WORKSPACE" -r "$REPO" --json --all | \ jq -r --arg author "$AUTHOR" '.pullRequests[] | select((.author.nickname // .author.display_name) == $author) | .id') for pr_id in $pr_ids; do echo "Approving PR #$pr_id..." bb pr approve "$pr_id" -w "$WORKSPACE" -r "$REPO" sleep 1 done echo "Done!" ``` ### PR status report [Section titled “PR status report”](#pr-status-report) Generate a markdown report of open PRs: ```bash #!/bin/bash set -euo pipefail WORKSPACE="myworkspace" REPO="myrepo" echo "# Open Pull Requests" echo "" echo "Generated: $(date)" echo "" bb pr list -w "$WORKSPACE" -r "$REPO" --json --all | jq -r '.pullRequests[] | "## PR #\(.id): \(.title)\n" + "- **Author:** \(.author.display_name)\n" + "- **Branch:** \(.source.branch.name) → \(.destination.branch.name)\n" + "- **Created:** \(.created_on)\n" + "- **Link:** \(.links.html.href)\n"' ``` ### Auto-close stale PRs [Section titled “Auto-close stale PRs”](#auto-close-stale-prs) Decline PRs not updated in 30 days: ```bash #!/bin/bash set -euo pipefail WORKSPACE="myworkspace" REPO="myrepo" DAYS_OLD=30 cutoff=$(date -d "$DAYS_OLD days ago" -Iseconds 2>/dev/null || \ date -v-${DAYS_OLD}d -Iseconds) # macOS fallback echo "Finding PRs older than $DAYS_OLD days..." stale_prs=$(bb pr list -w "$WORKSPACE" -r "$REPO" --json --all | \ jq -r --arg cutoff "$cutoff" '.pullRequests[] | select(.updated_on < $cutoff) | .id') if [ -z "$stale_prs" ]; then echo "No stale PRs found" exit 0 fi for pr_id in $stale_prs; do echo "Declining stale PR #$pr_id..." bb pr decline "$pr_id" -w "$WORKSPACE" -r "$REPO" sleep 1 done ``` # Changelog > What's new in Bitbucket CLI — curated highlights from recent releases. A curated summary of recent releases. The full, machine-generated changelog lives in the [GitHub repository](https://github.com/0pilatos0/bitbucket-cli/blob/main/CHANGELOG.md) and is updated on every release. Tip Hide the in-CLI update nudge with `bb config set skipVersionCheck true`. See [Configuration File](/reference/configuration/) for related settings. ## Unreleased — Typo suggestions and remediation hints [Section titled “Unreleased — Typo suggestions and remediation hints”](#unreleased--typo-suggestions-and-remediation-hints) * **“Did you mean …?”** on a mistyped command or enum value. Unknown top-level commands (`bb prr` → `(Did you mean pr?)`), every `must be one of` option (`--state`, `--kind`, `--priority`, `--sort`, `--status`, `--role`, `--strategy`, `--color`), `bb config get|set <key>`, each bad token in `bb pr activity --type`, and both HTTP-method forms of `bb api`. Matching folds case, and a value that is right apart from its case gets its own message: `(Values are case-sensitive — use OPEN.)` * **Remediation hints** on `401`, `403` and `404` failures — one actionable line pointing at `bb auth login`, at [Token Scopes](/reference/token-scopes/), or at the id/slug and `--workspace`/`--repo` you passed. Under `--json` the text arrives as a new optional top-level `hint` field; existing envelope keys are unchanged. The `404` hint is suppressed where the message already names the missing resource and for `bb api`, where you supplied the URL. * **`bb help <command>`** now works (`bb help pr`, `bb help pr comments`); it previously failed with `too many arguments`. * **`bb --json pr list`** now explains that `--json` swallowed `pr` as its field list and shows the correct flag position. * **Behavior change:** `bb pr diff --color <when>` validates its value. A typo such as `--color alwyas` used to silently disable color and exit `0`; it now fails with the valid values and a suggestion. Known limitation: `bb --json <typo>` with nothing following still prints root help and exits `0` — it is indistinguishable from a genuine field list. ## 1.22.0 — Pull request comment threads [Section titled “1.22.0 — Pull request comment threads”](#1220--pull-request-comment-threads) Four new `bb pr comments` subcommands complete the surface, and `list` can now filter by resolution state. * **`bb pr comments view <pr-id> <comment-id>`** shows one comment with its author, date, state (`[resolved]`/`[unresolved]`/`[pending]`) and raw content. * **`bb pr comments reply <pr-id> <comment-id> <message>`** posts a threaded reply attached to the parent comment. * **`bb pr comments resolve` / `unresolve <pr-id> <comment-id>`** close and reopen a thread. Bitbucket returns only a resolution record for `resolve` and no body for `unresolve`, so their `--json` payloads carry identifiers rather than the full comment — read it back with `bb pr comments view`. * **`bb pr comments list`** gained a `Status` column (`resolved`, `pending`, or `open`) plus `--resolved` / `--unresolved` filters. The active filter is echoed under `filters.resolution` in `--json`. ```bash bb pr comments list 42 --unresolved bb pr comments reply 42 987654 "Fixed in the follow-up commit." bb pr comments resolve 42 987654 ``` **Bug fixes:** `bb pr comments edit` and `reply` no longer fail with `Bad request` — the update payload was sending a `type` key the endpoint rejects. `bb pr comments resolve` now sends an empty JSON body, which that endpoint requires. API errors also carry Bitbucket’s `error.fields` detail now, so a rejected payload reports `Bad request (type: extra keys not allowed)` instead of a bare `Bad request`. See the [PR comments reference](/commands/pr/comments/) for the full flag list. ## 1.21.0 — Six new command groups [Section titled “1.21.0 — Six new command groups”](#1210--six-new-command-groups) **Commit & status** — `bb commit list` and `bb commit view <sha>` show commit history and details. `bb status list <sha>` lists build statuses for a commit; `bb status set <sha> --key <key> --state <state>` creates or updates a build status idempotently (CI re-runs can safely re-report the same key). **Issues** — `bb issue list`, `view`, `create`, `edit`, `close`, and `comment` mirror `gh issue` ergonomics. Filters include `--state`, `--kind`, `--assignee`, `--reporter`, and a raw `--query` escape hatch. Disabled issue trackers surface a clear 404 pointing to Repository settings. **Pipelines** — `bb pipeline list` (filter by `--status`/`--branch`, paginated), `bb pipeline view <id>` (details + per-step summary), `bb pipeline run` (trigger on branch, with `--commit`, custom `--pipeline`, and `--var key=value`), `bb pipeline stop <id>`, and `bb pipeline logs <id>` (`--step` by UUID or index). Pipeline IDs accept build numbers or UUIDs everywhere. **Workspace & project** — `bb workspace list` shows every workspace you can access (filter by `--role`); `bb workspace view [slug]` shows details. `bb project list`, `bb project view <key>`, and `bb project create --key <KEY> --name <name>` handle project discovery and creation. All six groups emit stable `--json` envelopes and integrate with repo-scoped context resolution. **Infrastructure** — Read requests now retry up to 3 times with exponential backoff on transient network failures (GET/HEAD/OPTIONS only). Concurrent OAuth token refreshes are serialized behind an in-flight lock so parallel requests share a single refresh. Shell completion is now derived from the live command tree and includes flag-value completion for enum options (e.g. `bb pr merge --strategy <Tab>` suggests valid strategies). ## 1.20.0 — `bb api` [Section titled “1.20.0 — bb api”](#1200--bb-api) A raw, authenticated passthrough to **any** Bitbucket Cloud 2.0 API endpoint — the escape hatch for anything not yet wrapped by a typed command. Mirrors `gh api`, reusing the same authenticated stack (auth, OAuth refresh, retry, secret redaction). * `bb api [method] <endpoint>` — method may be a leading verb (`bb api GET /user`) or path-only (`bb api /user`); defaults to `GET`, or `POST` when fields/body are present. * `-f/--raw-field` (string) and `-F/--field` (typed: `true`/`false`/`null`, numbers, `@file`, `@-` stdin). On `GET`/`HEAD` fields become query params, otherwise a JSON body. * `--input` sends a raw body from a file or stdin; `-H/--header` adds headers; `-i/--include` prints the status line and response headers. * `--paginate` follows the `next` cursor and merges every page’s `values`. * `{workspace}`/`{repo}` placeholders are filled from `--workspace`/`--repo` or the current repo; `--json`/`--jq` filter the response (`--jq` works without `--json` here). Absolute URLs are restricted to `api.bitbucket.org`. ```bash bb api /user # current user bb api /repositories/{workspace}/{repo}/pullrequests --paginate bb api POST /repositories/my-ws/my-repo/issues -f title=Bug -F priority=3 bb api /repositories/my-ws --jq '.values[].name' # filter with jq ``` See the [API command reference](/commands/api/) for the full flag list and examples. Patch releases in 1.20 added configurable request timeouts (`BB_HTTP_TIMEOUT`), `--with-token` for piping secrets via stdin, and fixes for `--jq` shell completion. A drift-guard test now fails CI when the completion tables fall out of sync with the live command tree. ## 1.19.0 — `BB_WORKSPACE` [Section titled “1.19.0 — BB\_WORKSPACE”](#1190--bb_workspace) * **`BB_WORKSPACE`** is now actually read. It slots into workspace resolution between git context and the config file, so the full order is `--workspace` → git remote → `BB_WORKSPACE` → `config.defaultWorkspace`. Previously the variable was advertised in `.env.example` but consulted nowhere. * New [Global Flags](/reference/global-flags/) reference page consolidating every flag that works on every command. * The environment-variable reference gained rows for `BB_WORKSPACE`, `BB_LOCALE`, and `BB_NO_UNICODE`, and clarified that `DEBUG` must be the literal string `true`. ## 1.18.0 — Pagination hints and `--all` [Section titled “1.18.0 — Pagination hints and --all”](#1180--pagination-hints-and---all) List commands now make truncation visible and let you opt out of pagination in one flag. * **`--all`** fetches every page and overrides `--limit`. Available on every `list`-style command. * When `--limit` truncates a list, a dim footer prints `Showing 25 repositories. Use --limit <n> or --all to see more.` — no more silently-clipped output. The hint is suppressed in `--json` mode. * **Bug fix:** table cells containing newlines, carriage returns, or tabs (e.g. a repo description with a line break) are now collapsed to a single space so rows stay aligned. Multi-line `text()` output is unaffected. See [Global Flags → `--all`](/reference/global-flags/#--all) for the current list of supported commands. ## 1.17.0 — Locale, Unicode toggle, spinner, global `--no-truncate` [Section titled “1.17.0 — Locale, Unicode toggle, spinner, global --no-truncate”](#1170--locale-unicode-toggle-spinner-global---no-truncate) * **Locale-aware dates** via `--locale <tag>` and `BB_LOCALE`. Resolution walks `--locale` → `BB_LOCALE` → `LC_TIME` → `LC_ALL` → `LANG` → `en-US`. * **`--no-unicode` / `BB_NO_UNICODE`** swap separators, arrows, and status icons for ASCII fallbacks. Useful for older terminals, constrained CI, or fonts that render the glyphs as tofu boxes. Mirrors `gh`’s `GH_NO_UNICODE`. * **Global `--no-truncate`** disables column truncation across every list command. The old command-local flag on `bb pr comments list` is now subsumed and no longer needs to be passed separately. * **Spinners** for long-running operations — `bb pr create`, `bb pr merge`, `bb repo clone`. Auto-disabled in JSON mode, non-TTY streams, and tests, so scripts are unaffected. ## 1.16.0 — `bb browse` [Section titled “1.16.0 — bb browse”](#1160--bb-browse) Open Bitbucket Cloud web pages — repo home, files, branches, commits, pull requests, pipelines, settings — directly from the terminal. Mirrors `gh browse`. * Smart positional resolution: `bb browse 217` opens PR #217, `bb browse abc1234` opens a commit, `bb browse src/cli.ts:42` opens a file at a line on the current branch. * Resource flags for every top-level repo page: `--pr`, `--prs`, `--branch`, `--branches`, `--commit` (defaults to HEAD), `--commits`, `--pipelines`, `--pipeline`, `--downloads`, `--issue`, `--issues`, `--wiki`, `--settings`. * `--no-browser` prints the URL to stdout; `--json url` emits `{ "url": "..." }` for scripting. ```bash bb browse # repo home bb browse src/cli.ts:42 # file at a line on the current branch bb browse --branch release/2.0 # branch tree bb browse 217 # PR #217 bb browse --pipelines # pipelines tab bb browse --pr 217 --json url # capture the URL for a script ``` See the [Browse command reference](/commands/browse/) for the full flag list and examples. Patch releases in the 1.16 line tightened help text, made the API client’s retry messages route through the output service (silenced in `--json` mode), and standardised the `--yes` confirmation gate across destructive commands: without `-y/--yes` they now fail uniformly with `Use --yes to confirm.` rather than prompting. ## 1.15.0 — Output consistency [Section titled “1.15.0 — Output consistency”](#1150--output-consistency) * Empty-result messages on list commands use a consistent `ℹ` info icon. * Dividers across framed output (`pr view`, `pr checks`, `snippet view`, the version-update banner) share a single helper, so they all render at the same width and colour. ## 1.14.0 — `--json <fields>` projection and `--jq <expression>` [Section titled “1.14.0 — --json \<fields> projection and --jq \<expression>”](#1140----json-fields-projection-and---jq-expression) Match the `gh` CLI’s JSON formatting flags so muscle memory and scripts port over cleanly. * `--json [fields]` accepts an optional comma-separated field list (e.g. `--json id,title,author.display_name`). Bare `--json` keeps the existing full-object output for backwards compatibility. * `--jq <expression>` runs the JSON output through an embedded [`jq-wasm`](https://www.npmjs.com/package/jq-wasm) engine. Requires `--json`. * Field projection drops the wrapper around list-style results (e.g. `pullRequests`, `repositories`, `snippets`) and projects per-item, matching `gh` semantics. * Dotted paths (`author.display_name`) traverse nested objects. * Invalid jq expressions exit non-zero with the underlying jq error. ```bash bb pr list --json id,title,state bb pr list --json author --jq '.[].author.display_name' bb pr list --json id,title,state --jq '.[] | select(.state == "OPEN") | .title' ``` See the [Scripting & Automation guide](/guides/scripting/) for end-to-end examples. ## 1.13.x — Stability and CI hardening [Section titled “1.13.x — Stability and CI hardening”](#113x--stability-and-ci-hardening) * **CI runs the full test + build matrix on Ubuntu, macOS, and Windows.** Bun and every GitHub Action are pinned to explicit versions/SHAs, and the release pipeline no longer tags or publishes until lint, format, and tests all pass. * **`--limit 0` now errors** instead of silently returning no results. `parseLimit` rejects any non-positive or non-finite value with a `VALIDATION_INVALID` `BBError`. * **Generated API client refreshed** from the latest Bitbucket Cloud OpenAPI spec, with a post-generation patch that dedupes duplicate enum declarations and corrects `PipelineSelector.type` optionality. ## 1.13.0 — Default reviewers [Section titled “1.13.0 — Default reviewers”](#1130--default-reviewers) * **`bb repo default-reviewers`** lets you inspect and manage the default reviewers configured on a repository, the same list Bitbucket suggests when someone opens a PR through the web UI. * **`bb pr create`** picks up those default reviewers automatically when the `prCreateIncludeDefaultReviewers` config key is enabled. See [`bb pr create`](/commands/pr/create-and-edit/) for the full flow. ## Older releases [Section titled “Older releases”](#older-releases) For releases prior to 1.13.0 — and the complete per-PR commit log — see the [full CHANGELOG on GitHub](https://github.com/0pilatos0/bitbucket-cli/blob/main/CHANGELOG.md). # FAQ - Frequently Asked Questions About Bitbucket CLI > Find answers to common questions about Bitbucket CLI. Compare with GitHub CLI, learn about supported features, authentication, troubleshooting, and best practices. ## General [Section titled “General”](#general) ### Is this an official Atlassian/Bitbucket tool? [Section titled “Is this an official Atlassian/Bitbucket tool?”](#is-this-an-official-atlassianbitbucket-tool) No. This is an **unofficial**, community-maintained CLI tool. It is not affiliated with or endorsed by Atlassian or Bitbucket. The project is open source and maintained by volunteers. *** ### How does this compare to GitHub CLI (gh)? [Section titled “How does this compare to GitHub CLI (gh)?”](#how-does-this-compare-to-github-cli-gh) `bb` follows `gh`’s command shapes for Bitbucket Cloud. It covers authentication, repositories, pull requests, issues, pipelines, commits and build statuses, snippets, workspaces and projects, browsing, configuration, and shell completion. Anything without a typed command — branch permissions, webhooks — is reachable through `bb api`, the analog of `gh api`. *** ### What Bitbucket features are supported? [Section titled “What Bitbucket features are supported?”](#what-bitbucket-features-are-supported) * **Authentication** - Login, logout, status, token display * **Repositories** - Clone, create, list, view, delete, default reviewers (list/add/remove) * **Pull requests** - Create (with optional default-reviewer attachment), list, view, edit, merge, approve, decline, ready (mark draft ready), checkout, diff, activity log, CI/CD checks, comments (list/add/edit/delete/view/reply/resolve/unresolve, with `--resolved`/`--unresolved` filters on list), reviewers (list/add/remove) * **Issues** - List, view, create, edit, close, comment * **Pipelines** - List, view, run (with `--var key=value`), stop, logs (`--step`) * **Commits & build statuses** - `bb commit list/view`, `bb status list/set` * **Workspaces & projects** - `bb workspace list/view`, `bb project list/view/create` * **Snippets** - List, view (with file contents), create, edit (metadata or file upload), delete, watch/unwatch, comments (list/add/edit/delete) * **Browse** - Open repository pages, PRs, files, commits, and pipelines in the browser * **Configuration** - Get, set, list settings * **Shell completion** - Bash, Zsh, Fish * **Raw API access** - `bb api` passthrough to any Bitbucket Cloud 2.0 endpoint No typed command yet — use `bb api`: * Branch permissions * Webhooks *** ### Does this work with Bitbucket Server/Data Center? [Section titled “Does this work with Bitbucket Server/Data Center?”](#does-this-work-with-bitbucket-serverdata-center) No. The CLI supports **Bitbucket Cloud** only. Bitbucket Server (self-hosted) uses a different API. If you need Bitbucket Server support, [open an issue](https://github.com/0pilatos0/bitbucket-cli/issues). *** ## Authentication [Section titled “Authentication”](#authentication) ### Where are my credentials stored? [Section titled “Where are my credentials stored?”](#where-are-my-credentials-stored) Credentials are stored in a local configuration file: | Platform | Location | | ----------- | -------------------------- | | macOS/Linux | `~/.config/bb/config.json` | | Windows | `%APPDATA%\bb\config.json` | The file is created with restricted permissions (owner read/write only on Unix systems). Caution Never share this file or commit it to version control. *** ### Can I use app passwords? [Section titled “Can I use app passwords?”](#can-i-use-app-passwords) **No, app passwords are deprecated.** Atlassian no longer allows creating new app passwords, and existing ones are being phased out — see the [official deprecation notice](https://bitbucket.org/blog/deprecating-app-passwords) for current timelines. Use **OAuth** (recommended) or **API tokens** instead: ```bash # OAuth (recommended — opens browser) bb auth login # API token bb auth login -u your-username -p your-api-token ``` *** ### How do I use multiple Bitbucket accounts? [Section titled “How do I use multiple Bitbucket accounts?”](#how-do-i-use-multiple-bitbucket-accounts) One config file, one active account. Switch by logging in again: ```bash # Switch to account A export BB_USERNAME=account-a export BB_API_TOKEN=token-a bb auth login # Later, switch to account B export BB_USERNAME=account-b export BB_API_TOKEN=token-b bb auth login ``` Each login overwrites the credentials in the config file, so parallel shells cannot hold different accounts. *** ### What scopes does my token need? [Section titled “What scopes does my token need?”](#what-scopes-does-my-token-need) **OAuth login requests one fixed set:** `account`, `repository`, `repository:admin`, `pullrequest`, `pullrequest:write`. You cannot change it. That covers auth, repositories, and pull requests, but **not** `bb repo delete`, `bb pipeline *`, `bb issue *`, `bb snippet *`, or `bb project *` — for those, log in with an API token carrying the scopes below. **API token scopes:** | Scope | Required for | | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------- | | `read:user:bitbucket` | `bb auth status`, plus the user lookups in `bb pr list --mine`, `bb pr create --reviewer`, and `bb pr reviewers add/remove` | | `read:repository:bitbucket` | `bb repo list`, `bb repo view`, `bb commit list/view`, `bb status list` | | `write:repository:bitbucket` | `bb status set` | | `admin:repository:bitbucket` | `bb repo create`, `bb repo default-reviewers add/remove` | | `delete:repository:bitbucket` | `bb repo delete` | | `read:pullrequest:bitbucket` | `bb pr list`, `bb pr view`, `bb repo default-reviewers list`, all `bb pr comments` subcommands | | `write:pullrequest:bitbucket` | `bb pr create`, `bb pr edit`, `bb pr merge`, `bb pr approve`, `bb pr decline`, `bb pr ready`, `bb pr reviewers add/remove` | | `read:pipeline:bitbucket` | `bb pipeline list/view/logs` | | `write:pipeline:bitbucket` | `bb pipeline run`, `bb pipeline stop` | | `read:issue:bitbucket` | `bb issue list`, `bb issue view` | | `write:issue:bitbucket` | `bb issue create/edit/close/comment` | | `read:snippet:bitbucket` | `bb snippet list`, `bb snippet view`, all `bb snippet comments` subcommands | | `write:snippet:bitbucket` | `bb snippet create/edit/watch/unwatch` | | `delete:snippet:bitbucket` | `bb snippet delete` | | `read:project:bitbucket` | `bb project list`, `bb project view` | | `admin:project:bitbucket` | `bb project create` | | `read:workspace:bitbucket` | `bb workspace list`, `bb workspace view` | See [Token Scopes](/reference/token-scopes/) for the per-command breakdown. *** ## Commands [Section titled “Commands”](#commands) ### How do I avoid typing workspace/repo every time? [Section titled “How do I avoid typing workspace/repo every time?”](#how-do-i-avoid-typing-workspacerepo-every-time) Don’t know your workspace slug? Run `bb workspace list`. **Option 1:** Set a default ```bash bb config set defaultWorkspace myworkspace ``` **Option 2:** Work from a cloned repository ```bash cd /path/to/myrepo bb pr list # workspace and repo come from the git remote ``` **Option 3:** Export `BB_WORKSPACE` for a shell session ```bash export BB_WORKSPACE=myworkspace ``` Precedence: `-w/--workspace` beats the git remote, which beats `BB_WORKSPACE`, which beats `defaultWorkspace`. See [Repository Context](/guides/repository-context/) for details. *** ### Does bb support interactive mode? [Section titled “Does bb support interactive mode?”](#does-bb-support-interactive-mode) Only `bb completion install`, which asks which shell you use. Every other command takes flags and arguments. `bb auth login` is browser-interactive but never prompts in the terminal — it opens your browser and waits up to 5 minutes for the callback on `http://localhost:19872/callback`. Destructive commands don’t prompt either. Without `-y/--yes` they fail with `Use --yes to confirm.`: ```bash bb repo delete myworkspace/old-repo --yes ``` That gate applies to `bb repo delete`, `bb repo default-reviewers remove`, `bb pr comments delete`, `bb snippet delete`, and `bb snippet comments delete`. *** ### Can I create a PR from uncommitted changes? [Section titled “Can I create a PR from uncommitted changes?”](#can-i-create-a-pr-from-uncommitted-changes) No. You must: 1. Commit your changes 2. Push to a remote branch 3. Then create the PR ```bash git add . git commit -m "My changes" git push -u origin my-branch bb pr create -t "My PR" ``` *** ### How do I see what’s in a PR before checking it out? [Section titled “How do I see what’s in a PR before checking it out?”](#how-do-i-see-whats-in-a-pr-before-checking-it-out) Use `bb pr diff`: ```bash # View changes bb pr diff 42 # Just see changed files bb pr diff 42 --name-only # See statistics bb pr diff 42 --stat ``` *** ## Integration [Section titled “Integration”](#integration) ### Can I use bb in CI/CD pipelines? [Section titled “Can I use bb in CI/CD pipelines?”](#can-i-use-bb-in-cicd-pipelines) Yes. See the [CI/CD Integration Guide](/guides/cicd/) for complete examples. Quick setup: 1. Store credentials as CI/CD secrets 2. Set `BB_USERNAME` and `BB_API_TOKEN` 3. Install the CLI and run `bb auth login` — those two variables are read only at login time, so every job needs the login step before any other command *** ### How do I pipe output to other commands? [Section titled “How do I pipe output to other commands?”](#how-do-i-pipe-output-to-other-commands) `--json` emits machine-readable JSON. `--jq <expression>` filters it with an embedded jq, so no external `jq` binary is needed and it behaves the same on Windows. ```bash # PR titles bb pr list --json --jq '.pullRequests[].title' # PR count bb pr list --json --jq '.count' # Filter by author bb pr list --json --jq '.pullRequests[] | select((.author.nickname // .author.display_name) == "alice")' ``` `--jq` requires `--json`. Field projection runs before jq and drops the envelope, so `--json id,title` hands jq a bare array: ```bash bb pr list --json id,title --jq '.[] | .title' ``` List commands return 25 items by default. Pass `--limit <n>` for a different cap, or `--all` to fetch every page (`--all` overrides `--limit`). *** ### Can I use bb with git hooks? [Section titled “Can I use bb with git hooks?”](#can-i-use-bb-with-git-hooks) Yes. Example pre-push hook that warns when a PR already exists: .git/hooks/pre-push ```bash #!/bin/bash branch=$(git branch --show-current) prs=$(bb pr list --json --jq "[.pullRequests[] | select(.source.branch.name == \"$branch\")] | length" 2>/dev/null) if [ "$prs" -gt 0 ]; then echo "Note: PR already exists for branch $branch" fi ``` The branch name is interpolated by the shell, not read from the environment: the embedded jq runs in a sandbox where `env` and `$ENV` do not see your shell variables. *** ## Contributing [Section titled “Contributing”](#contributing) ### How can I contribute? [Section titled “How can I contribute?”](#how-can-i-contribute) See [CONTRIBUTING.md](https://github.com/0pilatos0/bitbucket-cli/blob/main/CONTRIBUTING.md) for: * Development setup * Code style guidelines * Pull request process * Changeset requirements *** ### How do I report bugs? [Section titled “How do I report bugs?”](#how-do-i-report-bugs) 1. Check [existing issues](https://github.com/0pilatos0/bitbucket-cli/issues) 2. If not already reported, [open a new issue](https://github.com/0pilatos0/bitbucket-cli/issues/new) 3. Include: * CLI version (`bb --version`) * Operating system * Complete error message * Steps to reproduce *** ### How do I request features? [Section titled “How do I request features?”](#how-do-i-request-features) [Open an issue](https://github.com/0pilatos0/bitbucket-cli/issues/new) with: * Clear description of the feature * Use case / why it’s needed * Examples of how it would work *** ## Update notifications [Section titled “Update notifications”](#update-notifications) ### How do I disable update notifications? [Section titled “How do I disable update notifications?”](#how-do-i-disable-update-notifications) ```bash bb config set skipVersionCheck true ``` The CLI checks for a newer published version after every command, then prints a one-time banner to stderr. The banner is suppressed in `--json` mode, when stderr is not a TTY, and in CI. ### How often does the CLI check for updates? [Section titled “How often does the CLI check for updates?”](#how-often-does-the-cli-check-for-updates) By default, the CLI checks once per day (24 hours). You can change this interval: ```bash # Check weekly bb config set versionCheckInterval 7 # Check every 3 days bb config set versionCheckInterval 3 ``` The value is in days. `versionCheckInterval` must be a positive integer (`>= 1`). `skipVersionCheck` only accepts `true` or `false`. Both settings are stored as typed JSON values, so JSON output returns: ```json { "key": "skipVersionCheck", "value": true } ``` ### Will update checks slow down the CLI? [Section titled “Will update checks slow down the CLI?”](#will-update-checks-slow-down-the-cli) No. The check is: * Performed after the command’s own output, on stderr * Cached for 24 hours (or your configured interval) * Skipped entirely in CI environments * Suppressed in `--json` mode and when stderr is not a TTY, so piped output stays clean * Swallowed silently when the npm registry is unreachable ### Does the CLI auto-update? [Section titled “Does the CLI auto-update?”](#does-the-cli-auto-update) No. The CLI only notifies you that an update is available. You must manually update: ```bash bun install -g @pilatos/bitbucket-cli ``` # Troubleshooting > Common issues and their solutions Find your error message below. Errors go to stderr and exit 1, with a `✗` prefix (`ERR` under `--no-unicode` or `BB_NO_UNICODE`). Under `--json` a failure becomes a single-line JSON object on stderr instead. Errors raised before the command runs — unknown command, unknown option — stay plain text with an `error:` prefix either way. ## Authentication [Section titled “Authentication”](#authentication) ### Authentication required [Section titled “Authentication required”](#authentication-required) ```text ✗ Authentication required. Run 'bb auth login' or set BB_USERNAME and BB_API_TOKEN. ``` No credentials are stored — you have not logged in, or `bb auth logout` cleared them. ```bash bb auth login ``` *** ### OAuth token expired [Section titled “OAuth token expired”](#oauth-token-expired) ```text ✗ OAuth token expired. Run 'bb auth login' to re-authenticate. ``` The refresh token was revoked or expired, or the OAuth consumer was deleted. ```bash bb auth logout bb auth login ``` *** ### Invalid username or token [Section titled “Invalid username or token”](#invalid-username-or-token) `bb auth login` reports a rejected API token like this: ```text ✗ Invalid username or token: Unauthorized. Verify your Bitbucket username and that the API token is current and has the required scopes. ``` On any other command a 401 shows Bitbucket’s own message plus a dimmed remediation line: ```text ✗ Unauthorized Your Bitbucket credentials were rejected. Run `bb auth login` to re-authenticate. ``` If you authenticated with OAuth, re-authenticate: ```bash bb auth logout bb auth login ``` If you use an API token, mint a fresh one at [Bitbucket API Tokens](https://bitbucket.org/account/settings/api-tokens/) — scopes cannot be added to an existing token — then log in again, keeping the token out of shell history: ```bash echo "$BB_API_TOKEN" | bb auth login -u myuser --with-token ``` *** ### `bb auth login` never opens a browser [Section titled “bb auth login never opens a browser”](#bb-auth-login-never-opens-a-browser) The most common cause is environmental, not network: * **`BB_API_TOKEN` is exported in your shell.** Its mere presence — even set to an empty string — selects API-token auth and skips OAuth entirely. Run `unset BB_API_TOKEN` and retry. (`-u`, `-p`, `--app-password`, and `--with-token` select the same path, deliberately.) * SSH session, headless machine, or WSL without browser integration. * No default browser configured. When the browser cannot be opened, `bb` prints the authorization URL to stderr — copy it into any browser and the flow completes normally. Or skip OAuth: ```bash bb auth login -u myuser -p your-api-token ``` *** ### Port 19872 is already in use [Section titled “Port 19872 is already in use”](#port-19872-is-already-in-use) ```text ✗ Port 19872 is already in use. Close the application using it and try again. ``` The OAuth callback server binds `127.0.0.1:19872` and waits up to 5 minutes. ```bash lsof -i :19872 # macOS/Linux ``` Close the other `bb auth login` (or whatever holds the port) and retry. *** ### Token works in the browser but not in the CLI [Section titled “Token works in the browser but not in the CLI”](#token-works-in-the-browser-but-not-in-the-cli) 1. Confirm it is an **API token**, minted at [Bitbucket API Tokens](https://bitbucket.org/account/settings/api-tokens/). App passwords live at a different URL and are deprecated. 2. Check the scopes cover what you are running — see [Token Scopes](/reference/token-scopes/). A missing scope surfaces as a 403 with the hint `Your token may be missing a required scope.` 3. Strip whitespace when pasting: ```bash # Good - token only bb auth login -u myuser -p ATBB_xxxxx # Bad - leading space inside the quotes bb auth login -u myuser -p " ATBB_xxxxx" ``` *** ### Config file has insecure permissions [Section titled “Config file has insecure permissions”](#config-file-has-insecure-permissions) ```text ✗ Config file has insecure permissions (644); expected 600. Run: chmod 600 /home/me/.config/bb/config.json ``` On macOS and Linux, `bb` refuses to read a config file or directory that is readable by group or other. This usually follows copying a config between machines or restoring a dotfiles repository. Windows skips the check. ```bash chmod 700 ~/.config/bb chmod 600 ~/.config/bb/config.json ``` A hand-edited file that no longer parses gives: ```text ✗ Config file is not valid JSON: /home/me/.config/bb/config.json. Fix the file by hand or remove it and run `bb auth login` again. ``` Both are error code 4001 (`CONFIG_READ_FAILED`). *** ## Repository context [Section titled “Repository context”](#repository-context) ### Could not determine repository [Section titled “Could not determine repository”](#could-not-determine-repository) ```text ✗ Could not determine repository. Use --workspace and --repo options, or run this command from within a Bitbucket repository. ``` Three sibling messages name the specific reason: ```text ✗ Not in a git repository. Use --workspace and --repo options, or run this command from within a Bitbucket repository. ✗ Git repository has no remote configured. Add a Bitbucket remote with `git remote add origin <url>`, or use --workspace and --repo options, or run this command from within a Bitbucket repository. ✗ Remote 'git@github.com:me/thing.git' is not a Bitbucket URL. Use --workspace and --repo options, or run this command from within a Bitbucket repository. ``` All four are code 6001 (`CONTEXT_REPO_NOT_FOUND`). Pick whichever fix suits: ```bash bb pr list -w myworkspace -r myrepo # explicit flags bb config set defaultWorkspace myworkspace cd /path/to/cloned-bitbucket-repo && bb pr list ``` See [Repository Context](/guides/repository-context/) for the full precedence rules. *** ### Repository or resource not found [Section titled “Repository or resource not found”](#repository-or-resource-not-found) Commands that know what they were looking for name it, and stop there: ```text ✗ Repository my-ws/typo not found. ✗ Pull request #999 not found in my-ws/my-repo. ``` Everywhere else a 404 surfaces Bitbucket’s own message with a dimmed remediation line appended — see [Failures that tell you the next step](#failures-that-tell-you-the-next-step). In `--json` mode that line arrives as a top-level `hint` string on the error envelope. Usual causes: a typo in the workspace or repository slug, a repository you have no access to, or one that was renamed. To check what you can actually see: ```bash bb workspace list bb repo list -w myworkspace ``` *** ## Network [Section titled “Network”](#network) ### Cannot reach Bitbucket [Section titled “Cannot reach Bitbucket”](#cannot-reach-bitbucket) ```text ✗ Network error: Unable to reach Bitbucket API. Run with DEBUG=true for details. If you're behind a proxy or using a custom CA, check your environment. ``` ```bash curl -I https://api.bitbucket.org # connectivity export HTTPS_PROXY=http://proxy.example.com:8080 DEBUG=true bb repo list # [HTTP] tracing on stdout, secrets redacted ``` Bitbucket’s own availability is at [status.bitbucket.org](https://status.bitbucket.org). *** ### Request timed out [Section titled “Request timed out”](#request-timed-out) ```text ✗ Network error: Request to Bitbucket API timed out after 30000ms. The server accepted the connection but did not respond in time. Increase or disable the timeout via BB_HTTP_TIMEOUT (milliseconds; set BB_HTTP_TIMEOUT=0 to disable), or run with DEBUG=true for details. ``` The per-request timeout defaults to 30000 ms. ```bash BB_HTTP_TIMEOUT=60000 bb pr list # 60 seconds BB_HTTP_TIMEOUT=0 bb pr list # no timeout ``` *** ### Rate limiting [Section titled “Rate limiting”](#rate-limiting) A 429 is retried automatically. In human mode you see the attempts on stderr: ```text ⚠ Rate limited, retrying in 1.0s (attempt 1/3)... ``` Retries cover HTTP 429, 502, 503, and 504, up to 3 attempts. On a 429 the `Retry-After` header sets the delay when Bitbucket sends one; otherwise the delay is exponential backoff from 1s. Transient network failures on GET, HEAD, and OPTIONS share the same 3-attempt budget. Once it is exhausted, the command fails with Bitbucket’s own 429 message. The retry warning is suppressed in `--json` mode, so scripts see only the final failure. If the limit is sustained: 1. Wait a few minutes and retry. 2. Add a delay between calls in loops: ```bash for pr_id in 1 2 3 4 5; do bb pr view $pr_id sleep 1 done ``` 3. Fetch once and filter locally instead of calling per item: ```bash bb pr list --json --jq '.pullRequests[] | select((.author.nickname // .author.display_name) == "alice")' ``` *** ## Git integration [Section titled “Git integration”](#git-integration) ### Clone fails [Section titled “Clone fails”](#clone-fails) `bb repo clone` shells out to `git clone git@bitbucket.org:<workspace>/<repo>.git`, so the error text is git’s own, verbatim: ```text ✗ git@bitbucket.org: Permission denied (publickey). ``` That is an SSH problem, not a `bb auth` problem — the CLI does not pass its token to git. ```bash ssh -T git@bitbucket.org # verify your key git clone https://bitbucket.org/myworkspace/myrepo.git # HTTPS fallback ``` *** ## Command-specific issues [Section titled “Command-specific issues”](#command-specific-issues) ### Destructive commands do not prompt [Section titled “Destructive commands do not prompt”](#destructive-commands-do-not-prompt) ```text ✗ This will permanently delete myworkspace/old-repo. Use --yes to confirm. ``` The `-y, --yes` help text says “Skip confirmation prompt”, but there is no prompt — the command fails until you pass the flag. This affects `bb repo delete`, `bb repo default-reviewers remove`, `bb pr comments delete`, `bb snippet delete`, and `bb snippet comments delete`. ```bash bb repo delete myworkspace/old-repo --yes ``` *** ### Pull request creation is rejected [Section titled “Pull request creation is rejected”](#pull-request-creation-is-rejected) A missing title is caught locally, before any request: ```text ✗ Pull request title is required. Use --title option. ``` Everything else is Bitbucket’s own message, with any `error.fields` detail flattened in — for example: ```text ✗ Bad request (type: extra keys not allowed) ``` | Cause | Fix | | ----------------------------------------- | -------------------------------- | | Branch doesn’t exist on remote | `git push -u origin your-branch` | | PR already exists for branch | Check `bb pr list` | | Branch restrictions block the destination | Check repository settings | | No changes between branches | Ensure commits exist | *** ### Merge is rejected [Section titled “Merge is rejected”](#merge-is-rejected) Bitbucket returns the reason in the error message. Diagnose the rest without leaving the terminal: ```bash bb pr checks 42 # failing builds bb pr view 42 # reviewer approvals and merge state bb pr activity 42 # who requested changes ``` Common blockers are merge conflicts, unmet required approvals, and failing build checks. Fall back to the web UI only for branch-restriction rules, which the API does not expose. *** ### Diff shows nothing [Section titled “Diff shows nothing”](#diff-shows-nothing) ```bash bb pr diff 42 # (empty output) ``` The PR has no file changes, or the API returned an empty diff. ```bash bb pr view 42 # check state and branches bb pr diff 42 --web # compare against the web UI ``` *** ## Typos and “Did you mean?” [Section titled “Typos and “Did you mean?””](#typos-and-did-you-mean) `bb` suggests a correction when a command name or an option value is close to a valid one: ```bash bb prr # ✗ unknown command 'prr' # (Did you mean pr?) bb pr lst # error: unknown command 'lst' # (Did you mean list?) bb pr list --state opne # ✗ --state must be one of: OPEN, MERGED, DECLINED, SUPERSEDED # (Did you mean OPEN?) ``` Option values are matched case-sensitively, so `--state open` (lowercase against an uppercase set) tells you to fix the case rather than suggesting the same word back: ```bash bb pr list --state open # ✗ --state must be one of: OPEN, MERGED, DECLINED, SUPERSEDED # (Values are case-sensitive — use OPEN.) ``` Use `bb help <command>` (or `bb <command> --help`) to see a command’s valid values. ### `--json` must come after the subcommand [Section titled “--json must come after the subcommand”](#--json-must-come-after-the-subcommand) `--json` takes an optional field list, so it swallows the next word if you put it first: ```bash bb --json pr list ``` `--json` did parse, so the failure comes back as a JSON envelope on stderr: ```text {"name":"BBError","code":5002,"message":"--json consumed 'pr' as its field list, so 'list' was parsed as a top-level command.\nPut --json after the subcommand: bb pr list --json"} ``` `bb --json=id,title pr list` works, because the `--flag=value` form does not eat the next token. ### `--jq` needs `--json` [Section titled “--jq needs --json”](#--jq-needs---json) ```bash bb pr list --jq '.pullRequests[].title' # ✗ --jq requires --json ``` Because `--json` was never set, this failure renders as **plain text on stderr**, not as a JSON envelope — surprising in a script that only parses stdout. `bb api` is the one exception: it accepts `--jq` on its own. ```bash bb pr list --json --jq '.pullRequests[].title' # correct bb api /repositories/my-ws --jq '.values[].name' # allowed without --json ``` ### Empty `--json` field list [Section titled “Empty --json field list”](#empty---json-field-list) ```bash bb pr list --json "" ``` ```text {"name":"BBError","code":8002,"message":"--json field list cannot be empty"} ``` `--json ,,` fails the same way. Use bare `--json` for the full envelope. *** ## Failures that tell you the next step [Section titled “Failures that tell you the next step”](#failures-that-tell-you-the-next-step) `401`, `403`, and `404` failures append an actionable line beneath the error: ```bash bb repo list -w does-not-exist # ✗ No workspace with identifier 'does-not-exist'. # Verify the id or slug you passed, and that --workspace/--repo point at the right repository your token can see. ``` A `401` points you at `bb auth login`; a `403` explains that scopes can’t be added to an existing token and links [Token Scopes](/reference/token-scopes/). In `--json` mode the same text arrives as a `hint` field. See [Error codes](/reference/error-codes/) for the full list. *** ## Getting debug information [Section titled “Getting debug information”](#getting-debug-information) When reporting an issue, gather this: ```bash # CLI version bb --version # OS information uname -a # Linux/macOS systeminfo | findstr /B /C:"OS" # Windows # Bun version (required runtime) bun --version # Auth status (never prints the token; use bb auth token for that) bb auth status # Config (masks secrets) bb config list ``` `bb auth status` makes a live `GET /user` call, so it also fails when the network or proxy is the real problem. *** ## Still need help? [Section titled “Still need help?”](#still-need-help) 1. Check the [FAQ](/help/faq/) for questions that come up often 2. Search [existing issues](https://github.com/0pilatos0/bitbucket-cli/issues) 3. Open a [new issue](https://github.com/0pilatos0/bitbucket-cli/issues/new) with: * CLI version (`bb --version`) * Operating system * Complete error message * Steps to reproduce # Recipes > Cookbook of common Bitbucket CLI workflows — auto-merge, bulk reviewer assignment, fork sync, jq analytics, and retry wrappers. Ready-to-copy workflows that combine `bb` with `jq` and shell. Each recipe is a complete, runnable script — drop it into a CI job or a dotfile and adjust the workspace and repository names. For the *primitives* these recipes are built on, see the [Scripting & Automation guide](/guides/scripting/) and the [CI/CD Integration guide](/guides/cicd/). ## Available recipes [Section titled “Available recipes”](#available-recipes) [Auto-merge when CI is green](/recipes/auto-merge-on-ci-green/)Poll bb pr checks until all checks pass, then merge — the GitOps-friendly way. [Bulk reviewer assignment](/recipes/bulk-reviewer-assignment/)Assign a fixed list of reviewers across many open pull requests (team rotations, onboarding). [Fork synchronization](/recipes/fork-synchronization/)Fetch upstream, rebase your fork, and push the result for fork-based contribution flows. [Reporting & analytics with jq](/recipes/reporting-analytics/)Count PRs per state, sum diff sizes, group by author, and export to CSV. [Retry wrapper for transient failures](/recipes/retry-wrapper/)A shell wrapper that retries bb invocations with exponential backoff for persistent flakes. ## Conventions used in these recipes [Section titled “Conventions used in these recipes”](#conventions-used-in-these-recipes) * All recipes assume `bb auth login` has already succeeded — interactively, or via the `BB_USERNAME` and `BB_API_TOKEN` env vars. * `WORKSPACE` and `REPO` are read from the environment with a `${VAR:-default}` fallback. Export them in CI, or edit the defaults at the top of the script. * List commands default to `--limit 25`. Pass `--all` wherever a recipe has to see every result — the `Showing 25 pull requests. Use --limit <n> or --all to see more.` hint is printed with table output only, never under `--json`. * The CLI already retries HTTP 429, 502, 503 and 504 up to 3 times with exponential backoff. It also retries `ECONNRESET`, `ETIMEDOUT`, `ECONNABORTED`, `EAI_AGAIN` and `EPIPE` on GET, HEAD and OPTIONS. Nothing else is retried — a 500 is not, and neither is `ENOTFOUND` or a TLS failure. The [retry wrapper recipe](/recipes/retry-wrapper/) is for failures that persist past that. * `--jq` JSON-encodes its output: strings come back with quotes around them. Pipe `--json` to external `jq -r` when you need a raw string for the shell. See the [JSON Output reference](/reference/json-output/) for the envelope structure of list-style commands. # Auto-merge when CI is green > Poll bb pr checks until all CI checks have passed, then merge the pull request — a safe, GitOps-friendly auto-merge pattern. The “merge approved PRs” pattern in the [CI/CD guide](/guides/cicd/#merge-approved-prs-automatically) only checks whether a pull request (PR) has `participants[].approved` set — it ignores the actual CI status. This recipe adds the missing piece: poll [`bb pr checks`](/commands/pr/activity-and-checks/#bb-pr-checks) until every status is `SUCCESSFUL`, then merge. ## What “all-green” means [Section titled “What “all-green” means”](#what-all-green-means) `bb pr checks <id> --json` returns this envelope — each entry in `statuses` also carries `refname`, `createdOn` and `uuid`, trimmed here: ```json { "pullRequestId": 42, "workspace": "myworkspace", "repoSlug": "myrepo", "summary": { "successful": 3, "failed": 0, "pending": 0 }, "statuses": [ { "key": "build", "name": "Build & Test", "state": "SUCCESSFUL", "description": "Build #1234 succeeded", "url": "https://ci.example.com/build/1234", "updatedOn": "2025-01-01T12:00:00Z" } ] } ``` Possible `state` values: `SUCCESSFUL`, `FAILED`, `INPROGRESS`, `STOPPED`. A PR is all-green when **at least one check exists** *and* every status is `SUCCESSFUL`. Treat zero checks as “not ready”. `summary` counts only three of those states: `successful` for `SUCCESSFUL`, `failed` for `FAILED`, `pending` for `INPROGRESS`. Anything else — `STOPPED`, or any state Bitbucket adds later — is counted in none of them, so `summary.successful + failed + pending` can be less than `statuses | length`. Gate on `successful == total`, never on `failed == 0 and pending == 0`. Caution `bb pr checks` is not paginated. It issues one request and returns whatever Bitbucket puts on the first page — there is no `--limit` or `--all`. On a PR with more build statuses than fit one page, both `summary` and `statuses` are computed over a partial set, and an auto-merge gate can fire while a check you never saw is still failing. If a repository routinely posts more than a handful of statuses per PR, read them through `bb api` instead: ```bash bb api "/repositories/$WORKSPACE/$REPO/pullrequests/42/statuses" --paginate --json \ | jq -r '(.values | length) > 0 and all(.values[]; .state == "SUCCESSFUL")' ``` ### jq filter for all-green [Section titled “jq filter for all-green”](#jq-filter-for-all-green) ```bash # Returns "true" only if ≥1 check exists and every state is SUCCESSFUL bb pr checks 42 --json --jq ' (.statuses | length) > 0 and (.statuses | all(.state == "SUCCESSFUL")) ' ``` If you want to also gate on approval: ```bash bb pr view 42 --json --jq ' [.participants[] | select(.approved == true)] | length > 0 ' ``` ## Recipe: poll-then-merge [Section titled “Recipe: poll-then-merge”](#recipe-poll-then-merge) Drop this into a scheduled CI job or run locally. It polls a single PR until checks settle, then merges. ```bash #!/bin/bash # auto-merge-on-green.sh - Wait for CI to pass, then merge. set -euo pipefail WORKSPACE="${WORKSPACE:-myworkspace}" REPO="${REPO:-myrepo}" PR_ID="${1:?Usage: $0 <pr-id>}" TIMEOUT_SECONDS="${TIMEOUT_SECONDS:-1800}" # 30 minutes POLL_INTERVAL="${POLL_INTERVAL:-30}" deadline=$(( $(date +%s) + TIMEOUT_SECONDS )) while true; do if [ "$(date +%s)" -gt "$deadline" ]; then echo "Timed out waiting for PR #$PR_ID checks" >&2 exit 1 fi checks_json=$(bb pr checks "$PR_ID" -w "$WORKSPACE" -r "$REPO" --json) failed=$(echo "$checks_json" | jq '.summary.failed') successful=$(echo "$checks_json" | jq '.summary.successful') pending=$(echo "$checks_json" | jq '.summary.pending') total=$(echo "$checks_json" | jq '.statuses | length') if [ "$failed" -gt 0 ]; then echo "PR #$PR_ID has $failed failed check(s); aborting." >&2 exit 1 fi # successful == total, not "no failures and nothing pending": a STOPPED # check lands in none of the summary buckets, so the looser test would # merge a PR whose only build was cancelled. A STOPPED check keeps this # loop polling until TIMEOUT_SECONDS, which then exits 1. if [ "$total" -gt 0 ] && [ "$successful" -eq "$total" ]; then echo "All $total checks passed for PR #$PR_ID — merging." break fi echo "PR #$PR_ID: $successful/$total passed, $pending pending — sleeping ${POLL_INTERVAL}s" sleep "$POLL_INTERVAL" done bb pr merge "$PR_ID" \ -w "$WORKSPACE" -r "$REPO" \ --strategy squash --close-source-branch ``` ### Usage [Section titled “Usage”](#usage) ```bash WORKSPACE=myworkspace REPO=myrepo ./auto-merge-on-green.sh 42 ``` ## Recipe: scan all open PRs [Section titled “Recipe: scan all open PRs”](#recipe-scan-all-open-prs) Run this on a schedule (cron, GitHub Actions cron trigger, Bitbucket Pipelines schedule). It merges every approved PR whose checks are all green and skips the rest silently. `--all` is load-bearing. `bb pr list` defaults to `--limit 25`, and the `Use --limit <n> or --all to see more.` hint is printed with table output only — under `--json` you get 25 rows and no warning, so older approved PRs would never be merged. ```bash #!/bin/bash # auto-merge-scan.sh - Merge every approved, all-green PR. set -euo pipefail WORKSPACE="${WORKSPACE:-myworkspace}" REPO="${REPO:-myrepo}" open_prs=$(bb pr list -w "$WORKSPACE" -r "$REPO" --all --json --jq '.pullRequests[].id') for pr_id in $open_prs; do approved=$(bb pr view "$pr_id" -w "$WORKSPACE" -r "$REPO" --json --jq ' [.participants[] | select(.approved == true)] | length > 0 ') [ "$approved" = "true" ] || { echo "PR #$pr_id: not approved"; continue; } green=$(bb pr checks "$pr_id" -w "$WORKSPACE" -r "$REPO" --json --jq ' (.statuses | length) > 0 and (.statuses | all(.state == "SUCCESSFUL")) ') [ "$green" = "true" ] || { echo "PR #$pr_id: checks not green"; continue; } echo "Merging PR #$pr_id" if ! bb pr merge "$pr_id" -w "$WORKSPACE" -r "$REPO" \ --strategy squash --close-source-branch; then echo "PR #$pr_id: merge failed (conflicts or branch policy)" >&2 fi sleep 2 # gentle pacing across many PRs done ``` Caution `bb pr merge` will still fail if the destination branch has *branch restrictions* (e.g., required reviewer counts, merge checks). The script above logs that and continues. Don’t treat a passing CI job and an approval as sufficient policy on their own — Bitbucket’s branch restrictions are the ultimate gate. ## Related [Section titled “Related”](#related) * [`bb pr checks`](/commands/pr/activity-and-checks/#bb-pr-checks) — the underlying command * [`bb pr merge`](/commands/pr/review-and-merge/) — merge strategies and flags * [Scripting & Automation](/guides/scripting/) — JSON output, exit codes, jq patterns # Bulk reviewer assignment > Assign a list of reviewers across many open pull requests at once — useful for team rotations, onboarding, and review coverage policies. The [Scripting guide](/guides/scripting/#example-scripts) covers batch *approval*. Assigning reviewers across many pull requests (PRs) in one pass is a separate workflow — team rotations, onboarding new reviewers, and enforcing minimum reviewer coverage on existing PRs. ## Identifying reviewers [Section titled “Identifying reviewers”](#identifying-reviewers) `bb pr reviewers add` takes an **account ID** (`712020:3cfed7e0-…`) or a **braced UUID** (`{c1cb1bb5-…}`). Bitbucket Cloud no longer resolves login names here, so a pool of `alice bob charlie` fails with a 404 on every call. See [Identifying users](/commands/pr/reviewers/#identifying-users) for how to look the IDs up once. Pick one form and use it consistently — an account ID never equals a UUID, so a pool that mixes the two breaks any comparison you do against PR author fields. ## Recipe: assign a fixed reviewer list [Section titled “Recipe: assign a fixed reviewer list”](#recipe-assign-a-fixed-reviewer-list) Adds every account ID in `REVIEWERS` to every open PR in `WORKSPACE/REPO`. Existing reviewers are not removed; if a reviewer is already assigned, [`bb pr reviewers add`](/commands/pr/reviewers/#bb-pr-reviewers-add) is a no-op. bulk-assign-reviewers.sh ```bash #!/bin/bash set -euo pipefail WORKSPACE="${WORKSPACE:-myworkspace}" REPO="${REPO:-myrepo}" # Space-separated Bitbucket account IDs (not usernames, not display names). REVIEWERS="${REVIEWERS:?set REVIEWERS to space-separated account IDs}" # Optional: skip PRs authored by a reviewer (you can't review your own PR) SKIP_SELF_REVIEW="${SKIP_SELF_REVIEW:-true}" # --all: without it, bb pr list stops at 25 and says nothing about it under --json. # External `jq -r`: the built-in --jq has no raw mode, so this filter would # return a JSON-quoted string with a two-character \t instead of a real tab. open_prs=$(bb pr list -w "$WORKSPACE" -r "$REPO" --all --json \ | jq -r '.pullRequests[] | "\(.id)\t\(.author.account_id)"') while IFS=$'\t' read -r pr_id author; do [ -n "$pr_id" ] || continue echo "PR #$pr_id (by $author)" for reviewer in $REVIEWERS; do if [ "$SKIP_SELF_REVIEW" = "true" ] && [ "$reviewer" = "$author" ]; then echo " - skip $reviewer (PR author)" continue fi if bb pr reviewers add "$pr_id" "$reviewer" \ -w "$WORKSPACE" -r "$REPO" >/dev/null 2>&1; then echo " + added $reviewer" else echo " ! failed to add $reviewer (bad account ID, or permissions)" >&2 fi sleep 1 # rate-limit cushion done done <<< "$open_prs" ``` ### Usage [Section titled “Usage”](#usage) ```bash WORKSPACE=myworkspace REPO=myrepo \ REVIEWERS="712020:3cfed7e0-0ed6-49fc-bb35-410a00ccee6f 712020:9ab1f22c-51de-4e7d-9f0e-2b7a10cd3311" \ ./bulk-assign-reviewers.sh ``` Each `bb pr reviewers add` costs three API requests: one to resolve the user, then a GET and a PUT on the pull request. At `PRs × reviewers × 3` that adds up quickly — see [Handling rate limits](#handling-rate-limits) below. ## Recipe: rotation by hash bucket [Section titled “Recipe: rotation by hash bucket”](#recipe-rotation-by-hash-bucket) To give each PR *one* reviewer from a pool — a round-robin team rotation — hash the PR ID into the pool. The assignment is stable and reproducible without a database. rotation-assign.sh ```bash #!/bin/bash set -euo pipefail WORKSPACE="${WORKSPACE:-myworkspace}" REPO="${REPO:-myrepo}" # Account IDs, same rule as above. POOL=( "712020:3cfed7e0-0ed6-49fc-bb35-410a00ccee6f" "712020:9ab1f22c-51de-4e7d-9f0e-2b7a10cd3311" "712020:c40be5aa-7c19-4a0b-83f2-6d1e94ab7702" ) open_prs=$(bb pr list -w "$WORKSPACE" -r "$REPO" --all --json --jq '.pullRequests[].id') for pr_id in $open_prs; do idx=$(( pr_id % ${#POOL[@]} )) reviewer="${POOL[$idx]}" echo "PR #$pr_id -> $reviewer" bb pr reviewers add "$pr_id" "$reviewer" -w "$WORKSPACE" -r "$REPO" || true sleep 1 done ``` ## Handling rate limits [Section titled “Handling rate limits”](#handling-rate-limits) The CLI already retries 429 responses up to 3 times automatically. For *very* large bulk operations (hundreds of PRs × multiple reviewers), prefer: 1. A larger sleep between PRs (`sleep 2` or `sleep 3`). 2. Bounding each run: swap `--all` for `--limit 50` so one pass can’t stretch for hours. There is no offset flag, so a plain re-run sees the same 50 PRs — record the IDs you have already handled and skip them next time. 3. Splitting the run across cron windows. 4. Wrapping individual `bb` calls in the [retry wrapper](/recipes/retry-wrapper/) for the rare case of *persistent* 429s. ## Related [Section titled “Related”](#related) * [`bb pr reviewers add`](/commands/pr/reviewers/#bb-pr-reviewers-add) — single-PR command this recipe wraps * [`bb repo default-reviewers`](/commands/repo/) — repo-level defaults applied at PR creation time, often a better fit if you want this on *new* PRs only * [Reviewers reference](/commands/pr/reviewers/) — full subcommand reference # Fork synchronization > Keep a forked Bitbucket repository up to date with its upstream — fetch, rebase, and push using bb and git together. Forks drift from upstream fast. This recipe uses `bb repo view` to discover the upstream clone URL and plain `git` for the fetch, rebase and push. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) * Your local clone is the **fork**, not the upstream. * `origin` points at your fork. * The upstream is reachable as a separate remote (we’ll add it if missing). * You have permission to push to your fork’s `main` (or whichever branch you want to keep in sync). ## Recipe: one-shot sync [Section titled “Recipe: one-shot sync”](#recipe-one-shot-sync) ```bash #!/bin/bash # sync-fork.sh - Keep a fork's main branch in sync with its upstream. set -euo pipefail UPSTREAM_WORKSPACE="${UPSTREAM_WORKSPACE:?set UPSTREAM_WORKSPACE}" UPSTREAM_REPO="${UPSTREAM_REPO:?set UPSTREAM_REPO}" BRANCH="${BRANCH:-main}" # 1. Look up the upstream clone URL via bb (HTTPS). # Pipe --json to external `jq -r`: the built-in --jq JSON-encodes its # output, so the URL would come back wrapped in literal double quotes. upstream_url=$(bb repo view -w "$UPSTREAM_WORKSPACE" -r "$UPSTREAM_REPO" --json \ | jq -r '.links.clone[] | select(.name == "https") | .href') if [ -z "$upstream_url" ]; then echo "Could not resolve HTTPS clone URL for $UPSTREAM_WORKSPACE/$UPSTREAM_REPO" >&2 exit 1 fi # 2. Add the upstream remote if it isn't there. if ! git remote get-url upstream >/dev/null 2>&1; then echo "Adding upstream remote: $upstream_url" git remote add upstream "$upstream_url" else git remote set-url upstream "$upstream_url" fi # 3. Fetch upstream and your fork. git fetch upstream "$BRANCH" git fetch origin "$BRANCH" # 4. Switch to the branch and rebase onto upstream. git checkout "$BRANCH" git rebase "upstream/$BRANCH" # 5. Push the rebased branch back to your fork. # Use --force-with-lease, NOT --force, so concurrent fork-side pushes aren't clobbered. git push --force-with-lease origin "$BRANCH" echo "Fork '$BRANCH' synced with upstream $UPSTREAM_WORKSPACE/$UPSTREAM_REPO" ``` ### Usage [Section titled “Usage”](#usage) ```bash UPSTREAM_WORKSPACE=acme \ UPSTREAM_REPO=widget \ BRANCH=main \ ./sync-fork.sh ``` Caution The script rebases instead of merging. If `main` on your fork has commits that aren’t on upstream, the rebase will rewrite their hashes — anyone else pulling from your fork’s `main` will see history change. Use a merge instead (`git merge upstream/$BRANCH`) if your fork shares `main` with collaborators. ## Recipe: sync, then open a pull request for a feature branch [Section titled “Recipe: sync, then open a pull request for a feature branch”](#recipe-sync-then-open-a-pull-request-for-a-feature-branch) After syncing `main`, rebase your feature branch and open a pull request (PR) back to upstream. `bb pr create` cannot do this. Its `-s`/`--source` and `-d`/`--destination` are both plain branch names resolved inside the `-w`/`-r` repository, so it has no way to name your fork as the source — pointing it at upstream either 404s or opens a same-repo PR in upstream. Use [`bb api`](/guides/scripting/#raw-api-access-escape-hatch) to POST the cross-fork body yourself. sync-and-pr.sh ```bash #!/bin/bash set -euo pipefail UPSTREAM_WORKSPACE="${UPSTREAM_WORKSPACE:?set UPSTREAM_WORKSPACE}" UPSTREAM_REPO="${UPSTREAM_REPO:?set UPSTREAM_REPO}" FORK_WORKSPACE="${FORK_WORKSPACE:?set FORK_WORKSPACE}" # your workspace FORK_REPO="${FORK_REPO:?set FORK_REPO}" # your fork's repo slug FEATURE_BRANCH="${FEATURE_BRANCH:?set FEATURE_BRANCH}" TITLE="${TITLE:-Update from $FEATURE_BRANCH}" DESTINATION="${DESTINATION:-main}" # 1. Sync main, then rebase the feature branch onto fresh main. BRANCH=main ./sync-fork.sh git checkout "$FEATURE_BRANCH" git rebase main git push --force-with-lease origin "$FEATURE_BRANCH" # 2. Open a PR in the upstream repository, sourced from the fork's branch. # Build the body with jq so a title containing quotes or backslashes # can't break the JSON. jq -n \ --arg title "$TITLE" \ --arg source "$FEATURE_BRANCH" \ --arg fork "$FORK_WORKSPACE/$FORK_REPO" \ --arg destination "$DESTINATION" \ '{ title: $title, source: { branch: { name: $source }, repository: { full_name: $fork } }, destination: { branch: { name: $destination } } }' \ | bb api POST "/repositories/$UPSTREAM_WORKSPACE/$UPSTREAM_REPO/pullrequests" --input - ``` The path is fully interpolated from shell variables, so `bb api` has no `{workspace}`/`{repo}` placeholders left to substitute. Don’t mix the two forms in one path. ### Usage [Section titled “Usage”](#usage-1) ```bash UPSTREAM_WORKSPACE=acme UPSTREAM_REPO=widget \ FORK_WORKSPACE=myuser FORK_REPO=widget \ FEATURE_BRANCH=feat/login \ TITLE="Add login button" \ ./sync-and-pr.sh ``` Cross-fork PRs require that the upstream repository accepts forks as sources and that your token can read it. If Bitbucket rejects the request, its message is printed to stderr as `✗ …` and the CLI exits `1`. Re-run with `--json` to get the same error as one compact line on stderr: ```json {"name":"APIError","code":2003,"message":"You do not have access to create a pull request","statusCode":403} ``` ## Related [Section titled “Related”](#related) * [Repository Context](/guides/repository-context/) — how `bb` resolves workspace/repo from your git remote * [`bb repo view`](/commands/repo/) — used here to fetch the upstream HTTPS clone URL * [`bb pr create`](/commands/pr/create-and-edit/) — same-repository PRs, where the source branch lives in the target repository * [Raw API access](/guides/scripting/#raw-api-access-escape-hatch) — `bb api`, used here for the cross-fork POST # Reporting & analytics with jq > Count PRs per state, sum diff sizes, group by author, and export to CSV — practical jq filters built on bb pr list --json. The [Scripting guide](/guides/scripting/#jq-patterns) lists starter jq patterns. This recipe expands them into a small analytics toolkit you can paste into a weekly report job. All recipes assume: ```bash WORKSPACE=myworkspace REPO=myrepo ``` Two things will bite you on this page if you skip them: * **`count` is what was fetched, not what exists.** `bb pr list` stops at `--limit 25` by default, so `.count` maxes out at 25 and the `Use --limit <n> or --all to see more.` hint is suppressed under `--json`. Pass `--all` whenever the number itself is the answer. * **`--jq` JSON-encodes its output.** There is no raw mode. When you need a bare string for the shell or a file, pipe `--json` into external `jq -r` instead. ## Count pull requests per state [Section titled “Count pull requests per state”](#count-pull-requests-per-state) `bb pr list` returns one state at a time, so fetch each separately and combine: ```bash for state in OPEN MERGED DECLINED SUPERSEDED; do count=$(bb pr list -w "$WORKSPACE" -r "$REPO" -s "$state" --all --json --jq '.count') printf "%-12s %s\n" "$state" "$count" done ``` Sample output: ```text OPEN 12 MERGED 340 DECLINED 8 SUPERSEDED 2 ``` The loop is not avoidable: `--state` takes one value and defaults to `OPEN`, so a single fetch can only ever contain one state and `group_by(.state)` would return one group. Grouping is still useful on other attributes of a single fetch — open PRs per target branch, for example: ```bash bb pr list -w "$WORKSPACE" -r "$REPO" --all --json --jq ' .pullRequests | group_by(.destination.branch.name) | map({ branch: .[0].destination.branch.name, count: length }) | sort_by(-.count) ' ``` ## Sum additions and deletions across PRs [Section titled “Sum additions and deletions across PRs”](#sum-additions-and-deletions-across-prs) `bb pr list` does not include diff stats. `bb pr diff <id> --stat --json` does, and it already totals them for you: ```json { "workspace": "myworkspace", "repoSlug": "myrepo", "pullRequestId": 42, "mode": "stat", "files": [{ "path": "src/auth.ts", "additions": 31, "deletions": 4 }], "filesChanged": 1, "totalAdditions": 31, "totalDeletions": 4 } ``` The totals are per PR — there is no aggregate endpoint — so the outer loop still stands. Read `totalAdditions` and `totalDeletions` rather than re-summing `.files`: ```bash #!/bin/bash total_added=0 total_deleted=0 for pr_id in $(bb pr list -w "$WORKSPACE" -r "$REPO" -s MERGED --all --json \ --jq '.pullRequests[].id'); do stats=$(bb pr diff "$pr_id" -w "$WORKSPACE" -r "$REPO" --stat --json) added=$(echo "$stats" | jq '.totalAdditions') deleted=$(echo "$stats" | jq '.totalDeletions') total_added=$(( total_added + added )) total_deleted=$(( total_deleted + deleted )) sleep 1 done echo "Total added: $total_added" echo "Total deleted: $total_deleted" ``` Tip This makes one HTTP request per PR. For a few dozen PRs it’s fine; for hundreds, schedule it overnight or scope to a date range with `--jq '... | select(.updated_on >= "2025-01-01")'` before the inner loop. That is a lexicographic string compare, which works because Bitbucket’s timestamps are zero-padded ISO 8601. ## Group by author with counts [Section titled “Group by author with counts”](#group-by-author-with-counts) ```bash bb pr list -w "$WORKSPACE" -r "$REPO" --all --json --jq ' .pullRequests | group_by(.author.nickname // .author.display_name) | map({ author: (.[0].author.nickname // .[0].author.display_name), count: length, ids: [.[].id] }) | sort_by(-.count) ' ``` This sorts authors by descending PR count and includes the IDs for drilldown. ## Top reviewers across merged PRs [Section titled “Top reviewers across merged PRs”](#top-reviewers-across-merged-prs) Useful for identifying review load. Iterates over merged PRs and counts approvals per reviewer: ```bash bb pr list -w "$WORKSPACE" -r "$REPO" -s MERGED --limit 200 --json --jq ' [ .pullRequests[].participants[] | select(.approved == true) | .user.nickname // .user.display_name ] | group_by(.) | map({ reviewer: .[0], approvals: length }) | sort_by(-.approvals) ' ``` ## CSV export [Section titled “CSV export”](#csv-export) Use jq’s `@csv` — through **external** `jq -r`, not `--jq`. `@csv` produces a jq string, and `--jq` would JSON-encode it again, wrapping every line in a second pair of quotes and backslash-escaping the inner ones. The result is not valid CSV. ```bash bb pr list -w "$WORKSPACE" -r "$REPO" --all --json | jq -r ' ["id","title","author","state","created_on","source","destination"], ( .pullRequests[] | [ .id, .title, (.author.nickname // .author.display_name), .state, .created_on, .source.branch.name, .destination.branch.name ] ) | @csv ' > prs.csv head -3 prs.csv ``` Sample output: ```text "id","title","author","state","created_on","source","destination" 42,"Add login button","alice","OPEN","2025-01-04T09:11:00.993890+00:00","feat/login","main" 43,"Fix typo in README","bob","OPEN","2025-01-04T11:22:41.118201+00:00","fix/typo","main" ``` ## PR cycle time (created → merged) [Section titled “PR cycle time (created → merged)”](#pr-cycle-time-created--merged) Bitbucket timestamps look like `2018-08-15T23:50:59.993890+00:00`. jq’s `fromdateiso8601` is `strptime("%Y-%m-%dT%H:%M:%SZ")`, which rejects both the fractional seconds and the numeric offset — feeding it a raw Bitbucket timestamp fails the whole filter with `jq evaluation failed: …` (error code `8001`), it does not just skip a row. Strip both first: ```bash bb pr list -w "$WORKSPACE" -r "$REPO" -s MERGED --limit 100 --json --jq ' def ts: sub("\\.[0-9]+"; "") | sub("\\+00:00"; "Z") | fromdateiso8601; [ .pullRequests[] | { id, title, hours: ((.updated_on | ts) - (.created_on | ts)) / 3600 } ] | sort_by(.hours) ' ``` The `sub("\\.[0-9]+"; "")` is a no-op on the fraction-less variant Bitbucket also emits, so `ts` handles both. `updated_on` on a merged PR approximates the merge time. For the exact timestamp, read the merge event: ```bash bb pr activity 42 -w "$WORKSPACE" -r "$REPO" --type merge --json --jq '.activities[0].merge.date' ``` ## Related [Section titled “Related”](#related) * [Scripting & Automation guide](/guides/scripting/) — JSON output, exit codes, primitive jq patterns * [JSON Output reference](/reference/json-output/) — the envelope shape for list-style commands * [`bb pr list`](/commands/pr/) — flags like `-s`, `--limit`, `--json`, `--jq` # Retry wrapper for transient failures > A small shell wrapper that retries bb invocations with exponential backoff when the built-in retry isn't enough. The CLI already retries HTTP 429, 502, 503, and 504 responses up to **3 times** with exponential backoff — see [Built-in Resilience](/guides/scripting/#built-in-resilience). For nearly every workflow that’s enough. This recipe is for the cases where it isn’t: * A long-running batch job that hits the rate-limit envelope and needs *more* than 3 retries. * Network flakes where DNS or TLS itself misbehaves and never reaches the CLI’s retry layer. * A dependent system (CI runner, proxy) that occasionally rejects requests. ## What you’ll see when retry kicks in [Section titled “What you’ll see when retry kicks in”](#what-youll-see-when-retry-kicks-in) Each built-in retry announces itself on stderr — `⚠ Rate limited, retrying in 1.0s (attempt 1/3)...` — unless you passed `--json`, which suppresses the chatter so it can’t pollute a structured pipeline. After the third and final failure, the CLI prints Bitbucket’s own message to stderr, prefixed with a red `✗` (or `ERR `under `--no-unicode`). For a rate limit that is typically: ```text ✗ Rate limit for this resource has been exceeded ``` The HTTP status number does not appear in text mode. To branch on it, pass `--json`: the error envelope goes to stderr as a single compact line. ```json {"name":"APIError","code":2004,"message":"Rate limit for this resource has been exceeded","context":{"status":429},"statusCode":429,"response":{"type":"error","error":{"message":"Rate limit for this resource has been exceeded"}}} ``` The envelope is flat — there is no `error` wrapper object — and `code` is a number from the [Error Codes reference](/reference/error-codes/), here `2004` (`API_RATE_LIMITED`). `statusCode` and `response` appear on API errors only; a validation or config error has neither, and `context` on an API error also carries `method` and `url` (trimmed above). A `hint` string is added for 401, 403 and 404 responses; a 429 gets no hint. If the operation is idempotent, retrying is safe. Caution **Don’t blanket-retry mutating commands.** `bb pr create`, `bb pr merge`, `bb pr approve`, and similar can succeed *server-side* even when the response read fails. A retry might create a duplicate pull request (PR) or re-approve. Limit the wrapper below to read-only commands or commands you’ve made idempotent (e.g., check existence before creating). ## Recipe: bb-with-retry wrapper [Section titled “Recipe: bb-with-retry wrapper”](#recipe-bb-with-retry-wrapper) ```bash #!/bin/bash # bb-retry.sh - Run a bb command with exponential backoff. # # Usage: # ./bb-retry.sh pr list -w myworkspace -r myrepo --json # # Env vars: # MAX_ATTEMPTS default 5 # INITIAL_DELAY default 2 (seconds) # MAX_DELAY default 60 (seconds) set -euo pipefail MAX_ATTEMPTS="${MAX_ATTEMPTS:-5}" INITIAL_DELAY="${INITIAL_DELAY:-2}" MAX_DELAY="${MAX_DELAY:-60}" attempt=1 delay="$INITIAL_DELAY" while true; do # `bb "$@" && exit 0`, not `if bb "$@"; then exit 0; fi` — after a # non-taken `if` branch, $? is the status of the `if` itself (always 0), # so the wrapper would report "exit 0" and exit 0 on total failure. bb "$@" && exit 0 exit_code=$? if [ "$attempt" -ge "$MAX_ATTEMPTS" ]; then echo "bb $* failed after $attempt attempts (exit $exit_code)" >&2 exit "$exit_code" fi # Add jitter: ±25% of the current delay jitter=$(( RANDOM % (delay / 2 + 1) - delay / 4 )) sleep_time=$(( delay + jitter )) [ "$sleep_time" -lt 1 ] && sleep_time=1 echo "bb $* failed (exit $exit_code); retry $((attempt + 1))/$MAX_ATTEMPTS in ${sleep_time}s" >&2 sleep "$sleep_time" attempt=$(( attempt + 1 )) delay=$(( delay * 2 )) [ "$delay" -gt "$MAX_DELAY" ] && delay="$MAX_DELAY" done ``` ### Usage [Section titled “Usage”](#usage) ```bash chmod +x bb-retry.sh # Read-only: safe to retry freely. ./bb-retry.sh pr list -w myworkspace -r myrepo --json > prs.json # Tune the cap for big jobs. MAX_ATTEMPTS=10 INITIAL_DELAY=5 ./bb-retry.sh pr view 42 --json ``` ## Recipe: retry only on a specific error code [Section titled “Recipe: retry only on a specific error code”](#recipe-retry-only-on-a-specific-error-code) To retry rate limits but *not* authentication failures, run the command with `--json` and read `statusCode` off the error envelope. Do not grep the text-mode message for `429`: that message is Bitbucket’s own prose and usually contains no digits at all, while any PR title containing “502” would match. bb-retry-on-rate-limit.sh ```bash #!/bin/bash # # Usage: # ./bb-retry-on-rate-limit.sh pr list -w myworkspace -r myrepo # # Appends --json so the error envelope is machine-readable. set -euo pipefail MAX_ATTEMPTS=5 attempt=1 delay=2 while true; do err_file=$(mktemp) bb "$@" --json 2> "$err_file" && { rm -f "$err_file"; exit 0; } err_msg=$(cat "$err_file") rm -f "$err_file" # statusCode exists on API errors only; empty for validation/config errors. status=$(printf '%s' "$err_msg" | jq -r '.statusCode // empty' 2>/dev/null || true) # Retry only on rate-limit / transient gateway errors. case "$status" in 429|502|503|504) if [ "$attempt" -ge "$MAX_ATTEMPTS" ]; then echo "$err_msg" >&2 exit 1 fi echo "HTTP $status, retrying in ${delay}s..." >&2 sleep "$delay" delay=$(( delay * 2 )) attempt=$(( attempt + 1 )) ;; *) # Non-transient (or no statusCode at all): fail fast. echo "$err_msg" >&2 exit 1 ;; esac done ``` ## When *not* to write your own retry [Section titled “When not to write your own retry”](#when-not-to-write-your-own-retry) The wrappers above are the right answer when the built-in retry has been exhausted. They are *not* the right answer for: * **Auth failures** — `Authentication required. Run 'bb auth login' or set BB_USERNAME and BB_API_TOKEN.` (`code: 1001`). Retrying won’t help; fix the credentials. * **404 / not-found errors** (`code: 2002`) — these don’t get more found over time. * **Validation errors** (`code: 5001` or `5002`, e.g. `Option --title is required`) — bugs in your script, not transient. The CLI exits `1` for all of these, same as for transient errors. Branch on the JSON envelope instead. Use `jq -r '.statusCode // .code'`: `statusCode` is present on API errors, and `code` covers the rest. ## Related [Section titled “Related”](#related) * [Scripting & Automation: Built-in Resilience](/guides/scripting/#built-in-resilience) * [Error Codes reference](/reference/error-codes/) — the numeric `code` values to branch on * [JSON Output reference](/reference/json-output/) — the success/error envelope shapes # Configuration File > Complete reference for the bb configuration file All persistent settings live in one JSON file, written by `bb auth login` and `bb config set`. This page documents the file itself; for the commands that read and write it, see the [Config command reference](/commands/config/). ## File location [Section titled “File location”](#file-location) * macOS / Linux ```plaintext ~/.config/bb/config.json ``` * Windows ```plaintext %APPDATA%\bb\config.json ``` Typically: `C:\Users\<username>\AppData\Roaming\bb\config.json` *** ## Configuration schema [Section titled “Configuration schema”](#configuration-schema) | Key | Type | Description | Set by | | --------------------------------- | ---------------------- | ------------------------------------------------------------------------------ | -------------------------------- | | `authMethod` | `"basic"` \| `"oauth"` | Active authentication method | `bb auth login` | | `username` | string | Your Bitbucket username (API token auth) | `bb auth login -u` | | `apiToken` | string | Your API token (API token auth) | `bb auth login -p` | | `oauthAccessToken` | string | OAuth access token | `bb auth login` (OAuth) | | `oauthRefreshToken` | string | OAuth refresh token | `bb auth login` (OAuth) | | `oauthExpiresAt` | number | OAuth token expiry (Unix timestamp) | `bb auth login` (OAuth) | | `oauthClientId` | string | Custom OAuth consumer client ID | `bb auth login --client-id` | | `oauthClientSecret` | string | Custom OAuth consumer client secret | `bb auth login --client-secret` | | `defaultWorkspace` | string | Default workspace | `bb config set defaultWorkspace` | | `skipVersionCheck` | boolean | Disable update notifications | `bb config set` | | `versionCheckInterval` | number | Days between update checks (default: 1) | `bb config set` | | `prCreateIncludeDefaultReviewers` | boolean | Auto-add the repository’s default reviewers on `bb pr create` (default: false) | `bb config set` | | `lastVersionCheck` | string | Timestamp of last update check | Automatic | ### Example configuration (OAuth) [Section titled “Example configuration (OAuth)”](#example-configuration-oauth) ```json { "authMethod": "oauth", "oauthAccessToken": "xxxxxxxxxxxxxxxx", "oauthRefreshToken": "xxxxxxxxxxxxxxxx", "oauthExpiresAt": 1711036800, "defaultWorkspace": "myworkspace" } ``` ### Example configuration (API token) [Section titled “Example configuration (API token)”](#example-configuration-api-token) ```json { "authMethod": "basic", "username": "myuser", "apiToken": "ATBB_xxxxxxxxxxxxxxxxxxxx", "defaultWorkspace": "myworkspace", "skipVersionCheck": false, "versionCheckInterval": 7 } ``` *** ## Managing configuration [Section titled “Managing configuration”](#managing-configuration) ### View all settings [Section titled “View all settings”](#view-all-settings) ```bash bb config list ``` Output: ```text Config file: /Users/you/.config/bb/config.json KEY VALUE ---------------- ----------- username myuser defaultWorkspace myworkspace apiToken ******** skipVersionCheck false Settable keys: defaultWorkspace, skipVersionCheck, versionCheckInterval, prCreateIncludeDefaultReviewers. Run 'bb config set --help' for details. ``` The API token is masked. Use `bb auth token` to see the real value. ### Get a specific value [Section titled “Get a specific value”](#get-a-specific-value) ```bash bb config get defaultWorkspace # Output: myworkspace ``` Values are stored as native JSON types, so for the typed keys `--json` returns a real boolean or number rather than a quoted string: ```bash bb config get skipVersionCheck --json # {"key":"skipVersionCheck","value":true} ``` ### Set a value [Section titled “Set a value”](#set-a-value) ```bash bb config set defaultWorkspace myworkspace bb config set skipVersionCheck true bb config set versionCheckInterval 7 ``` #### Settable keys [Section titled “Settable keys”](#settable-keys) `bb config set` accepts these four keys; `bb config list` prints the current list as a footer. Everything else is written by `bb auth login` or by the CLI itself. | Key | Type | Example | | --------------------------------- | ------------------- | ---------------------------------------------------- | | `defaultWorkspace` | string | `bb config set defaultWorkspace myworkspace` | | `skipVersionCheck` | boolean | `bb config set skipVersionCheck true` | | `versionCheckInterval` | integer (days, ≥ 1) | `bb config set versionCheckInterval 7` | | `prCreateIncludeDefaultReviewers` | boolean | `bb config set prCreateIncludeDefaultReviewers true` | `skipVersionCheck` and `prCreateIncludeDefaultReviewers` accept only `true` or `false`. `versionCheckInterval` accepts only positive integers (`>= 1`). #### Readable keys [Section titled “Readable keys”](#readable-keys) `bb config get` has its own allowlist, and it is not the same one: ```text username, defaultWorkspace, skipVersionCheck, versionCheckInterval, prCreateIncludeDefaultReviewers ``` `username` is readable but not settable — change it with `bb auth login -u`. `bb config get apiToken` refuses: ```text Cannot display 'apiToken' - it is part of your authentication credentials, not config. Use 'bb auth token' to retrieve credentials, or run 'bb config list' to see readable keys. ``` Any other key throws `Unknown config key '<key>'` with the valid list and a suggestion, e.g. `(Did you mean defaultWorkspace?)`. #### `prCreateIncludeDefaultReviewers` and the `--default-reviewers` flag [Section titled “prCreateIncludeDefaultReviewers and the --default-reviewers flag”](#prcreateincludedefaultreviewers-and-the---default-reviewers-flag) | Config | Flag | Result | | --------------- | ------------------------ | ----------------------------------- | | unset / `false` | (none) | Default reviewers are **not** added | | `true` | (none) | Default reviewers are added | | unset / `false` | `--default-reviewers` | Default reviewers are added | | `true` | `--no-default-reviewers` | Default reviewers are **not** added | ### Protected keys [Section titled “Protected keys”](#protected-keys) These keys cannot be set with `bb config set`: | Key | Reason | How to set | | ------------------- | ---------------------- | ---------------------- | | `username` | Tied to authentication | Use `bb auth login -u` | | `apiToken` | Security-sensitive | Use `bb auth login -p` | | `authMethod` | Managed by login flow | Use `bb auth login` | | `oauthAccessToken` | Managed by OAuth flow | Use `bb auth login` | | `oauthRefreshToken` | Managed by OAuth flow | Use `bb auth login` | | `oauthExpiresAt` | Managed by OAuth flow | Use `bb auth login` | *** ## Update notifications [Section titled “Update notifications”](#update-notifications) After every command the CLI checks npm for a newer version, at most once per `versionCheckInterval` days (default 1). The notice goes to stderr, and only when stderr is a TTY, so `--json` and piped output stay clean. It is skipped entirely in CI and when `skipVersionCheck` is true. ### Example notification [Section titled “Example notification”](#example-notification) ```text ────────────────────────────────────────────────── A new version is available: <latest> (you have <current>) Run 'bun install -g @pilatos/bitbucket-cli' to update Or disable with 'bb config set skipVersionCheck true' ────────────────────────────────────────────────── ``` There is no warning glyph. The separator rules are 50 box-drawing dashes, or 50 ASCII hyphens under `--no-unicode`. ### Disable notifications [Section titled “Disable notifications”](#disable-notifications) ```bash bb config set skipVersionCheck true ``` ### Change check frequency [Section titled “Change check frequency”](#change-check-frequency) `versionCheckInterval` is in days. Once per week: ```bash bb config set versionCheckInterval 7 ``` *** ## Configuration precedence [Section titled “Configuration precedence”](#configuration-precedence) Command-line flags beat the git remote, which beats `BB_WORKSPACE`, which beats the config file: ```bash bb pr list -w otherworkspace -r otherrepo # flags win cd /path/to/cloned-repo && bb pr list # git remote BB_WORKSPACE=myworkspace bb repo list # env var bb config set defaultWorkspace myworkspace # config file ``` The full order, including which commands skip the git-remote step, is in [Environment Variables](/reference/environment-variables/#resolution-order). [Understanding Repository Context](/guides/repository-context/) has worked examples. Some runtime behavior is tuned only with environment variables, not config keys — `BB_HTTP_TIMEOUT` for the API request timeout, for example. *** ## File permissions [Section titled “File permissions”](#file-permissions) The config file holds your API token, so the CLI creates the directory `0700` and the file `0600`, and writes atomically (temp file, then rename). | Platform | Directory | File | | ----------- | --------------------------------- | --------------------------------- | | macOS/Linux | `0700` (owner only) | `0600` (owner read/write only) | | Windows | Inherits user profile permissions | Inherits user profile permissions | On macOS and Linux the CLI also *verifies* both on every read. If any group or other bit is set, every command fails with error 4001 until you fix it: ```text Config file has insecure permissions (644); expected 600. Run: chmod 600 /Users/you/.config/bb/config.json Config directory has insecure permissions (755); expected 700. Run: chmod 700 /Users/you/.config/bb ``` Windows skips the check, and a path that does not exist yet is not checked, so a fresh install never hits this. Security Never share your config file or commit it to version control. The API token grants access to your Bitbucket account. *** ## Reset configuration [Section titled “Reset configuration”](#reset-configuration) ### Clear authentication only [Section titled “Clear authentication only”](#clear-authentication-only) ```bash bb auth logout ``` This removes authentication credentials (OAuth tokens or API token) but keeps `defaultWorkspace` and other settings. For OAuth, it also revokes the token on Bitbucket’s side. ### Full reset [Section titled “Full reset”](#full-reset) Delete the config file entirely: * macOS / Linux ```bash rm ~/.config/bb/config.json ``` * Windows ```powershell Remove-Item $env:APPDATA\bb\config.json ``` Then re-authenticate: ```bash bb auth login ``` *** ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### “Config file is not valid JSON” [Section titled ““Config file is not valid JSON””](#config-file-is-not-valid-json) Fix the file by hand, or delete it and log in again: ```bash rm ~/.config/bb/config.json bb auth login ``` ### “Config file has insecure permissions” [Section titled ““Config file has insecure permissions””](#config-file-has-insecure-permissions) ```bash chmod 700 ~/.config/bb chmod 600 ~/.config/bb/config.json ``` ### “Failed to read config file” [Section titled ““Failed to read config file””](#failed-to-read-config-file) The path exists but is unreadable. Check ownership and permissions: ```bash ls -la ~/.config/bb/ ``` ### “Failed to write config file” / “Failed to create config directory” [Section titled ““Failed to write config file” / “Failed to create config directory””](#failed-to-write-config-file--failed-to-create-config-directory) The parent directory is missing or not writable: ```bash mkdir -p ~/.config/bb ls -ld ~/.config/bb ``` ### Config not being used [Section titled “Config not being used”](#config-not-being-used) Verify the CLI is reading from the expected location: ```bash bb config list # Check the "Config file:" line ``` Command-line flags, git context and `BB_WORKSPACE` all take precedence over config file settings. # Environment Variables > Configure Bitbucket CLI using environment variables Every environment variable the CLI reads. `bb --help` lists the main ones in its footer. ## Available variables [Section titled “Available variables”](#available-variables) | Variable | Description | Example | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | | `BB_USERNAME` | Your Bitbucket username (fallback for `bb auth login`) | `myuser` | | `BB_API_TOKEN` | Your Bitbucket API token (fallback for `bb auth login`; forces API token auth when set) | `ATBB...` | | `BB_WORKSPACE` | Default workspace. Overrides `config.defaultWorkspace`. `--workspace` always wins; the git remote wins too, but only on repository-scoped commands — see [Resolution order](#resolution-order). | `myworkspace` | | `BB_LOCALE` | BCP-47 locale tag for date/time formatting. `--locale` takes precedence; falls back to `LC_TIME`/`LC_ALL`/`LANG`, then `en-US`. | `de-DE` | | `BB_NO_UNICODE` | When set to any non-empty value, use ASCII fallbacks for separators, arrows, and status icons. Same effect as the global `--no-unicode` flag, but it cannot be overridden per command: `--unicode` is accepted and does nothing while this is set. Unset the variable instead. | `1` | | `NO_COLOR` | Disable color output globally. Triggers on any value, including the empty string. | `1` | | `FORCE_COLOR` | Force-enable color output globally (any value except `0`) | `1` | | `DEBUG` | Enable HTTP debug logging (request method, URL, status, response body for every API call). Must equal the literal string `true`. | `true` | | `BB_HTTP_TIMEOUT` | Per-request HTTP timeout in **milliseconds** for Bitbucket API calls. Prevents the CLI from hanging forever when a server accepts a connection but never responds. Defaults to `30000` (30s). Set to `0` to disable the timeout entirely. Invalid or negative values fall back to the default. A timed-out request is reported as a network error. | `60000` | | `BB_API_BASE_URL` | Base URL for Bitbucket API calls. Defaults to `https://api.bitbucket.org/2.0`. Point it at a gateway, a mirror, or a local mock server (trailing slashes are stripped). | `http://localhost:8080/2.0` | BB\_HTTP\_TIMEOUT is in milliseconds `BB_HTTP_TIMEOUT=60` means 60 milliseconds, so almost every request fails. For a 60-second ceiling use `BB_HTTP_TIMEOUT=60000`. In CI, set something short like `BB_HTTP_TIMEOUT=15000` so a stalled call fails fast instead of hanging the pipeline. `BB_HTTP_TIMEOUT=0` disables the timeout — useful for very large clones or exports, but a hung request in CI has no human to Ctrl-C. ### POSIX locale variables [Section titled “POSIX locale variables”](#posix-locale-variables) If neither `--locale` nor `BB_LOCALE` is set, the CLI reads the standard POSIX locale variables — `LC_TIME`, then `LC_ALL`, then `LANG` — and falls back to `en-US` if none is usable. `LC_TIME` is deliberately checked **before** `LC_ALL`, which is the reverse of the usual POSIX override order, so setting both means `LC_TIME` wins. Values are normalised before use: a `.UTF-8` codeset suffix and an `@euro`-style modifier are stripped, `_` becomes `-` (`de_DE.UTF-8` → `de-DE`), and the `C` and `POSIX` locales map to `en-US`. Unset them, or pass `--locale`, to pin formatting explicitly. ### CI detection [Section titled “CI detection”](#ci-detection) The update check is skipped when any of these is set to any value: `CI`, `CONTINUOUS_INTEGRATION`, `BUILD_ID`, `BUILD_NUMBER`, `DRONE`, `GITHUB_ACTIONS`, `GITLAB_CI`, `CIRCLECI`, `TRAVIS`, `JENKINS_URL`, `HUDSON_URL` Set `CI=1` to get the same behavior locally. ### Internal / system variables [Section titled “Internal / system variables”](#internal--system-variables) Set by the runtime, your shell, or your operating system rather than by you. Documented so they aren’t surprising during troubleshooting. | Variable | Set by | Description | | ----------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `NODE_ENV` | Test runners | When set to `test`, the CLI suppresses `process.exitCode = 1` on errors so a single failing test cannot cascade into later tests. Don’t set this in production. | | `COMP_LINE` | tabtab / your shell | Set automatically while shell completion is being computed (`bb completion`). Its presence triggers the completion path; you should not set it manually. | | `APPDATA` | Windows | Used to locate the config file at `%APPDATA%\bb\config.json` on Windows. The CLI falls back to `%USERPROFILE%\AppData\Roaming\bb\config.json` if it isn’t set. | ## Resolution order [Section titled “Resolution order”](#resolution-order) Workspace and repository, highest priority first: 1. **Command-line flags** (`--workspace`, `--repo`) 2. **Git repository context** (detected from the remote URL) 3. **`BB_WORKSPACE`** (workspace only) 4. **Configuration file** (`defaultWorkspace`, workspace only) Step 2 does not apply to workspace-only commands — `bb workspace view`, every `bb project` and `bb snippet` command, `bb repo list`, `bb repo create`, `bb repo clone`, and `bb api` filling a `{workspace}` placeholder go straight from the flag to `BB_WORKSPACE` to `defaultWorkspace`. Color, highest priority first. The default with none of them set is colors on: 1. `--color` — matched by a raw scan of argv, so `bb pr diff 42 --color never` still turns global color on 2. `FORCE_COLOR` (any value except `0`) 3. `--no-color` 4. `NO_COLOR` (any value, including the empty string) Credentials are **not** a chain. `bb pr list` and every other API call read the username and token from the config file only; if nothing is stored there the command fails with error 1001 even when `BB_USERNAME` and `BB_API_TOKEN` are exported. Those two variables are read by `bb auth login` and nowhere else — run it once and it writes the config file. Inside `bb auth login`: * `--username` / `-u` beats `BB_USERNAME`. * `--with-token` (token on stdin) beats `--password` / `-p`, which beats `BB_API_TOKEN`. Combining `--with-token` with `--password` is an error. * Setting `BB_API_TOKEN` at all selects API token auth instead of OAuth. ## Authentication with environment variables [Section titled “Authentication with environment variables”](#authentication-with-environment-variables) `bb auth login` picks up both variables, so it runs without prompts: ```bash export BB_USERNAME=myuser export BB_API_TOKEN=ATBB_your_token_here bb auth login bb pr list -w myworkspace -r myrepo ``` Or inline, without exporting: ```bash BB_USERNAME=myuser BB_API_TOKEN=ATBB_token bb auth login ``` To keep the token out of shell history and `ps` output, pipe it instead: ```bash echo "$BB_API_TOKEN" | bb auth login -u myuser --with-token ``` ## Shell configuration [Section titled “Shell configuration”](#shell-configuration) Add to your shell’s startup file, then reload it or open a new terminal: * Bash `~/.bashrc` or `~/.bash_profile`: ```bash export BB_USERNAME="your-username" export BB_API_TOKEN="your-api-token" ``` * Zsh `~/.zshrc`: ```zsh export BB_USERNAME="your-username" export BB_API_TOKEN="your-api-token" ``` * Fish `~/.config/fish/config.fish`: ```fish set -gx BB_USERNAME "your-username" set -gx BB_API_TOKEN "your-api-token" ``` * PowerShell Your profile (`$PROFILE`): ```powershell $env:BB_USERNAME = "your-username" $env:BB_API_TOKEN = "your-api-token" ``` ## Docker [Section titled “Docker”](#docker) ```bash docker run -e BB_USERNAME=myuser \ -e BB_API_TOKEN=ATBB_token \ your-image sh -lc "bb auth login && bb pr list -w workspace -r myrepo" ``` Or an env file: ```bash # .env.bb (not committed to git!) BB_USERNAME=myuser BB_API_TOKEN=ATBB_token ``` ```bash docker run --env-file .env.bb your-image sh -lc "bb auth login && bb pr list -w workspace -r myrepo" ``` ## CI/CD examples [Section titled “CI/CD examples”](#cicd-examples) The package is published to npm but runs on Bun — `bb` exits immediately under Node — so every runner needs Bun on `PATH`. ### GitHub Actions [Section titled “GitHub Actions”](#github-actions) ```yaml name: PR Status on: [push] jobs: check-prs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v1 with: bun-version: latest - name: Install Bitbucket CLI run: npm install -g @pilatos/bitbucket-cli - name: List PRs env: BB_USERNAME: ${{ secrets.BB_USERNAME }} BB_API_TOKEN: ${{ secrets.BB_API_TOKEN }} BB_HTTP_TIMEOUT: 15000 run: | bb auth login bb pr list -w myworkspace -r myrepo --json ``` ### GitLab CI [Section titled “GitLab CI”](#gitlab-ci) ```yaml check-prs: image: oven/bun:latest variables: BB_USERNAME: $BB_USERNAME BB_API_TOKEN: $BB_API_TOKEN BB_HTTP_TIMEOUT: 15000 script: - bun install -g @pilatos/bitbucket-cli - bb auth login - bb pr list -w myworkspace -r myrepo --json ``` ### Bitbucket Pipelines [Section titled “Bitbucket Pipelines”](#bitbucket-pipelines) ```yaml image: oven/bun:latest pipelines: default: - step: name: Check PRs script: - bun install -g @pilatos/bitbucket-cli - bb auth login - bb pr list -w $BITBUCKET_WORKSPACE -r $BITBUCKET_REPO_SLUG --json ``` `BITBUCKET_WORKSPACE` and `BITBUCKET_REPO_SLUG` are provided by Bitbucket Pipelines automatically. ## Keeping tokens safe [Section titled “Keeping tokens safe”](#keeping-tokens-safe) * Add `.env*` to `.gitignore` and pass tokens through your CI platform’s secrets store. Never commit them. * Grant the token only the scopes the script uses. See [Token Scopes](/reference/token-scopes/) for the scope each command needs. # Error Codes > Complete reference of error codes and their meanings Every failure carries a numeric `code` in the `--json` error payload (`{"code": 2002, …}`). The process exit status is always `1`, so branch on `code`, not on the exit status. Ctrl-F the number below. ## Error code ranges [Section titled “Error code ranges”](#error-code-ranges) | Range | Category | Description | | ----- | -------------------------- | -------------------------------------------------------------- | | 1xxx | Authentication | Login, credentials, and token issues | | 2xxx | API | Bitbucket API request failures | | 3xxx | Git | Local git operations | | 4xxx | Configuration | Config file read/write issues | | 5xxx | Validation | Invalid input or missing required fields | | 6xxx | Context | Repository/workspace detection issues | | 7xxx | Network | Transport/network failures before API response | | 8xxx | Output formatting | `--json fields` and `--jq` evaluation issues | | 9xxx | Shell completion / Unknown | Completion install/uninstall failures and uncategorized errors | *** ## Authentication errors (1xxx) [Section titled “Authentication errors (1xxx)”](#authentication-errors-1xxx) ### 1001 - AUTH\_REQUIRED [Section titled “1001 - AUTH\_REQUIRED”](#1001---auth_required) **Message:** Authentication required **Cause:** You haven’t logged in yet, or your credentials have been cleared. **Solution:** ```bash bb auth login ``` ### 1002 - AUTH\_INVALID [Section titled “1002 - AUTH\_INVALID”](#1002---auth_invalid) **Message:** Invalid credentials **Cause:** Your credentials were rejected by Bitbucket at request time. This is the code emitted for any 401 response that was *not* recovered by an OAuth refresh — e.g. a wrong API token, a revoked password, or basic-auth requests with bad credentials. **Solution:** 1. Verify your Bitbucket username 2. Generate a new API token at [Bitbucket API Tokens](https://bitbucket.org/account/settings/api-tokens/) 3. Re-authenticate: ```bash bb auth logout bb auth login ``` The CLI prints this next step alongside the error: > Your Bitbucket credentials were rejected. Run `bb auth login` to re-authenticate. ### 1003 - AUTH\_EXPIRED [Section titled “1003 - AUTH\_EXPIRED”](#1003---auth_expired) **Message:** OAuth token expired. Run `bb auth login` to re-authenticate. **Cause:** Specifically: an OAuth access token expired *and* the reactive refresh attempt also failed (refresh token revoked or expired). For non-OAuth flows, a stale token surfaces as `AUTH_INVALID` (1002) instead. **Solution:** 1. Re-run `bb auth login` to perform a fresh OAuth flow 2. If that also fails, create a new API token in Bitbucket settings and switch auth methods *** ## API errors (2xxx) [Section titled “API errors (2xxx)”](#api-errors-2xxx) ### 2001 - API\_REQUEST\_FAILED [Section titled “2001 - API\_REQUEST\_FAILED”](#2001---api_request_failed) **Message:** API request failed **Cause:** Bitbucket answered with an unexpected HTTP status below 500 that isn’t 401/403/404/429 — typically 400 (malformed request body) or 409 (conflict, e.g. merging a pull request that is already merged). The server did respond, so this is not a connectivity problem. **Solution:** Read `message` and `response` in the JSON error payload; they carry Bitbucket’s own explanation. ```bash bb pr merge 42 --json 2> err.json jq '.statusCode, .message, .response' err.json ``` Connection failures are [7001](#7001---network_error); server faults are [2005](#2005---api_server_error). ### 2002 - API\_NOT\_FOUND [Section titled “2002 - API\_NOT\_FOUND”](#2002---api_not_found) **Message:** Resource not found **Cause:** The requested repository, PR, or resource doesn’t exist. **Solution:** * Check spelling of workspace and repository names * Verify the resource exists in Bitbucket * Ensure you have access to the repository Where the message doesn’t already name the missing resource, the CLI appends: > Verify the id or slug you passed, and that –workspace/–repo point at the right repository your token can see. The hint is omitted when the message is already specific (for example `Pull request 999 not found in acme/demo.`) and for `bb api`, where you supplied the URL yourself. ### 2003 - API\_FORBIDDEN [Section titled “2003 - API\_FORBIDDEN”](#2003---api_forbidden) **Message:** Access denied **Cause:** Your API token doesn’t have the required permissions. **Solution:** 1. Check your API token scopes at [Bitbucket API Tokens](https://bitbucket.org/account/settings/api-tokens/) 2. See [Token Scopes](/reference/token-scopes/) for the exact scope each `bb` command requires. 3. If a scope is missing, mint a new token (you can’t add scopes to an existing one) and re-authenticate with `bb auth login`. The CLI prints this next step alongside the error: > Your token may be missing a required scope. Scopes can’t be added to an existing token — mint a new one, then run `bb auth login`. > > Docs: <https://bitbucket-cli.paulvanderlei.com/reference/token-scopes/> A `403` can also be a plain permission denial rather than a scope problem — the API doesn’t distinguish the two, hence the hedged wording. ### 2004 - API\_RATE\_LIMITED [Section titled “2004 - API\_RATE\_LIMITED”](#2004---api_rate_limited) **Message:** Rate limit exceeded **Cause:** Bitbucket returned 429 and the CLI’s three automatic retries — which honour the `Retry-After` header — were all exhausted. **Solution:** Reduce request volume. Prefer `--limit` over `--all`, and batch with `bb api --paginate` instead of looping single calls: ```bash bb pr list --limit 25 --json bb api /repositories/myworkspace/myrepo/pullrequests --paginate --json ``` ### 2005 - API\_SERVER\_ERROR [Section titled “2005 - API\_SERVER\_ERROR”](#2005---api_server_error) **Message:** Bitbucket server error **Cause:** Bitbucket’s servers are experiencing issues. **Solution:** * Check [status.bitbucket.org](https://status.bitbucket.org) * Retry after a few minutes *** ## Git errors (3xxx) [Section titled “Git errors (3xxx)”](#git-errors-3xxx) ### 3001 - GIT\_NOT\_REPOSITORY [Section titled “3001 - GIT\_NOT\_REPOSITORY”](#3001---git_not_repository) Reserved. No code path currently emits `3001` — running outside a git repository surfaces as [6001 CONTEXT\_REPO\_NOT\_FOUND](#6001---context_repo_not_found). Don’t branch on `3001` in scripts. ### 3002 - GIT\_COMMAND\_FAILED [Section titled “3002 - GIT\_COMMAND\_FAILED”](#3002---git_command_failed) **Message:** Git command failed **Cause:** A git operation (clone, fetch, checkout) failed. **Solution:** * Ensure git is installed and in your PATH * Check git error message for details * Verify you have proper SSH keys or credentials configured ### 3003 - GIT\_REMOTE\_NOT\_FOUND [Section titled “3003 - GIT\_REMOTE\_NOT\_FOUND”](#3003---git_remote_not_found) **Message:** No Bitbucket remote found **Cause:** The repository has no remote pointing to Bitbucket. **Solution:** * Add a Bitbucket remote: ```bash git remote add origin git@bitbucket.org:workspace/repo.git ``` * Or use explicit flags: `-w <workspace> -r <repo>` *** ## Config errors (4xxx) [Section titled “Config errors (4xxx)”](#config-errors-4xxx) ### 4001 - CONFIG\_READ\_FAILED [Section titled “4001 - CONFIG\_READ\_FAILED”](#4001---config_read_failed) **Message:** Cannot read config file **Cause:** The configuration file is corrupted or unreadable. **Solution:** 1. Check file permissions 2. If corrupted, delete and recreate: ```bash # macOS/Linux rm ~/.config/bb/config.json bb auth login # Windows del %APPDATA%\bb\config.json bb auth login ``` ### 4002 - CONFIG\_WRITE\_FAILED [Section titled “4002 - CONFIG\_WRITE\_FAILED”](#4002---config_write_failed) **Message:** Cannot write config file **Cause:** No write permission to the config directory. **Solution:** * Check directory permissions * Ensure the parent directory exists * On shared systems, verify you own the config directory ### 4003 - CONFIG\_INVALID\_KEY [Section titled “4003 - CONFIG\_INVALID\_KEY”](#4003---config_invalid_key) **Message:** Invalid configuration key **Cause:** Attempted to get or set an unknown configuration key. **Solution:** Use a valid key. `bb config set` accepts four: | Key | Meaning | | --------------------------------- | -------------------------------------------------------- | | `defaultWorkspace` | Workspace used when `-w` is omitted | | `skipVersionCheck` | Disable update notifications | | `versionCheckInterval` | Days between update checks | | `prCreateIncludeDefaultReviewers` | Add the repository’s default reviewers on `bb pr create` | `bb config get` accepts those four plus `username`. ```bash bb config set defaultWorkspace myworkspace bb config get username bb config list ``` Two keys get a distinct message instead of the unknown-key one. `bb config set username` and `bb config set apiToken` point you at `bb auth login`; `bb config get apiToken` points you at `bb auth token`. Every other credential field (`oauthAccessToken` and friends) is not a config key at all and falls through to the unknown-key message above. *** ## Validation errors (5xxx) [Section titled “Validation errors (5xxx)”](#validation-errors-5xxx) ### 5001 - VALIDATION\_REQUIRED [Section titled “5001 - VALIDATION\_REQUIRED”](#5001---validation_required) **Message:** Required field missing **Cause:** A required option or argument was not provided. **Solution:** Check command help for required options: ```bash bb <command> --help ``` Common required fields: * `bb pr create` requires `--title` * `bb repo create` requires a name argument ### 5002 - VALIDATION\_INVALID [Section titled “5002 - VALIDATION\_INVALID”](#5002---validation_invalid) **Message:** Invalid value **Cause:** A provided value doesn’t match expected format, or an unknown top-level command was given. **Solution:** * Check the expected format in command help * Common issues: * Pull request ID must be a number * State must be one of: OPEN, MERGED, DECLINED, SUPERSEDED * An unknown command (`bb prr`) * `--json` placed before the subcommand, so it ate the subcommand as its field list — see [Troubleshooting](/help/troubleshooting/) The misplaced-`--json` case names the token it swallowed. Because `--json` did take effect, it comes back as an error envelope on stderr: ```bash bb --json pr list ``` ```json {"name":"BBError","code":5002,"message":"--json consumed 'pr' as its field list, so 'list' was parsed as a top-level command.\nPut --json after the subcommand: bb pr list --json","context":{"command":"pr","args":["list"]}} ``` When a value or name is close to a valid one, the CLI suggests the correction. This fires for unknown commands, enum option values, config keys, `bb pr activity --type` tokens, and `bb api` HTTP methods: ```bash bb prr # ✗ unknown command 'prr' # (Did you mean pr?) bb pr list --state opne # ✗ --state must be one of: OPEN, MERGED, DECLINED, SUPERSEDED # (Did you mean OPEN?) bb config set defaultWorkspce foo # ✗ Unknown config key 'defaultWorkspce'. Valid keys: defaultWorkspace, skipVersionCheck, versionCheckInterval, prCreateIncludeDefaultReviewers # (Did you mean defaultWorkspace?) ``` Enum values are matched **case-sensitively**, so a value that is right apart from its case gets a distinct message rather than a suggestion: ```bash bb pr list --state open # ✗ --state must be one of: OPEN, MERGED, DECLINED, SUPERSEDED # (Values are case-sensitive — use OPEN.) ``` ### 5003 - FILE\_NOT\_FOUND [Section titled “5003 - FILE\_NOT\_FOUND”](#5003---file_not_found) **Message:** File not found: `<path>` **Cause:** A file referenced by an option (`--file` on `bb snippet create`/`edit`, `--body-file` on `bb pr edit`/`bb issue create`, `-F key=@file` or `--input` on `bb api`) doesn’t exist on disk, or a named file isn’t present inside a snippet. **Solution:** * Verify the path is correct relative to the current working directory * For `bb snippet view --file <name>`, list snippet files first to confirm the name The `context` field carries the offending path, so scripts can tell this apart from a generic `VALIDATION_INVALID`. The key depends on the command: | Key | Set by | | ---------- | ------------------------------------------------------------ | | `file` | `bb snippet create/edit/view`, `bb issue create --body-file` | | `bodyFile` | `bb pr edit --body-file` only | | `path` | `bb api -F key=@file`, `bb api --input <file>` | `bb snippet view --file` also attaches `available`, the list of filenames the snippet actually contains. `bb pr edit --body-file` only reports `5003` when the read failed with `ENOENT`. Any other read failure (a permission error, or pointing at a directory) is reported as [9999 UNKNOWN](#9999---unknown). *** ## Context errors (6xxx) [Section titled “Context errors (6xxx)”](#context-errors-6xxx) ### 6001 - CONTEXT\_REPO\_NOT\_FOUND [Section titled “6001 - CONTEXT\_REPO\_NOT\_FOUND”](#6001---context_repo_not_found) **Message:** Could not determine repository **Cause:** The CLI couldn’t figure out which repository to use. **Solution:** 1. Use explicit flags: ```bash bb pr list -w myworkspace -r myrepo ``` 2. Set a default: ```bash bb config set defaultWorkspace myworkspace ``` 3. Run from within a cloned Bitbucket repository See [Understanding Repository Context](/guides/repository-context/) for details. ### 6002 - CONTEXT\_WORKSPACE\_NOT\_FOUND [Section titled “6002 - CONTEXT\_WORKSPACE\_NOT\_FOUND”](#6002---context_workspace_not_found) **Message:** Could not determine workspace **Cause:** The CLI couldn’t figure out which workspace to use. **Solution:** 1. Use the `-w` flag: ```bash bb repo list -w myworkspace ``` 2. Set a default workspace: ```bash bb config set defaultWorkspace myworkspace ``` *** ## Network errors (7xxx) [Section titled “Network errors (7xxx)”](#network-errors-7xxx) ### 7001 - NETWORK\_ERROR [Section titled “7001 - NETWORK\_ERROR”](#7001---network_error) **Cause:** The request failed before an HTTP response was received (offline, DNS issue, proxy/TLS issue, etc.). Transient failures (dropped connections, temporary DNS errors, timeouts) on read requests are automatically retried up to 3 times with exponential backoff before this error surfaces. Permanent-looking failures (e.g. unknown host, connection refused) and write requests fail immediately. `7001` has two distinct messages. The connectivity one: > Network error: Unable to reach Bitbucket API. Run with DEBUG=true for details. If you’re behind a proxy or using a custom CA, check your environment. And the timeout one, when the server accepted the connection but never answered: > Network error: Request to Bitbucket API timed out after 30000ms. The server accepted the connection but did not respond in time. Increase or disable the timeout via BB\_HTTP\_TIMEOUT (milliseconds; set BB\_HTTP\_TIMEOUT=0 to disable), or run with DEBUG=true for details. **Solution:** * Check internet and DNS connectivity * Verify proxy/TLS settings if applicable * If the message says *timed out*, raise or remove the 30-second default: ```bash BB_HTTP_TIMEOUT=60000 bb pr list # 60 seconds BB_HTTP_TIMEOUT=0 bb pr list # no timeout ``` See [Environment Variables](/reference/environment-variables/) for the full list. *** ## Output formatting errors (8xxx) [Section titled “Output formatting errors (8xxx)”](#output-formatting-errors-8xxx) ### 8001 - JQ\_FAILED [Section titled “8001 - JQ\_FAILED”](#8001---jq_failed) **Message:** jq evaluation failed: `<jq compiler error>` **Cause:** The expression passed to `--jq` is invalid or produced a runtime error. **Solution:** * Test the expression interactively against the full output first: ```bash bb pr list --json | jq '<expression>' ``` * The embedded jq is jq 1.8.x; module imports (`include`, `import`) are not supported. * Remember `--jq` runs *after* field projection — when combined with `--json fields`, the input is already a flat array (the wrapper has been dropped). ### 8002 - JSON\_FORMAT\_INVALID [Section titled “8002 - JSON\_FORMAT\_INVALID”](#8002---json_format_invalid) `8002` has exactly two messages. **`--jq requires --json`** — add `--json`, with or without a field list: ```bash bb pr list --json --jq '.count' ``` `bb api` is exempt, because its output is already JSON: `bb api /repositories/my-ws --jq '.values[].name'` needs no `--json`. This one prints as plain text on stderr (`✗ --jq requires --json`) rather than as a JSON envelope, because JSON mode was never enabled — scripts cannot parse `.code` for it. **`--json field list cannot be empty`** — triggered by `--json ""` or `--json ,,,`. Drop the argument to get the full output, or name at least one field: ```bash bb pr list --json bb pr list --json id,title ``` *** ## Shell completion errors (9001–9002) [Section titled “Shell completion errors (9001–9002)”](#shell-completion-errors-90019002) ### 9001 - COMPLETION\_INSTALL\_FAILED [Section titled “9001 - COMPLETION\_INSTALL\_FAILED”](#9001---completion_install_failed) **Message:** Failed to install completions: `<reason>` **Cause:** `bb completion install` couldn’t write the shell completion hooks — typically because the target shell profile isn’t writable, or the underlying `tabtab` install failed. **Solution:** * Check write permissions on your shell rc file (e.g. `~/.zshrc`, `~/.bashrc`) * Re-run with `DEBUG=true bb completion install` for the underlying error * If the issue persists, install completions manually by following your shell’s documentation for `tabtab` ### 9002 - COMPLETION\_UNINSTALL\_FAILED [Section titled “9002 - COMPLETION\_UNINSTALL\_FAILED”](#9002---completion_uninstall_failed) **Message:** Failed to uninstall completions: `<reason>` **Cause:** `bb completion uninstall` couldn’t remove the completion hooks — usually because the rc file isn’t writable or the entry was already removed manually. **Solution:** * Check write permissions on your shell rc file * Manually remove the `tabtab` block from your shell rc file if needed *** ## Unknown errors (9999) [Section titled “Unknown errors (9999)”](#unknown-errors-9999) ### 9999 - UNKNOWN [Section titled “9999 - UNKNOWN”](#9999---unknown) **Message:** An unexpected error occurred **Cause:** The CLI encountered an error that doesn’t fit any known category. **Solution:** * Check the error message for details * Retry the command * If the issue persists, [report it](https://github.com/0pilatos0/bitbucket-cli/issues) with full debug output: ```bash DEBUG=true bb <your-command> 2>&1 ``` *** ## Exit codes and error codes [Section titled “Exit codes and error codes”](#exit-codes-and-error-codes) `0` on success, `1` on any failure. The exit status never carries the error code — read it from the stderr payload instead: ```bash bb pr view 999 --json 2> err.json || jq -r '.code' err.json # 2002 ``` That payload is a single-line JSON object: ```json {"name":"APIError","code":2002,"message":"Pull request 999 not found in acme/demo.","context":{"status":404,"method":"GET","url":"/repositories/acme/demo/pullrequests/999"},"statusCode":404} ``` See [Exit Codes in the scripting guide](/guides/scripting/#exit-codes) for a worked example, and [JSON Output](/reference/json-output/) for every payload field and the `context` shape per code. ## Handling errors in scripts [Section titled “Handling errors in scripts”](#handling-errors-in-scripts) Keep stdout and stderr on separate files. Folding stderr into the data file (`> prs.json 2>&1`) puts the error envelope — and any warning the CLI prints — inside `prs.json`, which breaks `jq` on the next line. ```bash #!/bin/bash set -euo pipefail if ! bb pr list -w myworkspace -r myrepo --json > prs.json 2> pr-error.json; then echo "Failed to list PRs: $(jq -r '.message // "unknown error"' pr-error.json)" exit 1 fi jq -r '.pullRequests[].title' prs.json ``` # Global Flags > Flags accepted by every bb command These flags are accepted by every `bb` command — the same set `bb --help` prints. `--limit` and `--all` look global but are not; see [List-command flags](#list-command-flags). ## Quick reference [Section titled “Quick reference”](#quick-reference) | Flag | Type | Default | Description | | ----------------------------- | ------------ | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | `--json [fields]` | optional CSV | *off* | Emit machine-readable JSON. Pass a comma-separated field list to project the output. | | `--jq <expression>` | string | *off* | Run the JSON output through an in-process `jq` filter. Requires `--json` everywhere except `bb api`. | | `--no-color` | boolean | colors on | Disable ANSI colors. Also honoured: `NO_COLOR`, `FORCE_COLOR`. | | `--no-unicode` | boolean | Unicode on | Use ASCII fallbacks for separators, arrows, and status icons. Also honoured: `BB_NO_UNICODE`. | | `--no-truncate` | boolean | *off* | Show full values in table output without truncating long cells. | | `--locale <locale>` | BCP-47 | system | Locale for date/time formatting (e.g. `de-DE`, `ja-JP`). Falls back to `BB_LOCALE`, then `LC_TIME`/`LC_ALL`/`LANG`, then `en-US`. | | `-w, --workspace <workspace>` | string | git remote / env / config | Override the workspace. | | `-r, --repo <repo>` | string | git remote | Override the repository. | | `-h, --help` | boolean | — | Print help for the command. | | `-V, --version` | boolean | — | Print the CLI version. | The positive forms `--color`, `--unicode` and `--truncate` are also accepted, even though `bb --help` does not list them. Only `--color` changes anything — see [Precedence summary](#precedence-summary). `bb help <command>` is equivalent to `bb <command> --help` and works at every depth (`bb help pr`, `bb help pr comments`). The root `Commands:` list does not show `help`, but it is there. ## Output flags [Section titled “Output flags”](#output-flags) ### `--json [fields]` [Section titled “--json \[fields\]”](#--json-fields) Switch a command to JSON output. With no argument, the full response is printed. Pass a comma-separated field list to project to just those keys: ```bash bb pr list --json bb pr list --json id,title,state ``` JSON mode also disables spinners, colors, and progress notes so the output is safe to pipe. `--json` takes an optional value, so a bare `--json` swallows the next plain token. Put it after the subcommand: ```bash bb pr list --json # correct bb --json=id,title pr list # correct — the '=' form swallows nothing bb --json pr list # error 5002 ``` The last one fails with `--json consumed 'pr' as its field list, so 'list' was parsed as a top-level command.` — rendered as a JSON envelope, since `--json` was set. The other global flags are not position-sensitive in this way. ### `--jq <expression>` [Section titled “--jq \<expression>”](#--jq-expression) Filter the JSON output through a `jq` expression. The filter runs in-process via the embedded jq engine, so you don’t need the `jq` binary installed. Requires `--json`: ```bash bb pr list --json --jq '.pullRequests[] | select(.state == "OPEN") | .title' ``` `bb api` is the one exception. Its output is already JSON, so it takes `--jq` on its own: ```bash bb api /repositories/my-ws --jq '.values[].name' ``` Everywhere else, `--jq` without `--json` fails with `--jq requires --json` (error 8002), printed as plain text on stderr rather than as a JSON envelope. Field projection runs *before* jq and drops the wrapper key, so when you combine `--json <fields>` with `--jq` the filter sees a flat array — start it with `.[]`, not `.pullRequests[]`: ```bash bb pr list --json id,title --jq '.[] | .title' ``` ### `--no-truncate` [Section titled “--no-truncate”](#--no-truncate) Show table cells in full. By default, long values (pull request descriptions, comment bodies, branch names) are truncated to keep rows on one line. `--no-truncate` disables that for the current invocation: ```bash bb pr comments list 42 --no-truncate ``` The truncation suffix is the three ASCII characters `...` and it counts against the column budget, so a 50-character cap yields 47 characters plus `...`. `--no-truncate` affects table output only — JSON payloads are never truncated, so passing it alongside `--json` does nothing. ### `--no-color` and `--no-unicode` [Section titled “--no-color and --no-unicode”](#--no-color-and---no-unicode) `--no-color` disables ANSI colors. `--no-unicode` swaps Unicode separators and status glyphs for plain ASCII equivalents — useful for log aggregators that mangle Unicode, or terminals that don’t render the symbols cleanly. Colors switch off on their own when stdout is not a TTY, so piping to a file already gives you plain text. Unicode does not: `bb pr list > out.txt` still writes the `─` separator rules, `→` branch arrows and `✓`/`✗`/`○` status glyphs. Pass `--no-unicode` or set `BB_NO_UNICODE` if you need ASCII in a redirect. Tables themselves are already ASCII — the header underline is plain `-` characters and there are no vertical bars or outer border — so `--no-unicode` does not change the table frame. The two environment variables are not symmetric: * `NO_COLOR` triggers on any value, including the empty string. Both `FORCE_COLOR` (any value except `0`) and a literal `--color` in argv override it. * `BB_NO_UNICODE` triggers on any non-empty value and cannot be overridden per command. `--unicode` is accepted but has no effect while `BB_NO_UNICODE` is set — unset the variable instead. ## List-command flags [Section titled “List-command flags”](#list-command-flags) `--limit` and `--all` are options on list commands, not global flags. `bb pr view --limit 5` fails with `error: unknown option '--limit'`. ### `--limit <n>` [Section titled “--limit \<n>”](#--limit-n) Cap the number of items returned. The default is 25 on every list command. This caps items, not pages. The CLI fetches up to 50 items per request and keeps paging until the cap is met, so `--limit 200` makes four round trips. Values below 1 fail with `--limit must be a positive integer`. ### `--all` [Section titled “--all”](#--all) Fetch every page. `--all` overrides `--limit`. Both flags are available on these twelve commands: * `bb repo list` * `bb pr list` * `bb pr activity` * `bb pr comments list` * `bb snippet list` * `bb snippet comments list` * `bb pipeline list` * `bb commit list` * `bb status list` * `bb issue list` * `bb workspace list` * `bb project list` `bb pr checks`, `bb pr reviewers list`, `bb repo default-reviewers list` and `bb config list` are single-request and accept neither. `bb api` uses `--paginate` instead. When `--limit` cuts a table short, the CLI prints a hint: ```text Showing 25 pull requests. Use --limit <n> or --all to see more. ``` That hint is table output only. Under `--json` nothing is printed, so compare the envelope’s `count` against your limit yourself. ## Context flags [Section titled “Context flags”](#context-flags) ### `-w, --workspace` and `-r, --repo` [Section titled “-w, --workspace and -r, --repo”](#-w---workspace-and--r---repo) Override the workspace and repository for the current command: ```bash bb pr list -w myworkspace -r myrepo ``` Repository-scoped commands fall back to the git remote of the current directory. Workspace-only commands never look at git — they resolve `--workspace`, then `BB_WORKSPACE`, then `defaultWorkspace`, and fail with `No workspace specified.` if none is set. That covers `bb workspace view`, every `bb project` and `bb snippet` command, `bb repo list`, `bb repo create`, `bb repo clone`, and `bb api` when it fills a `{workspace}` placeholder. Being inside a Bitbucket clone is not enough for those. The full order is in [Environment Variables](/reference/environment-variables/#resolution-order), with worked examples in [Understanding Repository Context](/guides/repository-context/). ## Locale flag [Section titled “Locale flag”](#locale-flag) ### `--locale <locale>` [Section titled “--locale \<locale>”](#--locale-locale) Pin a BCP-47 locale tag for date/time formatting. This affects every human-readable date the CLI prints — PR timestamps, activity entries, comment dates. JSON output is locale-independent. ```bash bb pr list --locale de-DE bb pr view 42 --locale ja-JP ``` If `--locale` is unset, the CLI walks `BB_LOCALE`, then the POSIX locale variables in the order `LC_TIME` → `LC_ALL` → `LANG`, then falls back to `en-US`. Note that `LC_TIME` is checked *before* `LC_ALL`, which is the reverse of the usual POSIX override order — if you set both, `LC_TIME` wins here. Values are normalised before use: a `.UTF-8` codeset or `@euro` modifier suffix is stripped, `_` becomes `-`, and `C` / `POSIX` map to `en-US`. An invalid BCP-47 tag never errors — it silently falls back to `en-US`. ## Precedence summary [Section titled “Precedence summary”](#precedence-summary) For settings that can come from multiple sources, the order is usually: 1. Command-line flag 2. Environment variable 3. Config file 4. Built-in default Two documented exceptions: `FORCE_COLOR` beats `--no-color`, and `--unicode` cannot override `BB_NO_UNICODE`. Color has one more wrinkle. `--color` is the highest-precedence color input of all — ahead of `FORCE_COLOR`, `--no-color` and `NO_COLOR` — and it is matched by a raw scan of argv. So `bb pr diff 42 --color never` turns global color on even though it leaves the diff body uncolored, because `bb pr diff` takes `--color <when>` with the choices `auto`, `always` and `never`. ## See also [Section titled “See also”](#see-also) * [Environment Variables](/reference/environment-variables/) — env-var equivalents and precedence * [JSON Output](/reference/json-output/) — schema, field projection, scripting tips * [Configuration File](/reference/configuration/) — persistent settings # JSON Output > Reference for JSON output behavior across all commands All commands support the global `--json` flag, with optional field selection and a built-in `--jq` filter modeled on the [`gh` CLI](https://cli.github.com/manual/gh_help_formatting). In `--json` mode stdout carries the JSON document and nothing else. The update-available banner and automatic-retry notices are suppressed, and errors go to stderr — so `bb … --json > out.json` is safe. ## Quick usage [Section titled “Quick usage”](#quick-usage) ```bash # Full JSON output bb pr list --json # Project to a comma-separated field list bb pr list --json id,title,state # Filter through jq (no external jq binary required) bb pr list --json id,title,state --jq '.[] | select(.state == "OPEN") | .title' # Disable color formatting and return JSON bb repo view --json --no-color ``` Tip Discover the exact JSON shape of any command by running it with `--json` and piping to `jq .`: ```bash bb <command> --json 2>/dev/null | jq . ``` ## Field selection (`--json fields`) [Section titled “Field selection (--json fields)”](#field-selection---json-fields) Pass a comma-separated field list to project the output to just those fields, matching the way `gh` CLI handles `--json`: ```bash bb pr list --json id,title,state bb pr list --json id,title,author.display_name ``` **Rules:** * Bare `--json` (no field list) keeps the full output — backwards compatible. * Top-level field names become the keys of each result object verbatim, including dotted paths (`author.display_name` becomes the literal key `"author.display_name"`). * Dotted paths traverse nested objects; missing intermediates yield `null`. * If the output is already an array, each item is projected. * If the output is an envelope object, the CLI looks for the first of these keys holding an **array** and projects that array instead, dropping the envelope — the result is a flat array. This matches `gh` CLI semantics. ```text pullRequests repositories snippets comments reviewers activities statuses files pipelines commits issues workspaces projects values ``` * If no key in that list holds an array, the envelope object itself is projected. #### Example: `bb pr list --json id,title,author.display_name` [Section titled “Example: bb pr list --json id,title,author.display\_name”](#example-bb-pr-list---json-idtitleauthordisplay_name) ```json [ { "id": 42, "title": "Add feature", "author.display_name": "Alice" }, { "id": 41, "title": "Fix bug", "author.display_name": "Bob" } ] ``` #### Before / after: shape change after projection [Section titled “Before / after: shape change after projection”](#before--after-shape-change-after-projection) `bb pr list --json` returns the full envelope with metadata and a named array: ```json { "workspace": "myworkspace", "repoSlug": "myrepo", "state": "OPEN", "filters": { "mine": false }, "count": 2, "pullRequests": [ { "id": 42, "title": "Add feature", "state": "OPEN", "author": { "display_name": "Alice", "nickname": "alice" }, "links": { "html": { "href": "..." } } }, { "id": 41, "title": "Fix bug", "state": "OPEN", "author": {...}, "links": {...} } ] } ``` The same command with `--json id,title,state` drops the envelope and projects each item to a flat array of just those fields: ```json [ { "id": 42, "title": "Add feature", "state": "OPEN" }, { "id": 41, "title": "Fix bug", "state": "OPEN" } ] ``` This is why `--jq` filters use `.[]` after projection (`.[] | select(...)`) but `.pullRequests[]` against the full envelope. #### Trap: envelopes whose array key is not in the list [Section titled “Trap: envelopes whose array key is not in the list”](#trap-envelopes-whose-array-key-is-not-in-the-list) `bb pipeline view` returns `{ workspace, repoSlug, pipeline, steps }`. `steps` is not a wrapper key, so nothing is unwrapped and the field list is applied to the envelope — where `build_number` does not exist: ```bash bb pipeline view 7 --json build_number ``` ```json { "build_number": null } ``` Use `--jq` to reach into the envelope instead: ```bash bb pipeline view 7 --json --jq '.pipeline.build_number' ``` `bb pipeline logs` (without `--step`) puts its array under `steps` too. `bb snippet view --files` returns `files` as an **object**, not an array, so it is not unwrapped either. The reverse trap also exists. `bb pr view` returns a bare pull request, and that payload carries a `reviewers` array — a wrapper key — so `bb pr view 42 --json links.html.href` projects the reviewers instead of the pull request. Use `--jq` against the full output: ```bash bb pr view 42 --json --jq '.links.html.href' ``` `bb api --paginate` merges every page into `{"values": [...]}`, and `values` **is** a wrapper key, so projection does unwrap it: ```bash bb api /repositories/my-ws --paginate --json name,full_name ``` ## Built-in jq (`--jq`) [Section titled “Built-in jq (--jq)”](#built-in-jq---jq) The `--jq <expression>` flag pipes the JSON output through an embedded jq engine ([jq-wasm](https://www.npmjs.com/package/jq-wasm)) — no external `jq` binary required, no `bash` pipe to fail on Windows. ```bash # One value per line (strings come out quoted — see the raw-output note below) bb pr list --json --jq '.pullRequests[].title' # Combine with field selection (jq runs after projection) bb pr list --json id,title,state --jq '.[] | select(.state == "OPEN") | .title' # Aggregate bb pr list --json --jq '.count' # Repository names bb repo list --json --jq '.repositories[].full_name' # Diff file paths bb pr diff 42 --stat --json --jq '.files[].path' # Auth status as a bare boolean bb auth status --json --jq '.authenticated' # Project + format with jq string interpolation (external jq -r for raw TSV) bb pr list --json id,title,author.display_name \ | jq -r '.[] | "\(.id)\t\(.["author.display_name"])\t\(.title)"' # Pull request URLs bb pr list --json --jq '.pullRequests[].links.html.href' # Project a nested URL out of a single resource bb repo view --json links.html.href --jq '.["links.html.href"]' # Top open PRs by author with built-in jq (no projection — full shape) bb pr list --json --jq '.pullRequests | group_by(.author.display_name) | map({ author: .[0].author.display_name, count: length }) | sort_by(-.count)' ``` Every expression above also works with an external `jq` binary — pipe the full output instead: `bb pr list --json | jq '.pullRequests[].title'`. **Rules:** * There is no raw-output switch. `--jq` behaves like `jq` **without** `-r`, so string results keep their quotes: ```bash bb pr list --json --jq '.pullRequests[].title' # "Add feature" # "Fix bug" ``` When a script needs unquoted text, pipe the full JSON to an external `jq -r`: ```bash bb pr list --json | jq -r '.pullRequests[].title' # Add feature # Fix bug ``` * `--jq` requires `--json`. Using `--jq` alone exits non-zero with `✗ --jq requires --json`. That message prints as plain text on stderr, not as a JSON envelope, because JSON mode was never enabled. * `bb api` is the exception: its output is already JSON, so `bb api /repositories/my-ws --jq '.values[].name'` works without `--json`. * jq runs *after* field projection, so `.` refers to the projected shape — a flat array when both `--json fields` and a wrapper-style command are involved. * Invalid jq expressions exit non-zero with the underlying jq compiler error (error code [8001](/reference/error-codes/#8001---jq_failed)). Caution The embedded jq is jq 1.8.x. Module imports (`include`, `import`) and filesystem-dependent features are not supported. ## Output patterns [Section titled “Output patterns”](#output-patterns) ### Pattern 1: collection (list commands) [Section titled “Pattern 1: collection (list commands)”](#pattern-1-collection-list-commands) Used by: `pr list`, `repo list`, `pr comments list`, `pr activity`, `snippet list`, `snippet comments list`, `pipeline list`, `commit list`, `status list`, `issue list`, `workspace list`, `project list` Returns an envelope with metadata, a `count`, and a named array: ```json { "workspace": "myworkspace", "repoSlug": "myrepo", "state": "OPEN", "filters": { "mine": false }, "count": 2, "pullRequests": [...] } ``` **Common envelope fields:** | Field | Type | Present in | | ----------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `workspace` | string | All collections except `workspace list` (whose slugs live in the items) | | `repoSlug` | string | Repository-scoped collections: `pr list`, `pr comments list`, `pr activity`, `pipeline list`, `commit list`, `status list`, `issue list` | | `count` | number | All collections | | `state` | string | `pr list` | | `filters` | object | `pr list`, `pr activity`, `pr comments list`, `issue list`, `workspace list` — always present, with an unset value inside (`{"mine": false}`, `{"types": []}`, `{"resolution": null}`) or `{}` | | `commit` | string | `status list` | | `sort` | string | `pipeline list` | **Collection key names:** | Command | Array key | | ----------------------- | -------------- | | `pr list` | `pullRequests` | | `repo list` | `repositories` | | `pr comments list` | `comments` | | `pr activity` | `activities` | | `pipeline list` | `pipelines` | | `commit list` | `commits` | | `status list` | `statuses` | | `issue list` | `issues` | | `workspace list` | `workspaces` | | `project list` | `projects` | | `snippet list` | `snippets` | | `snippet comments list` | `comments` | Three commands return collections without going through the shared list plumbing. They are not paginated and have no `--limit`/`--all`: | Command | Shape | | ----------------------------- | ---------------------------------------------------------------------------- | | `pr reviewers list` | `{ workspace, repoSlug, pullRequestId, count, reviewers }` | | `repo default-reviewers list` | `{ workspace, repoSlug, mode, count, reviewers }` | | `pr checks` | `{ pullRequestId, workspace, repoSlug, summary, statuses }` — **no `count`** | #### Example: `bb pr list --json` [Section titled “Example: bb pr list --json”](#example-bb-pr-list---json) ```json { "workspace": "myworkspace", "repoSlug": "myrepo", "state": "OPEN", "filters": { "mine": false }, "count": 2, "pullRequests": [ { "id": 42, "title": "Add feature", "state": "OPEN", "draft": false, "author": { "display_name": "Alice", "nickname": "alice" }, "source": { "branch": { "name": "feature/add-feature" } }, "destination": { "branch": { "name": "main" } }, "created_on": "2026-01-15T10:00:00.000000+00:00", "updated_on": "2026-01-16T14:30:00.000000+00:00", "links": { "html": { "href": "https://bitbucket.org/myworkspace/myrepo/pull-requests/42" } } } ] } ``` #### Example: `bb pr list --mine --json` [Section titled “Example: bb pr list --mine --json”](#example-bb-pr-list---mine---json) ```json { "workspace": "myworkspace", "repoSlug": "myrepo", "state": "OPEN", "filters": { "mine": true }, "count": 1, "pullRequests": [...] } ``` #### Example: `bb pr checks 42 --json` [Section titled “Example: bb pr checks 42 --json”](#example-bb-pr-checks-42---json) ```json { "pullRequestId": 42, "workspace": "myworkspace", "repoSlug": "myrepo", "summary": { "successful": 2, "failed": 0, "pending": 1 }, "statuses": [...] } ``` *** ### Pattern 2a: bare resource [Section titled “Pattern 2a: bare resource”](#pattern-2a-bare-resource) Used by: `pr view`, `pr create`, `pr edit`, `pr comments view`, `repo view`, `repo create`, `snippet view` (no `--file`/`--files`), `snippet create`, `snippet edit` Returns the raw Bitbucket API resource object directly, with no envelope: ```json { "type": "pullrequest", "id": 42, "title": "Add feature", "state": "OPEN", "author": {...}, "source": {...}, "destination": {...}, "participants": [...], "links": {...} } ``` Note Resource responses include the full Bitbucket API object. The exact fields depend on the resource type. Use `jq keys` to discover available fields: ```bash bb pr view 42 --json | jq 'keys' ``` ### Pattern 2b: enveloped resource [Section titled “Pattern 2b: enveloped resource”](#pattern-2b-enveloped-resource) The rest of the single-resource commands wrap the payload in a context envelope. Read the resource from the named key, not from the root: | Command | Shape | | --------------------------------------------------------- | ------------------------------------------------------------- | | `commit view` | `{ workspace, repoSlug, commit }` | | `issue view`, `issue create`, `issue edit`, `issue close` | `{ workspace, repoSlug, issue }` | | `project view`, `project create` | `{ workspace, project }` | | `workspace view` | `{ workspace }` (the workspace object) | | `status set` | `{ workspace, repoSlug, commit, status }` | | `pipeline view` | `{ workspace, repoSlug, pipeline, steps }` | | `pipeline run` | `{ workspace, repoSlug, pipeline }` | | `pipeline logs --step <uuid>` | `{ workspace, repoSlug, pipelineId, stepUuid, log }` | | `pipeline logs` (no `--step`) | `{ workspace, repoSlug, pipelineId, count, steps }` | | `snippet view --file <name>` | `{ file, content }` | | `snippet view --files` | `{ snippet, files }` (`files` is an object keyed by filename) | `pipeline view` and `pipeline logs` put their array under `steps`, which is not a projection wrapper key — see the trap above. *** ### Pattern 3: action (approve/merge/decline commands) [Section titled “Pattern 3: action (approve/merge/decline commands)”](#pattern-3-action-approvemergedecline-commands) Used by: `pr approve`, `pr decline`, `pr merge`, `pr ready`, `pr comments add/edit/delete/reply/resolve/unresolve`, `pr reviewers add/remove`, `auth logout` Returns a success indicator plus resource identifiers: ```json { "success": true, "pullRequestId": 42 } ``` Some action commands include the full resource in the response: ```json { "success": true, "pullRequestId": 42, "pullRequest": {...} } ``` Two action-style commands do **not** emit `success` — branch on their own key instead: * `auth login` → `{ "authenticated": true, "method": "oauth" | "api_token", "user": {...} }` * `pipeline stop` → `{ "workspace": "...", "repoSlug": "...", "pipelineId": "...", "stopped": true }` (`auth logout` does emit `success`: `{ "authenticated": false, "success": true }`, plus `"revokeFailed": true` when the OAuth token could not be revoked.) *** ### Pattern 4: mode-based (diff command) [Section titled “Pattern 4: mode-based (diff command)”](#pattern-4-mode-based-diff-command) Used by: `pr diff` (with `--stat`, `--web`, `--name-only`, or default diff mode) Returns context metadata plus mode-specific data. Every mode includes the same context envelope (`workspace`, `repoSlug`, `pullRequestId`, `mode`); the remaining fields depend on the mode. | Mode | Trigger | Mode-specific fields | | ----------- | ------------- | ------------------------------------------------------------- | | `diff` | (default) | `diff` (string — the raw unified diff text) | | `stat` | `--stat` | `filesChanged`, `totalAdditions`, `totalDeletions`, `files[]` | | `name-only` | `--name-only` | `files[]` (string array of paths) | | `web` | `--web` | `url` | #### `bb pr diff 42 --json` (default mode) [Section titled “bb pr diff 42 --json (default mode)”](#bb-pr-diff-42---json-default-mode) The default mode returns the raw unified diff as a single string under `diff`. Newlines are preserved, so the value is suitable for piping to `git apply` or writing to a `.patch` file. ```json { "workspace": "myworkspace", "repoSlug": "myrepo", "pullRequestId": 42, "mode": "diff", "diff": "diff --git a/src/index.ts b/src/index.ts\nindex abc123..def456 100644\n--- a/src/index.ts\n+++ b/src/index.ts\n@@ -1,3 +1,4 @@\n import { foo } from './foo';\n+import { bar } from './bar';\n \n export const main = () => {\n" } ``` Extract just the diff text in scripts. Use an external `jq -r` here — the built-in `--jq` would emit the value as a quoted, escaped JSON string: ```bash bb pr diff 42 --json | jq -r '.diff' > pr-42.patch ``` #### `bb pr diff 42 --stat --json` [Section titled “bb pr diff 42 --stat --json”](#bb-pr-diff-42---stat---json) ```json { "workspace": "myworkspace", "repoSlug": "myrepo", "pullRequestId": 42, "mode": "stat", "filesChanged": 3, "totalAdditions": 27, "totalDeletions": 11, "files": [ { "path": "src/index.ts", "additions": 10, "deletions": 3 } ] } ``` #### `bb pr diff 42 --name-only --json` [Section titled “bb pr diff 42 --name-only --json”](#bb-pr-diff-42---name-only---json) ```json { "workspace": "myworkspace", "repoSlug": "myrepo", "pullRequestId": 42, "mode": "name-only", "files": ["src/index.ts", "src/utils.ts"] } ``` #### `bb pr diff 42 --web --json` [Section titled “bb pr diff 42 --web --json”](#bb-pr-diff-42---web---json) ```json { "workspace": "myworkspace", "repoSlug": "myrepo", "pullRequestId": 42, "mode": "web", "url": "https://bitbucket.org/myworkspace/myrepo/pull-requests/42/diff" } ``` *** ### Pattern 5: auth & config (custom) [Section titled “Pattern 5: auth & config (custom)”](#pattern-5-auth--config-custom) These commands have unique output shapes: #### `bb auth status --json` [Section titled “bb auth status --json”](#bb-auth-status---json) ```json { "authenticated": true, "method": "oauth", "user": { "username": "myuser", "displayName": "My Name", "accountId": "70121:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }, "defaultWorkspace": "myworkspace", "tokenExpiresAt": 1767225600 } ``` `tokenExpiresAt` (a Unix timestamp in seconds) is present only for OAuth credentials. When no credentials are stored the whole payload is: ```json { "authenticated": false } ``` `method` is spelled differently by the two commands. `auth status` reports the stored value, `"basic"` or `"oauth"`; `auth login` reports `"api_token"` or `"oauth"` for the same credentials. Match on `"oauth"` versus everything else rather than on the literal `"api_token"`. #### `bb auth token --json` [Section titled “bb auth token --json”](#bb-auth-token---json) OAuth credentials return the access token: ```json { "token": "<access token>", "type": "bearer" } ``` API-token credentials return the base64 of `username:apiToken`: ```json { "token": "<base64 of username:apiToken>", "type": "basic" } ``` #### `bb config list --json` [Section titled “bb config list --json”](#bb-config-list---json) ```json { "configPath": "/Users/you/.config/bb/config.json", "config": { "username": "myuser", "defaultWorkspace": "myworkspace", "apiToken": "********", "skipVersionCheck": false } } ``` #### `bb config get <key> --json` [Section titled “bb config get \<key> --json”](#bb-config-get-key---json) ```json { "key": "defaultWorkspace", "value": "myworkspace" } ``` *** ## Scripting notes [Section titled “Scripting notes”](#scripting-notes) * Prefer `--json` in scripts rather than parsing text output. * Do not rely on text formatting symbols (`✓`, table separators, colors). * Prefer the built-in `--jq` and `--json fields` over external pipes — they avoid an extra binary dependency and behave identically across platforms. * Envelope keys (`count`, `pullRequests`, `repositories`, `success`) are owned by the CLI and stable. Item fields come straight from the Bitbucket API, so read `.pullRequests[].id` rather than assuming a shape for the whole item. * `pr list` returns lightweight PR objects. Use `pr view <id>` for full details including `participants` and `reviewers`. ## Errors [Section titled “Errors”](#errors) When a command fails, the CLI exits non-zero. * In normal mode, errors are plain text on stderr. * In `--json` mode, errors are compact JSON objects on stderr. Argument-parsing errors are still plain text Failures raised while parsing the command line — an unknown subcommand (`bb pr lst`) or an unknown option (`bb pr list --stat`) — are reported by the argument parser as plain text even under `--json`. An unknown **top-level** command (`bb prr --json`) does emit a JSON envelope. Scripts should treat a non-zero exit with unparseable stderr as a usage error. Example: ```bash bb config get invalidKey --json 2>error.json cat error.json # {"name":"BBError","code":4003,"message":"Unknown config key 'invalidKey'. Valid keys: username, defaultWorkspace, skipVersionCheck, versionCheckInterval, prCreateIncludeDefaultReviewers","context":{"key":"invalidKey"}} ``` Error JSON fields: | Field | Type | Description | | ------------ | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | Error class name (usually `BBError`; can also be `APIError`, `AuthError`, `GitError`, `ValidationError`) | | `code` | number | Numeric [error code](/reference/error-codes/) | | `message` | string | Human-readable message | | `context` | object | Optional structured metadata. Shape depends on `code` — see the table below | | `hint` | string | Optional. A single actionable next step, present only for `401`, `403`, and `404` failures where the CLI has advice to give. In human-readable mode the same text prints as a dimmed continuation line beneath the message. | | `statusCode` | number | `APIError` only. The upstream HTTP status. | | `response` | object | `APIError` only, and only when the upstream response had a body. The raw Bitbucket error payload. | `cause` (the underlying `Error`) and stack traces are never exposed in `--json` mode. Do not treat the field list above as closed: new optional keys such as `hint` may be added, so parse defensively rather than asserting an exact key set. #### `context` fields by error code [Section titled “context fields by error code”](#context-fields-by-error-code) The `context` object is omitted when there’s nothing useful to attach. When present, the shape is: | Code | Typical `context` keys | | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `1001` AUTH\_REQUIRED | *(none)* | | `1002` AUTH\_INVALID | `status` (HTTP status, OAuth verification failures only) | | `1003` AUTH\_EXPIRED | `status` (HTTP status from the token endpoint) | | `2001`–`2005` API\_\* | `status`, `method`, `url` — plus the top-level `statusCode` and `response` fields described above. `url` is the request path only; pagination and filter parameters the CLI sends are not part of it, though a query string you write yourself (`bb api '/repositories/acme?role=owner'`) is | | `3001` GIT\_NOT\_REPOSITORY | *(none — never thrown)* | | `3002` GIT\_COMMAND\_FAILED | `command`, `exitCode` | | `3003` GIT\_REMOTE\_NOT\_FOUND | `remote` | | `4001` CONFIG\_READ\_FAILED | *(none)* | | `4002` CONFIG\_WRITE\_FAILED | *(none)* | | `4003` CONFIG\_INVALID\_KEY | `key` | | `5001` VALIDATION\_REQUIRED | `field` (when thrown by `ValidationError`) | | `5002` VALIDATION\_INVALID | varies — usually `{ key, value }`, the offending option name, or the rejected ID | | `5003` FILE\_NOT\_FOUND | `file` (`snippet create/edit/view`, `issue create --body-file`), `bodyFile` (`pr edit --body-file`), or `path` (`bb api -F key=@file` / `--input`). `snippet view --file` also attaches `available`, the list of filenames in the snippet | | `6001` CONTEXT\_REPO\_NOT\_FOUND | *(none)* | | `6002` CONTEXT\_WORKSPACE\_NOT\_FOUND | *(none)* | | `7001` NETWORK\_ERROR | *(usually none; OAuth revoke failures include `status`, `body`)* | | `8001` JQ\_FAILED | `expression`, optional `exitCode` | | `8002` JSON\_FORMAT\_INVALID | *(none)* | | `9001` COMPLETION\_INSTALL\_FAILED | *(none)* | | `9002` COMPLETION\_UNINSTALL\_FAILED | *(none)* | | `9999` UNKNOWN | *(none)* | In automation, always check the process exit code before parsing stdout JSON. # Token Scopes > Required Bitbucket API token scopes for each bb command When you authenticate with an [API token](/getting-started/authentication/#api-token-for-cicd-and-headless-environments), you pick the scopes it grants. This page maps every `bb` command to the minimum scope it needs, so you can mint a token for one workflow and nothing more. Generate tokens at [Bitbucket API tokens](https://bitbucket.org/account/settings/api-tokens/). OAuth grants a fixed, narrower set `bb auth login` uses OAuth only when none of `--app-password`, `--with-token`, `-u` or `-p` are passed **and** `BB_API_TOKEN` is unset. The OAuth flow requests a hardcoded scope set — `account repository repository:admin pullrequest pullrequest:write` (legacy scope names, not the `<action>:<resource>:bitbucket` names used below) — and you cannot widen it, not even with a custom consumer. That covers repository, pull request, commit, build-status and workspace commands. It does **not** cover `bb pipeline`, `bb issue`, `bb snippet`, `bb project`, or `bb repo delete`. Use an API token for those. ## Scope reference [Section titled “Scope reference”](#scope-reference) Bitbucket Cloud API token scopes follow the format `<action>:<resource>:bitbucket`. The CLI uses these scopes: | Scope | Grants | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | `read:user:bitbucket` | Read user profiles — verifies any login, resolves your UUID for `bb pr list --mine`, and covers `bb workspace list` | | `read:repository:bitbucket` | List and view repositories, commits, and commit build statuses | | `write:repository:bitbucket` | Set commit build statuses | | `admin:repository:bitbucket` | Create repositories; add and remove default reviewers | | `delete:repository:bitbucket` | Delete repositories | | `read:pullrequest:bitbucket` | List, view, and diff pull requests; read comments, activity, checks, reviewers, and default reviewers | | `write:pullrequest:bitbucket` | Create, edit, approve, decline, merge, and mark pull requests ready; add/remove reviewers; add, edit, and delete comments | | `read:pipeline:bitbucket` | List and view pipelines and their steps, read step logs | | `write:pipeline:bitbucket` | Trigger and stop pipelines | | `read:issue:bitbucket` | List and view issues | | `write:issue:bitbucket` | Create, edit, comment on, and close issues | | `read:workspace:bitbucket` | List and view workspaces | | `read:project:bitbucket` | List and view projects | | `admin:project:bitbucket` | Create projects | | `read:snippet:bitbucket` | List and view snippets, read snippet comments | | `write:snippet:bitbucket` | Create, edit, and delete snippets; watch and unwatch; add, edit, and delete snippet comments | ## Command → scope map [Section titled “Command → scope map”](#command--scope-map) ### Auth (`bb auth …`) [Section titled “Auth (bb auth …)”](#auth-bb-auth-) | Command | Required scopes | | ---------------- | -------------------------------------------------------------------------- | | `bb auth login` | `read:user:bitbucket` (verifies the credentials) | | `bb auth logout` | *(none — local-only for API tokens; OAuth revoke uses the existing token)* | | `bb auth status` | `read:user:bitbucket` | | `bb auth token` | *(none — prints the locally-stored token)* | ### Repositories (`bb repo …`) [Section titled “Repositories (bb repo …)”](#repositories-bb-repo-) | Command | Required scopes | | ---------------------------------- | ----------------------------- | | `bb repo list` | `read:repository:bitbucket` | | `bb repo view` | `read:repository:bitbucket` | | `bb repo create` | `admin:repository:bitbucket` | | `bb repo delete` | `delete:repository:bitbucket` | | `bb repo default-reviewers list` | `read:pullrequest:bitbucket` | | `bb repo default-reviewers add` | `admin:repository:bitbucket` | | `bb repo default-reviewers remove` | `admin:repository:bitbucket` | `admin:` and `delete:` are separate scopes. A token with `admin:repository:bitbucket` can create repositories but cannot delete them. Default reviewers live under the pull request resource in Bitbucket’s API, which is why reading them needs a pull request scope while changing them needs the repository admin scope. `add` and `remove` also resolve the target account via `GET /users/{user}` first — that endpoint carries no scope of its own, but a token that cannot see the account will fail there. ### Pull requests (`bb pr …`) [Section titled “Pull requests (bb pr …)”](#pull-requests-bb-pr-) `read:pullrequest:bitbucket` covers `list`, `view`, `diff`, `checkout`, `activity`, `checks`, `comments list`, `comments view` and `reviewers list`. `write:pullrequest:bitbucket` covers `create`, `edit`, `ready`, `approve`, `decline`, `merge`, `reviewers add|remove`, and the comment mutations (`comments add|edit|reply|resolve|unresolve|delete`). Bitbucket’s API spec still maps the comment endpoints to the read scope, so a read-only token may be enough for `bb pr comments add` — grant the write scope anyway, that is the one to rely on. `bb pr list --mine` also needs `read:user:bitbucket` — it calls `GET /user` to resolve your UUID before filtering. So do the commands that take a `<user>` argument: `bb pr create --reviewer`, `bb pr reviewers add|remove`, and `bb repo default-reviewers add|remove` all resolve the handle you pass through `GET /users/{selected_user}` before making the change. Add `read:user:bitbucket` to any token that runs those. `bb pr checkout` runs `git fetch` and `git checkout` locally after reading the pull request, so it uses your normal git credentials too. No `bb pr` command needs `read:repository:bitbucket`. The CLI resolves the workspace and repository from your git remote (or `--workspace`/`--repo`), not from the API. ### Pipelines (`bb pipeline …`) [Section titled “Pipelines (bb pipeline …)”](#pipelines-bb-pipeline-) | Command | Required scopes | | ------------------ | -------------------------- | | `bb pipeline list` | `read:pipeline:bitbucket` | | `bb pipeline view` | `read:pipeline:bitbucket` | | `bb pipeline logs` | `read:pipeline:bitbucket` | | `bb pipeline run` | `write:pipeline:bitbucket` | | `bb pipeline stop` | `write:pipeline:bitbucket` | ### Commits and build statuses (`bb commit …`, `bb status …`) [Section titled “Commits and build statuses (bb commit …, bb status …)”](#commits-and-build-statuses-bb-commit--bb-status-) | Command | Required scopes | | ---------------- | ---------------------------- | | `bb commit list` | `read:repository:bitbucket` | | `bb commit view` | `read:repository:bitbucket` | | `bb status list` | `read:repository:bitbucket` | | `bb status set` | `write:repository:bitbucket` | ### Issues (`bb issue …`) [Section titled “Issues (bb issue …)”](#issues-bb-issue-) | Command | Required scopes | | ------------------ | ----------------------- | | `bb issue list` | `read:issue:bitbucket` | | `bb issue view` | `read:issue:bitbucket` | | `bb issue create` | `write:issue:bitbucket` | | `bb issue edit` | `write:issue:bitbucket` | | `bb issue close` | `write:issue:bitbucket` | | `bb issue comment` | `write:issue:bitbucket` | ### Workspaces (`bb workspace …`) [Section titled “Workspaces (bb workspace …)”](#workspaces-bb-workspace-) | Command | Required scopes | | ------------------- | ------------------------------------------------- | | `bb workspace list` | `read:workspace:bitbucket`, `read:user:bitbucket` | | `bb workspace view` | *(none — the endpoint is unscoped)* | `bb workspace list` calls `GET /workspaces`, which Bitbucket’s API spec scopes to `account` — the legacy name for `read:user:bitbucket`. Grant it alongside `read:workspace:bitbucket`. `GET /workspaces/{workspace}` carries no scope at all, so `bb workspace view` works with whatever grant already makes the workspace visible to you. ### Projects (`bb project …`) [Section titled “Projects (bb project …)”](#projects-bb-project-) | Command | Required scopes | | ------------------- | ------------------------- | | `bb project list` | `read:project:bitbucket` | | `bb project view` | `read:project:bitbucket` | | `bb project create` | `admin:project:bitbucket` | ### Snippets (`bb snippet …`) [Section titled “Snippets (bb snippet …)”](#snippets-bb-snippet-) | Command | Required scopes | | ---------------------------- | ------------------------- | | `bb snippet list` | `read:snippet:bitbucket` | | `bb snippet view` | `read:snippet:bitbucket` | | `bb snippet create` | `write:snippet:bitbucket` | | `bb snippet edit` | `write:snippet:bitbucket` | | `bb snippet delete` | `write:snippet:bitbucket` | | `bb snippet watch` | `write:snippet:bitbucket` | | `bb snippet unwatch` | `write:snippet:bitbucket` | | `bb snippet comments list` | `read:snippet:bitbucket` | | `bb snippet comments add` | `write:snippet:bitbucket` | | `bb snippet comments edit` | `write:snippet:bitbucket` | | `bb snippet comments delete` | `write:snippet:bitbucket` | As with pull request comments, Bitbucket’s API spec maps snippet comment writes to the read scope. Grant `write:snippet:bitbucket` anyway — that is the scope to rely on. ### Raw API (`bb api`) [Section titled “Raw API (bb api)”](#raw-api-bb-api) `bb api` needs whatever scope the endpoint you call requires — look the endpoint up in Atlassian’s Bitbucket Cloud API reference. A `403` from `bb api` means the token is missing that endpoint’s scope, not that the path is wrong. ### Local-only commands [Section titled “Local-only commands”](#local-only-commands) These don’t hit the API and don’t need any scope: * `bb repo clone` (builds the clone URL from workspace and repository names, then shells out to git — uses your normal git credentials) * `bb browse` (builds the URL from local git context) * `bb config` (all subcommands) * `bb completion` * `bb` (root, including the version-check) ## Common profiles [Section titled “Common profiles”](#common-profiles) ### Read-only automation (status checks, dashboards) [Section titled “Read-only automation (status checks, dashboards)”](#read-only-automation-status-checks-dashboards) ```text read:user:bitbucket read:repository:bitbucket read:pullrequest:bitbucket read:pipeline:bitbucket ``` ### Bot account that creates and merges pull requests [Section titled “Bot account that creates and merges pull requests”](#bot-account-that-creates-and-merges-pull-requests) ```text read:user:bitbucket read:pullrequest:bitbucket write:pullrequest:bitbucket ``` Add `read:repository:bitbucket` only if the bot also runs `bb repo`, `bb commit` or `bb status` commands. ### Repo provisioning automation [Section titled “Repo provisioning automation”](#repo-provisioning-automation) ```text read:user:bitbucket read:repository:bitbucket admin:repository:bitbucket delete:repository:bitbucket ``` Drop `delete:repository:bitbucket` unless the automation actually tears repositories down. ### CI/CD automation (trigger pipelines, report build statuses) [Section titled “CI/CD automation (trigger pipelines, report build statuses)”](#cicd-automation-trigger-pipelines-report-build-statuses) ```text read:user:bitbucket read:repository:bitbucket write:repository:bitbucket read:pipeline:bitbucket write:pipeline:bitbucket ``` ### Issue triage bot [Section titled “Issue triage bot”](#issue-triage-bot) ```text read:user:bitbucket read:repository:bitbucket read:issue:bitbucket write:issue:bitbucket ``` ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) If a command exits with [`2003` API\_FORBIDDEN](/reference/error-codes/#2003---api_forbidden), your token is missing the scope listed above. You can’t add scopes to an existing token — mint a new one and re-authenticate: ```bash bb auth logout echo "$NEW_TOKEN" | bb auth login -u your-username --with-token ``` `--with-token` reads the token from stdin, keeping it out of your shell history and out of `ps` output. `-p new-token` works too, but writes the secret into both.