Droid reviews Bitbucket pull requests on both hosting variants:
| Variant | API | CI that runs the review |
|---|---|---|
| Bitbucket Cloud | https://api.bitbucket.org/2.0 |
Bitbucket Pipelines (pull-requests: trigger) |
| Bitbucket Data Center / Server | <your server>/rest/api/1.0 |
Jenkins (Bitbucket Branch Source plugin), Bamboo, or any other CI |
What you get, matching the GitLab and GitHub integrations:
- A two-pass review (candidate generation, then validation) on every pull request update.
- Inline comments anchored to the changed lines. A finding on a line outside the diff is posted as a regular PR comment instead.
- One sticky tracking comment that shows progress, the review summary, comment counts, and run telemetry.
- An optional security reviewer running in parallel (
AUTOMATIC_SECURITY_REVIEW=true); its findings are prefixed[security]. REVIEW_DEPTH=deep(default) orshallow.- Draft pull requests are skipped unless
REVIEW_DRAFTS=true. A skipped draft gets nodroid-reviewbuild status. - An optional
droid-reviewcommit build status for merge enforcement (BUILD_STATUS=true).
@droid mentions in PR comments are not supported on Bitbucket.
Every CI system runs the same two commands, with the action cloned to a directory outside the checkout under review:
git clone --depth 1 --branch "${DROID_ACTION_REF:-main}" https://github.com/Factory-AI/droid-action.git /tmp/droid-action
bash /tmp/droid-action/bitbucket/droid-review.shA fixed path such as /tmp/droid-action is fine in Bitbucket Pipelines, where every step gets a fresh container. On Jenkins or Bamboo agents that run several builds at once, use a per-build directory instead, as the Jenkins and Bamboo examples do. The script itself keeps its prompts, state, and results in a fresh mktemp -d directory per run, so concurrent runs never share files.
bitbucket/droid-review.sh installs the Droid CLI (and bun, if missing), then:
bitbucket-preparefinds the pull request, creates or updates the tracking comment (before fetching the diff, so any later failure shows on the PR; an existing tracking comment is reused only if the token's own user wrote it; see the note on Cloud access tokens below), and writes the diff, existing comments, and description to disk.droid execpass 1 writes candidate findings.bitbucket-prepare-validatorbuilds the validation prompt.droid execpass 2 writes the approved findings.bitbucket-post-reviewposts the approved findings through the Bitbucket REST API.bitbucket-update-comment-linkalways runs last and renders the final tracking comment (and build status).
Both droid exec passes run without the Bitbucket credentials in their environment (including any other variable holding the same secret, such as Bamboo's bamboo_..._SECRET) and without any tool that can post to the pull request. The steps that hold the credentials run from the action checkout with bun --config=/dev/null --env-file=/dev/null, so .env or bunfig.toml files in the pull request are never loaded. Everything they publish (comments, error details, build statuses) has the job's credentials redacted. They keep Execute for investigating the code, so treat the review job like any CI job that builds untrusted code.
The agent needs bash, git, curl, and bun 1.2.x (the script installs bun if unzip is available). It needs outbound HTTPS to:
github.com, to clone droid-action (or your mirror's host, if you change the clone URL).registry.npmjs.org, forbun installof droid-action's dependencies.app.factory.ai, for the Droid CLI installer script and the Factory API.downloads.factory.ai, for the Droid CLI binary and its checksum.api.factory.ai, for the Factory API thatdroid execcalls.- Your Bitbucket API host:
api.bitbucket.orgon Cloud, or your server URL on Data Center. - Only when bun is not preinstalled (Jenkins, Bamboo, or other CI):
bun.shfor the installer, plusgithub.comandrelease-assets.githubusercontent.comfor the bun release download. - Only in the Pipelines templates:
deb.debian.org, where theoven/bunimage installsgitandcurlwithapt-get. - Only when
ORG_GUIDELINES_SOURCEis a URL or git repository: that host.
Pinning: DROID_ACTION_REF is a branch or tag (not a SHA). Pin a release tag for reproducible runs. Set DROID_ACTION_REPO and change the clone URL to use a private mirror.
| Variable | Notes |
|---|---|
FACTORY_API_KEY |
Required. Generate at https://app.factory.ai/settings/api-keys. |
DROID_BITBUCKET_TOKEN |
Sent as Authorization: Bearer. Cloud: repository, project, or workspace access token. Data Center: HTTP access token (project, repository, or personal). |
DROID_BITBUCKET_USERNAME + DROID_BITBUCKET_API_TOKEN |
Alternative, sent as HTTP Basic. Cloud API token with scopes; the username is your Atlassian account email. Also works with Data Center personal tokens. Bitbucket Cloud app passwords were permanently disabled on June 9, 2026; replace them with an API token. |
When both are set, the Bearer token wins. Store all of them as secured/masked variables. The names avoid the BITBUCKET_ prefix that Pipelines uses for its own variables. Tokens are never printed.
Permissions:
- Cloud access token:
pullrequest:write(read, comment on, and update pull requests) andrepository(read commits; therepositoryscope does not cover pull requests, so both are needed). Addrepository:writewhenBUILD_STATUS=true. Comments appear as the token's bot user. - Cloud API token:
read:pullrequest:bitbucket,write:pullrequest:bitbucket,read:repository:bitbucket(+write:repository:bitbucketfor build statuses, andread:user:bitbucketso the tracking comment is edited in place). Write scopes do not imply the matching read scope, so request both. - Data Center HTTP access token: Repository read (or Project read for a project-wide token) is enough to read, comment, and post build statuses. Comments appear as the token's bot user.
Cloud access tokens and the tracking comment. Droid reuses a tracking comment only when it can prove its own user wrote it, so a marker pasted by someone else is never taken over. Cloud access tokens cannot look up their own user (GET /2.0/user rejects them), so with an access token each run posts a fresh tracking comment and then deletes the earlier ones written by the same bot user (the author of the comment it just posted; comments with replies are kept). The PR still shows one tracking comment, but each run sends a new-comment notification. For a single tracking comment that is edited in place, use a Cloud API token with DROID_BITBUCKET_USERNAME (your Atlassian account email) and add the read:user:bitbucket scope.
The scope needed to post a Cloud build status (repository:write) and the Data Center permission for the repository-scoped build status endpoint (Repository read) follow Atlassian's documentation as of this writing; if a build status is refused with 403, grant the write level.
All inputs are environment variables; set them as CI variables or export them before the bash line.
| Variable | Default | Meaning |
|---|---|---|
AUTOMATIC_REVIEW |
true |
false turns the job into a no-op. |
AUTOMATIC_SECURITY_REVIEW |
false |
Run the security reviewer in parallel. |
REVIEW_DEPTH |
deep |
deep or shallow. |
REVIEW_MODEL / REASONING_EFFORT |
empty | Advanced overrides of the depth preset. |
INCLUDE_SUGGESTIONS |
true |
Allow suggestion blocks in comments. |
REVIEW_DRAFTS |
false |
Review draft pull requests too. |
BUILD_STATUS |
false |
Post a droid-review build status on the PR head commit (in progress, then successful or failed). Blocking merges on it needs Bitbucket Cloud Premium or Data Center; see Enforcement. |
DROID_SETTINGS |
empty | Droid Exec settings JSON, or a path to a JSON file. |
ORG_GUIDELINES_SOURCE / ORG_GUIDELINES_REF / ORG_GUIDELINES_PATH |
empty / empty / review-guidelines.md |
Organization review guidelines from a file path, an http(s) URL, or a git clone URL ending in .git. |
BITBUCKET_VARIANT (cloud or datacenter) is detected automatically: Data Center when BITBUCKET_SERVER_URL is set or the PR URL is a Data Center URL, Cloud when BITBUCKET_WORKSPACE is set.
- Bitbucket Pipelines: nothing to configure. The script reads
BITBUCKET_WORKSPACE,BITBUCKET_REPO_SLUG,BITBUCKET_PR_ID,BITBUCKET_COMMIT, and links the tracking comment to the pipeline step. - Data Center, first match wins:
BITBUCKET_SERVER_URL(including any context path, e.g.https://host/bitbucket),BITBUCKET_PROJECT_KEY,BITBUCKET_REPO_SLUG,BITBUCKET_PR_ID.- A pull request URL in
DROID_PR_URL, or Jenkins'CHANGE_URL(<server>/projects/<KEY>/repos/<slug>/pull-requests/<id>). Explicit variables override parts of it; whenBITBUCKET_SERVER_URLnames a different host than the URL, the review warns and callsBITBUCKET_SERVER_URL. - The PR id from Bamboo
bamboo_repository_pr_key, or from JenkinsCHANGE_IDonly whenCHANGE_URLis a Bitbucket pull request URL. Jenkins setsCHANGE_IDfor GitHub and GitLab change requests too, so any otherCHANGE_IDis ignored with a warning. - The CI link from
DROID_BUILD_URL, JenkinsBUILD_URL, or Bamboobamboo_resultsUrl.
A build without a pull request id logs Not a pull request build; skipping Droid review. and exits successfully.
Copy bitbucket/pipelines/bitbucket-pipelines.yml to the repository root as bitbucket-pipelines.yml. If the repository already has one, add the step under pipelines.pull-requests."**" (append to the existing list if that pattern exists). Then:
- Enable Pipelines: Repository settings → Pipelines → Settings, or
PUT /2.0/repositories/{workspace}/{repo}/pipelines_configwith{"enabled": true}. - Add secured repository variables
FACTORY_API_KEYandDROID_BITBUCKET_TOKEN: Repository settings → Pipelines → Repository variables, orPOST /2.0/repositories/{workspace}/{repo}/pipelines_config/variables/with{"key": "...", "value": "...", "secured": true}. - Open or update a pull request. The "Droid code review" step runs and the PR gets a tracking comment.
Secured variables are not available to pull requests from forks, so forked PRs fail with Missing Bitbucket credentials.
Requires the Bitbucket Cloud Premium plan. Sharing Pipelines configurations across repositories (export: true / import:) is a Premium-only feature (Atlassian: Share Pipelines Configurations). On Free or Standard, use the single-repository file in every repository instead.
With Premium, shared pipeline configurations let one repository own the pipeline definition:
-
Create a repository in the workspace (for example
droid-pipelines) and commitbitbucket/pipelines/shared-pipeline.ymlas itsbitbucket-pipelines.yml(it setsexport: true). -
Add secured workspace variables
FACTORY_API_KEYandDROID_BITBUCKET_TOKEN(a workspace access token): Workspace settings → Workspace variables, orPOST /2.0/workspaces/{workspace}/pipelines-config/variables. -
In each repository, enable Pipelines and commit:
pipelines: pull-requests: "**": import: droid-pipelines:main:droid-review
Imported pipelines use the consuming repository's variables plus workspace variables. Changing the central definition updates every repository on its next PR build. An import replaces the whole step list for that pattern, so a repository with its own pull-request steps must keep them under a different pattern.
Add a branch restriction that requires passing builds: Repository settings → Branch restrictions, or POST /2.0/repositories/{workspace}/{repo}/branch-restrictions with {"kind": "require_passing_builds_to_merge", "pattern": "main", "value": 1}.
Enforcement requires the Bitbucket Cloud Premium plan. Only Premium can turn on "Prevent a merge with unresolved merge checks"; on Free and Standard, a failed or missing build only shows a warning and the PR can still be merged. Enforcement proves the review ran successfully; it does not block on findings.
Set REVIEW_DRAFTS=true when you enforce the review. A skipped draft posts no droid-review status and its step still succeeds, and this merge check counts any successful build, so the skipping step would count once the draft is marked ready (which pushes no new commit).
- Install the Bitbucket Branch Source plugin, register your Data Center server under Manage Jenkins → System → Bitbucket Endpoints, and let the plugin manage webhooks so PR events trigger builds.
- Create a Multibranch Pipeline (one repository) or a Bitbucket Team/Project organization folder (every repository in a project) with "Discover pull requests" enabled.
- Add "Secret text" credentials
factory-api-keyandbitbucket-droid-token. - Commit
bitbucket/examples/Jenkinsfile(or add its stage to your existingJenkinsfile).
The example clones the action into $WORKSPACE@tmp/droid-action, Jenkins' per-workspace scratch directory, so concurrent builds never share it and it stays out of the checkout under review. It runs the oven/bun container as root only to apt-get install git and curl, then hands workspace files back to the workspace owner. With an agent image that already has bash, git, curl, and bun, drop args '-u root', the apt-get line, and the chown trap.
The plugin builds each pull request as PR-<id> and sets CHANGE_URL, CHANGE_ID, and BUILD_URL, which is all the review needs. With other plugins or generic webhook triggers, set BITBUCKET_SERVER_URL, BITBUCKET_PROJECT_KEY, BITBUCKET_REPO_SLUG, and BITBUCKET_PR_ID (or DROID_PR_URL) in the pipeline's environment block.
Link the Data Center repository, enable plan branches for pull requests, and use bitbucket/examples/bamboo-specs.yml as bamboo-specs/bamboo.yml. Fill in the server URL, project key, and repository slug variables, and add secret variables FACTORY_API_KEY_SECRET and DROID_BITBUCKET_TOKEN_SECRET. The example clones the action into a fresh mktemp -d directory per build and removes it afterwards, so concurrent builds on one agent never collide.
Export the context variables from Pull request context plus the credentials, then run the two commands from How it runs.
Run the review with BUILD_STATUS=true so it posts a build status with the fixed key droid-review, then add a Required builds merge check (Data Center 7.14+) for that key in repository or project settings. The Minimum successful builds merge check also works but counts any build. Enforcement proves the review ran successfully; it does not block on findings.
Set REVIEW_DRAFTS=true when you enforce the review. A skipped draft posts no droid-review status, so Required builds stays unsatisfied when the draft is marked ready until the build runs again; with Minimum successful builds, the skipping build itself would count.
| Message | Cause |
|---|---|
Missing Bitbucket credentials. |
No token variable reached the job (missing, or withheld from a forked PR). |
... was passed through as the literal string "$..." |
The CI passed an unexpanded variable reference ($NAME, ${NAME}, Bamboo's ${bamboo.NAME}). |
Bitbucket truncated the pull request diff |
The diff exceeds the Data Center server's diff size limit. The review covers only part of the changes, and the tracking comment says so. |
ignoring Jenkins CHANGE_ID |
Jenkins built a change request whose CHANGE_URL is not a Bitbucket pull request (for example a GitHub PR). Set BITBUCKET_PR_ID to review it anyway. |
Missing FACTORY_API_KEY. |
The Factory key is not set for this job. |
Could not determine the Bitbucket variant. |
Not running in Pipelines and no Data Center variables or PR URL are set. |
Missing Bitbucket Data Center context: ... |
The server URL, project key, or repository slug could not be resolved. |
Bitbucket API 401 |
Bad or expired token, or the wrong scheme: an API token needs DROID_BITBUCKET_USERNAME set to your Atlassian account email (Basic), and an access token goes in DROID_BITBUCKET_TOKEN. App passwords no longer work. |
Bitbucket API 403 |
The token lacks a scope or repository permission. |
Bitbucket API 404 |
Wrong workspace, project, repository, or PR, or the token cannot see the repository. |
bitbucket-post-review: all N approved comments failed to post |
Every inline and fallback comment was refused; check the token's permissions. |
Debug output (prompts, state, pass logs) is staged in .droid-debug/ in the working directory, with the Bitbucket and Factory credentials redacted and symlinks left out; the templates keep it as a build artifact. If staging fails, the directory is removed rather than uploaded unredacted. The pass logs hold the output of every command Droid ran, so treat the artifact as sensitive anyway.