Bitbucket Cloud CLI
Command-line tool for managing Bitbucket Cloud via af bitbucket (alias af bb).
Setup
Bitbucket Cloud authentication is separate from Jira/Confluence. Atlassian API tokens scoped for Jira do not authenticate against Bitbucket Cloud — they return 401. Add the following to your project's .env:
BITBUCKET_USERNAME— Bitbucket username or workspace token label (falls back toATLASSIAN_EMAIL/JIRA_EMAIL)BITBUCKET_API_TOKEN— Workspace API token or app password (BITBUCKET_APP_PASSWORDis also accepted as a legacy alias)
Generate credentials:
- Workspace API token (recommended for automation) —
https://bitbucket.org/<workspace>/workspace/settings/api-tokens - App password —
https://bitbucket.org/account/settings/app-passwords/
Verify credentials with af bb whoami — it prints the authenticated account (and its account ID). If that fails, nothing else will.
Workspace and Repo Resolution
The target workspace and repo are resolved in this order:
--workspace W --repo Rflags (highest priority)af.json:{ "bitbucket": { "workspace": "myws", "repo": "myrepo" } }- The git
originremote, if it points atbitbucket.org - Error with help text
Read-Only Inspection (No Clone Needed)
Reach for this before you clone. af bb can read a remote Bitbucket repo directly over the API — file contents, directory listings, branches, tags, commits, and diffs — at any ref. If you only need to look at code (answer a question about a file, check whether a branch exists, see what changed between two refs), do it here rather than cloning or fetching. Everything in this section is read-only and safe to run speculatively.
Account and Repository
af bb whoami— the authenticated accountaf bb repo list [--query Q] [--role R] [--sort S]— repos in the workspace; needs only a workspace, so it works outside a Bitbucket cloneaf bb repo get— the resolved repository (repoalone defaults toget)
Branches and Tags
af bb branch list [--query Q] [--sort S]/af bb branch get <name>af bb tag list [--query Q] [--sort S]/af bb tag get <name>
branch and tag alone default to list. Both drain all pages.
Commits
af bb commit list [--branch B] [--include REF] [--exclude REF] [--limit N]--include/--excludeare repeatable;--limitmust be a positive integer (default 25)
af bb commit get <sha> [--diff | --diffstat | --patch]— pick at most one; bare form prints commit metadata
Source and Diffs
af bb src read <path> [--ref REF]— raw file content straight to stdoutaf bb src ls [path] [--ref REF] [--recursive]— browse a directory at a refaf bb diff <spec> [--stat]— diff a revspec, e.g.main..feature
--ref defaults to the repository's main branch. src has no default sub-action — you must say read or ls. diff requires a revspec.
Quick Reference
There is no per-subcommand help. af bb pr --help prints the single full command and flag listing — as does bare af bb or af bb help. Both af bb --help and af bitbucket --help are intercepted by af's router and print only a short stub, so reach for one of the others.
Pull Requests
af bb pr list [--state OPEN|MERGED|DECLINED|SUPERSEDED|ALL] [--mine | --author Q]af bb pr get <id>af bb pr diff <id>af bb pr create --title T [--from B] [--to B] [--description / --description-file F] [--reviewers a,b] [--draft]--fromalso accepts--source/--src;--toalso accepts--destination/--dest(af's own README uses the alias spelling)
af bb pr update <id> [--title T] [--description / --description-file F] [--reviewers a,b]af bb pr approve <id>af bb pr unapprove <id>af bb pr request-changes <id>af bb pr merge <id> [--strategy merge_commit|squash|fast_forward] [--close-source]af bb pr decline <id>af bb pr status <id>— build/commit statuses, grouped by commit ("is this PR green?")af bb pr reviewers <id> [--pending]— reviewers and their approval state;--pendingnarrows to those who have not respondedaf bb pr activity <id> [--limit N]— chronological feed of approvals, updates, and comments (--limitis a positive integer, default 25)
Reviewers must be passed as Bitbucket Cloud account IDs (not usernames). Use af bb members --query <name> to look them up.
pr status is informational and always exits 0, even when a status is FAILED. Never gate a script on its exit code — parse --json instead.
PR Comments
Comment body shape is determined by flags on add:
af bb pr comment list <pr-id> [--resolved | --unresolved]- The two flags are mutually exclusive. Resolution is a thread property: the filter keeps or drops whole threads by their root comment's state, so the replies of a matching thread are retained. It narrows
--jsonoutput too.
- The two flags are mutually exclusive. Resolution is a thread property: the filter keeps or drops whole threads by their root comment's state, so the replies of a matching thread are retained. It narrows
af bb pr comment get <pr-id> <cid>af bb pr comment add <pr-id> --body / --body-file [--file PATH --line N] [--reply-to CID]--file PATH --line Nmakes the comment an inline anchor--reply-to CIDthreads the comment as a reply
af bb pr comment update <pr-id> <cid> --body / --body-fileaf bb pr comment delete <pr-id> <cid>af bb pr comment resolve <pr-id> <cid>— resolve a comment threadaf bb pr comment reopen <pr-id> <cid>— reopen a resolved thread
PR Tasks
Tasks can stand alone or be anchored to a comment:
af bb pr task list <pr-id> [--resolved | --unresolved]- Mutually exclusive, and unlike the thread-rooted comment filter this is a flat match on the task's own state
af bb pr task add <pr-id> --body / --body-file [--on-comment CID]af bb pr task update <pr-id> <tid> [--body / --body-file] [--resolved | --unresolved]af bb pr task delete <pr-id> <tid>
Pipelines
af bb pipeline list [--branch B] [--status PENDING|IN_PROGRESS|SUCCESSFUL|FAILED|...]af bb pipeline get <uuid|build-number>af bb pipeline trigger [--branch B] [--commit SHA] [--custom NAME] [--var k=v]af bb pipeline stop <uuid>af bb pipeline steps <uuid>af bb pipeline logs <pipeline-uuid> <step-uuid> [--follow]
Member Lookup
af bb members [--query Q]— Look up account IDs for use with--reviewers
Output Formats
- Default: Markdown
- JSON: Add
--jsonto any subcommand for raw API responses
Six commands emit raw text by design and ignore --json, because their payload is already a file, a diff, or a log:
af bb src read(raw file bytes)af bb diff <spec>without--stat(raw unified diff)af bb commit get --diffandaf bb commit get --patchaf bb pr diff <id>(raw unified diff)af bb pipeline logs(raw step log)
Their --stat / --diffstat counterparts do honour --json.
Common Workflows
Inspect a remote repo without cloning it
# What repos are in the workspace? (works outside a Bitbucket clone)
af bb repo list --query payments
# What branches exist, and what landed recently?
af bb branch list --query release
af bb commit list --branch main --limit 10
# Read a file at a ref, and browse around it
af bb src read src/auth/login.ts --ref release/2.1
af bb src ls src/auth --ref release/2.1 --recursive
# What changed between two refs?
af bb diff main..feature/sso --stat # summary first
af bb diff main..feature/sso # then the full diff
Review a PR
af bb pr get 42
af bb pr status 42 # is it green?
af bb pr reviewers 42 --pending
af bb pr diff 42
af bb pr comment list 42 --unresolved
af bb pr task list 42 --unresolved
af bb pr activity 42 --limit 20
Triage what is still outstanding
# Only the threads and tasks still open — the fast pre-merge sweep
af bb pr comment list 42 --unresolved
af bb pr task list 42 --unresolved
# Resolve a thread once you've addressed it (reopen if it wasn't really fixed)
af bb pr comment resolve 42 9876543
af bb pr comment reopen 42 9876543
Create a PR from current branch
af bb pr create --title "Add SonarQube support" \
--description-file ./PR_DESCRIPTION.md \
--reviewers 557058:abc-123,557058:def-456
Leave an inline review comment
# Anchor a comment to a specific line of a file in the diff
af bb pr comment add 42 \
--file src/auth/login.ts --line 87 \
--body "This branch isn't covered by tests — can we add one?"
# Thread a reply
af bb pr comment add 42 --reply-to 9876543 --body "Good catch, fixing."
Add and resolve PR tasks
# Standalone task
af bb pr task add 42 --body "Update CHANGELOG before merge"
# Task anchored to an existing comment
af bb pr task add 42 --on-comment 9876543 --body "Rename this variable"
# Resolve when done
af bb pr task update 42 12345 --resolved
Approve and merge
af bb pr approve 42
af bb pr merge 42 --strategy squash --close-source
Trigger and watch a pipeline
# Trigger a custom pipeline with variables
af bb pipeline trigger --branch main --custom deploy-prod --var ENV=prod
# Watch logs as the step runs
af bb pipeline list --branch main --status IN_PROGRESS
af bb pipeline steps <pipeline-uuid>
af bb pipeline logs <pipeline-uuid> <step-uuid> --follow
Look up reviewer account IDs
# Reviewers must be account IDs, not usernames
af bb members --query "Jane"
af bb pr update 42 --reviewers 557058:abc-123
Tips
- Use the alias
af bb— every subcommand below also works underaf bitbucket - Don't clone to read —
af bb src read/src ls/diffanswer most "what's in this file / what changed" questions straight off the remote - Reviewers are account IDs only — usernames silently fail; always resolve via
af bb members - Workspace tokens beat app passwords — they're scoped per-workspace and easier to rotate
--jsonfor scripting — pipe throughjqfor automation- PR descriptions from files —
--description-file ./PR_BODY.mdavoids quoting hell in the shell
Error Handling
- Errors always print as plain text to stderr.
--jsondoes not wrap them in a JSON envelope — there is no{"error": ...}output, and the flag is not consulted on any error path. - Exit codes are only ever
0(success) or1(any error, auth failures included).401is an HTTP status, never a process exit code — if you see one, it typically means Bitbucket-Cloud-specific credentials are missing or a Jira-scoped Atlassian token was supplied. Check withaf bb whoami. af bb pr statusexits0even when a build status isFAILED. Gate on its--jsonpayload, not on$?.