Skip to content

PRD: PR Management Commands for LLM-Assisted Developer Workflow #1

@zoldyzdk

Description

@zoldyzdk

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:

  1. bb pr checkout <number> -- Fetch a PR's source branch and check it out locally, so the developer (or LLM) can inspect the code.
  2. 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.
  3. 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.
  4. 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.
  5. 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

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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.
  8. 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.
  9. 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.
  10. As a developer, I want bb pr review 42 --comment --body "Looks good overall" to leave a general comment on a PR.
  11. As a developer, I want to combine --approve with --comment --body "LGTM" to approve and leave a comment in one command.
  12. As a developer, I want --approve and --request-changes to be mutually exclusive, so that contradictory actions are prevented.
  13. 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.
  14. 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.
  15. 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.
  16. 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.
  17. 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.
  18. As a developer, I want bb pr status to show open PRs I've authored, so I can track my own work.
  19. As a developer, I want bb pr status to show PRs requesting my review, so I know what needs my attention.
  20. 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.
  21. As a developer, I want bb pr list --author zoldyzdk to filter PRs by author nickname.
  22. 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.
  23. As a developer, I want bb pr list (without --author) to continue showing all PRs, preserving the existing default behavior.
  24. 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).
  25. 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

  1. API client enhancements (Put(), Delete(), new PR endpoints)
  2. pr list --author (smallest change, touches existing code)
  3. PR Resolution module + pr diff (introduces shared inference helper)
  4. pr checkout (independent, git operations)
  5. pr review (most complex, multiple API calls)
  6. 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions