agent-conveyor 0.1.6 → 0.1.8

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.
@@ -28,6 +28,17 @@ Not allowed: merge without green CI; compact/clear before handoff; run two child
28
28
  User confirmed: yes
29
29
  ```
30
30
 
31
+ ## Runtime Notes
32
+
33
+ On Node releases where `node:sqlite` is still experimental, Conveyor commands
34
+ may print a SQLite `ExperimentalWarning` before otherwise valid JSON or status
35
+ output. Treat the process exit code and parsed JSON payload as the command
36
+ result, and keep the warning in receipts only when it obscures a real failure.
37
+
38
+ If a dogfood run reports `database is locked`, prefer retrying the Conveyor CLI
39
+ command after the active manager/worker write completes. Avoid direct SQLite
40
+ inspection while Dispatch is writing to the same `--path` database.
41
+
31
42
  ## Recipe Summary
32
43
 
33
44
  | Recipe | Use When | Mode | Main Gates | Cleanup |
@@ -248,6 +259,31 @@ conveyor worker-inbox "$TASK" --consume-next --wait --timeout 60 --json
248
259
  conveyor manager-inbox "$TASK" --consume-next --wait --timeout 60 --json
249
260
  ```
250
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 the worker with fresh same-project `create_thread`, set a readable title
277
+ with `set_thread_title`, and pass the resulting id/title into
278
+ `conveyor create-disposable-binding` with
279
+ `--worker-codex-app-thread-id` and `--worker-codex-app-thread-title`. Use
280
+ `send_message_to_thread` only to deliver the generated `worker_handoff`
281
+ bootstrap prompt; 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
+
251
287
  The saved dogfood example is
252
288
  `docs/goals/live-codex-app-inbox-drill/notes/T001-live-drill.md`. It proves
253
289
  manager-to-worker `nudge_worker` delivery and worker-to-manager
@@ -275,6 +311,59 @@ acceptance criteria, command attempts, routed notifications, inbox backlog, and
275
311
  telemetry before deciding whether to wait, nudge, continue, compact, clear, or
276
312
  finish.
277
313
 
314
+ ## Package Dogfood Command
315
+
316
+ Use a disposable workspace and explicit database path when checking the
317
+ package-facing `goalbuddy-conveyor` recipe flow. The point is to prove the
318
+ published package, not a local checkout.
319
+
320
+ ```bash
321
+ mkdir -p /tmp/agent-conveyor-dogfood/workspace
322
+ git -C /tmp/agent-conveyor-dogfood/workspace init
323
+
324
+ conveyor pair \
325
+ --task dogfood-goalbuddy \
326
+ --worker-name dogfood-worker \
327
+ --manager-name dogfood-manager \
328
+ --task-goal "Dogfood the published package GoalBuddy conveyor recipe." \
329
+ --task-prompt "Create docs/dogfood-note.md with a short received-task note and report a concise receipt." \
330
+ --manager-recipe goalbuddy-conveyor \
331
+ --manager-mode strict \
332
+ --manager-objective "Run a one-child-at-a-time GoalBuddy conveyor until the disposable task is proven satisfied or blocked with evidence." \
333
+ --manager-guideline "Keep exactly one child board active at a time." \
334
+ --manager-guideline "Before activating the next child, update the parent receipt." \
335
+ --manager-acceptance "The disposable worker task has a receipt showing the note file was created or a blocker was recorded." \
336
+ --manager-acceptance "Manager config records the selected goalbuddy-conveyor recipe." \
337
+ --manager-allow-worker-compact-clear \
338
+ --manager-allow-pr \
339
+ --manager-allow-merge-green \
340
+ --manager-tool verification.run_tests \
341
+ --manager-tool context.fetch_prs \
342
+ --manager-epilogue draft-pr \
343
+ --manager-epilogue record-handoff \
344
+ --cwd /tmp/agent-conveyor-dogfood/workspace \
345
+ --path /tmp/agent-conveyor-dogfood/workerctl.db \
346
+ --accept-trust
347
+ ```
348
+
349
+ Expected clean transcript shape:
350
+
351
+ ```text
352
+ pair exits 0
353
+ dispatcher watch starts from an executable shipped with the package
354
+ manager_config.recipe_name = goalbuddy-conveyor
355
+ manager-ack and worker-ack are recorded against the same --path database
356
+ cycle shows worker_receipt for docs/dogfood-note.md
357
+ criteria --list shows all accepted criteria satisfied
358
+ finish-task --require-criteria-audit marks the task done
359
+ ```
360
+
361
+ If a dogfood run needs an operator to add `--path`, find the active database, or
362
+ replace a missing source-tree path with the installed `workerctl` bin, the
363
+ package setup is not yet ready for unattended dogfooding. Record the friction in
364
+ the dogfood board so the next recipe or prompt pass has something concrete to
365
+ fix.
366
+
278
367
  ## What The Database Records
279
368
 
280
369
  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.6",
3
+ "version": "0.1.8",
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,58 @@ 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. If running in the Codex app and thread tools are available, create a fresh
39
+ same-project worker thread with `create_thread`, name it with
40
+ `set_thread_title`, and keep the returned thread id/title. Use
41
+ `create_thread` for this flow; do not use `fork_thread` unless the user
42
+ explicitly asks to fork or resume this exact conversation.
43
+ 5. Create the no-tmux binding with `conveyor create-disposable-binding`
39
44
  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:
45
+ `--max-iterations`, and `--json`. When step 4 produced a worker thread id,
46
+ pass it through `--worker-codex-app-thread-id` and
47
+ `--worker-codex-app-thread-title` so Conveyor can surface the app identity
48
+ in `sessions`, `discover`, and setup JSON. If app thread tools are not
49
+ available, create the binding without those flags and ask the user to open a
50
+ separate Codex app worker session manually.
51
+ 6. Ensure Dispatch is running or tell the user the single command to start it:
42
52
  `conveyor dispatch --watch --dispatcher-id dispatch-local`.
43
- 6. Read the returned `communication` blocks. A worker or manager with
53
+ 7. Read the returned `communication` blocks. A worker or manager with
44
54
  `session_kind=tmux` and `receive_style=push` can receive direct tmux pushes;
45
55
  one with `session_kind=codex_app` and `receive_style=pull` must poll the
46
56
  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
57
+ 8. Give the worker Codex app session the generated `worker_handoff` prompt.
58
+ If step 4 created a fresh worker thread, use `send_message_to_thread` only
59
+ to deliver that bootstrap prompt. Durable manager/worker communication still
60
+ goes through Dispatch and `worker-inbox`/`manager-inbox`; direct app-thread
61
+ messages are not Dispatch receipts. The worker should keep polling
62
+ the exact command printed in the `worker_handoff` prompt through the bounded
63
+ loop until no inbox item remains or `max_iterations` is reached. Consuming a
64
+ `continue_iteration` inbox item advances the Ralph-loop run's durable
65
+ `current_iteration` and writes `ralph_loop_iteration_advanced` telemetry.
66
+ 9. After each worker pass, require concrete evidence and structured
52
67
  `loop-evidence adversarial-check` proof before queueing another
53
68
  `enqueue-continue-iteration`.
54
- 9. Use `conveyor loop-status <task> --run <run> --json` and telemetry/audit
69
+ 10. Use `conveyor loop-status <task> --run <run> --json` and telemetry/audit
55
70
  receipts before declaring the loop ready for manager review.
56
71
 
72
+ Idle polling rule for Codex app/no-tmux sessions:
73
+
74
+ - When a worker has `session_kind=codex_app` or `receive_style=pull`, its
75
+ idle/check-in command is the returned
76
+ `communication.poll_command` or generated `worker_handoff` command.
77
+ - When a manager has `session_kind=codex_app` or `receive_style=pull`, its
78
+ idle/check-in command is the returned `communication.poll_command`.
79
+ - The printed command may include a local `PATH=.../bin:$PATH conveyor` prefix;
80
+ preserve that prefix when giving the command to a Codex app thread.
81
+ - Repeat the appropriate command whenever the session is idle, after finishing
82
+ a received instruction, and before deciding there is nothing more to do.
83
+ A timeout is not completion; it is only a quiet poll interval.
84
+ - Keep `conveyor dispatch --watch --dispatcher-id dispatch-local` running so
85
+ Dispatch can route new messages into those inboxes.
86
+ - For bounded Ralph loops, treat `ralph_loop_iteration_advanced` telemetry as
87
+ the receipt that a worker actually consumed and began the requested
88
+ iteration.
89
+
57
90
  Reference docs:
58
91
 
59
92
  - `README.md` command reference
@@ -77,6 +110,9 @@ Supervision is built on three primitives: **sessions**, **tasks**, and
77
110
  `communication` block. Use it to decide the receive style for both worker and
78
111
  manager: tmux sessions are push-capable, while Codex app/no-tmux sessions
79
112
  receive through `manager-inbox` or `worker-inbox` polling.
113
+ - App-assisted setup may also record optional `codex_app_thread_id` and
114
+ `codex_app_thread_title` metadata. This identifies the human-readable Codex
115
+ app thread; it does not replace rollout ingest or Dispatch inbox receipts.
80
116
  - A **task** is a unit of supervised work with a goal.
81
117
  - A **binding** ties one worker session and one manager session to one task.
82
118
 
@@ -224,6 +260,15 @@ conveyor register-worker --name foo --pid <WORKER_PID> \
224
260
  --cwd "$PWD" --tmux-session codex-foo
225
261
  ```
226
262
 
263
+ When a Codex app tool created or identified the thread, preserve that identity
264
+ with optional metadata flags:
265
+
266
+ ```bash
267
+ conveyor register-worker --name foo --pid <WORKER_PID> \
268
+ --cwd "$PWD" --codex-app-thread-id <THREAD_ID> \
269
+ --codex-app-thread-title "Human readable title"
270
+ ```
271
+
227
272
  If `lsof` discovery fails, pass the rollout path explicitly:
228
273
 
229
274
  ```bash
@@ -433,7 +478,7 @@ manager decision, then run:
433
478
  ```bash
434
479
  decision_id=$(conveyor record-decision my-task nudge \
435
480
  --reason "Worker context should be compacted after handoff" \
436
- | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')
481
+ | node -e 'const fs = require("fs"); console.log(JSON.parse(fs.readFileSync(0, "utf8")).id)')
437
482
  conveyor request-worker-compact my-task \
438
483
  --decision-id "$decision_id" --strict-decisions
439
484
  ```
@@ -567,7 +612,7 @@ Criteria command examples:
567
612
  conveyor criteria my-task --list
568
613
  conveyor criteria my-task --add --criterion "..." --source worker_proposed --status proposed
569
614
  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"}'
615
+ conveyor criteria my-task --satisfy 12 --evidence-json '{"command":"npm test -- --runInBand","status":"pass"}'
571
616
  conveyor criteria my-task --defer 13 --rationale "Follow-up after this task"
572
617
  conveyor criteria my-task --reject 14 --rationale "Duplicate or out of scope"
573
618
  ```
@@ -576,8 +621,8 @@ Replace placeholder `...` values with the actual criterion and verification
576
621
  command. To add a criterion and satisfy that same row after verification:
577
622
 
578
623
  ```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"}'
624
+ 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)')
625
+ conveyor criteria my-task --satisfy "$criterion_id" --evidence-json '{"command":"npm test -- --runInBand","status":"pass"}'
581
626
  ```
582
627
 
583
628
  When making multiple criteria changes, use each mutation response's
@@ -681,6 +726,16 @@ etc.) run `conveyor db-doctor --live`.
681
726
 
682
727
  ## Natural-Language Command Mapping
683
728
 
729
+ - "set up a Codex app Ralph loop": if the current session has Codex app thread
730
+ tools, call `create_thread` for a fresh same-project worker, call
731
+ `set_thread_title`, run `conveyor create-disposable-binding` with
732
+ `--worker-codex-app-thread-id` and `--worker-codex-app-thread-title`, then
733
+ send the returned `worker_handoff` using `send_message_to_thread`. If those
734
+ tools are unavailable, run `create-disposable-binding` without thread
735
+ metadata and give the user the `worker_handoff` prompt to paste into a
736
+ manually opened worker. Keep Dispatch as the source of durable communication,
737
+ and make both Codex app sessions repeat their role-specific inbox poll while
738
+ idle.
684
739
  - "register this Codex session as the worker for dashboard setup <CODE>":
685
740
  derive `dashboard-<CODE>-worker`, run `conveyor doctor-self`, then
686
741
  `conveyor register-worker --name dashboard-<CODE>-worker --pid <PID> --cwd <CWD> --tmux-session <SESSION>`.