Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .mergequeue.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ merge_to_live_target_minutes = 10
auto_promote = true
intent_scope = "head" # safest: a trusted source agent refreshes replacement heads
pause_on_failure = true
# Receives best-effort events, including retryable thread-deployed messages.
# webhook_url_env = "DEPLOYBOT_WEBHOOK_URL"

# [[pipeline.verifications]]
Expand Down
30 changes: 27 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,10 @@ they cannot create the original per-pull-request deploy intent.

## Delivery controller

`deploybot status` reports active metadata-only agent threads, every PR stage,
deploy requests, queue order, overlaps, exact-`main` CI, deployment, and pipeline
pause state. It never stores prompts, transcripts, source, or credentials.
`deploybot status` reports active metadata-only agent threads, pending native
notifications, every PR stage, deploy requests, queue order, overlaps,
exact-`main` CI, deployment, and pipeline pause state. It never stores prompts,
transcripts, source, or credentials.

`deploybot react` promotes ready intent, skips blockers, drains independent
work, and creates integration PRs when configured. A conflict produces a repair
Expand All @@ -171,6 +172,28 @@ 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`.

At merge time, DeployBot records a non-expiring notification obligation. At
exact-main verification, it promotes every contained obligation to `pending`,
moves the matching source 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 source thread then
acknowledges delivery and becomes `completed`:

```bash
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 source 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.
Source adapters attach a native thread heartbeat before returning from an
asynchronous deploy request, so the originating thread can retrieve, acknowledge,
and display the final notification even when no interactive coordinator remains.

```toml
[pipeline]
ci_workflows = ["CI"]
Expand Down Expand Up @@ -251,6 +274,7 @@ 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]
Expand Down
26 changes: 26 additions & 0 deletions adapters/claude-code/skills/deploybot/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,29 @@ cumulative base heads until CI, deployment, and configured health checks verify.
Use `diagnose`/`deploybot doctor` for setup drift and `delivery_metrics` for p50,
p95, and slow-stage evidence. A failed cumulative CI or deployment pauses the
controller; only a designated coordinator may unpause after recovery.

## Notify Source Threads

After exact-main verification, `follow_release` returns one
`thread_notifications` entry per source thread and records that thread as
`deployed`. Deliver every entry's `message` into the recorded native thread so
the user can see completion by looking at that thread. In Codex, use the app's
`send_message_to_thread` tool to wake that thread with the supplied message and
instruct it to make the supplied message user-visible, then call
`acknowledge_thread_deployment` without doing more code work. Pass that entry's
`notification_id` to the acknowledgement. If already operating in the source
thread, show the message first, acknowledge it, and finish with the same status.

Treat `notification_id` as the idempotency key. Never acknowledge a thread
before its native-thread delivery succeeds, and never substitute a registry
comment for the native message. If native delivery is unavailable or fails,
leave the notification `pending`; a later coordinator or the provider-neutral
`thread-deployed` webhook can retry it.

The source thread that calls `request_deployment` also owns a durable wake-up.
If it will stop running before verification, attach the provider's native
thread heartbeat or follow-up monitor before returning. In Codex, use a thread
heartbeat automation. On wake, read `pipeline_status`; once this thread is
listed under pending `notifications`, first show its supplied message to the
user, then acknowledge it and remove the heartbeat. Do not use a tight polling
loop.
10 changes: 10 additions & 0 deletions adapters/claude-code/skills/manage-merge-queue/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,13 @@ honor dependencies, route overlap or cumulative validation through
`create_integration_pull_request`, return repair packets to the source thread,
and use `resume_pull_request` after fresh review. Finish with `follow_release`;
a failed CI or deployment pauses the pipeline until verified recovery.

When `follow_release` returns `thread_notifications`, send each supplied
message to its native source thread. The source thread calls
`acknowledge_thread_deployment` with the matching `notification_id` and reports
completion to the user. Leave failed notifications `pending` so they remain
retryable.

Before a requesting source thread stops running, attach a native follow-up
monitor that checks `pipeline_status` and wakes it to report and acknowledge its
matching pending notification.
26 changes: 26 additions & 0 deletions adapters/codex/agent-merge-queue/skills/deploybot/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,29 @@ cumulative base heads until CI, deployment, and configured health checks verify.
Use `diagnose`/`deploybot doctor` for setup drift and `delivery_metrics` for p50,
p95, and slow-stage evidence. A failed cumulative CI or deployment pauses the
controller; only a designated coordinator may unpause after recovery.

## Notify Source Threads

After exact-main verification, `follow_release` returns one
`thread_notifications` entry per source thread and records that thread as
`deployed`. Deliver every entry's `message` into the recorded native thread so
the user can see completion by looking at that thread. In Codex, use the app's
`send_message_to_thread` tool to wake that thread with the supplied message and
instruct it to make the supplied message user-visible, then call
`acknowledge_thread_deployment` without doing more code work. Pass that entry's
`notification_id` to the acknowledgement. If already operating in the source
thread, show the message first, acknowledge it, and finish with the same status.

Treat `notification_id` as the idempotency key. Never acknowledge a thread
before its native-thread delivery succeeds, and never substitute a registry
comment for the native message. If native delivery is unavailable or fails,
leave the notification `pending`; a later coordinator or the provider-neutral
`thread-deployed` webhook can retry it.

The source thread that calls `request_deployment` also owns a durable wake-up.
If it will stop running before verification, attach the provider's native
thread heartbeat or follow-up monitor before returning. In Codex, use a thread
heartbeat automation. On wake, read `pipeline_status`; once this thread is
listed under pending `notifications`, first show its supplied message to the
user, then acknowledge it and remove the heartbeat. Do not use a tight polling
loop.
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,13 @@ dependencies, and use `create_integration_pull_request` for overlaps or a
cumulative batch gate. Return repair packets to their source thread and use
`resume_pull_request` after fresh review. Finish with `follow_release`; a failed
CI or deployment pauses the pipeline until verified recovery.

When `follow_release` returns `thread_notifications`, send each supplied
message to its native source thread. In Codex use `send_message_to_thread`;
the source thread calls `acknowledge_thread_deployment` with the matching
`notification_id` and reports completion to the user. Leave failed
notifications `pending` so they remain retryable.

Before a requesting source thread stops running, attach a native thread
heartbeat that checks `pipeline_status` and wakes it to report and acknowledge
its matching pending notification.
9 changes: 9 additions & 0 deletions adapters/cursor/.cursor/rules/deploybot.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,12 @@ exact heads, blockers, overlap, CI, and deployment. Only the user's exact
the stable Cursor thread ID, never prompts or transcripts. Refresh intent only
after replacement-head review. Only the coordinator may react, integrate,
drain, follow, pause, or resume repaired work.

After exact-main verification, deliver each returned `thread_notifications`
message into its native source thread, then call
`acknowledge_thread_deployment` with the matching `notification_id`. Leave a
failed notification `pending` so a later coordinator can retry it; a registry
comment is not a user notification.

Before the requesting source thread stops, attach a native follow-up monitor
that wakes it when `pipeline_status` lists its pending notification.
8 changes: 8 additions & 0 deletions adapters/cursor/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,11 @@ Never poll, merge an unlabeled PR, or absorb unrelated work. Let the event worke
promote fresh exact heads, use one integration PR for overlaps or cumulative
validation, return repair packets to the source thread, atomically resume after
fresh review, and follow cumulative `main` through verified deployment.

For each verified `thread_notifications` entry, post its message back to the
native source thread and only then call `acknowledge_thread_deployment`. Leave
failed notifications `pending` for a later retry, and pass the matching
`notification_id` when acknowledging.

Before a requesting source thread stops, attach a native follow-up monitor that
wakes it when `pipeline_status` lists its pending notification.
18 changes: 14 additions & 4 deletions docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ DeployBot resolves the pull request for the current branch.
| `deploybot init [--force]` | Write a safe starter policy. Existing files are preserved unless `--force` is supplied. |
| `deploybot ensure-labels` | Create or refresh the configured queue, blocked, intent, pause, and registry labels. |
| `deploybot doctor [--json]` | Check authentication, policy, labels, actors, checks, workflows, and branch protection without changing repository state. |
| `deploybot status [--json]` | Read active thread metadata, PR stages, deploy intent, queue state, exact-main CI, deployment, and pipeline control state. |
| `deploybot status [--json]` | Read active thread metadata, pending native notifications, PR stages, deploy intent, queue state, exact-main CI, deployment, and pipeline control state. |
| `deploybot plan [--json]` | Read the ordered queue, dependencies, blockers, and source-overlap groups. |
| `deploybot inspect [PR] [--json]` | Evaluate one exact PR head without granting merge authority. |
| `deploybot metrics [--limit N] [--json]` | Summarize p50, p95, and maximum delivery timings for recent merged PRs. The default limit is 25. |
Expand All @@ -36,7 +36,8 @@ batch marker.

| Command | Purpose |
| --- | --- |
| `deploybot thread update --provider CLIENT --thread-id ID --phase PHASE [--title TEXT] [--branch NAME] [--pr NUMBER] [--url URL]` | Publish metadata-only thread state. Valid phases are `working`, `pr-draft`, `pr-review`, `ready`, `deploy-requested`, `queued`, `merged`, `blocked`, `completed`, and `abandoned`. |
| `deploybot thread update --provider CLIENT --thread-id ID --phase PHASE [--title TEXT] [--branch NAME] [--pr NUMBER] [--url URL]` | Publish metadata-only thread state. Valid client-published phases are `working`, `pr-draft`, `pr-review`, `ready`, `deploy-requested`, `queued`, `merged`, `blocked`, `completed`, and `abandoned`; `deployed` is controller-owned. |
| `deploybot thread acknowledge --provider CLIENT --thread-id ID --notification-id ID` | Mark the matching `deployed` notification `completed` only after its native-thread message is delivered. Repeated acknowledgement is safe; stale IDs are rejected. |
| `deploybot request [PR] [--provider CLIENT] [--thread-id ID] [--thread-url URL]` | Record the user's durable deploy intent for the current exact head, even while gates are pending. |
| `deploybot cancel-request [PR]` | Cancel an unmerged durable deploy request. |
| `deploybot refresh-request [PR]` | Bind existing user intent to a freshly reviewed replacement head. |
Expand Down Expand Up @@ -97,6 +98,7 @@ arguments shown below are the tool-specific arguments.
| `follow_release` | `follow --json` | optional `timeout_seconds` |
| `delivery_metrics` | `metrics --json` | optional `limit` |
| `update_agent_thread` | `thread update` | `provider`, `thread_id`, `phase`; optional `pull_request`, `title`, `branch`, `url` |
| `acknowledge_thread_deployment` | `thread acknowledge` | `provider`, `thread_id`, `notification_id` |
| `block_pull_request` | `block PR` | `pull_request`, `reason` |
| `unblock_pull_request` | `unblock PR` | `pull_request` |
| `resume_pull_request` | `resume PR` | `pull_request` |
Expand Down Expand Up @@ -156,7 +158,7 @@ Provider fields are:
| `pause_label` | `"deploybot-paused"` |
| `registry_label` | `"deploybot-registry"` |
| `registry_title` | `"DeployBot delivery registry"` |
| `thread_active_hours` | Positive integer; default 72. |
| `thread_active_hours` | Positive integer; default 72. Notification obligations and pending messages use their own non-expiring outbox. |
| `ci_workflows` | Workflow names followed as exact-main CI. Default: `["CI"]`. |
| `deploy_workflows` | Deployment workflow names. Default: `["Deploy"]`. |
| `batch_settle_seconds` | Non-negative window for coalescing near-ready deploy requests before freezing a batch. Default: 15. |
Expand All @@ -167,7 +169,7 @@ Provider fields are:
| `auto_promote` | Default `true`. |
| `intent_scope` | Currently must be `"head"`. |
| `pause_on_failure` | Default `true`. |
| `webhook_url_env` | Optional environment-variable name containing a best-effort event webhook URL. GitHub remains authoritative if notification fails. |
| `webhook_url_env` | Optional environment-variable name containing a best-effort event webhook URL. It receives retryable `thread-deployed` payloads after exact-main verification. GitHub remains authoritative if notification fails. |
| `verifications` | Optional array of post-deployment HTTP verification tables. Default: empty. |
| `name` | Required health-check display name in each `pipeline.verifications` entry. |
| `url` | Required URL checked after deployment in each `pipeline.verifications` entry. |
Expand Down Expand Up @@ -207,3 +209,11 @@ list aligned with `pipeline.ci_workflows`.
webhook URL.
- The composite Action maps `github.token` to `GH_TOKEN`; callers do not need to
create a separate token when its documented permissions are sufficient.

The `thread-deployed` event contains `notification_id`, `repository`,
`provider`, `thread_id`, `main_sha`, and a user-facing `message`, plus available
thread, pull-request, CI, and deployment URLs. Consumers must deduplicate on
`notification_id`, deliver `message` into the native provider thread, and call
`acknowledge_thread_deployment` only after that succeeds. Until acknowledgement,
the independent outbox record remains `pending` even if thread lifecycle moves
on, and later release followers can retry the same notification.
26 changes: 26 additions & 0 deletions skills/deploybot/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,29 @@ cumulative base heads until CI, deployment, and configured health checks verify.
Use `diagnose`/`deploybot doctor` for setup drift and `delivery_metrics` for p50,
p95, and slow-stage evidence. A failed cumulative CI or deployment pauses the
controller; only a designated coordinator may unpause after recovery.

## Notify Source Threads

After exact-main verification, `follow_release` returns one
`thread_notifications` entry per source thread and records that thread as
`deployed`. Deliver every entry's `message` into the recorded native thread so
the user can see completion by looking at that thread. In Codex, use the app's
`send_message_to_thread` tool to wake that thread with the supplied message and
instruct it to make the supplied message user-visible, then call
`acknowledge_thread_deployment` without doing more code work. Pass that entry's
`notification_id` to the acknowledgement. If already operating in the source
thread, show the message first, acknowledge it, and finish with the same status.

Treat `notification_id` as the idempotency key. Never acknowledge a thread
before its native-thread delivery succeeds, and never substitute a registry
comment for the native message. If native delivery is unavailable or fails,
leave the notification `pending`; a later coordinator or the provider-neutral
`thread-deployed` webhook can retry it.

The source thread that calls `request_deployment` also owns a durable wake-up.
If it will stop running before verification, attach the provider's native
thread heartbeat or follow-up monitor before returning. In Codex, use a thread
heartbeat automation. On wake, read `pipeline_status`; once this thread is
listed under pending `notifications`, first show its supplied message to the
user, then acknowledge it and remove the heartbeat. Do not use a tight polling
loop.
Loading