patchrelay 0.47.2 → 0.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,417 +1,126 @@
1
1
  # PatchRelay
2
2
 
3
- PatchRelay is a self-hosted harness for delegated Linear work and upkeep of linked pull requests on your own machine.
3
+ Self-hosted toolkit for shipping code with agents: a Linear-driven harness that runs Codex sessions inside your real repos, plus two GitHub-native services that review PRs and deliver them through a merge queue. Each component works on its own, and they communicate only through GitHub.
4
4
 
5
- It receives Linear webhooks, routes issues to the right local repository, prepares durable issue worktrees, runs Codex sessions through `codex app-server`, and keeps the issue loop observable and resumable from the CLI. GitHub webhooks drive reactive loops for CI repair, review fixes, and merge-steward incidents on linked delegated PRs. Separate downstream services own review automation and merge execution.
5
+ ## The stack
6
6
 
7
- PatchRelay is the system around the model:
7
+ This repository ships **three independent services**. Install one, two, or all three.
8
8
 
9
- - webhook intake and verification (Linear and GitHub)
10
- - Linear OAuth and workspace installations
11
- - issue-to-repo routing
12
- - issue worktree and branch lifecycle
13
- - context packaging, run orchestration, and thread continuity
14
- - reactive CI repair and review fix loops
15
- - queue repair runs triggered by Merge Steward evictions
16
- - native Linear agent input forwarding into active runs
17
- - read-only inspection and run reporting
9
+ | Service | Package | Role |
10
+ |-|-|-|
11
+ | [`patchrelay`](./) | `npm install -g patchrelay` | Linear-driven harness that runs Codex sessions inside your real repos. Fully autonomous on webhooks: implementation, review fix, CI repair, queue repair. |
12
+ | [`review-quill`](./packages/review-quill) | `npm install -g review-quill` | GitHub PR review bot. Reviews every merge-ready head from a real local checkout and posts a normal `APPROVE` / `REQUEST_CHANGES` review. |
13
+ | [`merge-steward`](./packages/merge-steward) | `npm install -g merge-steward` | Serial merge queue. Speculatively integrates approved PRs on top of the latest `main`, runs CI on the integrated SHA, and fast-forwards `main` only when that tested result is green. |
18
14
 
19
- If you want Codex to work inside your real repos with your real tools, secrets, SSH access, and deployment surface, PatchRelay is the harness that makes that loop reliable.
15
+ Common setups:
20
16
 
21
- ## Why PatchRelay
17
+ - **Full autonomy** — all three. PatchRelay implements from a Linear issue, review-quill reviews, merge-steward delivers. No human in the room.
18
+ - **Supervised delivery** — `review-quill` + `merge-steward` without PatchRelay, driven by your own agent (Claude Code, Cursor, Codex CLI, …). See [Use with your own agent](#use-with-your-own-agent).
19
+ - **Queue only** or **review only** — run either downstream service on its own if you already have the other half of the story.
22
20
 
23
- - Keep the agent in the real environment instead of rebuilding that environment in a hosted sandbox.
24
- - Use your existing machine, repos, secrets, SSH config, shell tools, and deployment access.
25
- - Keep deterministic workflow logic outside the model: context packaging, routing, run orchestration, worktree ownership, verification, and reporting.
26
- - Choose the Codex approval and sandbox settings that match your risk tolerance.
27
- - Let Linear drive the loop through delegation and native agent sessions.
28
- - Let GitHub drive reactive loops through PR reviews and CI check events.
29
- - Drop into the exact issue worktree and resume control manually when needed.
21
+ ### What this buys you
30
22
 
31
- ## What PatchRelay Owns
23
+ - **PRs ship tested against the latest `main`.** The queue re-validates on the integrated SHA at admission time, and retries if `main` moves during validation. No more "green yesterday, broken today."
24
+ - **Many PR failures have mechanical fixes an agent can handle.** Requested changes like a rename, a missing null check, a new test; rebase on `main`; resolving a conflict surfaced by speculation; rerunning a flaky job. Both services publish structured failure reasons (inline review comments, failing check names, queue incidents) an agent can act on directly.
25
+ - **No prerequisites beyond GitHub.** A GitHub App, a webhook, and `npm install -g` per service.
32
26
 
33
- PatchRelay does the deterministic harness work that you do not want to re-implement around every model run:
27
+ ## Use with your own agent
34
28
 
35
- - verifies and deduplicates Linear and GitHub webhooks
36
- - maps issue events to the correct local project
37
- - packages the right issue, repo, review, and failure context for each loop
38
- - creates and reuses one durable worktree and branch per issue lifecycle
39
- - starts Codex threads for implementation runs
40
- - triggers reactive runs for CI failures, review feedback, and Merge Steward evictions
41
- - opens and updates PRs for delegated implementation work
42
- - marks its own PRs ready when implementation is complete
43
- - can later repair a linked PR that was opened externally once the issue is delegated
44
- - persists enough state to correlate the Linear issue, local workspace, run, and Codex thread
45
- - reports progress back to Linear and forwards follow-up agent input into active runs
46
- - exposes CLI and optional read-only inspection surfaces so operators can understand what happened
29
+ For supervised delivery an agent you drive from Claude Code / Cursor / Codex iterating on PRs in real time — install the [`ship-pr`](https://github.com/krasnoperov/patchrelay-agents) skill from the companion marketplace:
47
30
 
48
- PatchRelay does not own review decisions or queue admission. GitHub is the source of truth for PR readiness, `reviewbot` owns review automation, and [Merge Steward](./packages/merge-steward) owns queueing and merge execution.
49
-
50
- ## System Layers
51
-
52
- PatchRelay works best when read as five layers with clear ownership:
53
-
54
- - policy layer: repo workflow files (`IMPLEMENTATION_WORKFLOW.md`, `REVIEW_WORKFLOW.md`)
55
- - coordination layer: issue claiming, run scheduling, retry budgets, and reconciliation
56
- - execution layer: durable worktrees, Codex threads, and queued turn input delivery
57
- - integration layer: Linear webhooks, GitHub webhooks, OAuth, project routing, and state sync
58
- - observability layer: CLI inspection, session status, and operator endpoints
59
-
60
- That separation is intentional. PatchRelay is not the policy itself and it is not the coding agent. It is the harness that keeps context, action, verification, and repair coordinated in a real repository with real operational state.
61
-
62
- ## Runtime Model
63
-
64
- PatchRelay is designed for a local, operator-owned setup:
65
-
66
- - PatchRelay service runs on your machine or server (default `127.0.0.1:8787`)
67
- - Codex runs through `codex app-server`
68
- - Linear is the control surface
69
- - `patchrelay` CLI is the operator interface
70
- - a reverse proxy exposes the Linear-facing and GitHub-facing webhook routes
71
-
72
- Linux and Node.js `24+` are the intended runtime.
73
-
74
- You will also need:
75
-
76
- - `git`
77
- - `codex`
78
- - a Linear OAuth app for this PatchRelay deployment
79
- - a Linear webhook secret
80
- - a public HTTPS entrypoint such as Caddy, nginx, or a tunnel so Linear and GitHub can reach your PatchRelay webhooks
81
-
82
- ## How It Works
83
-
84
- 1. A human delegates PatchRelay on an issue to start automation.
85
- 2. PatchRelay verifies the webhook, routes the issue to the right local project, and packages the issue context for the first loop.
86
- 3. Delegated issues create or reuse the issue worktree and launch the appropriate first run through `codex app-server`.
87
- 4. PatchRelay persists thread ids, run state, and observations so the work stays inspectable and resumable.
88
- 5. GitHub webhooks drive reactive verification and repair loops: CI repair on check failures and review fix on changes requested.
89
- 6. Implementation issues usually open draft PRs while work is in progress and mark PatchRelay-owned PRs ready when implementation is complete.
90
- 7. Downstream automation reacts to GitHub truth: `reviewbot` reviews ready PRs with green CI, and Merge Steward admits ready PRs with green CI and approval into the merge queue.
91
- 8. If requested changes, red CI, or a merge-steward incident lands on a linked delegated PR, PatchRelay resumes work on that same PR branch.
92
- 9. Native agent prompts and Linear comments can steer the active run. An operator can take over from the exact same worktree when needed.
93
-
94
- Not every delegated issue should produce its own PR. Some delegated issues are coordination-only:
95
-
96
- - parent trackers that spawn or coordinate child implementation issues
97
- - audit or convergence issues that should wait for child issues before doing a narrow final pass
98
- - planning/specification issues that are complete once the right follow-up issues or decisions exist
99
-
100
- In those cases, PatchRelay should avoid opening an overlapping umbrella PR and should finish through coordination, follow-up issue creation, or a no-PR completion path instead.
101
-
102
- ### Undelegation And Re-delegation
103
-
104
- Undelegation pauses PatchRelay authority. It does not erase PR truth.
105
-
106
- - If there is no PR yet, the issue keeps its literal local-work state such as `delegated` or `implementing`, but PatchRelay becomes paused.
107
- - If a PR already exists, the issue keeps its PR-backed state and PatchRelay becomes observer-only.
108
- - Worktrees, branches, and PRs remain in place.
109
- - PatchRelay still reflects GitHub review, CI, queue, merge, and close events while undelegated.
110
- - PatchRelay does not enqueue implementation, review-fix, CI-repair, or queue-repair work again until the issue is delegated back.
111
- - If someone opens a new PR for the issue while it is undelegated, PatchRelay can link that PR when the title, body, or branch name contains one unambiguous tracked issue key for the project.
112
-
113
- Downstream services stay PR-centric:
114
-
115
- - `review-quill` may still review a qualifying PR
116
- - `merge-steward` may still queue or merge a qualifying PR
117
-
118
- When the issue is delegated back to PatchRelay, it should resume from current truth:
119
-
120
- - no PR: queue implementation
121
- - PR with requested changes: queue review fix or branch upkeep
122
- - PR with failing CI: queue CI repair
123
- - PR with queue eviction/conflict: queue queue repair
124
- - healthy open PR: keep waiting on review
125
- - approved PR: keep waiting downstream
126
-
127
- ## Ownership Model
128
-
129
- PatchRelay keeps ownership simple:
130
-
131
- - workflow truth: the current factory state plus GitHub PR/review/CI facts
132
- - runtime authority: whether PatchRelay may actively write or repair code right now
133
-
134
- PatchRelay persists one explicit authority bit:
135
-
136
- - `delegatedToPatchRelay`: whether PatchRelay may actively implement or repair code for the issue right now
137
-
138
- Once a PR is linked to an issue, delegation decides whether PatchRelay may repair it. The PR may have been opened by PatchRelay, a human, or another external system.
139
-
140
- That authority does not change just because:
141
-
142
- - the issue is undelegated
143
- - the PR becomes ready for review
144
- - the PR is approved
145
- - the PR enters or leaves the merge queue
146
-
147
- ## Factory State Machine
148
-
149
- Each issue progresses through a factory state machine:
150
-
151
- ```text
152
- delegated → preparing → implementing → pr_open → awaiting_review
153
- → changes_requested (review fix run) → back to implementing
154
- → repairing_ci (CI repair run) → back to pr_open
155
- → awaiting_queue → done (merged)
156
- → repairing_queue (queue repair run) → back to pr_open
157
- → escalated or failed (when retry budgets are exhausted)
31
+ ```
32
+ /plugin marketplace add krasnoperov/patchrelay-agents
33
+ /plugin install ship-pr@patchrelay
158
34
  ```
159
35
 
160
- Run types:
161
-
162
- - `implementation` — initial coding work
163
- - `review_fix` — address reviewer feedback
164
- - `ci_repair` — fix failing CI checks
165
- - `queue_repair` — fix merge queue failures
166
-
167
- PatchRelay treats these as distinct loop types with different context, entry conditions, and success criteria rather than as one generic "ask the agent again" workflow.
168
-
169
- The long-term runtime model is a small durable `IssueSession`:
170
-
171
- - `idle`
172
- - `running`
173
- - `waiting_input`
174
- - `done`
175
- - `failed`
176
-
177
- Waiting on review or queue should be represented as a waiting reason, not as a large internal control-plane state machine.
178
-
179
- `awaiting_input` is reserved for real human-needed situations:
180
-
181
- - a completion check asked a question
182
- - an operator explicitly stopped the run and wants a next decision
183
- - a reply is required before PatchRelay can continue
184
-
185
- Undelegated local work should stay in its literal workflow state and show a paused waiting reason instead.
186
-
187
- ## Restart And Reconciliation
188
-
189
- PatchRelay treats restart safety as part of the harness contract, not as a best-effort extra.
190
-
191
- After a restart, the service can answer:
192
-
193
- - which issue owns each active worktree
194
- - which run was active or queued
195
- - which Codex thread and turn belong to that work
196
- - whether the issue is still eligible to continue
197
- - whether the run should resume, hand off, or fail back to a human state
198
-
199
- This is why PatchRelay keeps a durable `issues` and `runs` table alongside Codex thread history and Linear state. The goal is not to duplicate the model transcript. The goal is to make automation restartable, inspectable, and recoverable when the process or machine is interrupted.
200
-
201
- ## Workflow Files
202
-
203
- PatchRelay uses repo-local workflow files as prompts for Codex runs:
204
-
205
- - `IMPLEMENTATION_WORKFLOW.md` — used for implementation, CI repair, and queue repair runs
206
- - `REVIEW_WORKFLOW.md` — used for review fix runs
207
-
208
- These files define how the agent should work in that repository. Keep them short, action-oriented, and human-authored.
209
-
210
- The built-in PatchRelay prompt scaffold lives in `src/prompting/patchrelay.ts`. It is intentionally small: task objective, scope discipline, reactive repair context, workflow guidance, and publication contract. Installation-level and repo-level prompt config can add one extra instructions file or replace a small set of policy sections. See [`docs/prompting.md`](./docs/prompting.md).
211
-
212
- ## Knowledge And Validation Surfaces
213
-
214
- PatchRelay works best when repository guidance follows progressive disclosure:
215
-
216
- - keep the root entrypoints short and navigational
217
- - treat deeper `docs/` content as the durable system of record
218
- - capture architecture, workflow, and product decisions in versioned files instead of chat history or operator memory
219
-
220
- PatchRelay should also help agents validate their own work inside the issue loop:
221
-
222
- - package the smallest useful context for the current run instead of replaying ever-growing transcript history
223
- - preserve high-signal failure evidence such as review feedback, failing checks, and queue incidents
224
- - make repo-local validation surfaces legible per worktree so the next run can see what passed, what failed, and what needs repair
225
-
226
- Keeping those knowledge and validation surfaces clean is part of the harness, not optional documentation polish.
227
-
228
- ## Access Control
229
-
230
- PatchRelay reacts only for issues that route to a configured project.
231
-
232
- - use `linear_team_ids`, `issue_key_prefixes`, and optional labels to keep unrelated or public boards out of scope
233
- - in the normal setup, anyone with access to the routed Linear project can delegate work to the PatchRelay app
234
- - use `trusted_actors` only when a project needs a narrower allowlist inside Linear
36
+ `ship-pr` teaches the agent to block on `review-quill pr status --wait` and `merge-steward pr status --wait`, read structured failure reasons on exit `2`, fix the code, push, and re-enter the wait. No polling loop, no LLM-judged "is it done yet?". See [patchrelay-agents](https://github.com/krasnoperov/patchrelay-agents) for more.
235
37
 
236
- That keeps the default model simple without forcing an extra allowlist for every team.
38
+ ## Quick start (PatchRelay harness)
237
39
 
238
- ## Quick Start
40
+ Prerequisites:
239
41
 
240
- ### 1. Install
42
+ - Linux with shell access, Node.js `24+`
43
+ - `git` and `codex` (authenticated for the same user that will run PatchRelay)
44
+ - a Linear OAuth app and webhook secret
45
+ - a public HTTPS entrypoint (Caddy, nginx, tunnel) so Linear and GitHub can reach your webhooks
241
46
 
242
47
  ```bash
243
48
  npm install -g patchrelay
244
- ```
245
-
246
- ### 2. Bootstrap config
247
-
248
- ```bash
249
49
  patchrelay init https://patchrelay.example.com
250
50
  ```
251
51
 
252
- `patchrelay init` requires the public HTTPS origin up front because Linear needs a fixed webhook URL and OAuth callback URL for this PatchRelay instance.
253
-
254
- It creates the local config, env file, and system service units:
255
-
256
- - `~/.config/patchrelay/runtime.env`
257
- - `~/.config/patchrelay/service.env`
258
- - `~/.config/patchrelay/patchrelay.json`
259
- - `/etc/systemd/system/patchrelay.service`
260
-
261
- The generated `patchrelay.json` is intentionally minimal, and `patchrelay init` prints the webhook URL, OAuth callback URL, and the Linear app values you need next.
262
-
263
- ### 3. Configure access
264
-
265
- Edit `~/.config/patchrelay/service.env` and fill in only the Linear OAuth client values. Keep the generated webhook secret and token-encryption key:
52
+ `init` writes the local config, env files, and systemd unit. Edit `~/.config/patchrelay/service.env` to fill in the Linear OAuth client id and secret (the webhook secret and token-encryption key are generated for you). Then:
266
53
 
267
54
  ```bash
268
- LINEAR_WEBHOOK_SECRET=generated-by-patchrelay-init
269
- PATCHRELAY_TOKEN_ENCRYPTION_KEY=generated-by-patchrelay-init
270
- LINEAR_OAUTH_CLIENT_ID=replace-with-linear-oauth-client-id
271
- LINEAR_OAUTH_CLIENT_SECRET=replace-with-linear-oauth-client-secret
272
- ```
273
-
274
- Keep service secrets in `service.env`. `runtime.env` is for non-secret overrides such as `PATCHRELAY_DB_PATH` or `PATCHRELAY_LOG_FILE`. Everyday local inspection commands do not require exporting these values in your shell.
275
-
276
- ### 4. Connect PatchRelay to Linear
277
-
278
- Connect PatchRelay to one Linear workspace:
279
-
280
- ```bash
281
- patchrelay linear connect
282
- patchrelay linear sync
283
- ```
284
-
285
- This authorizes the workspace once, then caches its teams and projects locally. Workspace auth is separate from repo linking.
286
-
287
- ### 5. Link a GitHub repo
288
-
289
- Link repos by GitHub identity, not by local path:
290
-
291
- ```bash
292
- patchrelay repo link krasnoperov/usertold --workspace usertold --team USE
293
- ```
294
-
295
- PatchRelay treats the GitHub repo as the source of truth. It reuses an existing local clone under the managed repo root when `origin` already matches, or clones it automatically when missing. Use `--path <path>` only when you want a non-default local location.
296
-
297
- The generated `~/.config/patchrelay/patchrelay.json` stays machine-level service config. Repo links should be created with the CLI, not by hand-editing the file.
298
-
299
- `patchrelay repo link` is idempotent:
300
-
301
- - it creates or updates the linked repo entry
302
- - it refreshes the selected Linear workspace catalog before resolving teams/projects
303
- - it reloads the service when it can
304
- - if workflow files or secrets are still missing, it tells you exactly what to fix and can be rerun safely
305
-
306
- ### 6. Add workflow docs to the repo
307
-
308
- PatchRelay looks for:
309
-
310
- ```text
311
- IMPLEMENTATION_WORKFLOW.md
312
- REVIEW_WORKFLOW.md
313
- ```
314
-
315
- These files define how the agent should work in that repo.
316
-
317
- ### 7. Validate
318
-
319
- ```bash
320
- patchrelay doctor
55
+ patchrelay linear connect # one-time Linear OAuth
56
+ patchrelay linear sync # cache teams/projects
57
+ patchrelay repo link krasnoperov/usertold \
58
+ --workspace usertold --team USE # link a GitHub repo
59
+ patchrelay doctor # validate
321
60
  patchrelay service status
322
61
  patchrelay dashboard
323
62
  ```
324
63
 
325
- ### 8. Check linked workspaces and repos
326
-
327
- ```bash
328
- patchrelay linear list
329
- patchrelay repo list
330
- ```
331
-
332
- If you later add another local repo from the same workspace, run `patchrelay repo link <owner/repo> --workspace <workspace> --team <team>` again. PatchRelay reuses the existing workspace installation instead of opening a new OAuth flow.
333
-
334
- Important:
64
+ Each repo needs two workflow files that act as agent prompts:
335
65
 
336
- - Linear needs a public HTTPS URL to reach your webhook.
337
- - `patchrelay init <public-base-url>` writes `server.public_base_url`, which PatchRelay uses when it prints webhook URLs.
338
- - For ingress, OAuth app setup, and webhook details, use the self-hosting docs.
66
+ - `IMPLEMENTATION_WORKFLOW.md` implementation, CI repair, queue repair runs
67
+ - `REVIEW_WORKFLOW.md` review fix runs
339
68
 
340
- ## Daily Loop
69
+ Keep them short, action-oriented, human-authored. See [prompting.md](./docs/prompting.md) for how the built-in scaffold composes them with the rest of the prompt.
341
70
 
342
- 1. Delegate a Linear issue to the PatchRelay app.
343
- 2. Linear sends the delegation and agent-session webhooks to PatchRelay, which creates or reuses the issue worktree and launches an implementation run.
344
- 3. Follow up in the Linear agent session to steer the active run or wake it with fresh input while it remains delegated.
345
- 4. GitHub webhooks automatically trigger CI repair, review fix, or merge queue repair runs when needed.
346
- 5. Watch progress from the terminal or open the same worktree and take over manually.
71
+ Full install, ingress, and GitHub/Linear app setup: [self-hosting.md](./docs/self-hosting.md). Daily ops and CLI cheatsheet: [operator-guide.md](./docs/operator-guide.md).
347
72
 
348
- Useful commands:
73
+ ## How it works
349
74
 
350
- - `patchrelay dashboard`
351
- - `patchrelay issue list --active`
352
- - `patchrelay issue show APP-123`
353
- - `patchrelay issue watch APP-123`
354
- - `patchrelay issue path APP-123 --cd`
355
- - `patchrelay issue open APP-123`
356
- - `patchrelay issue retry APP-123`
357
- - `patchrelay service restart`
358
- - `patchrelay service logs --lines 100`
75
+ 1. A human delegates an issue to the PatchRelay Linear app.
76
+ 2. PatchRelay verifies the webhook, routes the issue to the right local repo, prepares a durable worktree, and launches an implementation run through `codex app-server`.
77
+ 3. PatchRelay persists thread ids, run state, and observations so work stays inspectable and restartable.
78
+ 4. GitHub webhooks drive reactive repair loops — CI repair on check failures, review fix on requested changes, queue repair on merge-steward evictions.
79
+ 5. `review-quill` reviews ready PRs; `merge-steward` admits approved, green PRs and delivers them by speculative integration.
80
+ 6. An operator can take over inside the same worktree at any time.
359
81
 
360
- PatchRelay's operator surface is being reduced to its own runtime responsibilities: issue status,
361
- active work, waiting reason, worktree handoff, and retry controls.
82
+ Architecture and failure taxonomy: [architecture.md](./docs/architecture.md). Downstream delivery: [merge-queue.md](./docs/merge-queue.md).
362
83
 
363
- `patchrelay issue open` is the handoff bridge: it opens a normal Codex CLI session in the issue worktree and resumes the existing thread when PatchRelay has one.
84
+ ## Downstream services
364
85
 
365
- If automation looks stuck, this is the usual operator path:
86
+ Two separate services handle review and delivery. Both are independent, GitHub-native, and usable without PatchRelay.
366
87
 
367
- 1. `patchrelay dashboard` to see active issues and waiting reasons across the service.
368
- 2. `patchrelay issue show APP-123` or `patchrelay issue watch APP-123` to inspect one issue in more detail.
369
- 3. `patchrelay issue open APP-123` to take over inside the exact worktree and continue from the same issue context.
370
- 4. `patchrelay service logs --lines 100` if the problem looks like webhook intake, Codex startup, or service runtime failure.
88
+ ### review-quill
371
89
 
372
- Today that takeover path is intentionally YOLO mode: it launches Codex with `--dangerously-bypass-approvals-and-sandbox`.
90
+ Watches PRs and posts ordinary GitHub reviews from a real local checkout of the PR head. By default reviews as soon as the head updates; can optionally wait for configured checks to go green first.
373
91
 
374
- ## Operator View
375
-
376
- PatchRelay keeps enough durable state to answer the questions that matter during and after a run:
377
-
378
- - which worktree and branch belong to an issue
379
- - which run is active or queued
380
- - which Codex thread owns the current work
381
- - what the agent said
382
- - which commands it ran
383
- - which files it changed
384
- - whether the run completed, failed, or needs handoff
385
-
386
- ## Merge Steward
92
+ ```bash
93
+ review-quill init https://review.example.com
94
+ review-quill repo attach owner/repo
95
+ review-quill doctor --repo repo
96
+ ```
387
97
 
388
- [Merge Steward](./packages/merge-steward) is a separate service that owns serial merge queue integration. PatchRelay develops code and produces pull requests. Merge Steward delivers those PRs into production — rebasing onto main, waiting for CI, and merging when green.
98
+ See the [review-quill package README](./packages/review-quill/README.md) for the pitch and quick start, or [docs/review-quill.md](./docs/review-quill.md) for the full operator reference.
389
99
 
390
- The two services communicate through GitHub. PatchRelay makes its own PR ready, and Merge Steward decides queue admission and merge execution from GitHub truth. On failure, the steward reports the incident through GitHub signals, and PatchRelay can trigger a queue repair run in response.
100
+ ### merge-steward
391
101
 
392
- The steward now has its own bootstrap flow:
102
+ Serial merge queue with speculative integration. Rebases each approved PR onto the current `main`, runs CI on the integrated SHA, and fast-forwards `main` only when that tested result is green. Evictions produce a durable incident and a GitHub check run — the signal an agent uses to trigger a repair.
393
103
 
394
104
  ```bash
395
105
  merge-steward init https://queue.example.com
396
- merge-steward attach app owner/repo --base-branch main --required-check test,lint
397
- merge-steward doctor --repo app
106
+ merge-steward attach owner/repo --base-branch main
107
+ merge-steward doctor --repo repo
398
108
  merge-steward service status
399
- merge-steward queue status --repo app
400
109
  ```
401
110
 
402
- See [Merge queue](./docs/merge-queue.md) for the full two-service overview and [Merge Steward README](./packages/merge-steward/README.md) for operational details.
111
+ See the [merge-steward package README](./packages/merge-steward/README.md) for the pitch and quick start, [docs/merge-steward.md](./docs/merge-steward.md) for the full operator reference, or [docs/merge-queue.md](./docs/merge-queue.md) for the two-service overview.
403
112
 
404
113
  ## Docs
405
114
 
406
- Use the README for the product overview and quick start. Use the docs for operating details:
407
-
408
- - [Merge queue and delivery](./docs/merge-queue.md)
409
- - [Self-hosting and deployment](./docs/self-hosting.md)
410
- - [Architecture](./docs/architecture.md)
411
- - [Design docs index](./docs/design-docs/index.md)
412
- - [Design principles](./docs/design-docs/core-beliefs.md)
413
- - [External reference patterns](./docs/references/external-patterns.md)
414
- - [Security policy](./SECURITY.md)
115
+ - [Self-hosting and deployment](./docs/self-hosting.md) install, ingress, OAuth and GitHub App setup
116
+ - [Architecture](./docs/architecture.md) — components, ownership, state machine, failure taxonomy
117
+ - [Operator guide](./docs/operator-guide.md) — daily loop, CLI cheatsheet, troubleshooting
118
+ - [Merge queue](./docs/merge-queue.md) — the two-service delivery story
119
+ - [Prompting](./docs/prompting.md) — how workflow files and the built-in scaffold compose
120
+ - [Secrets](./docs/secrets.md) — systemd credentials, resolution order
121
+ - [review-quill reference](./docs/review-quill.md) · [merge-steward reference](./docs/merge-steward.md)
122
+ - [Product specs](./docs/product-specs/index.md) · [Design docs](./docs/design-docs/index.md) · [Core beliefs](./docs/design-docs/core-beliefs.md)
123
+ - [Contributing](./CONTRIBUTING.md) · [Security policy](./SECURITY.md)
415
124
 
416
125
  ## Status
417
126
 
@@ -19,6 +19,14 @@ function implementationPlan() {
19
19
  { content: "Merge", status: "pending" },
20
20
  ];
21
21
  }
22
+ function orchestrationPlan() {
23
+ return [
24
+ { content: "Review umbrella goal and child set", status: "pending" },
25
+ { content: "Wait for or inspect child progress", status: "pending" },
26
+ { content: "Audit delivered outcome", status: "pending" },
27
+ { content: "Close umbrella or create follow-up work", status: "pending" },
28
+ ];
29
+ }
22
30
  function reviewFixPlan() {
23
31
  return [
24
32
  { content: "Prepare workspace", status: "completed" },
@@ -95,6 +103,38 @@ function resolvePlanRunType(params) {
95
103
  }
96
104
  }
97
105
  export function buildAgentSessionPlan(params) {
106
+ if (params.issueClass === "orchestration") {
107
+ const settling = params.orchestrationSettleUntil
108
+ ? Number.isFinite(Date.parse(params.orchestrationSettleUntil)) && Date.parse(params.orchestrationSettleUntil) > Date.now()
109
+ : false;
110
+ if (settling) {
111
+ return [
112
+ { content: "Wait for child set to settle", status: "inProgress" },
113
+ { content: "Review umbrella goal and child set", status: "pending" },
114
+ { content: "Wait for or inspect child progress", status: "pending" },
115
+ { content: "Audit delivered outcome", status: "pending" },
116
+ ];
117
+ }
118
+ switch (params.factoryState) {
119
+ case "done":
120
+ return setStatuses(orchestrationPlan(), ["completed", "completed", "completed", "completed"]);
121
+ case "awaiting_input":
122
+ case "failed":
123
+ case "escalated":
124
+ return setStatuses(orchestrationPlan(), ["completed", "completed", "completed", "inProgress"]);
125
+ case "implementing":
126
+ case "changes_requested":
127
+ case "repairing_ci":
128
+ case "repairing_queue":
129
+ return setStatuses(orchestrationPlan(), ["completed", "inProgress", "pending", "pending"]);
130
+ case "pr_open":
131
+ case "awaiting_queue":
132
+ return setStatuses(orchestrationPlan(), ["completed", "completed", "inProgress", "pending"]);
133
+ case "delegated":
134
+ default:
135
+ return setStatuses(orchestrationPlan(), ["inProgress", "pending", "pending", "pending"]);
136
+ }
137
+ }
98
138
  const runType = resolvePlanRunType(params);
99
139
  switch (params.factoryState) {
100
140
  case "delegated":
@@ -151,6 +191,8 @@ export function buildAgentSessionPlanForIssue(issue, options) {
151
191
  factoryState: issue.factoryState,
152
192
  ciRepairAttempts: issue.ciRepairAttempts,
153
193
  queueRepairAttempts: issue.queueRepairAttempts,
194
+ ...(issue.issueClass ? { issueClass: issue.issueClass } : {}),
195
+ ...(issue.orchestrationSettleUntil ? { orchestrationSettleUntil: issue.orchestrationSettleUntil } : {}),
154
196
  ...(issue.pendingRunType ? { pendingRunType: issue.pendingRunType } : {}),
155
197
  ...(options?.activeRunType ? { activeRunType: options.activeRunType } : {}),
156
198
  });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "service": "patchrelay",
3
- "version": "0.47.2",
4
- "commit": "8e7084588da7",
5
- "builtAt": "2026-04-18T12:47:45.623Z"
3
+ "version": "0.49.0",
4
+ "commit": "e4ca4c92eb96",
5
+ "builtAt": "2026-04-19T10:24:09.505Z"
6
6
  }