A gh-equivalent CLI for Bitbucket Cloud. Work in progress.
bun installbun run src/index.ts --helpbbcli reads its configuration from $XDG_CONFIG_HOME/bbcli/config.json
(falls back to ~/.config/bbcli/config.json).
The config file carries your Atlassian email and a way to retrieve your Bitbucket API token. Create an API token at https://id.atlassian.com/manage-profile/security/api-tokens.
You need to generate a scope token (general ones doesn't work, don't know why) and add this scopes:
read:account
read:me
read:pipeline:bitbucket
read:pullrequest:bitbucket
read:repository:bitbucket
read:user:bitbucket
read:workspace:bitbucket
write:pullrequest:bitbucket
write:repository:bitbucket
write:user:bitbucket
The recommended form keeps the token out of the config file by having bbcli run an external command to fetch it. On Linux with libsecret:
{
"email": "you@example.com",
"token_command": [
"secret-tool", "lookup",
"service", "bbcli",
"account", "bitbucket_api_token"
]
}Then store the token in your keyring once:
secret-tool store --label='bbcli' \
service bbcli account bitbucket_api_tokentoken_command is an argv array, not a shell string — no shell
interpretation. If you need a pipeline, use ["sh", "-c", "..."]
explicitly. Any command that prints the token to stdout works:
pass show bitbucket/token, op read "op://Private/Bitbucket/token",
security find-generic-password -s bbcli -w on macOS, and so on.
If you would rather keep the token directly in the config file:
{
"email": "you@example.com",
"token": "ATATT3x..."
}If you choose this form, lock down the file permissions:
chmod 600 ~/.config/bbcli/config.jsonExactly one of token or token_command must be set — bbcli errors if
both or neither are present.
bun run src/index.ts auth statusOn success it prints Logged in to Bitbucket Cloud as <name> (<email>).
If the credentials are missing or invalid, it prints an actionable
error and exits non-zero.
When piping bb pr diff to a pager that opens less (e.g. delta,
bat, less itself), scrolling can break — keystrokes get echoed and
require Enter, instead of single-key navigation. The first invocation
after a recompile sometimes works; subsequent ones don't.
Root cause is upstream in Bun: its runtime issues TCSETS2 on stdin and
stderr at process exit, restoring the terminal to whatever state it
captured at startup. When that captured state has ICANON|ECHO set, the
terminal ends up in cooked mode for the downstream less, which then
can't get raw keystrokes.
Workaround — redirect both stdin and stderr away from the terminal:
bb pr diff <id> </dev/null 2>/dev/null | deltaOr alias it once:
alias bbdiff='bb pr diff </dev/null 2>/dev/null'
# then: bbdiff <id> | deltaCaveat: 2>/dev/null swallows error output. If you'd rather keep
errors visible, redirect to a file (2>/tmp/bb.err) instead.
# Run all tests
bun test
# Regenerate the Bitbucket API types from Atlassian's OpenAPI spec
bun run generate:apiThe generated schema lives at src/shared/bitbucket-http/generated.d.ts
and is committed. Re-run the generator when you need new endpoints or
when Atlassian publishes a spec update.