Skip to content

Forward-Future/DeployBot

Repository files navigation

DeployBot

DeployBot is a provider-neutral GitHub merge queue for coding agents. Codex, Claude Code, Cursor, or any MCP client can prepare and review a pull request; the user keeps the final merge decision by saying deploy.

DeployBot stores authority in GitHub labels and authenticated comments. It records deploy intent immediately, promotes the final exact reviewed head, freezes bursts, merges independent work back-to-back, scaffolds cumulative integration PRs, follows main through production, and pauses after failures.

Install

Install the reviewed v0.2.19 source commit directly from GitHub:

python3 -m pip install \
  'deploybot-merge-queue[mcp] @ git+https://github.com/Forward-Future/DeployBot.git@1b6379a258a0b6f743ce77c2d108dfd7e83d582b'
deploybot init

deploybot init writes the safe starter policy. The annotated example policy shows every supported section, and the CLI, MCP, policy, and Action reference lists every current command, tool, option, and configuration field.

Invoke the bundled $deploybot skill to inspect or operate the queue. Typical requests include “show the delivery pipeline,” “why is PR 42 blocked?”, and “deploy this PR.” Status and diagnostics are read-only:

deploybot status
deploybot status --json
deploybot doctor
deploybot metrics --json
deploybot inspect 42 --json

For development from the Astro source tree, install ./packages/agent-merge-queue[mcp] instead.

Edit .mergequeue.toml to name the required checks, optional review providers, and every exact GitHub login whose queue markers are trusted. Do not grant authority by broad repository role. GitHub verifies comment authors; its normal token permissions control label, comment, and merge writes. Authentication comes from the GitHub CLI:

gh auth login
deploybot ensure-labels
deploybot doctor

The base installation has no review-service dependency. Repositories can use required checks alone or add GitHub approvals, a generic bot, an agent-review check, or any combination.

Security model

Protect the base branch with a GitHub ruleset that independently requires the same checks named in .mergequeue.toml, and do not give DeployBot's merge credential permission to bypass that ruleset. DeployBot reads check display names to coordinate the queue; GitHub's ruleset is the authoritative check identity and the final atomic merge guard.

Keep workflow changes reviewed, pin third-party Actions to full commit hashes, and never execute pull-request-head code in the privileged coordinator. The MCP server uses the local process's existing GitHub credentials and accepts explicit repository selectors, so run it only from a trusted coding client and workspace.

Durable manual deploy gate

The installed agent adapter treats the user's exact deploy instruction as authority for that thread's PR only. It records the intent immediately—even if CI or review is still running:

deploybot request <pr-number> \
  --provider codex --thread-id "$CODEX_THREAD_ID"

The event worker promotes only the intent-bound exact head after all checks and review providers pass. If review fixes create a replacement head, the trusted source agent runs deploybot refresh-request <pr> after its fresh evidence; the user does not repeat deploy. No polling timer is involved.

Install examples/github-workflow.yml on the default branch. It reacts to deploy labels, ready/synchronize events, reviews, named CI workflow_run completions, and completed external check suites. Keep its workflows list aligned with pipeline.ci_workflows. A five-minute scheduled reconciliation rereads all durable state in case GitHub concurrency coalesces the last pending event in a burst. The privileged worker never checks out or executes pull-request code. The Action follows releases by default so the same serialized worker can dispatch deployment when GitHub suppresses the workflow_run event for token-dispatched CI. Pin the Action to the full reviewed release commit:

- uses: Forward-Future/DeployBot@1b6379a258a0b6f743ce77c2d108dfd7e83d582b

The Action uses GitHub's built-in workflow token. GitHub intentionally does not turn merges made by that token into ordinary push workflow runs, so DeployBot dispatches each configured CI workflow once after it merges a batch. GitHub can also suppress the usual workflow_run handoff after that token-driven CI run, so DeployBot explicitly dispatches each configured deployment workflow after exact-main CI succeeds. CI workflows must accept workflow_dispatch. Deployment workflows must accept workflow_dispatch inputs named ci_sha and ci_run_id, verify that run through the GitHub API, and deploy only when it is successful CI for the current base-branch head. Skipped deployment wake-ups from pull-request CI are ignored. Set Action input dispatch_ci: "false" only when a caller supplies a different merge identity that already triggers push CI.

When integration PR checks depend on normal PR-authored events, mint a GitHub App installation token in an earlier workflow step and pass it as the Action's token input. Set integration.require_non_actions_author = true so a missing App token fails before it freezes or creates an unusable integration PR. Add the App's exact bot login (for example, deploybot-app[bot]) to queue.coordinator_actors so its integration records are trusted.

The deployment workflow keeps its normal workflow_run trigger for push CI and adds this exact-input recovery path for DeployBot-dispatched CI:

on:
  workflow_run:
    workflows: [CI]
    types: [completed]
  workflow_dispatch:
    inputs:
      ci_sha:
        required: true
        type: string
      ci_run_id:
        required: true
        type: string

Before releasing, use ci_run_id to read the run from GitHub and require its workflow name, base branch, head SHA, event, status, and conclusion to match the expected successful exact-main CI run. The deployment must still pull the current base branch and stop if it no longer equals ci_sha.

The workflow bot and each person allowed to request deployment must be explicitly listed:

[queue]
trusted_actors = ["@repository-owner"]
coordinator_actors = ["@repository-owner", "github-actions[bot]"]

@repository-owner resolves to the owner in owner/repository. Organization repositories should replace it with the exact human or bot logins they trust. Coordinator accounts may promote, freeze, integrate, and complete batches, but they cannot create the original per-pull-request deploy intent.

Delivery controller

deploybot status reports active metadata-only agent threads, pending native notifications, every PR stage, deploy requests and their exact authorized heads, queue order, queued and pre-queue intent overlaps, exact-main CI, deployment, and pipeline pause state. It alerts when a deploy request exceeds the configured ready-to-merge target and names the current gate. It never stores prompts, transcripts, source, or credentials.

deploybot react promotes ready intent, skips blockers, drains independent work, and creates integration PRs when configured. New batches contain at most integration.max_batch_size entries; later FIFO work remains in the next batch. A larger indivisible source-overlap or dependency closure is the sole exception: it ships alone, never mixed with unrelated work. After any merge, admission stays closed until the cumulative exact-main release is verified live, preventing newer merges from starving an older deployment. Draft status and incomplete checks or reviews remain waiting states; they do not create a repair latch. A conflict, failed gate, unresolved review, manual block, or stale authorized head produces a repair handoff containing the source thread, base/head SHAs, source paths, and one return command. Old draft-only repair latches self-clear once the controller recognizes them:

In overlap mode, a ready source waits when another active, near-ready intent belongs to the same source-overlap component. Unrelated ready work still drains, and the held component freezes together once its remaining gates pass. When more than one cumulative integration pull request needs controller-owned exact-head CI, DeployBot dispatches every missing workflow before it waits. The workflows then run in parallel instead of making later batches wait for an earlier runner delay. Slow-queue status names the missing, queued, or failed exact integration workflow instead of reporting only a generic merge worker.

deploybot resume <pr-number>

resume atomically verifies the replacement head, clears the block, requeues, and emits a new wake-up event. follow tracks newer cumulative main revisions until exact CI, deployment, and optional HTTP checks pass. A CI or deploy failure can pause further merges until deploybot unpause. Before presenting an unpause request, adapters must refresh deploybot status --json and suppress stale prompts when the durable controller is already running or the release advanced. The original deploy instruction authorizes the coordinator to unpause the matching failed release after its elected repair head passes fresh checks and review. Pass that status result's failed main SHA and unique control_id to deploybot unpause --sha SHA --control-id ID so a concurrent newer pause remains authoritative. Rollback, bypass, and mismatched recovery still require explicit user direction.

Before starting an exact-main recovery, an agent runs deploybot claim-release-repair --provider CLIENT --thread-id ID. A deterministic branch ref elects exactly one repair owner for that failed SHA; other threads receive the recorded owner instead of creating duplicate PRs.

At merge time, DeployBot records a non-expiring notification obligation. At exact-main verification, it promotes every contained obligation to pending, moves the matching PR-opening thread to deployed when that thread has not moved on, and returns a stable thread_notifications payload for each one. The provider adapter posts the supplied message into that native thread; for Codex it wakes the thread with send_message_to_thread. The PR-opening thread then acknowledges delivery and becomes completed. The message is a human-readable release receipt with the pull-request title and link, up to three feature highlights from its release notes, the exact deployed main, and CI/deployment evidence. Adapters present that receipt verbatim and keep successful acknowledgement IDs internal. PR-authored text is rendered inert; only DeployBot-generated PR and release-evidence links remain clickable:

deploybot thread acknowledge --provider codex --thread-id "$CODEX_THREAD_ID" \
  --notification-id "$DEPLOYBOT_NOTIFICATION_ID"

DeployBot does not treat a registry comment as user notification. If native delivery fails, an independent outbox entry stays visible under pending notifications, even if the PR-opening thread starts new work, and the same notification_id can be retried. When pipeline.webhook_url_env is configured, the provider-neutral webhook also receives the thread-deployed payload and scheduled followers retry it. Without a configured webhook, pending receipts do not keep the release worker running; the source adapter's native thread heartbeat retrieves, acknowledges, and displays the final notification instead. The first trusted thread update in pr-draft, pr-review, or ready phase that includes a PR number immutably binds that PR to its opening native thread. Later deploy, repair, integration, and coordinator threads cannot replace it. deploybot request uses that recorded owner even when another thread authorizes the release. An unowned PR cannot enter the delivery pipeline, so DeployBot never silently routes its receipt to the authorizing caller. The request result makes this ownership explicit in notification_handoff.required_action; clients must complete that action before ending the PR-opening-thread response.

[pipeline]
ci_workflows = ["CI"]
deploy_workflows = ["Deploy"]
batch_settle_seconds = 15
ci_failure_grace_seconds = 90
promotion_workers = 4
hold_merges_while_releasing = true
repair_branch_prefix = "deploybot/repair"
ready_to_merge_target_minutes = 15
merge_to_live_target_minutes = 10
auto_promote = true
intent_scope = "head"
pause_on_failure = true

[[pipeline.verifications]]
name = "Login"
url = "https://example.com/login"
expected_status = 200

[integration]
# manual, overlap, or all (one cumulative pre-merge validation PR)
mode = "overlap"
max_batch_size = 3
# require_non_actions_author = true
# ci_satisfies_checks = ["Stable PR head", "Full test suite"]

For overlap or all mode with the hosted coordinator, enable Allow GitHub Actions to create and approve pull requests under the repository's Actions workflow-permission settings. deploybot doctor reports this prerequisite.

Review providers

Required checks are always exact-head gates. Optional providers use normalized pass, waiting, or blocked verdicts.

[queue]
required_checks = ["CI"]

[review]

[[review.providers]]
kind = "github-approvals"
name = "Human approval"
allowed_reviewers = ["reviewer-login"]
minimum_approvals = 1

[[review.providers]]
kind = "bot"
name = "Review bot"
login = "review-bot"
check_name = "Review Bot"
require_formal_review = true
require_resolved_threads = true

A bot score is optional. When used, its comment must contain the exact reviewed commit SHA so an older score can never authorize a replacement head.

Clients

  • Codex: install the CLI and the CLI-only plugin under adapters/codex/agent-merge-queue. The Codex adapter intentionally does not start an MCP subprocess.
  • Claude Code: install the plugin under adapters/claude-code.
  • Cursor: copy the files under adapters/cursor or use its MCP configuration.
  • Other clients: connect deploybot-mcp over stdio or call the CLI directly.

The Claude Code and Cursor MCP configurations launch the pinned public release with uvx. The mergeq and mergeq-mcp command aliases remain for compatibility.

Command overview

All commands accept the global --config PATH and --repository OWNER/REPO options before the subcommand. A missing pull-request selector resolves the PR for the current branch.

deploybot init [--force]
deploybot ensure-labels
deploybot status --json
deploybot plan --json
deploybot doctor --json
deploybot inspect [PR] --json
deploybot thread update --provider CLIENT --thread-id ID --phase PHASE [metadata]
deploybot thread acknowledge --provider CLIENT --thread-id ID --notification-id ID
deploybot request [PR] [--provider CLIENT] [--thread-id ID] [--thread-url URL]
deploybot cancel-request [PR]
deploybot refresh-request [PR]
deploybot enqueue [PR]
deploybot promote
deploybot freeze --json
deploybot drain --json
deploybot react [--follow] [--dispatch-ci] [--timeout SECONDS]
deploybot integrate [--all]
deploybot follow [--timeout SECONDS] [--poll SECONDS] [--json]
deploybot metrics --json
deploybot pause --reason "main CI failed"
deploybot unpause --sha FAILED_MAIN_SHA --control-id PAUSE_CONTROL_ID
deploybot block [PR] --reason "..."
deploybot unblock [PR]
deploybot resume [PR]
deploybot dequeue [PR] --reason "..."
deploybot merge [PR] --batch BATCH_ID

status is the read-only full delivery view. plan is the narrower queue-only view. doctor verifies CLI auth, policy, labels, actors, check names, and branch protection without changing the repository.

The MCP server exposes named equivalents for the operational commands, plus explicit repository and config arguments on every tool. See the complete reference for the exact mapping and arguments.

drain merges only independent, green, exact-head-reviewed PRs. Integration mode overlap creates one cumulative PR for shared source; mode all routes the whole frozen batch through one cumulative PR before main. DeployBot never invents a conflict resolution: it prepares the branch and hands the exact repair back to an agent.

About

Agent-managed GitHub merge queue for Codex, Claude Code, Cursor, and MCP clients

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages