agent-conveyor 0.1.7 → 0.1.9

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.
@@ -259,6 +259,61 @@ conveyor worker-inbox "$TASK" --consume-next --wait --timeout 60 --json
259
259
  conveyor manager-inbox "$TASK" --consume-next --wait --timeout 60 --json
260
260
  ```
261
261
 
262
+ Dispatch delivery is not a wake-up mechanism for idle Codex app threads. When
263
+ `communication.requires_polling=true`, install or verify a thread heartbeat for
264
+ each pull-required manager and worker session. The default heartbeat should run
265
+ about every two minutes, poll the role-specific inbox once with a short wait,
266
+ execute only a consumed item, and otherwise stop after a one-line idle receipt.
267
+ Do not delete or pause heartbeat automation because an inbox poll is idle; idle
268
+ polling is only a quiet interval. The manager or operator owns terminal loop
269
+ teardown. When all accepted criteria are satisfied, deferred, or rejected and
270
+ there is no next worker task, the manager should record the terminal decision,
271
+ run `conveyor finish-task "$TASK" --require-criteria-audit`, and explicitly
272
+ report heartbeat teardown status. If the task or binding still appears active,
273
+ report that as a control-plane blocker instead of calling the loop complete.
274
+
275
+ When the manager is running in the Codex app and thread tools are available,
276
+ create fresh same-project manager and worker threads with `create_thread`, set
277
+ readable titles, and pass both ids/titles into `conveyor
278
+ create-disposable-binding` with `--manager-codex-app-thread-id`,
279
+ `--manager-codex-app-thread-title`, `--worker-codex-app-thread-id`, and
280
+ `--worker-codex-app-thread-title`. Use `send_message_to_thread` for bootstrap
281
+ prompts only; ongoing manager/worker communication should still be routed
282
+ through Dispatch and consumed from inboxes. If app thread tools are unavailable,
283
+ open the worker session manually and paste the same `worker_handoff` prompt.
284
+ Do not use `fork_thread` for this recipe unless the user explicitly wants a
285
+ fork of the current conversation.
286
+
287
+ ### Codex App Native Manager/Worker Loop
288
+
289
+ ```bash
290
+ conveyor doctor
291
+ conveyor db-doctor
292
+ conveyor create-disposable-binding "$TASK" \
293
+ --worker "$WORKER" \
294
+ --manager "$MANAGER" \
295
+ --worker-codex-app-thread-id "$WORKER_THREAD_ID" \
296
+ --worker-codex-app-thread-title "$WORKER_THREAD_TITLE" \
297
+ --manager-codex-app-thread-id "$MANAGER_THREAD_ID" \
298
+ --manager-codex-app-thread-title "$MANAGER_THREAD_TITLE" \
299
+ --adversarial \
300
+ --json
301
+ conveyor dispatch --watch --dispatcher-id dispatch-local
302
+ conveyor app-heartbeat "$TASK" --role manager --json
303
+ conveyor app-heartbeat "$TASK" --role worker --json
304
+ conveyor app-loop-status "$TASK" --json
305
+ conveyor app-wakeup-plan "$TASK" --json
306
+ conveyor app-wakeup-dispatch "$TASK" --json
307
+ ```
308
+
309
+ Use `app-loop-status` as the operator status surface. If it reports stale
310
+ manager, worker, or Dispatch leases, use `app-wakeup-plan` to get the exact
311
+ thread prompt to send through Codex app automation or `send_message_to_thread`.
312
+ Use `app-wakeup-dispatch` when the manager needs a durable Conveyor receipt for
313
+ which app wake actions were prepared, skipped, or blocked. It only prepares
314
+ adapter-ready actions; direct app-thread delivery remains an app/operator
315
+ action, and Dispatch/inboxes remain the durable task state.
316
+
262
317
  The saved dogfood example is
263
318
  `docs/goals/live-codex-app-inbox-drill/notes/T001-live-drill.md`. It proves
264
319
  manager-to-worker `nudge_worker` delivery and worker-to-manager
@@ -286,6 +341,59 @@ acceptance criteria, command attempts, routed notifications, inbox backlog, and
286
341
  telemetry before deciding whether to wait, nudge, continue, compact, clear, or
287
342
  finish.
288
343
 
344
+ ## Package Dogfood Command
345
+
346
+ Use a disposable workspace and explicit database path when checking the
347
+ package-facing `goalbuddy-conveyor` recipe flow. The point is to prove the
348
+ published package, not a local checkout.
349
+
350
+ ```bash
351
+ mkdir -p /tmp/agent-conveyor-dogfood/workspace
352
+ git -C /tmp/agent-conveyor-dogfood/workspace init
353
+
354
+ conveyor pair \
355
+ --task dogfood-goalbuddy \
356
+ --worker-name dogfood-worker \
357
+ --manager-name dogfood-manager \
358
+ --task-goal "Dogfood the published package GoalBuddy conveyor recipe." \
359
+ --task-prompt "Create docs/dogfood-note.md with a short received-task note and report a concise receipt." \
360
+ --manager-recipe goalbuddy-conveyor \
361
+ --manager-mode strict \
362
+ --manager-objective "Run a one-child-at-a-time GoalBuddy conveyor until the disposable task is proven satisfied or blocked with evidence." \
363
+ --manager-guideline "Keep exactly one child board active at a time." \
364
+ --manager-guideline "Before activating the next child, update the parent receipt." \
365
+ --manager-acceptance "The disposable worker task has a receipt showing the note file was created or a blocker was recorded." \
366
+ --manager-acceptance "Manager config records the selected goalbuddy-conveyor recipe." \
367
+ --manager-allow-worker-compact-clear \
368
+ --manager-allow-pr \
369
+ --manager-allow-merge-green \
370
+ --manager-tool verification.run_tests \
371
+ --manager-tool context.fetch_prs \
372
+ --manager-epilogue draft-pr \
373
+ --manager-epilogue record-handoff \
374
+ --cwd /tmp/agent-conveyor-dogfood/workspace \
375
+ --path /tmp/agent-conveyor-dogfood/workerctl.db \
376
+ --accept-trust
377
+ ```
378
+
379
+ Expected clean transcript shape:
380
+
381
+ ```text
382
+ pair exits 0
383
+ dispatcher watch starts from an executable shipped with the package
384
+ manager_config.recipe_name = goalbuddy-conveyor
385
+ manager-ack and worker-ack are recorded against the same --path database
386
+ cycle shows worker_receipt for docs/dogfood-note.md
387
+ criteria --list shows all accepted criteria satisfied
388
+ finish-task --require-criteria-audit marks the task done
389
+ ```
390
+
391
+ If a dogfood run needs an operator to add `--path`, find the active database, or
392
+ replace a missing source-tree path with the installed `workerctl` bin, the
393
+ package setup is not yet ready for unattended dogfooding. Record the friction in
394
+ the dogfood board so the next recipe or prompt pass has something concrete to
395
+ fix.
396
+
289
397
  ## What The Database Records
290
398
 
291
399
  The SQLite control plane is the audit surface for these recipes.
@@ -1,26 +1,23 @@
1
1
  # TypeScript Migration CLI Contract
2
2
 
3
- This contract freezes the current Python CLI surface before TypeScript migration.
4
- The TypeScript CLI must preserve this surface unless a Judge receipt explicitly
5
- approves and documents a diff.
3
+ This contract records the archived Python CLI surface from before the
4
+ TypeScript migration. The TypeScript CLI must preserve this surface unless a
5
+ Judge receipt explicitly approves and documents a diff.
6
6
 
7
7
  ## Public Entry Points
8
8
 
9
- - `conveyor` package-installed command from `pyproject.toml`.
10
- - `workerctl` package-installed compatibility command from `pyproject.toml`.
9
+ - `conveyor` package-installed command from `package.json`.
10
+ - `workerctl` package-installed compatibility command from `package.json`.
11
11
  - `bin/conveyor` local wrapper.
12
12
  - `bin/workerctl` local wrapper.
13
13
  - `scripts/workerctl` repository-local entry point.
14
- - `python -m workerctl` until Python compatibility is retired by an explicit
15
- migration decision.
16
14
 
17
- Program name behavior must preserve both `conveyor` and `workerctl`. The Python
18
- implementation currently selects the name from `CONVEYOR_CLI_PROG`, the
19
- invoked filename, or defaults to `conveyor`.
15
+ Program name behavior must preserve both `conveyor` and `workerctl`.
20
16
 
21
17
  ## Command Inventory
22
18
 
23
- Source of truth: `scripts/workerctl --help` and `workerctl/cli.py`.
19
+ Source of truth: `scripts/workerctl --help` and the archived command inventory
20
+ at `docs/archive/python-runtime/cli-command-inventory.json`.
24
21
 
25
22
  The top-level command inventory to preserve is:
26
23
 
@@ -139,9 +136,9 @@ artifact for:
139
136
  scripts/workerctl --help
140
137
  CONVEYOR_CLI_PROG=conveyor scripts/workerctl --help
141
138
  CONVEYOR_CLI_PROG=workerctl scripts/workerctl --help
142
- rg -n "add_parser\\(|set_defaults\\(" workerctl/cli.py
139
+ node scripts/ts-migration-audit.mjs --require-zero-python
143
140
  ```
144
141
 
145
142
  The TypeScript implementation must have an adjudicated command/flag diff against
146
- the Python surface. Unreviewed missing commands, missing aliases, changed JSON
147
- shape, or changed help program name block migration completion.
143
+ the archived Python surface. Unreviewed missing commands, missing aliases,
144
+ changed JSON shape, or changed help program name block migration completion.
@@ -26,7 +26,7 @@ The historical Python metadata exposed:
26
26
  - package name `agent-conveyor`
27
27
  - console script `conveyor`
28
28
  - compatibility console script `workerctl`
29
- - bundled `workerctl/assets/skills/**/*`
29
+ - bundled `workerctl/assets/skills/**/*` in the historical wheel
30
30
 
31
31
  The historical Python/PyPI release path is archived in
32
32
  `docs/archive/python-package-history.md`.
@@ -6,32 +6,26 @@ run or inspect evidence that would expose it, and record residual risk.
6
6
 
7
7
  ## Deterministic Local Gates
8
8
 
9
- Current baseline before the migration board:
9
+ Current post-archive baseline:
10
10
 
11
11
  | Gate | Command | Current baseline |
12
12
  | --- | --- | --- |
13
- | Python unit tests | `python3 -m unittest discover -s tests -v` | pass, 645 tests |
14
- | ResourceWarning gate | `scripts/check-resource-warnings` | pass, 645 tests |
15
- | Python compile gate | `python3 -m py_compile scripts/workerctl scripts/check-resource-warnings workerctl/*.py` | pass |
13
+ | Node test ResourceWarning gate | `scripts/check-resource-warnings -- npm test -- --runInBand` | pass |
16
14
  | Node/dashboard tests | `npm test -- --runInBand` | pass, 161 tests |
17
15
  | Dashboard build | `npm run build` | pass |
18
16
  | TypeScript migration audit | `npm run migration:audit:final` | pass after package cutover; npm tarball has no Python runtime/bridge files |
19
17
  | Shell syntax | `bash -n scripts/live-smoke scripts/live-smoke-repeat scripts/package-smoke scripts/release-check scripts/rc-check` | pass |
20
18
 
21
- While Python remains in the repository, the Python gates remain required. A
22
- TypeScript replacement may retire them only after equivalent TypeScript gates
23
- and package smoke prove the migrated command surface no longer imports or
24
- executes Python for the migrated paths.
19
+ The archived Python runtime lives under `docs/archive/python-runtime` for
20
+ historical inspection only. Active gates must use the TypeScript runtime and
21
+ Node-based release helpers.
25
22
 
26
23
  ## Release-Candidate Gate
27
24
 
28
25
  `scripts/rc-check --skip-live-smoke-repeat` currently runs:
29
26
 
30
- - Python unittest.
31
- - ResourceWarning gate.
32
- - Python compile gate.
33
- - TypeScript migration audit.
34
- - Dashboard tests.
27
+ - Node test ResourceWarning gate.
28
+ - TypeScript migration final audit.
35
29
  - Dashboard build.
36
30
  - Smoke script syntax checks.
37
31
 
@@ -84,9 +84,8 @@ Useful commands:
84
84
 
85
85
  ```bash
86
86
  WORKERCTL_STATE_ROOT="$(mktemp -d)" scripts/workerctl db-doctor --json
87
- python3 -m unittest tests.test_workerctl.DatabaseTests tests.test_workerctl.SessionsSchemaTests tests.test_workerctl.CodexEventsSchemaTests -v
88
- python3 -m py_compile workerctl/*.py
87
+ npm test -- --runInBand
89
88
  ```
90
89
 
91
90
  Completion is blocked if the TypeScript-created schema differs from the
92
- Python-created schema without a recorded Judge decision.
91
+ archived schema contract without a recorded Judge decision.
@@ -8,16 +8,16 @@ away from the compatibility bridge yet.
8
8
 
9
9
  | Python source | TypeScript source | Proof |
10
10
  | --- | --- | --- |
11
- | `workerctl/tmux.py` command builders, permission text, paste-buffer cleanup, session pane targeting | `src/runtime/tmux.ts` | `src/runtime/runtime.test.ts` covers argument order, liveness checks, permission normalization, cleanup on failure, pane targets, and side-effect audit flags. |
12
- | `workerctl/codex_session.py` session metadata, native pid selection, lsof rollout lookup, discovery result shape | `src/runtime/codex-session.ts` | `src/runtime/runtime.test.ts` covers metadata parsing, lsof path extraction, pid-to-native-child selection, and end-to-end discovery with fixtures. |
13
- | `workerctl/ingest.py` JSONL parser and one-session ingest cycle | `src/runtime/ingest.ts` | `src/runtime/runtime.test.ts` covers offsets, malformed complete lines, partial trailing lines, event persistence, heartbeat/offset update, telemetry, idempotent re-ingest, appended partial completion, and shrink refusal. |
14
- | `workerctl/classify.py` startup and busy-wait classifier | `src/runtime/classify.ts` | `src/runtime/runtime.test.ts` covers Python classifier scenarios: trust, ready, working, empty, error, MCP startup, rate limit, Enter confirmation, trust prompt, plan prompt, active approval, historical approval negative control, fresh status suppression, and recent-event long-running suppression. |
11
+ | archived `workerctl/tmux.py` command builders, permission text, paste-buffer cleanup, session pane targeting | `src/runtime/tmux.ts` | `src/runtime/runtime.test.ts` covers argument order, liveness checks, permission normalization, cleanup on failure, pane targets, and side-effect audit flags. |
12
+ | archived `workerctl/codex_session.py` session metadata, native pid selection, lsof rollout lookup, discovery result shape | `src/runtime/codex-session.ts` | `src/runtime/runtime.test.ts` covers metadata parsing, lsof path extraction, pid-to-native-child selection, and end-to-end discovery with fixtures. |
13
+ | archived `workerctl/ingest.py` JSONL parser and one-session ingest cycle | `src/runtime/ingest.ts` | `src/runtime/runtime.test.ts` covers offsets, malformed complete lines, partial trailing lines, event persistence, heartbeat/offset update, telemetry, idempotent re-ingest, appended partial completion, and shrink refusal. |
14
+ | archived `workerctl/classify.py` startup and busy-wait classifier | `src/runtime/classify.ts` | `src/runtime/runtime.test.ts` covers classifier scenarios: trust, ready, working, empty, error, MCP startup, rate limit, Enter confirmation, trust prompt, plan prompt, active approval, historical approval negative control, fresh status suppression, and recent-event long-running suppression. |
15
15
 
16
16
  ## Bridge Decision
17
17
 
18
- Public `conveyor` and `workerctl` command handlers still intentionally route
19
- through `src/cli/python-bridge.ts` for T005. That preserves the frozen CLI
20
- contract while the runtime modules move to TypeScript in testable pieces.
18
+ This note records the historical T005 bridge decision. The public `conveyor`
19
+ and `workerctl` command handlers now use the TypeScript runtime; the Python
20
+ runtime is archived under `docs/archive/python-runtime`.
21
21
 
22
22
  The remaining command-handler migration belongs to T006/T007:
23
23
 
@@ -26,9 +26,9 @@ The remaining command-handler migration belongs to T006/T007:
26
26
  - T007 owns npm package/install/release/CI/docs conversion and final tarball
27
27
  behavior.
28
28
 
29
- This means T005 is complete when the TypeScript runtime helpers pass local
30
- gates and the Python compatibility suite still passes. It does not claim that
31
- the public CLI no longer executes Python.
29
+ T005 was complete when the TypeScript runtime helpers passed local gates while
30
+ the compatibility bridge was still present. Later migration stages removed the
31
+ bridge and archived the Python runtime.
32
32
 
33
33
  ## Strongest Failure Mode
34
34
 
@@ -40,8 +40,8 @@ or CLI error behavior.
40
40
  Disproof evidence:
41
41
 
42
42
  - Node runtime tests exercise the TypeScript behavior directly.
43
- - The full Python compatibility suite still passes under an isolated state
44
- root, proving the bridge-backed public CLI behavior was not regressed.
43
+ - The archived command inventory and TypeScript migration audit preserve the
44
+ historical CLI contract without executing Python.
45
45
  - `npm run build` proves the TypeScript helper API compiles into the package.
46
46
  - The GoalBuddy board keeps T006/T007 queued for public command-handler and
47
47
  package-routing migration before final completion.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-conveyor",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Local agent manager/worker conveyor control plane for Codex sessions.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -6,8 +6,8 @@ description: Use when the user asks to set up an Agent Conveyor Ralph loop, regi
6
6
  # Manage Codex Workers
7
7
 
8
8
  Use `conveyor ...` as the primary CLI. It is installed by the `agent-conveyor`
9
- Python package. The legacy `workerctl` command remains a compatibility alias,
10
- but skill-driven flows should prefer `conveyor`.
9
+ Node/TypeScript package. The legacy `workerctl` command remains a compatibility
10
+ alias, but skill-driven flows should prefer `conveyor`.
11
11
 
12
12
  ## One-Prompt Codex App Ralph Loop
13
13
 
@@ -35,25 +35,71 @@ Skill behavior:
35
35
  report blockers.
36
36
  3. Choose concise task, worker, manager, and run names when the user does not
37
37
  provide them. Do not ask the user to invent generated names.
38
- 4. Create the no-tmux binding with `conveyor create-disposable-binding`
38
+ 4. Preferred fully app-native setup: if running in the Codex app and thread
39
+ tools are available, create fresh same-project manager and worker threads
40
+ with `create_thread`, give both readable titles, and keep both returned
41
+ thread ids/titles. Use `create_thread` for this flow; do not use
42
+ `fork_thread` unless the user explicitly asks to fork or resume this exact
43
+ conversation. If the current thread is explicitly acting as the manager,
44
+ use the current thread as manager and create only the worker thread.
45
+ 5. Create the no-tmux binding with `conveyor create-disposable-binding`
39
46
  using `--template` when a template is known, `--adversarial`, a bounded
40
- `--max-iterations`, and `--json`.
41
- 5. Ensure Dispatch is running or tell the user the single command to start it:
47
+ `--max-iterations`, and `--json`. When step 4 produced app thread ids, pass
48
+ them through `--manager-codex-app-thread-id`,
49
+ `--manager-codex-app-thread-title`, `--worker-codex-app-thread-id`, and
50
+ `--worker-codex-app-thread-title` so Conveyor can surface app identities in
51
+ `sessions`, `discover`, and setup JSON. If app thread tools are not
52
+ available, create the binding without those flags and ask the user to open
53
+ separate Codex app sessions manually.
54
+ 6. Ensure Dispatch is running or tell the user the single command to start it:
42
55
  `conveyor dispatch --watch --dispatcher-id dispatch-local`.
43
- 6. Read the returned `communication` blocks. A worker or manager with
56
+ 7. Read the returned `communication` blocks. A worker or manager with
44
57
  `session_kind=tmux` and `receive_style=push` can receive direct tmux pushes;
45
58
  one with `session_kind=codex_app` and `receive_style=pull` must poll the
46
- printed inbox command.
47
- 7. Give the worker Codex app session the generated `worker_handoff` prompt.
48
- It should keep polling `conveyor worker-inbox <task> --consume-next --wait
49
- --timeout 60 --json` through the bounded loop until no inbox item remains
50
- or `max_iterations` is reached.
51
- 8. After each worker pass, require concrete evidence and structured
59
+ printed `app-heartbeat` command, using direct inbox commands only when the
60
+ heartbeat output or setup JSON provides them as fallbacks.
61
+ 8. Give the worker Codex app session the generated `worker_handoff` prompt.
62
+ If step 4 created a fresh worker thread, use `send_message_to_thread` only
63
+ to deliver that bootstrap prompt. Durable manager/worker communication still
64
+ goes through Dispatch and `worker-inbox`/`manager-inbox`; direct app-thread
65
+ messages are not Dispatch receipts. The worker should keep polling
66
+ the exact command printed in the `worker_handoff` prompt through the bounded
67
+ loop until no inbox item remains or `max_iterations` is reached. Consuming a
68
+ `continue_iteration` inbox item advances the Ralph-loop run's durable
69
+ `current_iteration` and writes `ralph_loop_iteration_advanced` telemetry.
70
+ 9. After each worker pass, require concrete evidence and structured
52
71
  `loop-evidence adversarial-check` proof before queueing another
53
72
  `enqueue-continue-iteration`.
54
- 9. Use `conveyor loop-status <task> --run <run> --json` and telemetry/audit
73
+ 10. Use `conveyor loop-status <task> --run <run> --json` and telemetry/audit
55
74
  receipts before declaring the loop ready for manager review.
56
75
 
76
+ Idle polling rule for Codex app/no-tmux sessions:
77
+
78
+ - When a worker has `session_kind=codex_app` or `receive_style=pull`, its
79
+ default idle/check-in command is the returned `app-heartbeat` worker command.
80
+ Use `communication.poll_command` or the generated `worker_handoff` command as
81
+ fallback/direct inbox polling.
82
+ - When a manager has `session_kind=codex_app` or `receive_style=pull`, its
83
+ default idle/check-in command is the returned `app-heartbeat` manager command.
84
+ Use `communication.poll_command` as fallback/direct inbox polling.
85
+ - The printed command may include a local `PATH=.../bin:$PATH conveyor` prefix;
86
+ preserve that prefix when giving the command to a Codex app thread.
87
+ - Repeat the appropriate command whenever the session is idle, after finishing
88
+ a received instruction, and before deciding there is nothing more to do.
89
+ A timeout is not completion; it is only a quiet poll interval.
90
+ - Keep `conveyor dispatch --watch --dispatcher-id dispatch-local` running so
91
+ Dispatch can route new messages into those inboxes.
92
+ - Use `conveyor app-loop-status <task> --json` as the operator status surface,
93
+ and `conveyor app-wakeup-plan <task> --json` to produce exact stale-thread
94
+ wake prompts for Codex app automation or `send_message_to_thread`.
95
+ - Use `conveyor app-wakeup-dispatch <task> --json` when the manager needs an
96
+ auditable wake orchestration receipt. It prepares adapter-ready app-thread
97
+ actions, reports skipped and blocked roles, and records telemetry; it does
98
+ not send direct app-thread messages itself.
99
+ - For bounded Ralph loops, treat `ralph_loop_iteration_advanced` telemetry as
100
+ the receipt that a worker actually consumed and began the requested
101
+ iteration.
102
+
57
103
  Reference docs:
58
104
 
59
105
  - `README.md` command reference
@@ -77,6 +123,9 @@ Supervision is built on three primitives: **sessions**, **tasks**, and
77
123
  `communication` block. Use it to decide the receive style for both worker and
78
124
  manager: tmux sessions are push-capable, while Codex app/no-tmux sessions
79
125
  receive through `manager-inbox` or `worker-inbox` polling.
126
+ - App-assisted setup may also record optional `codex_app_thread_id` and
127
+ `codex_app_thread_title` metadata. This identifies the human-readable Codex
128
+ app thread; it does not replace rollout ingest or Dispatch inbox receipts.
80
129
  - A **task** is a unit of supervised work with a goal.
81
130
  - A **binding** ties one worker session and one manager session to one task.
82
131
 
@@ -224,6 +273,15 @@ conveyor register-worker --name foo --pid <WORKER_PID> \
224
273
  --cwd "$PWD" --tmux-session codex-foo
225
274
  ```
226
275
 
276
+ When a Codex app tool created or identified the thread, preserve that identity
277
+ with optional metadata flags:
278
+
279
+ ```bash
280
+ conveyor register-worker --name foo --pid <WORKER_PID> \
281
+ --cwd "$PWD" --codex-app-thread-id <THREAD_ID> \
282
+ --codex-app-thread-title "Human readable title"
283
+ ```
284
+
227
285
  If `lsof` discovery fails, pass the rollout path explicitly:
228
286
 
229
287
  ```bash
@@ -433,7 +491,7 @@ manager decision, then run:
433
491
  ```bash
434
492
  decision_id=$(conveyor record-decision my-task nudge \
435
493
  --reason "Worker context should be compacted after handoff" \
436
- | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')
494
+ | node -e 'const fs = require("fs"); console.log(JSON.parse(fs.readFileSync(0, "utf8")).id)')
437
495
  conveyor request-worker-compact my-task \
438
496
  --decision-id "$decision_id" --strict-decisions
439
497
  ```
@@ -567,7 +625,7 @@ Criteria command examples:
567
625
  conveyor criteria my-task --list
568
626
  conveyor criteria my-task --add --criterion "..." --source worker_proposed --status proposed
569
627
  conveyor criteria my-task --accept 12 --rationale "Must-have for this task"
570
- conveyor criteria my-task --satisfy 12 --evidence-json '{"command":"python3 -m unittest tests.test_workerctl.ManagerBootstrapPromptTests -v","status":"pass"}'
628
+ conveyor criteria my-task --satisfy 12 --evidence-json '{"command":"npm test -- --runInBand","status":"pass"}'
571
629
  conveyor criteria my-task --defer 13 --rationale "Follow-up after this task"
572
630
  conveyor criteria my-task --reject 14 --rationale "Duplicate or out of scope"
573
631
  ```
@@ -576,8 +634,8 @@ Replace placeholder `...` values with the actual criterion and verification
576
634
  command. To add a criterion and satisfy that same row after verification:
577
635
 
578
636
  ```bash
579
- criterion_id=$(conveyor criteria my-task --add --criterion "Targeted prompt tests pass" --source worker_proposed --status proposed | python3 -c 'import json,sys; print(json.load(sys.stdin)["affected_criterion"]["id"])')
580
- conveyor criteria my-task --satisfy "$criterion_id" --evidence-json '{"command":"python3 -m unittest tests.test_workerctl.ManagerBootstrapPromptTests -v","status":"pass"}'
637
+ criterion_id=$(conveyor criteria my-task --add --criterion "Targeted prompt tests pass" --source worker_proposed --status proposed | node -e 'const fs = require("fs"); console.log(JSON.parse(fs.readFileSync(0, "utf8")).affected_criterion.id)')
638
+ conveyor criteria my-task --satisfy "$criterion_id" --evidence-json '{"command":"npm test -- --runInBand","status":"pass"}'
581
639
  ```
582
640
 
583
641
  When making multiple criteria changes, use each mutation response's
@@ -681,6 +739,20 @@ etc.) run `conveyor db-doctor --live`.
681
739
 
682
740
  ## Natural-Language Command Mapping
683
741
 
742
+ - "set up a Codex app Ralph loop": if the current session has Codex app thread
743
+ tools, call `create_thread` for fresh same-project manager and worker
744
+ threads unless the current thread is explicitly the manager, set readable
745
+ titles, run `conveyor create-disposable-binding` with both
746
+ `--manager-codex-app-thread-id`/`--manager-codex-app-thread-title` and
747
+ `--worker-codex-app-thread-id`/`--worker-codex-app-thread-title`, then send
748
+ the returned bootstrap prompts using `send_message_to_thread`. If those tools
749
+ are unavailable, run `create-disposable-binding` without thread metadata and
750
+ give the user the handoff prompts to paste into manually opened sessions. Keep
751
+ Dispatch as the source of durable communication, and make both Codex app
752
+ sessions repeat their role-specific `app-heartbeat` command while idle. Use
753
+ `app-loop-status` and `app-wakeup-plan` for operator status and stale-thread
754
+ recovery, and `app-wakeup-dispatch` when the manager needs an auditable
755
+ prepared/skipped/blocked wake receipt.
684
756
  - "register this Codex session as the worker for dashboard setup <CODE>":
685
757
  derive `dashboard-<CODE>-worker`, run `conveyor doctor-self`, then
686
758
  `conveyor register-worker --name dashboard-<CODE>-worker --pid <PID> --cwd <CWD> --tmux-session <SESSION>`.