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 +71 -362
- package/dist/agent-session-plan.js +42 -0
- package/dist/build-info.json +3 -3
- package/dist/db/issue-store.js +101 -4
- package/dist/db/migrations.js +44 -0
- package/dist/db.js +12 -0
- package/dist/github-webhook-terminal-handler.js +7 -0
- package/dist/idle-reconciliation.js +19 -0
- package/dist/issue-class.js +35 -0
- package/dist/issue-overview-query.js +2 -0
- package/dist/issue-session-events.js +12 -2
- package/dist/issue-session.js +6 -0
- package/dist/linear-client.js +13 -0
- package/dist/linear-status-comment-sync.js +1 -0
- package/dist/no-pr-completion-check.js +18 -3
- package/dist/orchestration-parent-wake.js +96 -0
- package/dist/prompting/patchrelay.js +99 -22
- package/dist/run-orchestrator.js +22 -9
- package/dist/tracked-issue-list-query.js +3 -0
- package/dist/tracked-issue-projector.js +3 -0
- package/dist/waiting-reason.js +7 -0
- package/dist/webhooks/comment-wake-handler.js +6 -1
- package/dist/webhooks/decision-helpers.js +3 -0
- package/dist/webhooks/desired-stage-recorder.js +86 -1
- package/dist/webhooks.js +7 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,417 +1,126 @@
|
|
|
1
1
|
# PatchRelay
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
5
|
+
## The stack
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
This repository ships **three independent services**. Install one, two, or all three.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
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
|
-
|
|
15
|
+
Common setups:
|
|
20
16
|
|
|
21
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
27
|
+
## Use with your own agent
|
|
34
28
|
|
|
35
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
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
|
-
|
|
38
|
+
## Quick start (PatchRelay harness)
|
|
237
39
|
|
|
238
|
-
|
|
40
|
+
Prerequisites:
|
|
239
41
|
|
|
240
|
-
|
|
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
|
-
`
|
|
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
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
-
|
|
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
|
-
-
|
|
337
|
-
- `
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
73
|
+
## How it works
|
|
349
74
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
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
|
-
|
|
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
|
-
|
|
84
|
+
## Downstream services
|
|
364
85
|
|
|
365
|
-
|
|
86
|
+
Two separate services handle review and delivery. Both are independent, GitHub-native, and usable without PatchRelay.
|
|
366
87
|
|
|
367
|
-
|
|
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
|
-
|
|
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
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
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
|
-
[
|
|
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
|
-
|
|
100
|
+
### merge-steward
|
|
391
101
|
|
|
392
|
-
|
|
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
|
|
397
|
-
merge-steward doctor --repo
|
|
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 [
|
|
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
|
-
|
|
407
|
-
|
|
408
|
-
- [
|
|
409
|
-
- [
|
|
410
|
-
- [
|
|
411
|
-
- [
|
|
412
|
-
- [
|
|
413
|
-
- [
|
|
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
|
});
|
package/dist/build-info.json
CHANGED