cueline 0.1.2 → 0.1.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.
Files changed (116) hide show
  1. package/.claude-plugin/plugin.json +2 -2
  2. package/.codex-plugin/plugin.json +3 -3
  3. package/CHANGELOG.md +38 -0
  4. package/README.ja.md +65 -21
  5. package/README.ko.md +65 -21
  6. package/README.md +70 -23
  7. package/README.zh-CN.md +65 -21
  8. package/README.zh-TW.md +68 -22
  9. package/dist/src/api-contracts.d.ts +77 -0
  10. package/dist/src/api-contracts.js +2 -0
  11. package/dist/src/api-contracts.js.map +1 -0
  12. package/dist/src/api-controller-handoff.d.ts +6 -0
  13. package/dist/src/api-controller-handoff.js +253 -0
  14. package/dist/src/api-controller-handoff.js.map +1 -0
  15. package/dist/src/api-runtime-lifecycle.d.ts +22 -0
  16. package/dist/src/api-runtime-lifecycle.js +568 -0
  17. package/dist/src/api-runtime-lifecycle.js.map +1 -0
  18. package/dist/src/api.d.ts +9 -27
  19. package/dist/src/api.js +138 -42
  20. package/dist/src/api.js.map +1 -1
  21. package/dist/src/browser/browser-adapter.d.ts +11 -1
  22. package/dist/src/browser/codex-iab/bootstrap.d.ts +16 -0
  23. package/dist/src/browser/codex-iab/bootstrap.js +49 -0
  24. package/dist/src/browser/codex-iab/bootstrap.js.map +1 -1
  25. package/dist/src/browser/codex-iab/chatgpt-client.js +346 -120
  26. package/dist/src/browser/codex-iab/chatgpt-client.js.map +1 -1
  27. package/dist/src/browser/codex-iab/recovery-evidence.d.ts +6 -0
  28. package/dist/src/browser/codex-iab/recovery-evidence.js +37 -0
  29. package/dist/src/browser/codex-iab/recovery-evidence.js.map +1 -0
  30. package/dist/src/browser/codex-iab/submission-url.d.ts +2 -0
  31. package/dist/src/browser/codex-iab/submission-url.js +53 -0
  32. package/dist/src/browser/codex-iab/submission-url.js.map +1 -0
  33. package/dist/src/cli/main.js +305 -20
  34. package/dist/src/cli/main.js.map +1 -1
  35. package/dist/src/core/controller-abort.d.ts +1 -0
  36. package/dist/src/core/controller-abort.js +11 -0
  37. package/dist/src/core/controller-abort.js.map +1 -0
  38. package/dist/src/core/controller-command-execution.d.ts +9 -0
  39. package/dist/src/core/controller-command-execution.js +299 -0
  40. package/dist/src/core/controller-command-execution.js.map +1 -0
  41. package/dist/src/core/controller-loop.d.ts +3 -37
  42. package/dist/src/core/controller-loop.js +386 -291
  43. package/dist/src/core/controller-loop.js.map +1 -1
  44. package/dist/src/core/controller-turn.d.ts +16 -0
  45. package/dist/src/core/controller-turn.js +309 -0
  46. package/dist/src/core/controller-turn.js.map +1 -0
  47. package/dist/src/core/controller-types.d.ts +58 -0
  48. package/dist/src/core/controller-types.js +2 -0
  49. package/dist/src/core/controller-types.js.map +1 -0
  50. package/dist/src/core/persisted-run.d.ts +4 -0
  51. package/dist/src/core/persisted-run.js +19 -0
  52. package/dist/src/core/persisted-run.js.map +1 -0
  53. package/dist/src/core/process-liveness.d.ts +2 -0
  54. package/dist/src/core/process-liveness.js +44 -0
  55. package/dist/src/core/process-liveness.js.map +1 -0
  56. package/dist/src/core/run-status.d.ts +53 -0
  57. package/dist/src/core/run-status.js +224 -0
  58. package/dist/src/core/run-status.js.map +1 -0
  59. package/dist/src/core/state-machine.d.ts +17 -4
  60. package/dist/src/core/state-machine.js +170 -16
  61. package/dist/src/core/state-machine.js.map +1 -1
  62. package/dist/src/jobs/status.d.ts +7 -1
  63. package/dist/src/jobs/status.js.map +1 -1
  64. package/dist/src/jobs/supervisor.d.ts +2 -0
  65. package/dist/src/jobs/supervisor.js +47 -13
  66. package/dist/src/jobs/supervisor.js.map +1 -1
  67. package/dist/src/protocol/types.d.ts +1 -1
  68. package/dist/src/protocol/validate-command.js +18 -0
  69. package/dist/src/protocol/validate-command.js.map +1 -1
  70. package/dist/src/router/resolver.d.ts +2 -1
  71. package/dist/src/router/resolver.js +31 -13
  72. package/dist/src/router/resolver.js.map +1 -1
  73. package/dist/src/runners/process-runner.d.ts +2 -2
  74. package/dist/src/runners/process-runner.js +113 -9
  75. package/dist/src/runners/process-runner.js.map +1 -1
  76. package/dist/src/runners/runner-adapter.d.ts +9 -2
  77. package/dist/src/runners/runner-adapter.js.map +1 -1
  78. package/dist/src/state/atomic-write.js +17 -2
  79. package/dist/src/state/atomic-write.js.map +1 -1
  80. package/dist/src/state/cancellation.d.ts +42 -0
  81. package/dist/src/state/cancellation.js +168 -0
  82. package/dist/src/state/cancellation.js.map +1 -0
  83. package/dist/src/state/event-log.d.ts +17 -1
  84. package/dist/src/state/event-log.js +328 -18
  85. package/dist/src/state/event-log.js.map +1 -1
  86. package/dist/src/state/paths.d.ts +4 -0
  87. package/dist/src/state/paths.js +4 -0
  88. package/dist/src/state/paths.js.map +1 -1
  89. package/dist/src/state/runtime-lease.d.ts +53 -0
  90. package/dist/src/state/runtime-lease.js +727 -0
  91. package/dist/src/state/runtime-lease.js.map +1 -0
  92. package/dist/src/state/runtime-retirement.d.ts +16 -0
  93. package/dist/src/state/runtime-retirement.js +95 -0
  94. package/dist/src/state/runtime-retirement.js.map +1 -0
  95. package/dist/src/state/runtime-takeover-intent.d.ts +1 -0
  96. package/dist/src/state/runtime-takeover-intent.js +18 -0
  97. package/dist/src/state/runtime-takeover-intent.js.map +1 -0
  98. package/dist/src/state/store.d.ts +12 -1
  99. package/dist/src/state/store.js +246 -40
  100. package/dist/src/state/store.js.map +1 -1
  101. package/dist/src/version.d.ts +1 -1
  102. package/dist/src/version.js +1 -1
  103. package/docs/architecture.md +16 -11
  104. package/docs/assets/cueline-loop-en.svg +11 -10
  105. package/docs/assets/cueline-loop-ja.svg +11 -10
  106. package/docs/assets/cueline-loop-ko.svg +11 -10
  107. package/docs/assets/cueline-loop-zh-CN.svg +11 -10
  108. package/docs/assets/cueline-loop-zh-TW.svg +11 -10
  109. package/docs/compatibility.md +16 -8
  110. package/docs/controller-protocol.md +8 -4
  111. package/docs/runner-contract.md +26 -6
  112. package/docs/state-and-recovery.md +69 -16
  113. package/package.json +4 -3
  114. package/schemas/controller-observation.schema.json +1 -1
  115. package/scripts/validate-plugin.mjs +66 -0
  116. package/skills/cueline/SKILL.md +89 -13
@@ -23,7 +23,9 @@ CueLine is standalone. Its runtime does not import Omnilane or GPT Relay, and it
23
23
 
24
24
  ### Browser adapter
25
25
 
26
- `src/browser/codex-iab/` implements a text-only adapter over Codex's IAB client. It claims an existing ChatGPT tab when possible, otherwise opens the requested ChatGPT URL. It fills the composer, emits durable pre-click and post-click checkpoints, sends one turn, waits for a stable completed assistant message, and records the resulting conversation URL. Its recovery path is read-only: it imports an existing response only when the exact last user prompt matches the persisted pending turn and both Pro model checks pass.
26
+ `src/browser/codex-iab/` implements a text-only adapter over Codex's IAB client. It claims an existing ChatGPT tab when possible, otherwise opens the requested ChatGPT URL. It fills the composer, waits for the DOM to settle as either `inline_ready` or `attachment_ready`, emits durable submission checkpoints, makes at most one send attempt, waits for a stable completed assistant message, and records the resulting conversation URL. ChatGPT may automatically convert a long text prompt into an attachment; this is supported without treating an empty composer as proof that nothing is ready.
27
+
28
+ Recovery is read-only. Inline turns normally require the exact last user prompt. A manually submitted attachment turn may instead be recovered only after an append-only operator confirmation and exact conversation, Pro model, and protocol/run/round/request envelope checks. Response text and the conversation URL are captured in the same DOM evaluation so navigation cannot mix evidence from two pages. Ambiguous clicks remain `possibly_sent`; CueLine never retries or coordinate-clicks after a possibly accepted send.
27
29
 
28
30
  The adapter can receive an injected browser or resolve `globalThis.iab` / `agent.browsers.get("iab")` from Codex's runtime. Plain Node does not provide these globals.
29
31
 
@@ -33,26 +35,28 @@ The adapter can receive an injected browser or resolve `globalThis.iab` / `agent
33
35
 
34
36
  ### Controller loop
35
37
 
36
- `src/core/controller-loop.ts` owns the run:
38
+ `src/core/controller-loop.ts` advances the run:
37
39
 
38
40
  1. Persist the intended controller turn.
39
41
  2. Persist browser submission checkpoints around the send boundary.
40
- 3. Send an observation through the browser adapter.
41
- 4. Persist the assistant response.
42
+ 3. With the built-in browser in caller mode, submit once, capture the exact `/c/...` URL, persist `submitted`, return `awaiting_controller`, and release the runtime lease. CueLine does not create a detached Node daemon because Codex's injected IAB object does not exist there.
43
+ 4. A later continuation performs one read-only `observeTurn`. An unfinished Pro response returns `awaiting_controller` immediately without another send; an exact completed response is persisted.
42
44
  5. Validate protocol identity and every pre-spawn route, then persist the accepted command.
43
- 6. Execute the command through the local supervisor.
45
+ 6. In the default `caller` executor, persist `advise` jobs and return them to the current Codex. In explicit `process` execution, run registered workers through the local supervisor.
44
46
  7. Snapshot the derived state.
45
- 8. Repeat until `complete`, `blocked`, or the round limit is reached.
47
+ 8. Repeat through ownerless controller/caller pauses until `complete`, `blocked`, or the round limit is reached. Neither terminal action is accepted while any required or optional job remains pending/running.
48
+
49
+ The default limits are 12 controller rounds and two repair attempts per pending command. An explicit `maxRounds` is persisted with run creation and remains the total budget across split caller continuations; omitting it later reuses the persisted value, while a different value is rejected.
46
50
 
47
- The default limits are 12 controller rounds and two repair attempts per pending command.
51
+ ### Execution modes, routing, and runners
48
52
 
49
- ### Routing and runners
53
+ `caller` is the default for both `startCueLineRun` and `runCueLine`. A controller turn first returns `awaiting_controller` after its one durable submission; each continuation observes the same URL/request once and never resends. A controller `dispatch` then creates durable pending jobs and returns `awaiting_caller`; the current Codex performs each exact local inspection and calls `submitCueLineCallerJobResult`, then continues the same run. ChatGPT only issued the text command—it did not use local tools. Caller mode accepts `advise` only; `work` is rejected until CueLine can issue a duplicate-safe execution claim.
50
54
 
51
- `src/router/` chooses an enabled, available candidate before any process starts. `src/runners/` requires an explicitly registered `argv[0]`, uses `spawn` with `shell: false`, and never performs post-spawn fallback. `src/jobs/` coordinates foreground/background execution and persists job status.
55
+ `process` is opt-in. `src/router/` chooses an enabled, available candidate before any process starts. `src/runners/` requires an explicitly registered `argv[0]`, uses `spawn` with `shell: false`, and never performs post-spawn fallback. `src/jobs/` coordinates foreground/background execution and persists job status. Process execution defaults to two concurrent jobs globally and two per lane; an accepted batch containing any `work` job is serial. Owned process groups are settled on success, cancellation, and timeout so descendants are not left behind.
52
56
 
53
57
  ### Durable state
54
58
 
55
- `src/state/` writes a per-run JSONL event log and an atomic materialized snapshot. The event log is authoritative; a snapshot is a replay optimization. Pending controller turns and request-correlated browser failure evidence survive replay. A prompt is retried only when the exact sole pending request is proven `definitely_not_sent`; ambiguous submissions require read-only reconciliation. Job status files are atomically replaced.
59
+ `src/state/` writes a per-run logical event log and an atomic disposable snapshot. The event log is authoritative and is replayed on load. Immutable fsynced sequence segments avoid a shared-host append lock; a durable legacy-prefix fence isolates still-loaded older writers. Runtime-authored events carry owner identity. Exact takeover intent is durable before replacement; the successful atomic lease replacement embeds the retired owner's sequence cutoff, so a failed replacement leaves the old owner authoritative while a committed cutoff keeps later writes visible for audit but unable to change replayed state. The cutoff is mirrored to immutable retirement evidence before the replacement lease is removed. Pending and recoverably abandoned controller turns, composer state, manual confirmation, and request-correlated browser failure evidence survive replay. A prompt is retried only when the exact sole pending request is proven `definitely_not_sent`; ambiguous submissions require read-only reconciliation. Job status files are atomically replaced, but authoritative terminal run events win if a retired owner writes a conflicting file later. Runtime leases serialize continuation and caller result submission; ownerless `controller_response_pending` and `caller_jobs_pending` phases are intentional healthy boundaries.
56
60
 
57
61
  ## Authority and trust
58
62
 
@@ -64,6 +68,7 @@ The controller can request local work, but a request is not equivalent to proces
64
68
  - config-derived registered executable allow-list
65
69
  - no shell interpolation
66
70
  - deterministic job identity and duplicate-dispatch suppression
71
+ - caller-mode `advise`-only enforcement
67
72
  - no nested CueLine routing (`CUELINE_DEPTH`)
68
73
  - no retry after a worker has started
69
74
 
@@ -72,7 +77,7 @@ These gates reduce accidental execution ambiguity; they do not make an allowed w
72
77
  ## Data flow
73
78
 
74
79
  1. The original user request becomes part of every controller observation.
75
- 2. Job outputs and errors are stored locally and included in later observations (individual fields are bounded before browser submission).
80
+ 2. Full job stdout and stderr remain in local status. Successful non-empty stdout is preferred for controller evidence, and all controller job evidence shares one 12,000-character budget with an explicit truncation notice.
76
81
  3. ChatGPT returns a command; only the control envelope is machine-executed.
77
82
  4. On `complete`, CueLine returns `final_delivery_text` to Codex.
78
83
  5. On `blocked`, CueLine preserves the controller's reason and optional delivery text.
@@ -1,4 +1,4 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 590" width="1000" height="590" role="img" aria-label="A CueLine run read as a promptbook: the machine reports an observation, the controller calls one command, the registered runner executes it, until the controller calls complete.">
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 612" width="1000" height="612" role="img" aria-label="A caller-first CueLine run: ChatGPT emits text commands, the current Codex performs local advice, and CueLine returns bounded evidence until complete.">
2
2
  <title>A CueLine run, read as a promptbook</title>
3
3
  <style>
4
4
  text { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace }
@@ -28,8 +28,8 @@
28
28
 
29
29
  <text x="505" y="44" class="hd" text-anchor="end">ChatGPT web conversation</text>
30
30
  <text x="505" y="64" class="sub" text-anchor="end">the controller — plans, calls, judges</text>
31
- <text x="555" y="44" class="hd">your machine</text>
32
- <text x="555" y="64" class="sub">CueLine — validates, routes, executes, records</text>
31
+ <text x="555" y="44" class="hd">current Codex + CueLine</text>
32
+ <text x="555" y="64" class="sub">validates, persists, hands off, records</text>
33
33
 
34
34
  <path d="M40 84H505" class="rule"/>
35
35
  <path d="M555 84H960" class="rule"/>
@@ -45,23 +45,23 @@
45
45
  <path d="M545 162H565" class="tick"/>
46
46
  <text x="575" y="166" class="note">routed before anything starts</text>
47
47
 
48
- <text x="555" y="200" class="note">codex exec (read-only) → succeeded</text>
48
+ <text x="555" y="200" class="note">current Codex (caller advise) → result submitted</text>
49
49
 
50
50
  <text x="40" y="264" class="rnd">ROUND 2</text>
51
51
  <path d="M505 260H524" class="tick"/>
52
- <text x="555" y="264" class="obs">observation · the evidence, verbatim</text>
52
+ <text x="555" y="264" class="obs">observation · bounded evidence · stdout preferred</text>
53
53
  <path d="M524 256 517 260 524 264z" class="cue"/>
54
54
 
55
55
  <path d="M536 296 545 300 536 304z" class="cue"/>
56
- <text x="505" y="304" class="say" text-anchor="end">dispatch · patch · mode work</text>
56
+ <text x="505" y="304" class="say" text-anchor="end">dispatch · follow-up · mode advise</text>
57
57
  <path d="M545 300H565" class="tick"/>
58
- <text x="575" y="304" class="note">argv[0] must already be allowed</text>
58
+ <text x="575" y="304" class="note">durable caller handoff</text>
59
59
 
60
- <text x="555" y="338" class="note">codex exec (workspace-write) succeeded</text>
60
+ <text x="555" y="338" class="note">current Codexsecond result submitted</text>
61
61
 
62
62
  <text x="40" y="402" class="rnd">ROUND 3</text>
63
63
  <path d="M505 398H524" class="tick"/>
64
- <text x="555" y="402" class="obs">observation · updated evidence</text>
64
+ <text x="555" y="402" class="obs">observation · updated bounded evidence</text>
65
65
  <path d="M524 394 517 398 524 402z" class="cue"/>
66
66
 
67
67
  <path d="M536 434 545 438 536 442z" class="cue"/>
@@ -73,5 +73,6 @@
73
73
 
74
74
  <path d="M40 520H960" class="rule"/>
75
75
  <text x="40" y="546" class="foot">Five actions only — dispatch · wait · inspect · complete · blocked.</text>
76
- <text x="40" y="568" class="foot">Nothing outside the envelope is executed. No worker is retried once it has started.</text>
76
+ <text x="40" y="568" class="foot">One send awaiting_controller one-shot observe; never resend.</text>
77
+ <text x="40" y="590" class="foot">Caller accepts advise only. Process execution is explicit and never silently retried.</text>
77
78
  </svg>
@@ -1,4 +1,4 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 590" width="1000" height="590" role="img" aria-label="CueLine の 1 回の実行をプロンプトブックとして読む:マシンが観測を送り、コントローラーがコマンドを 1 つ出し、登録済みの runner が実行し、complete が出るまで続く。">
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 612" width="1000" height="612" role="img" aria-label="CueLine の 1 回の実行をプロンプトブックとして読む:マシンが観測を送り、コントローラーがコマンドを 1 つ出し、登録済みの runner が実行し、complete が出るまで続く。">
2
2
  <title>CueLine の実行を、プロンプトブックとして読む</title>
3
3
  <style>
4
4
  text { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Hiragino Sans", "Noto Sans CJK JP", "Yu Gothic", monospace }
@@ -28,8 +28,8 @@
28
28
 
29
29
  <text x="505" y="44" class="hd" text-anchor="end">ChatGPT ウェブ会話</text>
30
30
  <text x="505" y="64" class="sub" text-anchor="end">コントローラー — 計画し、指示し、判断する</text>
31
- <text x="555" y="44" class="hd">あなたのマシン</text>
32
- <text x="555" y="64" class="sub">CueLine — 検証・ルーティング・実行・記録</text>
31
+ <text x="555" y="44" class="hd">現在の Codex + CueLine</text>
32
+ <text x="555" y="64" class="sub">検証・永続化・引き渡し・記録</text>
33
33
 
34
34
  <path d="M40 84H505" class="rule"/>
35
35
  <path d="M555 84H960" class="rule"/>
@@ -45,23 +45,23 @@
45
45
  <path d="M545 162H565" class="tick"/>
46
46
  <text x="575" y="166" class="note">プロセス起動の前にルートが決まる</text>
47
47
 
48
- <text x="555" y="200" class="note">codex exec(読み取り専用)→ 成功 · 出力を保存</text>
48
+ <text x="555" y="200" class="note">現在の Codex(caller advise)→ 結果提出済み</text>
49
49
 
50
50
  <text x="40" y="264" class="rnd">ラウンド 2</text>
51
51
  <path d="M505 260H524" class="tick"/>
52
- <text x="555" y="264" class="obs">observation · 証拠をそのまま</text>
52
+ <text x="555" y="264" class="obs">observation · 有界な証拠 · stdout 優先</text>
53
53
  <path d="M524 256 517 260 524 264z" class="cue"/>
54
54
 
55
55
  <path d="M536 296 545 300 536 304z" class="cue"/>
56
- <text x="505" y="304" class="say" text-anchor="end">dispatch · patch · mode work</text>
56
+ <text x="505" y="304" class="say" text-anchor="end">dispatch · 追加確認 · mode advise</text>
57
57
  <path d="M545 300H565" class="tick"/>
58
- <text x="575" y="304" class="note">argv[0] は事前の許可が必要</text>
58
+ <text x="575" y="304" class="note">永続 caller 引き渡し</text>
59
59
 
60
- <text x="555" y="338" class="note">codex exec(workspace-write)→ 成功</text>
60
+ <text x="555" y="338" class="note">現在の Codex → 2 件目の結果提出済み</text>
61
61
 
62
62
  <text x="40" y="402" class="rnd">ラウンド 3</text>
63
63
  <path d="M505 398H524" class="tick"/>
64
- <text x="555" y="402" class="obs">observation · 更新された証拠</text>
64
+ <text x="555" y="402" class="obs">observation · 更新済みの有界な証拠</text>
65
65
  <path d="M524 394 517 398 524 402z" class="cue"/>
66
66
 
67
67
  <path d="M536 434 545 438 536 442z" class="cue"/>
@@ -73,5 +73,6 @@
73
73
 
74
74
  <path d="M40 520H960" class="rule"/>
75
75
  <text x="40" y="546" class="foot">アクションは 5 つだけ — dispatch · wait · inspect · complete · blocked。</text>
76
- <text x="40" y="568" class="foot">エンベロープの外は実行されない。起動後のワーカーは再試行しない。</text>
76
+ <text x="40" y="568" class="foot">1 回送信 → awaiting_controller → 1 回の読み取り観測。再送しません。</text>
77
+ <text x="40" y="590" class="foot">Caller は advise のみ。process は明示的で、暗黙の再試行はしません。</text>
77
78
  </svg>
@@ -1,4 +1,4 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 590" width="1000" height="590" role="img" aria-label="CueLine 실행 한 번을 프롬프트북처럼 읽기: 머신이 관측을 보내고, 컨트롤러가 명령 하나를 내리고, 등록된 runner가 실행하며, complete가 나올 때까지 이어집니다.">
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 612" width="1000" height="612" role="img" aria-label="CueLine 실행 한 번을 프롬프트북처럼 읽기: 머신이 관측을 보내고, 컨트롤러가 명령 하나를 내리고, 등록된 runner가 실행하며, complete가 나올 때까지 이어집니다.">
2
2
  <title>CueLine 실행을 프롬프트북처럼 읽기</title>
3
3
  <style>
4
4
  text { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Apple SD Gothic Neo", "Noto Sans CJK KR", "Malgun Gothic", monospace }
@@ -28,8 +28,8 @@
28
28
 
29
29
  <text x="505" y="44" class="hd" text-anchor="end">ChatGPT 웹 대화</text>
30
30
  <text x="505" y="64" class="sub" text-anchor="end">컨트롤러 — 계획하고, 지시하고, 판단합니다</text>
31
- <text x="555" y="44" class="hd">당신의 머신</text>
32
- <text x="555" y="64" class="sub">CueLine — 검증 · 라우팅 · 실행 · 기록</text>
31
+ <text x="555" y="44" class="hd">현재 Codex + CueLine</text>
32
+ <text x="555" y="64" class="sub">검증 · 지속화 · 인계 · 기록</text>
33
33
 
34
34
  <path d="M40 84H505" class="rule"/>
35
35
  <path d="M555 84H960" class="rule"/>
@@ -45,23 +45,23 @@
45
45
  <path d="M545 162H565" class="tick"/>
46
46
  <text x="575" y="166" class="note">프로세스가 뜨기 전에 경로가 정해집니다</text>
47
47
 
48
- <text x="555" y="200" class="note">codex exec (읽기 전용) → 성공 · 출력 저장</text>
48
+ <text x="555" y="200" class="note">현재 Codex (caller advise) → 결과 제출 완료</text>
49
49
 
50
50
  <text x="40" y="264" class="rnd">라운드 2</text>
51
51
  <path d="M505 260H524" class="tick"/>
52
- <text x="555" y="264" class="obs">observation · 증거를 그대로</text>
52
+ <text x="555" y="264" class="obs">observation · 제한된 증거 · stdout 우선</text>
53
53
  <path d="M524 256 517 260 524 264z" class="cue"/>
54
54
 
55
55
  <path d="M536 296 545 300 536 304z" class="cue"/>
56
- <text x="505" y="304" class="say" text-anchor="end">dispatch · patch · mode work</text>
56
+ <text x="505" y="304" class="say" text-anchor="end">dispatch · 후속 점검 · mode advise</text>
57
57
  <path d="M545 300H565" class="tick"/>
58
- <text x="575" y="304" class="note">argv[0]은 미리 허용되어 있어야 합니다</text>
58
+ <text x="575" y="304" class="note">지속 caller 인계</text>
59
59
 
60
- <text x="555" y="338" class="note">codex exec (workspace-write) 성공</text>
60
+ <text x="555" y="338" class="note">현재 Codex두 번째 결과 제출 완료</text>
61
61
 
62
62
  <text x="40" y="402" class="rnd">라운드 3</text>
63
63
  <path d="M505 398H524" class="tick"/>
64
- <text x="555" y="402" class="obs">observation · 갱신된 증거</text>
64
+ <text x="555" y="402" class="obs">observation · 갱신된 제한 증거</text>
65
65
  <path d="M524 394 517 398 524 402z" class="cue"/>
66
66
 
67
67
  <path d="M536 434 545 438 536 442z" class="cue"/>
@@ -73,5 +73,6 @@
73
73
 
74
74
  <path d="M40 520H960" class="rule"/>
75
75
  <text x="40" y="546" class="foot">동작은 다섯 개뿐 — dispatch · wait · inspect · complete · blocked.</text>
76
- <text x="40" y="568" class="foot">엔벨로프 밖은 실행되지 않고, 시작된 워커는 재시도되지 않습니다.</text>
76
+ <text x="40" y="568" class="foot">한 전송 awaiting_controller 번 읽기 관측. 재전송 금지.</text>
77
+ <text x="40" y="590" class="foot">Caller는 advise만 허용. process는 명시적이며 자동 재시도하지 않음.</text>
77
78
  </svg>
@@ -1,4 +1,4 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 590" width="1000" height="590" role="img" aria-label="一次 CueLine 运行像一本提示本:机器发出观测,控制器发出一条指令,已注册的 runner 执行它,直到控制器发出 complete。">
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 612" width="1000" height="612" role="img" aria-label="一次 CueLine 运行像一本提示本:机器发出观测,控制器发出一条指令,已注册的 runner 执行它,直到控制器发出 complete。">
2
2
  <title>一次 CueLine 运行,像读一本提示本</title>
3
3
  <style>
4
4
  text { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Noto Sans CJK SC", "PingFang SC", "Microsoft YaHei", monospace }
@@ -28,8 +28,8 @@
28
28
 
29
29
  <text x="505" y="44" class="hd" text-anchor="end">ChatGPT 网页会话</text>
30
30
  <text x="505" y="64" class="sub" text-anchor="end">控制器 — 规划、发令、审阅证据</text>
31
- <text x="555" y="44" class="hd">你的机器</text>
32
- <text x="555" y="64" class="sub">CueLine — 校验、路由、执行、记录</text>
31
+ <text x="555" y="44" class="hd">当前 Codex + CueLine</text>
32
+ <text x="555" y="64" class="sub">校验、持久化、交接、记录</text>
33
33
 
34
34
  <path d="M40 84H505" class="rule"/>
35
35
  <path d="M555 84H960" class="rule"/>
@@ -45,23 +45,23 @@
45
45
  <path d="M545 162H565" class="tick"/>
46
46
  <text x="575" y="166" class="note">任何进程启动之前就先确定路由</text>
47
47
 
48
- <text x="555" y="200" class="note">codex exec(只读)→ 成功 · 输出已保存</text>
48
+ <text x="555" y="200" class="note">当前 Codex(caller advise)→ 结果已提交</text>
49
49
 
50
50
  <text x="40" y="264" class="rnd">第 2 轮</text>
51
51
  <path d="M505 260H524" class="tick"/>
52
- <text x="555" y="264" class="obs">observation · 证据原样回传</text>
52
+ <text x="555" y="264" class="obs">observation · 有界证据 · stdout 优先</text>
53
53
  <path d="M524 256 517 260 524 264z" class="cue"/>
54
54
 
55
55
  <path d="M536 296 545 300 536 304z" class="cue"/>
56
- <text x="505" y="304" class="say" text-anchor="end">dispatch · patch · mode work</text>
56
+ <text x="505" y="304" class="say" text-anchor="end">dispatch · 后续检查 · mode advise</text>
57
57
  <path d="M545 300H565" class="tick"/>
58
- <text x="575" y="304" class="note">argv[0] 必须事先被允许</text>
58
+ <text x="575" y="304" class="note">持久 caller 交接</text>
59
59
 
60
- <text x="555" y="338" class="note">codex exec(workspace-write)→ 成功</text>
60
+ <text x="555" y="338" class="note">当前 Codex → 第二份结果已提交</text>
61
61
 
62
62
  <text x="40" y="402" class="rnd">第 3 轮</text>
63
63
  <path d="M505 398H524" class="tick"/>
64
- <text x="555" y="402" class="obs">observation · 更新后的证据</text>
64
+ <text x="555" y="402" class="obs">observation · 更新后的有界证据</text>
65
65
  <path d="M524 394 517 398 524 402z" class="cue"/>
66
66
 
67
67
  <path d="M536 434 545 438 536 442z" class="cue"/>
@@ -73,5 +73,6 @@
73
73
 
74
74
  <path d="M40 520H960" class="rule"/>
75
75
  <text x="40" y="546" class="foot">只有五个动作 — dispatch · wait · inspect · complete · blocked。</text>
76
- <text x="40" y="568" class="foot">信封之外的文本一律不执行;worker 一旦启动就不会自动重试。</text>
76
+ <text x="40" y="568" class="foot">只发送一次 → awaiting_controller → 单次只读观测;绝不重发。</text>
77
+ <text x="40" y="590" class="foot">Caller 只允许 advise;process 必须显式选择,并且不会静默重试。</text>
77
78
  </svg>
@@ -1,4 +1,4 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 590" width="1000" height="590" role="img" aria-label="一次 CueLine 執行像一本提示本:機器送出觀測,主控端喊出一道指令,已註冊的 runner 執行它,直到主控端喊 complete。">
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 612" width="1000" height="612" role="img" aria-label="一次 CueLine 執行像一本提示本:機器送出觀測,主控端喊出一道指令,已註冊的 runner 執行它,直到主控端喊 complete。">
2
2
  <title>一次 CueLine 執行,像讀一本提示本</title>
3
3
  <style>
4
4
  text { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Noto Sans CJK TC", "PingFang TC", "Microsoft JhengHei", monospace }
@@ -28,8 +28,8 @@
28
28
 
29
29
  <text x="505" y="44" class="hd" text-anchor="end">ChatGPT 網頁對話</text>
30
30
  <text x="505" y="64" class="sub" text-anchor="end">主控端 — 規劃、喊 cue、審查證據</text>
31
- <text x="555" y="44" class="hd">你的機器</text>
32
- <text x="555" y="64" class="sub">CueLine — 驗證、路由、執行、記錄</text>
31
+ <text x="555" y="44" class="hd">目前的 Codex + CueLine</text>
32
+ <text x="555" y="64" class="sub">驗證、保存、交接、記錄</text>
33
33
 
34
34
  <path d="M40 84H505" class="rule"/>
35
35
  <path d="M555 84H960" class="rule"/>
@@ -45,23 +45,23 @@
45
45
  <path d="M545 162H565" class="tick"/>
46
46
  <text x="575" y="166" class="note">任何程序啟動之前就先決定路由</text>
47
47
 
48
- <text x="555" y="200" class="note">codex exec(唯讀)→ 成功 · 輸出已保存</text>
48
+ <text x="555" y="200" class="note">目前的 Codex(caller advise)→ 結果已提交</text>
49
49
 
50
50
  <text x="40" y="264" class="rnd">第 2 輪</text>
51
51
  <path d="M505 260H524" class="tick"/>
52
- <text x="555" y="264" class="obs">observation · 證據原樣送回</text>
52
+ <text x="555" y="264" class="obs">observation · 有界證據 · stdout 優先</text>
53
53
  <path d="M524 256 517 260 524 264z" class="cue"/>
54
54
 
55
55
  <path d="M536 296 545 300 536 304z" class="cue"/>
56
- <text x="505" y="304" class="say" text-anchor="end">dispatch · patch · mode work</text>
56
+ <text x="505" y="304" class="say" text-anchor="end">dispatch · 後續查驗 · mode advise</text>
57
57
  <path d="M545 300H565" class="tick"/>
58
- <text x="575" y="304" class="note">argv[0] 必須事先被允許</text>
58
+ <text x="575" y="304" class="note">持久 caller 交接</text>
59
59
 
60
- <text x="555" y="338" class="note">codex exec(workspace-write)→ 成功</text>
60
+ <text x="555" y="338" class="note">目前的 Codex → 第二份結果已提交</text>
61
61
 
62
62
  <text x="40" y="402" class="rnd">第 3 輪</text>
63
63
  <path d="M505 398H524" class="tick"/>
64
- <text x="555" y="402" class="obs">observation · 更新後的證據</text>
64
+ <text x="555" y="402" class="obs">observation · 更新後的有界證據</text>
65
65
  <path d="M524 394 517 398 524 402z" class="cue"/>
66
66
 
67
67
  <path d="M536 434 545 438 536 442z" class="cue"/>
@@ -73,5 +73,6 @@
73
73
 
74
74
  <path d="M40 520H960" class="rule"/>
75
75
  <text x="40" y="546" class="foot">只有五個動作 — dispatch · wait · inspect · complete · blocked。</text>
76
- <text x="40" y="568" class="foot">封包以外的文字一律不執行;工作行程一旦啟動就不會自動重試。</text>
76
+ <text x="40" y="568" class="foot">只送一次 → awaiting_controller → 單次唯讀觀測;絕不重送。</text>
77
+ <text x="40" y="590" class="foot">Caller 只允許 advise;process 必須明確選用,而且不會偷偷重試。</text>
77
78
  </svg>
@@ -6,8 +6,9 @@
6
6
  |---|---|---|
7
7
  | Node.js 22+ ESM | Supported | Core protocol, state, router, runners, fake browser tests |
8
8
  | Codex Node REPL + built-in Browser (IAB) | Required for live control | Provides the imported API with the authenticated ChatGPT tab/browser client |
9
- | `codex` CLI | Required by default route | Custom routing may register a different executable |
10
- | ChatGPT web conversation | Supported, text only | Uses the model currently selected in the page |
9
+ | Current Codex caller | Default local executor | Performs durable caller-mode `advise` jobs and submits their results |
10
+ | `codex` CLI | Required only by bundled process route | `executor: "process"` is explicit; custom routing may register a different executable |
11
+ | ChatGPT web conversation | Supported, text commands | Controller has no direct local tools; CueLine requires a Pro composer and Pro response slug |
11
12
  | macOS | Primary supported desktop | Codex desktop + symlink installer target |
12
13
  | Linux | Core/CI target | Live Codex IAB availability depends on the host product |
13
14
  | Windows | Not verified | `install.sh` and symlink layout are not a Windows installer |
@@ -16,9 +17,9 @@ The npm package has no runtime dependencies. Development requires TypeScript and
16
17
 
17
18
  ## ChatGPT requirements
18
19
 
19
- CueLine is designed for a conversation already authenticated by the user at `chatgpt.com`, including a ChatGPT Pro account when Pro is the intended controller. CueLine neither handles credentials nor verifies plan entitlement. It does not switch models; the page's current selection is authoritative.
20
+ CueLine is designed for a conversation already authenticated by the user at `chatgpt.com`. CueLine neither handles credentials nor verifies plan entitlement. Before each controller turn it may switch the composer to `Pro`; that is its only automatic model switch. It also requires Pro evidence on the completed response.
20
21
 
21
- The v0.1 adapter relies on accessible textbox/button roles and assistant-message markup in the current ChatGPT web UI. UI changes can cause explicit `COMPOSER_MISSING`, `SEND_BUTTON_MISSING`, or response-timeout errors. A fake adapter test cannot prove that the current live page still matches.
22
+ The v0.1 adapter relies on accessible textbox/button roles, attachment chips, and assistant-message markup in the current ChatGPT web UI. ChatGPT's automatic conversion of a long filled prompt into an attachment is supported. Deliberate file upload is not. UI changes can cause explicit `COMPOSER_MISSING`, `SEND_BUTTON_MISSING`, or response-timeout errors. A fake adapter test cannot prove that the current live page still matches.
22
23
 
23
24
  ## Supported in v0.1
24
25
 
@@ -26,27 +27,34 @@ The v0.1 adapter relies on accessible textbox/button roles and assistant-message
26
27
  - text controller observations and commands
27
28
  - `dispatch`, `wait`, `inspect`, `complete`, and `blocked`
28
29
  - foreground and background local jobs
30
+ - caller-first execution: durable pending `advise` jobs are performed by the current Codex and submitted through the API
31
+ - durable built-in-IAB submit/one-shot-observe pauses that let Pro think beyond one outer tool waiter without resending
32
+ - explicit process execution with default global/per-lane concurrency of two and serialized batches containing `work`
29
33
  - deterministic routing before spawn
30
34
  - append-only run recovery and atomic snapshots
31
35
  - continuation by run ID and stored conversation URL
32
36
  - read-only persisted-state loading through `loadCueLineRunState`
37
+ - cross-session run status, runtime ownership, run/job cancellation, and optional run deadlines
38
+ - automatic long-text attachment recognition, one-click ambiguous-send safety, and operator-confirmed manual reconciliation
39
+ - bounded controller evidence (successful stdout preferred; full stdout/stderr retained locally)
33
40
  - injected fake browser/runner for offline tests
34
41
 
35
42
  ## Not supported in v0.1
36
43
 
37
- - automatic model selection or switching in ChatGPT
44
+ - model switching other than CueLine selecting `Pro`
38
45
  - images, screenshots as controller input, audio, or binary payloads
39
46
  - file upload/download through the ChatGPT page
40
47
  - Deep Research, Projects, Apps, or custom GPT UI flows
41
48
  - multiple simultaneous controller conversations for one run
42
49
  - direct browser-to-local tool calls
50
+ - caller-mode `work` execution (explicit process execution is required)
43
51
  - automatic retry/fallback after a worker starts
44
52
  - cross-host transfer of browser sessions, credentials, child processes, or local runtime state
45
53
  - unattended guarantee across ChatGPT UI or authentication changes
46
54
 
47
55
  ## CLI boundary
48
56
 
49
- `cueline doctor`, `routing`, `jobs`, and `config path` diagnose the local installation and state. They do not drive the ChatGPT page. Live orchestration is an imported API run inside Codex so that the IAB browser object can be injected or resolved.
57
+ `cueline doctor`, `routing`, `jobs`, `run status`, `api path`, and `config path` are read-only. `install`/`uninstall` change only the package-owned skill link. `run reconcile`, `run takeover`, `run reconcile-runtime`, `run cancel` / `run stop`, and `job cancel` append audit evidence or change local durable state; `cueline help` lists their exact positional syntax and options. None drives the ChatGPT page. `run reconcile --manual-send-confirmed` records an operator's exact manual send; the imported API still performs identity/Pro reconciliation through Codex's IAB browser object. `run takeover` retires only an exact stale owner/heartbeat and refuses a fresh active owner.
50
58
 
51
59
  ## Live readiness checklist
52
60
 
@@ -54,7 +62,7 @@ The v0.1 adapter relies on accessible textbox/button roles and assistant-message
54
62
  2. `npm run build` succeeds for a checkout, or the installed package contains `dist/`.
55
63
  3. Codex exposes its built-in Browser runtime.
56
64
  4. A logged-in `https://chatgpt.com/` tab is open and the intended model/conversation is selected.
57
- 5. `cueline doctor` reports a readable routing config and `codex-default` (or a configured alternative) as available.
58
- 6. A text-only live smoke completes one harmless controller round before using `work` mode.
65
+ 5. `cueline doctor` reports `caller_ready yes` and at least one enabled caller lane. `process_available_lanes` may be zero without degrading caller mode; explicit process mode additionally requires `codex-default` (or a configured alternative) to be available.
66
+ 6. A live smoke completes one harmless controller round and one caller `advise` result handoff before explicit process `work` is considered.
59
67
 
60
68
  Readiness does not prove a worker will succeed. Preserve the run evidence and report the exact missing prerequisite when a step fails.
@@ -35,7 +35,7 @@ A stale or mismatched value is rejected. CueLine parses only the **last complete
35
35
  }
36
36
  ```
37
37
 
38
- Job states are `pending`, `running`, `succeeded`, `failed`, `timed_out`, or `ambiguous`. Before browser submission, a single output/error field is bounded to 40,000 characters and only the most recent 20 notices are sent. The local event log remains the recovery record.
38
+ Job states are `pending`, `running`, `succeeded`, `failed`, `timed_out`, `cancelled`, or `ambiguous`. Successful jobs with non-empty stdout use stdout as controller evidence instead of a combined stdout/stderr stream. Failed and timed-out jobs retain bounded diagnostic error evidence. All job evidence in one controller observation shares a global 12,000-character budget; omitted content is reported once with the exact omitted count. Full stdout/stderr remain in local job status, and only the most recent 20 notices are sent. The local event log remains the recovery record.
39
39
 
40
40
  ## Command envelope
41
41
 
@@ -81,7 +81,11 @@ Schedules one or more local jobs.
81
81
  }
82
82
  ```
83
83
 
84
- `job_key` must be unique inside the command and match the supported identifier form. `mode` is `advise` or `work`. Optional fields are `required`, `timeout_ms`, `runner`, `workdir`, and `background`. The local runtime—not ChatGPT—resolves the configured executable. `lane` must be a listed available lane; a runner ID is not a lane name. When `runner` is supplied, it must name an enabled, available candidate in the selected lane. CueLine validates every new route in the dispatch before registering or starting any job. One invalid route rejects the whole command and requests a corrected envelope with the same pending identity. Repeating an already persisted deterministic job is ignored rather than spawned again.
84
+ `job_key` must be unique inside the command and match the supported identifier form. `mode` is `advise` or `work`. Optional fields are `required`, `timeout_ms`, `runner`, `workdir`, and `background`. `runner_id` is invalid and produces an explicit correction to use `runner`. The local runtime—not ChatGPT—resolves the configured executable. `lane` must be a listed available lane; a runner ID is not a lane name. When `runner` is supplied, it must name an enabled, available candidate in the selected lane. CueLine validates every new route in the dispatch before registering or starting any job. One invalid route rejects the whole command and requests a corrected envelope with the same pending identity. Repeating an already persisted deterministic job is ignored rather than executed again.
85
+
86
+ The default executor is `caller`. It persists pending `advise` jobs and returns them to the current Codex, which executes the exact local inspections and submits terminal results. The web controller has no local tool access. Caller-mode `work` is rejected with `CALLER_WORK_REQUIRES_CLAIM` because CueLine cannot yet issue a duplicate-safe side-effect claim.
87
+
88
+ The `process` executor must be selected explicitly. Independent `advise` jobs run with a default global concurrency of two and a default per-lane limit of two (both configurable). If any job is `work`, the entire batch remains serial in command order.
85
89
 
86
90
  ### `wait`
87
91
 
@@ -93,11 +97,11 @@ Asks CueLine to present the currently persisted job state on the next round. It
93
97
 
94
98
  ### `complete`
95
99
 
96
- Ends the run with non-empty `final_delivery_text`. Completion is rejected while any required job remains `pending` or `running`; the controller receives a notice and must decide again. Completed required jobs may have failed—the controller is responsible for judging that evidence.
100
+ Ends the run with non-empty `final_delivery_text`. Completion is rejected while any required or optional job remains `pending` or `running`; the controller receives a notice and must wait, inspect, cancel, or otherwise settle every job before deciding again. Terminal jobs may have failed—the controller is responsible for judging that evidence.
97
101
 
98
102
  ### `blocked`
99
103
 
100
- Ends the run with a non-empty `reason` and optional `final_delivery_text`. This is a terminal, explicit statement that the controller cannot responsibly proceed with the available evidence or authority.
104
+ Ends the run with a non-empty `reason` and optional `final_delivery_text`. Like `complete`, it is rejected while any required or optional job remains active so terminalization cannot orphan background work. Once jobs are settled, it is an explicit statement that the controller cannot responsibly proceed with the available evidence or authority.
101
105
 
102
106
  ## Validation and repair
103
107
 
@@ -1,6 +1,12 @@
1
1
  # Runner contract
2
2
 
3
- ## Routing happens before spawn
3
+ ## Caller execution is the default
4
+
5
+ `startCueLineRun` and `runCueLine` default to `executor: "caller"`. With the built-in browser, one durable submission returns `awaiting_controller`; later continuations observe the same URL/request once without resending. A validated dispatch then persists pending jobs and returns them to the current Codex; it does not spawn `codex exec`. The caller executes each exact `advise` task with its own permitted local tools, submits one terminal result through `submitCueLineCallerJobResult`, and continues the same run. Duplicate terminal submissions return `already_terminal`.
6
+
7
+ The ChatGPT web controller only emits a text command. It does not inspect the repository, call tools, or run the job itself. Caller execution rejects `work` with `CALLER_WORK_REQUIRES_CLAIM`; use caller `advise`, or explicitly opt into the process executor after the user has authorized local mutation.
8
+
9
+ ## Process routing happens before spawn
4
10
 
5
11
  A controller job names a lane, not arbitrary shell text. CueLine loads an enabled lane and examines candidates in configured order. Disabled or unavailable candidates are skipped before execution. The first available candidate becomes the resolved route.
6
12
 
@@ -13,6 +19,8 @@ Every process uses a `RunnerSpec`:
13
19
  ```ts
14
20
  interface RunnerSpec {
15
21
  jobId: string;
22
+ runId?: string;
23
+ jobKey?: string;
16
24
  argv: readonly string[];
17
25
  stdin?: string;
18
26
  mode: "advise" | "work";
@@ -22,6 +30,7 @@ interface RunnerSpec {
22
30
  task?: string;
23
31
  cwd?: string;
24
32
  env?: NodeJS.ProcessEnv;
33
+ signal?: AbortSignal;
25
34
  }
26
35
  ```
27
36
 
@@ -32,9 +41,12 @@ interface RunnerSpec {
32
41
  - `CUELINE_DEPTH=1` is injected into the child.
33
42
  - A pre-existing `CUELINE_DEPTH` in the process or job environment rejects nested routing.
34
43
  - Standard input is closed unless the route explicitly selects stdin task input; stdout and stderr are captured as UTF-8 text.
35
- - The effective output is stdout, stderr, or both in that order.
44
+ - Full stdout and stderr are persisted separately. Successful non-empty stdout is the preferred controller evidence; combined output remains diagnostic status only.
36
45
  - Exit code 0 is `succeeded`; a non-zero exit or spawn error is `failed`.
37
46
  - At timeout CueLine sends `SIGTERM`, then schedules `SIGKILL` after 250 ms if needed; the result is `timed_out`.
47
+ - Cancellation uses the same owned-process termination path. `advise` becomes `cancelled`; started `work` becomes `ambiguous`.
48
+ - The owned POSIX process group is checked and settled on normal leader exit, cancellation, and timeout so surviving descendants cannot make a dead leader look terminal.
49
+ - Any non-normal owned process-loop exit, including controller repair or round-limit exhaustion, cancels and settles every active job before releasing runtime ownership. `advise` becomes `cancelled` when termination is proven; started `work` remains `ambiguous` when side effects cannot be disproved.
38
50
  - Empty output is explicitly recorded instead of being replaced with invented content.
39
51
  - Results are never marked retryable by the process runner.
40
52
 
@@ -42,9 +54,17 @@ For an unsuccessful `work` job, `ambiguousSideEffects` is true because CueLine c
42
54
 
43
55
  ## Foreground and background
44
56
 
45
- A foreground `start` waits for the single execution and persists its terminal status. A background `start` persists and returns `running` immediately while the same completion promise continues. `waitForCompletion(jobId)` returns that completion or the last persisted status.
57
+ A foreground `start` waits for the single execution and persists its terminal status. A background `start` persists and returns `running` immediately while the same completion promise continues. `waitForCompletion(jobId)` returns that completion or the last persisted status. The supervisor persists run ID, job key, lane, mode, and child PID after spawn. PID is observability, not stand-alone cancellation authority.
58
+
59
+ `cancel(jobId)` and `cancelAll()` operate only on executions owned by the current supervisor. Cross-session CLI cancellation is a durable request consumed by that owner. CueLine does not kill an unverified process merely because a stale status file contains a PID.
60
+
61
+ The controller loop derives deterministic job IDs from the run, `job_key`, and job specification. A duplicate dispatch already present in run state is recorded as a notice and skipped. Caller result submission and continuation are runtime-lease serialized, so the first terminal evidence committed for a job wins and later submissions return `already_terminal`.
62
+
63
+ That lease is **not** an execution claim. Two sessions can both perform the same caller `advise` task before either one submits a result. Coordinate a single caller executor when resuming a handoff. This is why caller mode is restricted to non-mutating `advise`; `work` is rejected until CueLine has a duplicate-safe execution claim.
64
+
65
+ ## Process concurrency
46
66
 
47
- The controller loop derives deterministic job IDs from the run, `job_key`, and job specification. A duplicate dispatch already present in run state is recorded as a notice and skipped. This is the run-level at-most-once gate; it is not a distributed transaction across hosts.
67
+ Explicit process execution defaults to at most two active jobs globally and two active jobs per lane. `maxConcurrency` and `laneConcurrency` may reduce or increase those limits. An all-`advise` batch uses the bounded scheduler; a batch containing any `work` job is always serial in command order.
48
68
 
49
69
  ## Availability
50
70
 
@@ -56,6 +76,6 @@ Use `advise` for analysis that should not mutate the target. Use `work` only whe
56
76
 
57
77
  The controller chooses the intent; Codex and local runtime policy remain responsible for whether that intent is authorized and executable.
58
78
 
59
- ## Bundled default
79
+ ## Bundled process route
60
80
 
61
- The `default` lane contains one candidate, `codex-default`. It runs `codex exec` without a shell, sends the task over stdin, uses the requested work directory, and maps `advise` to `read-only` and `work` to `workspace-write`. The default route is unavailable when the `codex` executable is not on `PATH`; CueLine reports that fact instead of selecting an unrelated worker.
81
+ When `executor: "process"` is selected, the `default` lane contains one candidate, `codex-default`. It runs `codex exec` without a shell, sends the task over stdin, uses the requested work directory, and maps `advise` to `read-only` and `work` to `workspace-write`. The route is unavailable when the `codex` executable is not on `PATH`; CueLine reports that fact instead of selecting an unrelated worker.