open-research-protocol 0.4.2 → 0.4.4

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.
@@ -0,0 +1,521 @@
1
+ # ORP Link And Runner Plan
2
+
3
+ Use this document as the implementation plan for making project linking, session linking, and hosted runner delivery first-class ORP CLI features.
4
+
5
+ ## Goal
6
+
7
+ Make the npm/CLI package the source of truth for:
8
+
9
+ - linking a local repo to a hosted ORP idea/world
10
+ - linking one or more local ORP sessions to live Codex sessions
11
+ - syncing machine/project/session availability to the hosted app
12
+ - receiving hosted jobs and routing them to the correct local Codex session
13
+
14
+ The Rust desktop app should remain the best UX for session discovery, terminal/window management, and local operator flow, but it should rely on the CLI-owned contract instead of maintaining a divergent one.
15
+
16
+ ## Current State
17
+
18
+ What already exists:
19
+
20
+ - The CLI already supports project/world binding through `orp world bind`.
21
+ - The CLI already supports hosted auth, hosted ideas, hosted world inspection, hosted checkpoint queueing, and a checkpoint-oriented worker surface.
22
+ - The Rust app already shells out to `orp world bind` when linking a project.
23
+ - The Rust app already has a machine-runner sync and targeted prompt execution model based on linked projects and linked sessions.
24
+
25
+ What is misaligned:
26
+
27
+ - The Rust app stores local project/session state in `.orp/...`.
28
+ - The CLI stores repo governance state in `orp/` and `.git/orp/runtime.json`.
29
+ - Project binding exists as a low-level CLI command, but there is no CLI-owned project/session registry surface yet.
30
+ - There are effectively two worker lanes:
31
+ - checkpoint worker lane in the CLI
32
+ - machine-runner prompt lane in the Rust app
33
+
34
+ ## Product Boundary
35
+
36
+ The CLI should own:
37
+
38
+ - the machine-readable project link format
39
+ - the machine-readable linked session format
40
+ - the machine runner sync format
41
+ - the hosted runner work loop contract
42
+
43
+ The Rust app should own:
44
+
45
+ - desktop UI
46
+ - session discovery
47
+ - session/window/tab management
48
+ - calling the CLI for canonical project/session link operations
49
+
50
+ ## Canonical Concepts
51
+
52
+ ### Linked Project
53
+
54
+ A linked project is a local repo that is associated with one hosted idea/world.
55
+
56
+ Required fields:
57
+
58
+ - `idea_id`
59
+ - `project_root`
60
+
61
+ Important optional fields:
62
+
63
+ - `idea_title`
64
+ - `world_id`
65
+ - `world_name`
66
+ - `github_url`
67
+ - `linked_at_utc`
68
+ - `linked_email`
69
+
70
+ ### Linked Session
71
+
72
+ A linked session is a machine-local ORP session that can route work into a specific Codex session.
73
+
74
+ Required fields:
75
+
76
+ - `orp_session_id`
77
+ - `label`
78
+ - `state`
79
+
80
+ Important optional fields:
81
+
82
+ - `codex_session_id`
83
+ - `project_root`
84
+ - `role`
85
+ - `terminal_target`
86
+ - `last_active_at_utc`
87
+ - `archived`
88
+ - `primary`
89
+
90
+ ### Machine Runner
91
+
92
+ A machine runner is the machine-local worker identity exposed to the hosted app.
93
+
94
+ Required fields:
95
+
96
+ - `machine_id`
97
+ - `machine_name`
98
+ - `platform`
99
+ - `runner_enabled`
100
+
101
+ Important optional fields:
102
+
103
+ - `last_heartbeat_at_utc`
104
+ - `last_sync_at_utc`
105
+ - `app_version`
106
+ - `linked_email`
107
+
108
+ ### Hosted Job
109
+
110
+ A hosted job is a transport-agnostic unit of work that can target a project or an exact linked session.
111
+
112
+ Required fields:
113
+
114
+ - `job_id`
115
+ - `kind`
116
+ - `status`
117
+
118
+ Important optional fields:
119
+
120
+ - `idea_id`
121
+ - `world_id`
122
+ - `machine_id`
123
+ - `project_root`
124
+ - `orp_session_id`
125
+ - `codex_session_id`
126
+ - `prompt`
127
+ - `lease_id`
128
+ - `created_at_utc`
129
+ - `started_at_utc`
130
+ - `finished_at_utc`
131
+
132
+ ## Storage Plan
133
+
134
+ ### Repo-tracked state
135
+
136
+ Keep repo governance where the CLI already writes it:
137
+
138
+ - `orp/governance.json`
139
+ - `orp/agent-policy.json`
140
+ - `orp/HANDOFF.md`
141
+ - `orp/checkpoints/CHECKPOINT_LOG.md`
142
+ - `orp/state.json`
143
+
144
+ ### Repo-local machine state
145
+
146
+ Store machine-local link/session data under `.git/orp/link/` so it does not dirty the worktree or leak machine-specific identifiers into git history.
147
+
148
+ Planned files:
149
+
150
+ - `.git/orp/link/project.json`
151
+ - `.git/orp/link/sessions/<orp_session_id>.json`
152
+ - `.git/orp/link/runner.json`
153
+ - `.git/orp/link/runtime.json`
154
+
155
+ ### Global machine state
156
+
157
+ Store cross-repo machine identity in the user config directory:
158
+
159
+ - `~/.config/orp/machine.json`
160
+
161
+ ### Migration source
162
+
163
+ Treat the Rust app's `.orp/project.json` and `.orp/sessions/*.json` as import sources during migration, not as long-term canonical storage.
164
+
165
+ ## Planned CLI Surface
166
+
167
+ ### Project link commands
168
+
169
+ ```sh
170
+ orp link project bind --idea-id <idea-id> [--idea-title <title>] [--github-url <url>] [--codex-session-id <session-id>] --json
171
+ orp link project show --json
172
+ orp link project status --json
173
+ orp link project unbind --json
174
+ ```
175
+
176
+ Behavior:
177
+
178
+ - `bind` should call the hosted `world bind` flow and write `.git/orp/link/project.json`.
179
+ - `show` should print the stored local linked-project record.
180
+ - `status` should combine:
181
+ - local stored link
182
+ - hosted world state
183
+ - local repo governance status
184
+ - whether at least one linked session exists
185
+ - `unbind` should remove the local link record and optionally leave the hosted world intact unless an explicit hosted unlink is requested later.
186
+
187
+ ### Session link commands
188
+
189
+ ```sh
190
+ orp link session discover --json
191
+ orp link session register --orp-session-id <orp-session-id> --codex-session-id <codex-session-id> --label <label> [--primary] --json
192
+ orp link session list --json
193
+ orp link session show <orp-session-id> --json
194
+ orp link session set-primary <orp_session_id> --json
195
+ orp link session archive <orp_session_id> --json
196
+ orp link session unarchive <orp_session_id> --json
197
+ orp link session remove <orp_session_id> --json
198
+ orp link session import-rust --json
199
+ ```
200
+
201
+ Behavior:
202
+
203
+ - `discover` should find candidate Codex sessions relevant to the current project root.
204
+ - `register` should create or update a linked session record under `.git/orp/link/sessions/`.
205
+ - `list` should show active plus archived sessions.
206
+ - `set-primary` should guarantee only one primary session per linked project.
207
+ - `import-rust` should ingest Rust `.orp/sessions/*.json` state into CLI storage.
208
+
209
+ ### Link summary commands
210
+
211
+ ```sh
212
+ orp link status --json
213
+ orp link doctor --json
214
+ ```
215
+
216
+ Behavior:
217
+
218
+ - `status` should provide a single machine-readable view of linked project, linked sessions, and runner readiness.
219
+ - `doctor` should validate stale paths, missing Codex session ids, moved repos, duplicate primaries, and missing hosted auth.
220
+
221
+ ### Runner commands
222
+
223
+ ```sh
224
+ orp runner status --json
225
+ orp runner enable --json
226
+ orp runner disable --json
227
+ orp runner sync --json
228
+ orp runner work --once --json
229
+ orp runner work --continuous --poll-interval 30 --json
230
+ orp runner cancel [<job-id>] [--lease-id <lease-id>] --json
231
+ orp runner retry [<job-id>] [--lease-id <lease-id>] --json
232
+ ```
233
+
234
+ Behavior:
235
+
236
+ - `status` should report machine runner state plus linked project/session counts.
237
+ - `enable` / `disable` should toggle the local runner state.
238
+ - `sync` should publish linked projects and linked sessions to the hosted service.
239
+ - `work` should poll or subscribe, claim jobs, route work to a selected linked session, append logs/messages, and complete or fail the job.
240
+ - `cancel` / `retry` should operate on the local active or most recent lease-aware runner state when explicit ids are omitted.
241
+
242
+ ## File Schemas
243
+
244
+ Formal schemas live in:
245
+
246
+ - [link-project.schema.json](/Users/codymitchell/Documents/code/orp/spec/v1/link-project.schema.json)
247
+ - [link-session.schema.json](/Users/codymitchell/Documents/code/orp/spec/v1/link-session.schema.json)
248
+ - [runner-machine.schema.json](/Users/codymitchell/Documents/code/orp/spec/v1/runner-machine.schema.json)
249
+ - [runner-runtime.schema.json](/Users/codymitchell/Documents/code/orp/spec/v1/runner-runtime.schema.json)
250
+
251
+ Planned file locations and schema usage:
252
+
253
+ - `.git/orp/link/project.json` -> `spec/v1/link-project.schema.json`
254
+ - `.git/orp/link/sessions/<orp_session_id>.json` -> `spec/v1/link-session.schema.json`
255
+ - `.git/orp/link/runner.json` -> `spec/v1/runner-machine.schema.json`
256
+ - `.git/orp/link/runtime.json` -> `spec/v1/runner-runtime.schema.json`
257
+
258
+ ## Hosted Contract
259
+
260
+ The hosted runner contract should be transport-agnostic.
261
+
262
+ Do not couple business logic to polling.
263
+
264
+ Required lifecycle:
265
+
266
+ 1. `sync`
267
+ - machine publishes linked projects and linked sessions
268
+ 2. `claim`
269
+ - worker claims one job or receives one via push
270
+ 3. `start`
271
+ - worker marks the job running
272
+ 4. `heartbeat`
273
+ - worker renews lease while executing
274
+ 5. `message` / `log`
275
+ - worker publishes progress
276
+ 6. `cancel` / `retry`
277
+ - operator or automation can explicitly interrupt or requeue lease-aware work
278
+ 7. `complete` or `fail`
279
+ - worker posts final result
280
+
281
+ All lifecycle operations after `claim` should carry the same `lease_id`.
282
+
283
+ Transport options that should all work with the same contract:
284
+
285
+ - polling
286
+ - SSE
287
+ - WebSocket
288
+
289
+ ## First Implementation Slice
290
+
291
+ Scope:
292
+
293
+ - establish CLI-owned local linked-project and linked-session storage
294
+ - expose project/session status and manipulation commands
295
+ - do not replace the Rust machine-runner execution path yet
296
+
297
+ ### Slice 1 Checklist
298
+
299
+ - [x] Add local link helpers in `cli/orp.py` for:
300
+ - link root resolution
301
+ - reading/writing `.git/orp/link/project.json`
302
+ - reading/writing `.git/orp/link/sessions/*.json`
303
+ - loading and validating schema-compatible records
304
+ - [x] Add `orp link project bind`
305
+ - [x] Add `orp link project show`
306
+ - [x] Add `orp link project status`
307
+ - [x] Add `orp link project unbind`
308
+ - [x] Add `orp link session register`
309
+ - [x] Add `orp link session list`
310
+ - [x] Add `orp link session set-primary`
311
+ - [x] Add `orp link session archive`
312
+ - [x] Add `orp link session remove`
313
+ - [x] Add `orp link status`
314
+ - [x] Add `orp link doctor`
315
+ - [x] Add `orp link session import-rust`
316
+ - [x] Add tests for:
317
+ - bind writes project file
318
+ - bind reuses hosted `world bind`
319
+ - session register writes session file
320
+ - exactly one primary session is enforced
321
+ - archive/remove behaviors
322
+ - Rust import reads `.orp/project.json` and `.orp/sessions/*.json`
323
+ - `link status` reports hosted auth / project / session readiness correctly
324
+
325
+ ### Slice 1 Non-goals
326
+
327
+ - no hosted runner protocol rewrite yet
328
+ - no SSE/WebSocket delivery work yet
329
+ - no deprecation of Rust session storage yet
330
+ - no UI migration yet
331
+
332
+ ### Slice 1 Acceptance Criteria
333
+
334
+ - A linked project can be created entirely from the CLI.
335
+ - One or more linked sessions can be registered entirely from the CLI.
336
+ - The Rust app can keep calling `orp world bind`, but also has a documented path to mirror its session state into the CLI registry.
337
+ - `orp link status --json` can answer:
338
+ - is this repo linked?
339
+ - what idea/world is it linked to?
340
+ - what sessions are available?
341
+ - which session is primary?
342
+ - is the repo runner-ready?
343
+
344
+ ## Second Implementation Slice
345
+
346
+ Scope:
347
+
348
+ - add CLI-owned machine runner identity and sync
349
+ - keep transport as polling first
350
+
351
+ Checklist:
352
+
353
+ - [x] Add `~/.config/orp/machine.json`
354
+ - [x] Add `orp runner status`
355
+ - [x] Add `orp runner enable`
356
+ - [x] Add `orp runner disable`
357
+ - [x] Add `orp runner sync`
358
+ - [x] Reuse the Rust app's current sync payload shape for compatibility
359
+ - [x] Add tests for runner state persistence and sync payload generation
360
+
361
+ ## Third Implementation Slice
362
+
363
+ Scope:
364
+
365
+ - add CLI-owned runner work loop for `session.prompt`
366
+
367
+ Checklist:
368
+
369
+ - [x] Add `orp runner work --once`
370
+ - [x] Add `orp runner work --continuous`
371
+ - [x] Implement claim/start/log/message/complete/fail flow
372
+ - [x] Route jobs by:
373
+ - explicit `orp_session_id` first
374
+ - primary linked session second
375
+ - first active linked session with a `codex_session_id` third
376
+ - [x] Add lease heartbeat support
377
+ - [x] Add tests for selection logic and job completion/failure handling
378
+
379
+ ## Rust App Integration Checklist
380
+
381
+ - [x] Replace direct hosted link persistence with CLI-owned project link files
382
+ - [x] Replace direct session persistence with CLI-owned session link files or mirrored writes
383
+ - [x] Call `orp link session register` when adopting or labeling a session
384
+ - [x] Call `orp link session archive` when archiving a session
385
+ - [x] Call `orp runner sync` when the app's linked-project/session state changes
386
+ - [x] Either:
387
+ - keep the current Rust worker temporarily but make it conform to CLI schemas, or
388
+ - replace it with a wrapper around `orp runner work`
389
+
390
+ ## Migration Checklist
391
+
392
+ - [x] Add `orp link session import-rust`
393
+ - [x] Add `orp link import-rust --all`
394
+ - [x] Detect `.orp/project.json` and `.orp/sessions/*.json`
395
+ - [x] Preserve `world_id`, `idea_id`, `idea_title`, and linked email where available
396
+ - [x] Preserve session labels and active/closed state
397
+ - [x] Preserve archived and ignored session tracking where possible
398
+ - [x] Do not delete Rust files during the initial migration phase
399
+
400
+ ## Remaining Hosted Platform Checklist
401
+
402
+ The CLI and Rust app now share one client-side project/session/runner contract, but the hosted web app still needs to expose the matching server contract. The remaining work is now a hosted-platform implementation plan rather than more client-side alignment.
403
+
404
+ ### Hosted Contract Alignment
405
+
406
+ - [x] Add the `/api/cli/runner/...` route family to the hosted app:
407
+ - `POST /api/cli/runner/sync`
408
+ - `POST /api/cli/runner/heartbeat`
409
+ - `GET /api/cli/runner/jobs/poll`
410
+ - `POST /api/cli/runner/jobs/:id/start`
411
+ - `POST /api/cli/runner/jobs/:id/messages`
412
+ - `POST /api/cli/runner/jobs/:id/logs`
413
+ - `POST /api/cli/runner/jobs/:id/complete`
414
+ - `POST /api/cli/runner/jobs/:id/cancel`
415
+ - `POST /api/cli/runner/jobs/:id/retry`
416
+ - [x] Extend hosted session state so synced sessions can persist `orp_session_id` in addition to `codex_session_id`.
417
+ - [x] Extend hosted job state so the server can persist `lease_id`, `lease_expires_at`, and `last_heartbeat_at`.
418
+ - [x] Keep the hosted runner API device-token authenticated, matching the existing CLI workspace routes.
419
+
420
+ ### Hosted Queue Bridge
421
+
422
+ - [x] Bridge queued idea checkpoints onto the new runner API so existing checkpoint work can flow through `orp runner work`.
423
+ - [x] Return runner jobs as prompt-style work items with enough metadata to route by `ideaId`, `worldId`, `projectRoot`, and optional `orpSessionId`.
424
+ - [x] On completion, write successful and failed checkpoint responses back into `idea_checkpoint_responses` and checkpoint/job status fields.
425
+ - [x] Preserve existing `orp agent work` compatibility until the runner API is proven in production.
426
+
427
+ ### Hosted Lease Hardening
428
+
429
+ - [x] Add local runner runtime state in `.git/orp/link/runtime.json` for active lease tracking, last job status, and operator events.
430
+ - [x] Add lease ids to runner claim/start/heartbeat/complete payloads and persist them across the full job lifecycle.
431
+ - [x] Add explicit cancel and retry/requeue endpoints plus CLI handling for those transitions.
432
+ - [x] Add stale local lease detection and operator-facing status warnings.
433
+ - [x] Add hosted stale-lease expiry and safe job reclamation rules.
434
+ - [x] Add server-side start/complete/cancel/retry validation against the active lease and machine id.
435
+ - [x] Bind synced hosted world sessions to the syncing runner machine so poll only claims jobs for repos/sessions that machine actually owns.
436
+ - [x] Layer SSE wake-up delivery on top of the same lease protocol while keeping polling as the stable fallback/default.
437
+ - Implemented on March 16, 2026.
438
+ - Added hosted `GET /api/cli/runner/events/stream`.
439
+ - Added CLI `--transport auto|poll|sse` for `orp runner work` and `orp agent work`.
440
+ - SSE is used only as a wake-up signal; job claiming still happens through the existing poll/lease flow.
441
+ - Deployed live on March 16, 2026 via Vercel deployment `dpl_EyxVoapbmsHXF795yKoHN9ua1qRm`.
442
+ - Verified direct production SSE stream response on `https://orp.earth/api/cli/runner/events/stream`.
443
+ - Verified a live `orp runner work --continuous --transport auto` smoke by queueing checkpoint `d6ddb357-ae66-46bb-98ef-4a19169fc59f`, claiming job `49ee5377-a7df-48af-8350-45524f7a6a77`, and finishing it successfully.
444
+
445
+ ### Future Hosted Expansion
446
+
447
+ - [x] Add a first-class hosted enqueue path for generic `session.prompt` jobs beyond checkpoint reviews.
448
+ - [x] Keep checkpoint review jobs and prompt jobs on one hosted job system with distinct job kinds.
449
+
450
+ ### Internal Rollout Operations
451
+
452
+ - [x] Add an internal admin runners console for machine heartbeat, active lease, and last completed/failed work visibility.
453
+ - [x] Add internal queue recovery controls for cancel/retry without the original machine lease.
454
+ - [x] Add route/helper logging for failed poll/start/complete flows, lease mismatches, missing-routeable-session failures, and repeated retry patterns.
455
+ - [x] Surface runner health in the Rust desktop app so operators can see online/syncing/working/error states locally.
456
+ - [x] Add an internal rollout and recovery runbook:
457
+ - [RUNNER_INTERNAL_OPERATIONS.md](/Users/codymitchell/Documents/code/orp/docs/RUNNER_INTERNAL_OPERATIONS.md)
458
+ - [x] Deploy the hosted runner backend changes to the real internal environment.
459
+ - [x] Run a live internal smoke on deployed infrastructure.
460
+ - Completed on March 16, 2026 against `https://orp.earth`.
461
+ - Verified `orp link project bind`, `orp link session register`, `orp runner enable`, `orp runner sync`, `orp checkpoint queue`, `orp runner work --once`, and `orp agent work --once`.
462
+ - Confirmed the production `orp` checkpoint job `78cd459a-fc0b-451b-af06-be2d27379169` completed successfully and produced checkpoint response `41087b8b-9556-4ec1-90c6-eefb69bac585`.
463
+ - [x] Add and verify a reusable Rust-side smoke harness for the desktop wrapper path.
464
+ - Implemented at [runner_smoke.rs](/Users/codymitchell/Documents/code/orp-rust/src/bin/runner_smoke.rs).
465
+ - Verified on March 16, 2026 against `https://orp.earth`.
466
+ - Confirmed Rust-side smoke job `853a55f9-b0e5-42f7-8f2f-cdc8db1a354c` completed successfully and produced checkpoint response `6b5aee77-f176-4249-a127-978b987da946`.
467
+
468
+ ### Hosted Verification
469
+
470
+ - [x] Run route-level unit coverage for the hosted runner API surface.
471
+ - [x] Run TypeScript validation for the hosted app after runner changes.
472
+ - [x] Run a real disposable Postgres-backed smoke flow:
473
+ - `sync`
474
+ - `enqueue`
475
+ - `heartbeat`
476
+ - `poll`
477
+ - `start`
478
+ - `messages`
479
+ - `logs`
480
+ - `complete`
481
+ - final `poll -> job: null`
482
+ - [x] Fix backend issues surfaced by the real smoke flow:
483
+ - `dev_jobs.idea_id` text-to-uuid join mismatch in runner polling/loading
484
+ - `complete` returning terminal success while leaving `dev_jobs.state = running`
485
+ - [x] Fix backend issues surfaced by the live internal smoke:
486
+ - queued runner poll was not scoped to the syncing machine's linked world sessions
487
+ - `idea_world_sessions.runner_id` now binds each synced session to its owning runner machine
488
+ - [x] Fix CLI compatibility issues surfaced by the Rust-side smoke:
489
+ - `orp agent work` now preserves the caller's `repo_root` when constructing runner-primary compatibility args
490
+
491
+ ## Edge Cases
492
+
493
+ - repo linked but no sessions registered
494
+ - multiple sessions, none primary
495
+ - multiple sessions, more than one marked primary
496
+ - project moved on disk
497
+ - linked world deleted remotely
498
+ - hosted account switched
499
+ - stale `codex_session_id`
500
+ - session archived locally but still referenced by hosted jobs
501
+ - no hosted auth while local link files exist
502
+ - runner enabled with zero linked projects
503
+ - runner enabled with linked projects but zero usable sessions
504
+ - Rust `.orp` state and CLI `.git/orp/link` state disagree
505
+
506
+ ## Decision Log
507
+
508
+ Current decisions:
509
+
510
+ - Project and session link state should be machine-local and git-ignored by default.
511
+ - The CLI should own the canonical project/session/runner contract.
512
+ - The Rust app should remain the strongest desktop UX, not the source of truth.
513
+ - Transport choice should not change the hosted runner job lifecycle.
514
+ - Polling remains the stable v1 transport, and SSE is now available as an optional wake-up layer on the same lease protocol.
515
+ - Checkpoint review jobs and generic prompt jobs should share one hosted job system with distinct kinds.
516
+ - `orp runner work` is the primary worker surface, while `orp agent work` remains the compatibility path for now.
517
+ - Hosted routing should prefer an exact linked session first, then the primary linked session for that repo.
518
+ - Session discovery should stay Rust-led for now, with the CLI remaining the canonical registry and runner contract.
519
+ - Rollout should stay internal-first and staged.
520
+ - WebSocket is still optional future polish, not a prerequisite for the runner contract.
521
+ - Production has already proven the SSE wake-up layer with `--transport auto`; it is now polish, not speculation.
@@ -5,10 +5,25 @@ Use this checklist when releasing ORP as the unified public CLI and product surf
5
5
  ## 1. CLI readiness
6
6
 
7
7
  - Run:
8
+ - `bash scripts/orp-release-smoke.sh`
8
9
  - `python3 -m unittest discover -s tests -v`
10
+ - `git status --short`
11
+ - `git rev-list --left-right --count origin/main...HEAD`
12
+ - `npm view open-research-protocol version dist-tags --json`
9
13
  - `npm pack --dry-run --cache /tmp/orp-npm-cache`
14
+ - `npm publish --dry-run`
10
15
  - Smoke-test in a fresh directory:
16
+ - `bash scripts/orp-release-smoke.sh --hosted --codex-session-id <session-id>`
11
17
  - `npm i -g open-research-protocol`
18
+ - `orp -h`
19
+ - `orp init`
20
+ - `orp status --json`
21
+ - `orp branch start work/bootstrap --allow-dirty --json`
22
+ - `orp checkpoint create -m "bootstrap governance" --json`
23
+ - `orp backup -m "backup bootstrap governance" --json`
24
+ - `orp gate run --profile default --json`
25
+ - `orp checkpoint create -m "capture passing validation" --json`
26
+ - `orp ready --json`
12
27
  - `orp about --json`
13
28
  - `orp auth login`
14
29
  - `orp whoami --json`
@@ -26,15 +41,21 @@ Use this checklist when releasing ORP as the unified public CLI and product surf
26
41
 
27
42
  ## 3. Worker loop readiness
28
43
 
44
+ - Status:
45
+ Verified internally on March 16, 2026 against `https://orp.earth` with machine-scoped session routing and the polling-based runner lease flow, from both the direct CLI path and the Rust-side smoke harness.
29
46
  - Confirm one bound world can complete:
30
47
  - `orp checkpoint queue --idea-id <idea-id> --json`
31
- - `orp agent work --once --json`
48
+ - `orp runner work --once --json`
49
+ - `orp agent work --once --json` remains available as the compatibility path
32
50
  - Confirm the checkpoint response lands back in the hosted workspace.
51
+ - Confirm the hosted operator console reflects the same lifecycle at `/dashboard/admin/runners`.
52
+ - Use [RUNNER_INTERNAL_OPERATIONS.md](/Users/codymitchell/Documents/code/orp/docs/RUNNER_INTERNAL_OPERATIONS.md) for the internal rollout and recovery flow.
33
53
 
34
54
  ## 4. Package release
35
55
 
36
56
  - Bump `package.json` version.
37
57
  - Commit and push `main`.
58
+ - Expect `npm publish` to fail if the worktree is dirty or the release commit is not already on GitHub.
38
59
  - Tag and push:
39
60
  - `git tag vX.Y.Z`
40
61
  - `git push origin vX.Y.Z`
@@ -54,6 +75,8 @@ Use this checklist when releasing ORP as the unified public CLI and product surf
54
75
  - `npm view open-research-protocol version`
55
76
  - `npm i -g open-research-protocol`
56
77
  - `orp -h`
78
+ - `orp init`
79
+ - `orp status --json`
57
80
  - `orp about --json`
58
81
 
59
82
  ## 7. Web app rollout coordination
@@ -0,0 +1,107 @@
1
+ # ORP Runner Internal Operations
2
+
3
+ Use this guide for the internal-first rollout of the hosted ORP runner.
4
+
5
+ Current production note:
6
+
7
+ - The SSE wake-up route is live on `https://orp.earth` as of March 16, 2026 via Vercel deployment `dpl_EyxVoapbmsHXF795yKoHN9ua1qRm`.
8
+ - A live `orp runner work --continuous --transport auto` smoke has already succeeded against production with checkpoint `d6ddb357-ae66-46bb-98ef-4a19169fc59f` and job `49ee5377-a7df-48af-8350-45524f7a6a77`.
9
+
10
+ ## Source of truth
11
+
12
+ - Session discovery stays Rust-led.
13
+ - The ORP CLI is the canonical link/session/runner contract.
14
+ - The hosted web app is the queue and lease authority.
15
+ - `orp runner work` is the primary worker surface.
16
+ - `orp agent work` remains available only as a compatibility path.
17
+
18
+ ## Healthy runner definition
19
+
20
+ A healthy internal runner should satisfy all of the following:
21
+
22
+ - `orp auth login` succeeds for the operator account.
23
+ - `orp link project bind` has linked the repo to the intended hosted idea/world.
24
+ - At least one non-archived linked session exists for the repo.
25
+ - One linked session is primary, or the hosted job targets an exact session.
26
+ - `orp runner enable` has created a machine identity on the Mac.
27
+ - `orp runner sync` succeeds and the hosted admin runners console shows the machine.
28
+ - `orp runner work --once` can poll without lease errors.
29
+ - `orp runner work --continuous --transport auto` can idle without missing queued work.
30
+ - Heartbeats continue while work is running.
31
+ - Completed work clears the lease and updates the hosted world/checkpoint state.
32
+
33
+ ## Deployment checklist
34
+
35
+ 1. Apply the latest hosted database migrations.
36
+ 2. Deploy the hosted web app with the `/api/cli/runner/...` routes enabled.
37
+ 3. Confirm the admin runners console loads at `/dashboard/admin/runners`.
38
+ 4. Confirm at least one internal machine can still sign in through the published `orp` CLI.
39
+ 5. Confirm the Rust desktop app still discovers sessions and mirrors them into CLI link state.
40
+ 6. After any machine-scoped session-schema change, run `orp runner sync` once on every active internal runner machine so hosted `idea_world_sessions.runner_id` is refreshed before expecting queued jobs to route correctly.
41
+
42
+ ## Internal smoke flow
43
+
44
+ Run this on one internal machine after deploy:
45
+
46
+ 1. `orp auth login`
47
+ 2. `orp link project bind --idea-id <idea-id>`
48
+ 3. `orp link session register --orp-session-id <orp-session-id> --codex-session-id <codex-session-id> --primary`
49
+ 4. `orp runner enable`
50
+ 5. `orp runner sync`
51
+ 6. `orp checkpoint queue --idea-id <idea-id> --json`
52
+ 7. `orp runner work --once --json`
53
+ 8. Optionally leave a longer-lived worker running with `orp runner work --continuous --transport auto --json`
54
+ 9. Confirm the checkpoint response lands in the hosted idea.
55
+ 10. Confirm `/dashboard/admin/runners` shows:
56
+ - the machine heartbeat
57
+ - the claimed job
58
+ - lease cleared after completion
59
+
60
+ Latest known-good production smoke:
61
+
62
+ - Direct SSE probe returned `event: ready` followed by `event: timeout` against `https://orp.earth/api/cli/runner/events/stream`.
63
+ - Continuous runner mode with `--transport auto` claimed the queued checkpoint job immediately and completed it successfully.
64
+
65
+ ## Rust desktop smoke harness
66
+
67
+ For a repeatable non-GUI Rust-side smoke, run the harness in `orp-rust` against the same live ORP CLI contract:
68
+
69
+ 1. Point `ORP_CLI_BIN` at the CLI build you want the Rust app to exercise.
70
+ 2. Run:
71
+ `cargo run --bin runner_smoke -- --project-root <repo-root> --idea-id <idea-id> --codex-session-id <codex-session-id> --queue-checkpoint-note "<note>" --work-once --agent-work-once`
72
+ 3. Confirm:
73
+ - `runner_work.claimed = true`
74
+ - `runner_work.ok = true`
75
+ - `agent_work.compatibility.mode = runner-primary`
76
+ - `agent_work.claimed = false` once the queued job has already been consumed
77
+
78
+ ## Admin console workflow
79
+
80
+ Use `/dashboard/admin/runners` to:
81
+
82
+ - inspect online and stale machines
83
+ - inspect queued, dispatched, and running jobs
84
+ - watch the top-level operational alerts for stale leases, missing sessions, stale heartbeats, and repeat retries
85
+ - spot missing-routeable-session issues
86
+ - spot stale leases
87
+ - spot repeated retry patterns
88
+ - cancel a stuck job
89
+ - requeue a failed or stale job
90
+
91
+ ## Recovery playbook
92
+
93
+ Use these defaults unless there is a clearer incident-specific reason to do otherwise:
94
+
95
+ - If a job is `running` or `dispatched` with an expired lease, requeue it.
96
+ - If a job is clearly invalid or targeting the wrong repo/session, cancel it.
97
+ - If the same job has been retried 3+ times, pause and inspect the runner, session link, and prompt payload before requeueing again.
98
+ - If a machine is stale, verify the desktop app or CLI runner is still open before requeueing its work.
99
+ - If jobs queue up with no routeable session, repair the project/session link first instead of repeatedly retrying the job.
100
+
101
+ ## Rollout policy
102
+
103
+ - Start with one internal operator machine.
104
+ - Expand to a small set of trusted internal machines after the first full smoke passes.
105
+ - Prefer one or a small handful of linked repos per machine during rollout.
106
+ - Treat the admin runners console as the operational dashboard for the staged rollout.
107
+ - Do not make WebSocket a prerequisite for rollout; polling remains the stable v1 transport and SSE is optional polish on top.