Problem Statement
Developers using bb-cli alongside LLMs in their workflow are forced to context-switch to the Bitbucket browser UI to perform common PR operations: checking out PR branches, reading diffs, submitting reviews, checking PR status, and filtering PR lists by author. This constant switching between the terminal/LLM and the browser breaks focus and defeats the purpose of having an LLM assistant that can operate on your behalf.
The CLI needs a set of PR management commands -- inspired by GitHub's gh pr commands -- that allow an LLM agent (or the developer) to perform the full PR review lifecycle without ever leaving the terminal.
Solution
Implement five PR commands that cover the core PR review workflow end-to-end:
bb pr checkout <number> -- Fetch a PR's source branch and check it out locally, so the developer (or LLM) can inspect the code.
bb pr diff [<number>] -- Retrieve the raw diff of a PR from the Bitbucket API. When no number is given, infer the PR from the current branch.
bb pr review [<number>] -- Submit a review action on a PR: approve, request changes (with a message), or leave a general comment. Supports --body and --body-file (including stdin) for LLM-friendly piping.
bb pr status -- Show a summary of PRs relevant to the current user: the PR for the current branch, PRs authored by the user, and PRs requesting the user's review.
bb pr list --author <nickname> -- Enhance the existing pr list command with an --author filter. Supports @me to resolve to the authenticated user's nickname.
All commands follow existing bb-cli conventions: workspace/repo resolution (flags → config → git remote), Basic Auth via config, and Cobra command registration.
User Stories
- As a developer using an LLM assistant, I want to run
bb pr checkout 42 so that the LLM can check out a PR's branch without me navigating Bitbucket.
- As a developer, I want
bb pr checkout to use the PR's source branch name as the local branch name by default, so that branch names are intuitive and consistent.
- As a developer, I want to override the local branch name with
bb pr checkout 42 --branch my-local-name, so that I can avoid conflicts with existing local branches.
- As a developer, I want
bb pr checkout 42 --force to reset an existing local branch to the latest PR state, so that I can re-checkout after the PR has been updated without manually deleting the branch.
- As a developer using an LLM, I want
bb pr diff 42 to return the raw unified diff from Bitbucket's API, so the LLM can parse and analyze the changes.
- As a developer, I want
bb pr diff (no number) to infer the PR from my current branch, so the LLM can run it without needing to know the PR number.
- As a developer, I want
bb pr diff --name-only to list only the changed file names, so the LLM can quickly scope which files to review.
- As a developer using an LLM, I want
bb pr review 42 --approve to approve a PR from the terminal, so I don't have to open the browser.
- As a developer, I want
bb pr review 42 --request-changes --body "Please fix the error handling" to request changes with a message, so the LLM can submit review feedback on my behalf.
- As a developer, I want
bb pr review 42 --comment --body "Looks good overall" to leave a general comment on a PR.
- As a developer, I want to combine
--approve with --comment --body "LGTM" to approve and leave a comment in one command.
- As a developer, I want
--approve and --request-changes to be mutually exclusive, so that contradictory actions are prevented.
- As a developer, I want
bb pr review (no number) to infer the PR from my current branch, matching the behavior of bb pr diff.
- As a developer, I want
bb pr review 42 --comment --body-file review.md to read the comment body from a file, so the LLM can write a review to a file and submit it.
- As a developer, I want
bb pr review 42 --comment --body-file - to read the comment body from stdin, so the LLM can pipe content directly.
- As a developer, I want
bb pr review with no action flags to fail with a clear usage message, so I don't accidentally submit an empty review.
- As a developer, I want
bb pr status to show the PR for my current branch (if any), so I can quickly see its state.
- As a developer, I want
bb pr status to show open PRs I've authored, so I can track my own work.
- As a developer, I want
bb pr status to show PRs requesting my review, so I know what needs my attention.
- As a developer, I want each section of
bb pr status to show up to 10 PRs with approval counts, so the output is informative but not overwhelming.
- As a developer, I want
bb pr list --author zoldyzdk to filter PRs by author nickname.
- As a developer, I want
bb pr list --author @me to resolve to my authenticated user's nickname, so I don't have to remember it.
- As a developer, I want
bb pr list (without --author) to continue showing all PRs, preserving the existing default behavior.
- As a developer, I want clear error messages when a PR number cannot be inferred from the current branch (no matching PR or multiple matches).
- As a developer, I want all new commands to respect the existing workspace/repo resolution order (flags → config → git remote).
Implementation Decisions
Modules to build or modify
-
API Client (internal/api/client.go) -- Add Put() and Delete() HTTP methods, mirroring the existing Get() and Post() pattern. Needed for future unapprove/remove-request-changes operations and other endpoints.
-
PR API (internal/api/pullrequests.go) -- Add new Bitbucket API methods:
GetPullRequestDiff -- GET /repositories/{w}/{r}/pullrequests/{id}/diff, returns raw diff as string
ApprovePullRequest -- POST /repositories/{w}/{r}/pullrequests/{id}/approve
RequestChanges -- POST /repositories/{w}/{r}/pullrequests/{id}/request-changes
CreatePullRequestComment -- POST /repositories/{w}/{r}/pullrequests/{id}/comments with body content
- Enhance
ListPullRequests to accept a Bitbucket query string parameter (q=...) for author and reviewer filtering
-
PR Resolution module (cmd/pr_resolve.go) -- NEW deep module. Encapsulates the logic of inferring a PR from the current git branch:
getCurrentBranch() -- wraps git rev-parse --abbrev-ref HEAD
resolvePRFromCurrentBranch(client, workspace, repo) -- queries Bitbucket for open PRs matching the current branch name; returns the PR if exactly one match, errors on zero or multiple matches
- Shared by
pr diff, pr review, and pr status
-
Git Operations module (cmd/git_ops.go) -- NEW module. Encapsulates git command execution via os/exec (consistent with existing git_remote.go):
fetchBranch(remote, branch, localBranch, force) -- runs git fetch origin <branch>:<localBranch> with optional --force
checkoutBranch(branch) -- runs git checkout <branch>
- Used by
pr checkout
-
Command: pr checkout (cmd/pr_checkout.go) -- NEW. Flags: --branch / -b, --force / -f. Requires PR number as argument.
-
Command: pr diff (cmd/pr_diff.go) -- NEW. Flags: --name-only. Optional PR number argument; falls back to branch inference.
-
Command: pr review (cmd/pr_review.go) -- NEW. Flags: --approve / -a, --request-changes / -r, --comment / -c, --body / -b, --body-file / -F. Optional PR number argument; falls back to branch inference. Validation: --approve and --request-changes are mutually exclusive; at least one action flag is required; --body or --body-file is required when --request-changes is used.
-
Command: pr status (cmd/pr_status.go) -- NEW. No custom flags. Shows three sections capped at 10 PRs each, with approval counts from the participants field. Current user UUID obtained from GET /user.
-
pr list enhancement (cmd/pr_list.go) -- MODIFY. Add --author / -A flag. @me resolves to authenticated user's nickname. Filtering uses Bitbucket query parameter q=author.nickname="<value>".
Architectural decisions
- No fork support for
pr checkout in this iteration. Only PRs from the same repository (using origin remote) are supported.
- API-sourced diff for
pr diff (not local git diff). This returns the canonical diff matching the Bitbucket UI and works without the branch being checked out locally.
- Bitbucket review model mapping: Bitbucket treats approve, request-changes, and comments as separate API endpoints (unlike GitHub's unified review model). The
bb pr review command maps its flags to different API calls under the hood, making two calls when combining --approve/--request-changes with --comment.
- No interactive prompts for any new command. All commands are designed for non-interactive (LLM-driven) use. Missing required input results in an error with usage guidance.
- No JSON output mode in this iteration. Human-readable text output only.
- No pagination beyond the existing
pagelen parameter.
- Branch inference (for
pr diff, pr review, pr status) queries Bitbucket for open PRs matching the current git branch name. This is stateless -- it doesn't rely on metadata stored during bb pr checkout.
Implementation order
- API client enhancements (
Put(), Delete(), new PR endpoints)
pr list --author (smallest change, touches existing code)
- PR Resolution module +
pr diff (introduces shared inference helper)
pr checkout (independent, git operations)
pr review (most complex, multiple API calls)
pr status (reuses inference helper, multiple queries)
Testing Decisions
What makes a good test
Tests should verify external behavior through the module's public interface, not implementation details. A good test calls the public function, provides controlled inputs (mocked dependencies), and asserts on the output or side effects. Tests should not assert on internal method calls, intermediate state, or specific API URL construction.
Modules to test now
- PR Resolution module (
cmd/pr_resolve.go): Test the branch-to-PR inference logic:
- Exactly one open PR matches the current branch → returns that PR
- Zero PRs match → returns a descriptive error
- Multiple PRs match → returns an error listing the ambiguous PRs
@me nickname resolution for author filtering
- The API client can be mocked by extracting an interface for the methods
resolvePRFromCurrentBranch depends on
Modules to test later
- Git Operations module (
cmd/git_ops.go): Test fetch/checkout sequences, force behavior, and error handling. Deferred because it requires either git repo fixtures or mocking os/exec, which adds test infrastructure complexity.
- API layer and command modules: Thin orchestration; lower value for unit tests. Consider integration tests in the future.
Prior art
There are no existing tests in the codebase. These will be the first test files. Use standard Go testing (testing package) with table-driven tests. Introduce an interface for the API client dependency to enable mocking without third-party libraries.
Out of Scope
- Fork PR support for
pr checkout (PRs from forked repositories)
- Inline/file-level comments in
pr review (comments on specific files and lines)
- Unapprove / remove request-changes actions
- JSON output mode (
--json flag) for structured LLM consumption
- Pipeline/build status in
pr status
- Full pagination (automatic next-page fetching)
- Interactive prompts (editor-based review, PR selector)
- Color/syntax highlighting for diff output
bb pr merge, bb pr close, bb pr reopen and other PR lifecycle commands
- Git Operations tests (documented above as future work)
Further Notes
- The command design is modeled after GitHub CLI (
gh) for familiarity, but adapted to Bitbucket's API model where they diverge (especially reviews).
- The primary consumer of these commands is an LLM agent operating in the developer's terminal. This drives several design choices: no interactive prompts, raw text output, stdin support for piping, and descriptive error messages.
- The PR Resolution module is the most critical piece to get right -- incorrect branch-to-PR inference could lead to reviewing or diffing the wrong PR. This is why it's the only module with tests in this iteration.
- Bitbucket API endpoints used:
GET /repositories/{w}/{r}/pullrequests/{id}/diff
POST /repositories/{w}/{r}/pullrequests/{id}/approve
POST /repositories/{w}/{r}/pullrequests/{id}/request-changes
POST /repositories/{w}/{r}/pullrequests/{id}/comments
GET /repositories/{w}/{r}/pullrequests?q=<filter> (enhanced listing)
GET /user (current user for @me and pr status)
Problem Statement
Developers using
bb-clialongside LLMs in their workflow are forced to context-switch to the Bitbucket browser UI to perform common PR operations: checking out PR branches, reading diffs, submitting reviews, checking PR status, and filtering PR lists by author. This constant switching between the terminal/LLM and the browser breaks focus and defeats the purpose of having an LLM assistant that can operate on your behalf.The CLI needs a set of PR management commands -- inspired by GitHub's
gh prcommands -- that allow an LLM agent (or the developer) to perform the full PR review lifecycle without ever leaving the terminal.Solution
Implement five PR commands that cover the core PR review workflow end-to-end:
bb pr checkout <number>-- Fetch a PR's source branch and check it out locally, so the developer (or LLM) can inspect the code.bb pr diff [<number>]-- Retrieve the raw diff of a PR from the Bitbucket API. When no number is given, infer the PR from the current branch.bb pr review [<number>]-- Submit a review action on a PR: approve, request changes (with a message), or leave a general comment. Supports--bodyand--body-file(including stdin) for LLM-friendly piping.bb pr status-- Show a summary of PRs relevant to the current user: the PR for the current branch, PRs authored by the user, and PRs requesting the user's review.bb pr list --author <nickname>-- Enhance the existingpr listcommand with an--authorfilter. Supports@meto resolve to the authenticated user's nickname.All commands follow existing
bb-cliconventions: workspace/repo resolution (flags → config → git remote), Basic Auth via config, and Cobra command registration.User Stories
bb pr checkout 42so that the LLM can check out a PR's branch without me navigating Bitbucket.bb pr checkoutto use the PR's source branch name as the local branch name by default, so that branch names are intuitive and consistent.bb pr checkout 42 --branch my-local-name, so that I can avoid conflicts with existing local branches.bb pr checkout 42 --forceto reset an existing local branch to the latest PR state, so that I can re-checkout after the PR has been updated without manually deleting the branch.bb pr diff 42to return the raw unified diff from Bitbucket's API, so the LLM can parse and analyze the changes.bb pr diff(no number) to infer the PR from my current branch, so the LLM can run it without needing to know the PR number.bb pr diff --name-onlyto list only the changed file names, so the LLM can quickly scope which files to review.bb pr review 42 --approveto approve a PR from the terminal, so I don't have to open the browser.bb pr review 42 --request-changes --body "Please fix the error handling"to request changes with a message, so the LLM can submit review feedback on my behalf.bb pr review 42 --comment --body "Looks good overall"to leave a general comment on a PR.--approvewith--comment --body "LGTM"to approve and leave a comment in one command.--approveand--request-changesto be mutually exclusive, so that contradictory actions are prevented.bb pr review(no number) to infer the PR from my current branch, matching the behavior ofbb pr diff.bb pr review 42 --comment --body-file review.mdto read the comment body from a file, so the LLM can write a review to a file and submit it.bb pr review 42 --comment --body-file -to read the comment body from stdin, so the LLM can pipe content directly.bb pr reviewwith no action flags to fail with a clear usage message, so I don't accidentally submit an empty review.bb pr statusto show the PR for my current branch (if any), so I can quickly see its state.bb pr statusto show open PRs I've authored, so I can track my own work.bb pr statusto show PRs requesting my review, so I know what needs my attention.bb pr statusto show up to 10 PRs with approval counts, so the output is informative but not overwhelming.bb pr list --author zoldyzdkto filter PRs by author nickname.bb pr list --author @meto resolve to my authenticated user's nickname, so I don't have to remember it.bb pr list(without--author) to continue showing all PRs, preserving the existing default behavior.Implementation Decisions
Modules to build or modify
API Client (
internal/api/client.go) -- AddPut()andDelete()HTTP methods, mirroring the existingGet()andPost()pattern. Needed for future unapprove/remove-request-changes operations and other endpoints.PR API (
internal/api/pullrequests.go) -- Add new Bitbucket API methods:GetPullRequestDiff--GET /repositories/{w}/{r}/pullrequests/{id}/diff, returns raw diff as stringApprovePullRequest--POST /repositories/{w}/{r}/pullrequests/{id}/approveRequestChanges--POST /repositories/{w}/{r}/pullrequests/{id}/request-changesCreatePullRequestComment--POST /repositories/{w}/{r}/pullrequests/{id}/commentswith body contentListPullRequeststo accept a Bitbucket query string parameter (q=...) for author and reviewer filteringPR Resolution module (
cmd/pr_resolve.go) -- NEW deep module. Encapsulates the logic of inferring a PR from the current git branch:getCurrentBranch()-- wrapsgit rev-parse --abbrev-ref HEADresolvePRFromCurrentBranch(client, workspace, repo)-- queries Bitbucket for open PRs matching the current branch name; returns the PR if exactly one match, errors on zero or multiple matchespr diff,pr review, andpr statusGit Operations module (
cmd/git_ops.go) -- NEW module. Encapsulates git command execution viaos/exec(consistent with existinggit_remote.go):fetchBranch(remote, branch, localBranch, force)-- runsgit fetch origin <branch>:<localBranch>with optional--forcecheckoutBranch(branch)-- runsgit checkout <branch>pr checkoutCommand:
pr checkout(cmd/pr_checkout.go) -- NEW. Flags:--branch/-b,--force/-f. Requires PR number as argument.Command:
pr diff(cmd/pr_diff.go) -- NEW. Flags:--name-only. Optional PR number argument; falls back to branch inference.Command:
pr review(cmd/pr_review.go) -- NEW. Flags:--approve/-a,--request-changes/-r,--comment/-c,--body/-b,--body-file/-F. Optional PR number argument; falls back to branch inference. Validation:--approveand--request-changesare mutually exclusive; at least one action flag is required;--bodyor--body-fileis required when--request-changesis used.Command:
pr status(cmd/pr_status.go) -- NEW. No custom flags. Shows three sections capped at 10 PRs each, with approval counts from the participants field. Current user UUID obtained fromGET /user.pr listenhancement (cmd/pr_list.go) -- MODIFY. Add--author/-Aflag.@meresolves to authenticated user's nickname. Filtering uses Bitbucket query parameterq=author.nickname="<value>".Architectural decisions
pr checkoutin this iteration. Only PRs from the same repository (usingoriginremote) are supported.pr diff(not localgit diff). This returns the canonical diff matching the Bitbucket UI and works without the branch being checked out locally.bb pr reviewcommand maps its flags to different API calls under the hood, making two calls when combining--approve/--request-changeswith--comment.pagelenparameter.pr diff,pr review,pr status) queries Bitbucket for open PRs matching the current git branch name. This is stateless -- it doesn't rely on metadata stored duringbb pr checkout.Implementation order
Put(),Delete(), new PR endpoints)pr list --author(smallest change, touches existing code)pr diff(introduces shared inference helper)pr checkout(independent, git operations)pr review(most complex, multiple API calls)pr status(reuses inference helper, multiple queries)Testing Decisions
What makes a good test
Tests should verify external behavior through the module's public interface, not implementation details. A good test calls the public function, provides controlled inputs (mocked dependencies), and asserts on the output or side effects. Tests should not assert on internal method calls, intermediate state, or specific API URL construction.
Modules to test now
cmd/pr_resolve.go): Test the branch-to-PR inference logic:@menickname resolution for author filteringresolvePRFromCurrentBranchdepends onModules to test later
cmd/git_ops.go): Test fetch/checkout sequences, force behavior, and error handling. Deferred because it requires either git repo fixtures or mockingos/exec, which adds test infrastructure complexity.Prior art
There are no existing tests in the codebase. These will be the first test files. Use standard Go testing (
testingpackage) with table-driven tests. Introduce an interface for the API client dependency to enable mocking without third-party libraries.Out of Scope
pr checkout(PRs from forked repositories)pr review(comments on specific files and lines)--jsonflag) for structured LLM consumptionpr statusbb pr merge,bb pr close,bb pr reopenand other PR lifecycle commandsFurther Notes
gh) for familiarity, but adapted to Bitbucket's API model where they diverge (especially reviews).GET /repositories/{w}/{r}/pullrequests/{id}/diffPOST /repositories/{w}/{r}/pullrequests/{id}/approvePOST /repositories/{w}/{r}/pullrequests/{id}/request-changesPOST /repositories/{w}/{r}/pullrequests/{id}/commentsGET /repositories/{w}/{r}/pullrequests?q=<filter>(enhanced listing)GET /user(current user for@meandpr status)