delegation-layer 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,6 +8,7 @@ and retrieving results with evidence.
8
8
  · [Example](#ask-naturally)
9
9
  · [Providers](https://github.com/hishamkaram/delegation-layer/blob/main/docs/providers.md)
10
10
  · [Teams](https://github.com/hishamkaram/delegation-layer/blob/main/docs/teams.md)
11
+ · [Start recurring tasks](docs/getting-started.md#recurring-tasks)
11
12
  · [Docs](https://github.com/hishamkaram/delegation-layer/blob/main/docs/README.md)
12
13
 
13
14
  <p align="center">
@@ -55,6 +56,10 @@ for activation and limits.
55
56
  For a manual CLI task, use the packaged
56
57
  [read-only example](skills/agent-integration/examples/read-only-task.md).
57
58
 
59
+ For recurring work, follow the [scheduler walkthrough](docs/getting-started.md#recurring-tasks)
60
+ to save a definition, start the scheduler in your own terminal or tmux pane,
61
+ inspect its first result and stop or restart it.
62
+
58
63
  ## Help and contributing
59
64
 
60
65
  See [troubleshooting](https://github.com/hishamkaram/delegation-layer/blob/main/docs/troubleshooting.md),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "delegation-layer",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Multi-provider AI agent delegation CLI and Agent Skill for running bounded coding tasks across provider CLIs.",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "delegation-layer",
3
3
  "displayName": "Delegation Layer",
4
- "version": "0.2.0",
4
+ "version": "0.3.0",
5
5
  "description": "Consult external AI harnesses and CCR-configured models for reviews, research, implementation, and debate through the resumable Delegate CLI.",
6
6
  "author": {
7
7
  "name": "Hesham Karam",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "delegation-layer",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Consult external AI harnesses and CCR-configured models for reviews, research, implementation, and debate through the resumable Delegate CLI.",
5
5
  "author": {
6
6
  "name": "Hesham Karam",
@@ -34,17 +34,34 @@ else
34
34
  status_exit=$?
35
35
  fi
36
36
  printf '%s\n' "$status_exit" >"$RESPONSE.status.exit"
37
+ cat "$RESPONSE.status"
38
+ ```
39
+
40
+ Read the saved status JSON and apply
41
+ [Observe and collect](../references/result-handling.md#observe-and-collect)
42
+ before running another command. Run the collection below only when that
43
+ guidance calls for it.
44
+
45
+ ```sh
37
46
  if delegate --root "${DELEGATE_ROOT:-$HOME/delegation-state}" collect TASK_ID --watch 5s --json >"$RESPONSE.collect"; then
38
47
  collect_exit=0
39
48
  else
40
49
  collect_exit=$?
41
50
  fi
42
51
  printf '%s\n' "$collect_exit" >"$RESPONSE.collect.exit"
52
+ cat "$RESPONSE.collect"
43
53
  ```
44
54
 
45
- Continue observing that created task when collection exits `3`. Wait for the
46
- workspace to return to `state: retained` and inspect its final capture. Only
47
- after the Lead explicitly chooses release, run:
55
+ Apply that same decision order to the collection JSON before treating exit `3`
56
+ as pending. Cancellation, `failure.code: "task_cancelled"` or
57
+ `failure.next_action: "stop_and_report"` ends pending polling; do not continue
58
+ the task or dispatch a replacement. Bounded
59
+ [failure diagnosis](../references/result-handling.md#failure-diagnosis)
60
+ remains available. Keep observing the same task with a finite watch only when
61
+ the canonical guidance calls for it.
62
+
63
+ Before release, wait for the workspace to return to `state: retained` and inspect
64
+ its final capture. Only after the Lead explicitly chooses release, run:
48
65
 
49
66
  ```sh
50
67
  if delegate --root "${DELEGATE_ROOT:-$HOME/delegation-state}" workspace release WORKSPACE_ID \
@@ -62,10 +79,11 @@ Follow the same result decisions rather than assuming either response is
62
79
  completed cleanup.
63
80
 
64
81
  Save each response and exit code once. A created task is observed with
65
- `status` first and collected in the foreground. Exit `3` means pending, not
66
- success; continue observing the same task. The Lead reviews the capture and
67
- owns landing any changes. `workspace release` is explicit; no automatic
68
- apply, commit, branch merge, TTL eviction, or provider-CLI fallback occurs.
82
+ `status` first and collected in the foreground, following the canonical
83
+ observation decisions before each next step. Exit `3` alone is not a reason
84
+ to keep polling. The Lead reviews the capture and owns landing any changes.
85
+ `workspace release` is explicit; no automatic apply, commit, branch merge,
86
+ TTL eviction, or provider-CLI fallback occurs.
69
87
 
70
88
  ## Fork from a checkpoint
71
89
 
@@ -3,18 +3,21 @@
3
3
  Use this reference when asked to consult Claude Code Router (CCR), use one of
4
4
  its configured model aliases, or compare its models with other harnesses.
5
5
  CCR runs Claude Code against a configured third-party or local provider.
6
+ `ROOT` below is the exact absolute state root selected for dispatch; use it
7
+ unchanged for model discovery and dispatch.
6
8
 
7
9
  1. Resolve CCR through `delegate providers --json`; its profile is `ccr:print`.
8
10
  2. Preserve an explicitly requested CCR alias as `--model ALIAS`. Do not replace
9
11
  it with an upstream model ID or reject it solely because discovery omitted it.
10
12
  3. If no alias was chosen, run
11
- `delegate models --provider ccr:print --cwd ABSOLUTE_WORKSPACE --json`.
13
+ `delegate --root ROOT models --provider ccr:print --cwd ABSOLUTE_WORKSPACE --json`.
12
14
  Choose a suitable configured alias from the available metadata and report
13
15
  the choice. Clarify when the intended model remains ambiguous. If discovery
14
16
  is unavailable and no alias is known, report the blocker; do not guess.
15
- 4. Dispatch through Delegate with `--provider ccr:print --model ALIAS`, the brief,
16
- workspace, permission, finite budget, and `--json`. Use the normal status,
17
- collect, and continuation procedure from the main skill.
17
+ 4. Dispatch through Delegate with the same `--root ROOT`,
18
+ `--provider ccr:print --model ALIAS`, the brief, workspace, permission, finite
19
+ budget, and `--json`. Use the normal status, collect, and continuation procedure
20
+ from the main skill.
18
21
 
19
22
  CCR requires an explicit alias. Unspecified external collaboration still uses
20
23
  `dispatch --auto`; do not prefer CCR unless the request calls for it. Multiple
@@ -22,7 +22,7 @@ The main skill owns [root selection](../SKILL.md#3-prepare-separate-paths-and-a-
22
22
  | `workspace`, `checkpoint` | [Git resources](workspaces.md) | Helpers, not provider turns |
23
23
  | `teams` | [Optional configuration and Member selection](#teams) | None |
24
24
  | `schedule` | [Recurring definitions](#schedules), [history and execution evidence](#schedule-history-and-execution) | None |
25
- | `scheduler run` | [Independent scheduler](#scheduler-runtime) | Admits due occurrences through normal dispatch |
25
+ | `scheduler serve/status/stop` (when supported), `scheduler run` | [User-started host and compatibility runtime](#scheduler-runtime) | Due occurrences use normal dispatch; status/stop do not launch providers |
26
26
 
27
27
  Prefix every task command with `delegate --root ROOT`, using the same
28
28
  explicit root across invocations.
@@ -186,9 +186,16 @@ not prove admission, provider readiness or successful publication.
186
186
 
187
187
  ## Schedules
188
188
 
189
- The management commands below save and inspect definitions. They do not start
190
- a scheduler, launch a provider, or prove that a task ran. Start the
191
- [scheduler](#scheduler-runtime) separately to execute due occurrences.
189
+ The management commands below save and inspect definitions; they do not start a
190
+ scheduler, launch a provider themselves, or prove that a task ran. On builds with
191
+ [host controls](#scheduler-runtime), create/resume check for a compatible live
192
+ host after saving. When a response includes `scheduler.serve_command`, retain
193
+ the saved ID and give that argv array intact to the user for an independent
194
+ terminal or tmux pane. For run-only builds, use the
195
+ [compatibility instructions](#scheduler-runtime); do not expect those host fields.
196
+ Never start a persistent scheduler inside the agent's bounded task or submit
197
+ another create to obtain a running scheduler.
198
+ See [definition and host results](result-handling.md#schedule-definition-and-host-results).
192
199
 
193
200
  ```text
194
201
  delegate --root ROOT schedule create --brief FILE --cwd ABS \
@@ -235,7 +242,9 @@ delegate --root ROOT schedule delete SCHEDULE_ID --json
235
242
  - Definitions are immutable. Pause blocks future admissions; resume skips the
236
243
  interval from the stored cursor through now without catch-up. A clock behind
237
244
  the cursor leaves that cursor unchanged. Delete is terminal and retains
238
- history. Pause/delete do not cancel an active occurrence.
245
+ history. Pause/delete do not cancel an active occurrence or require a live
246
+ host. Create/resume preserve the saved definition even when the host is
247
+ absent, starting, in backoff or otherwise not confirmed ready.
239
248
  - Only create initializes absent schedule storage. An absent store lists as
240
249
  empty; show/state commands report not found. List defaults to 50 rows, at most
241
250
  100, including paused/deleted definitions. Use the returned cursor to page.
@@ -244,8 +253,11 @@ delegate --root ROOT schedule delete SCHEDULE_ID --json
244
253
  when output or storage reports uncertainty; inspect it with show rather than
245
254
  submitting another create. Reusing an existing ID conflicts.
246
255
 
247
- Handler results use exit `0` for success/advisory warnings, `2` for invalid
248
- input/state transitions and `1` for not-found, conflicts or operational failures.
256
+ Handler results use exit `0` for confirmed completion/advisory warnings, `2` for
257
+ invalid input/state transitions and `1` for not-found, conflicts or operational
258
+ failures. On builds with host controls, create/resume also use exit `3` for saved
259
+ definitions needing user host start or pending host readiness; keep the same ID
260
+ and follow [result handling](result-handling.md#schedule-definition-and-host-results).
249
261
  `--json` applies to handler responses; argument/usage errors retain the CLI's
250
262
  normal stderr behavior. A valid rule with no future occurrence in the supported
251
263
  timestamp range has a distinct range error, not a claim of permanent invalidity.
@@ -282,31 +294,116 @@ for freshness, no-result states, response bounds, exit codes and recovery.
282
294
 
283
295
  ## Scheduler runtime
284
296
 
297
+ Check `delegate help` for the installed build's command surface. Use `serve`,
298
+ `status` and `stop` only when that help advertises them; prefer `serve` for managed
299
+ recovery. The signatures below describe the current command surface. Keep the
300
+ same explicit absolute `ROOT` used by the schedule commands.
301
+
285
302
  ```text
303
+ delegate --root ROOT scheduler serve
304
+ delegate --root ROOT scheduler status
305
+ delegate --root ROOT scheduler stop
286
306
  delegate --root ROOT scheduler run [--pueue-config ABS] [--json]
287
307
  ```
288
308
 
289
- The scheduler requires the automatic managed worker. Use colocated `delegate`
309
+ If installed help offers only `scheduler run`, the user runs
310
+ `delegate --root ROOT scheduler run` in an independent terminal or tmux pane and
311
+ leaves it in the foreground. Ctrl-C in its original pane stops it; it has no
312
+ automatic child restart. Keep the saved schedule ID and inspect
313
+ [history and execution](#schedule-history-and-execution) for actual occurrences.
314
+ Do not issue unsupported `scheduler status` or `scheduler stop` commands, or
315
+ expect `start_required` or `scheduler.serve_command` fields from that build.
316
+ The managed-host controls and response fields below apply only when installed
317
+ help supports them.
318
+
319
+ The user starts one foreground `serve` host per canonical execution root in an
320
+ independent terminal or tmux pane and leaves it running. It manages every saved
321
+ schedule in that root. When returned, agents give the exact
322
+ `scheduler.serve_command` argv array to the user. Agents must not start either
323
+ persistent scheduler command inside their own bounded task. The guard recognizes
324
+ an explicit Delegate task-scope marker and, on Linux, native Delegate
325
+ cgroup membership. It does not reconstruct guardian ownership or detect every
326
+ enclosing ancestor. A successful check or missing marker does not prove
327
+ independent placement; independent user launch remains required. Delegate
328
+ installs no OS service, enables no reboot/login startup and
329
+ does not automatically launch a detached host.
330
+
331
+ When present, `scheduler.serve_command` preserves spaces and shell metacharacters
332
+ as separate arguments. Human output also prints JSON argv, not an unquoted shell string.
333
+ Preserve those boundaries; see the [scheduler response fields](result-handling.md#schedule-definition-and-host-results).
334
+
335
+ Serve requires existing schedule storage; create owns initialization. A second
336
+ host or competing `run` cannot acquire the same root's ownership. The host uses
337
+ its retained launch context and the saved requested provider choices. For
338
+ Team-targeted schedules, new occurrences read the pinned catalog's latest Member
339
+ defaults through normal admission; existing task IDs retain saved settings. Use
340
+ the intended user configuration context, or a different catalog instance fails
341
+ admission even when Team/Member IDs match. Context changes require completed stop
342
+ and a fresh user start; full launch environments are not persisted.
343
+
344
+ While the host lives, it restarts its scheduler child after an unexpected exit,
345
+ including a clean exit while running is still desired. A successful Start needs
346
+ its exact child Wait before replacement; a definitively failed Start that
347
+ created no child may retry without Wait. Retry delays are 1, 2, 4, 8, 16, 30, 60,
348
+ 120 and 300 seconds, capped at five minutes indefinitely. Five continuous healthy
349
+ minutes reset the policy;
350
+ elapsed healthy time and delays use monotonic timing. Create/resume/status do not
351
+ reset cooldown. A live but unready child or uncertain launch is not replaced.
352
+ Before the child reports Ready or scans for due work, the application's
353
+ before-Ready check validates every current saved definition. An incompatible
354
+ definition leaves the host degraded and stops automatic child restart for that
355
+ incompatibility; it does not enter an endless crash/retry loop. Preserve the
356
+ saved definitions and report the compatibility fault.
357
+ If the host, terminal/tmux pane or machine stops, automatic recovery ends; the
358
+ user must run serve again.
359
+
360
+ `scheduler status` is passive: it does not start, migrate, repair or clean
361
+ anything. It observes starting, ready, backoff, degraded, stopping or stopped
362
+ state, or a compatibility runtime's `foreground` generation, and available
363
+ attempt, bounded diagnostic and retry information. Optional
364
+ `scheduler.fault: true` is the host owner's permanent fault decision; degraded state or
365
+ `last_error` alone is not that decision. After a definition is saved,
366
+ transport-only unreachability returns pending exit `3` without a top-level
367
+ `error`; a permanent host fault returns exit `1`, retaining
368
+ `schedule.saved: true` and the same ID.
369
+
370
+ `scheduler stop` persists a stopped fence, interrupts backoff, ends admission and
371
+ joins accepted controls, GoCron shutdown and child Wait. The host remains
372
+ responsive to authenticated status/stop while joining its child or waiting for a
373
+ prior execution owner. Under host ownership, it writes a closure witness once
374
+ execution ownership is free. Completed stop requires that witness and exact
375
+ host absence; acceptance, timeout or host death alone is not completion.
376
+ Authenticated acceptance remains visible even if later readback fails; concrete
377
+ faults remain visible too. SIGINT, SIGTERM and SIGHUP use the same fenced shutdown
378
+ path. Independently admitted tasks retain their own supervisors and budgets.
379
+ See [host result decisions](result-handling.md#schedule-definition-and-host-results).
380
+
381
+ `scheduler run` runs the foreground runtime directly and remains a compatibility
382
+ path without automatic child restart. On builds with host controls, it shares
383
+ root ownership with serve and announces its current foreground generation,
384
+ which an older managed-host stop
385
+ receipt cannot hide. Status reports `scheduler.state: foreground`.
386
+ `scheduler stop` does not terminate the raw invocation: it returns
387
+ `stop_accepted: false` and `next_action: stop_foreground_runtime`. The user ends
388
+ it with Ctrl-C in its original pane; prefer `scheduler serve` for managed
389
+ recovery. The existing manual OS-service hosting option is separate from the new
390
+ foreground host path; see [operator hosting](https://github.com/hishamkaram/delegation-layer/blob/main/docs/cli-reference.md#scheduler-hosting).
391
+
392
+ Serve and run require the automatic managed worker. Use colocated `delegate`
290
393
  and `delegate-run` binaries from the same build and omit the advanced `--runner`
291
394
  override. An override selects custom ownership even when it names the bundled
292
- worker; startup rejects it with exit `2` before opening storage or acquiring a
293
- lease. Ordinary explicit custom-runner dispatch and continuation retain their
395
+ worker. `scheduler run` rejects it with exit `2` before opening storage or
396
+ acquiring a lease. `scheduler serve` checks existing state and schedule storage
397
+ before rejecting the override with exit `2`, so a storage error can take
398
+ precedence. Ordinary explicit custom-runner dispatch and continuation retain their
294
399
  existing compatibility rules. Historical custom-runner claims are not
295
400
  automatically repaired or released.
296
401
 
297
- This foreground command requires existing schedule storage. One process owns
298
- each root; a second fails busy. It uses the service launch environment and the
299
- saved requested provider choices. Saving a definition never starts the service.
300
- For Team-targeted schedules, new occurrences read the pinned catalog's latest
301
- Member defaults through normal admission; existing task IDs retain saved settings.
302
- Use the same intended user configuration context as creation, or a different
303
- catalog instance fails admission even when Team/Member IDs match.
304
- See [operator hosting](https://github.com/hishamkaram/delegation-layer/blob/main/docs/cli-reference.md#scheduler-hosting).
305
-
306
402
  Startup skips past appointments. Expired, overlapping or capacity-limited
307
403
  appointments are skipped with a recorded reason; no catch-up queue or automatic
308
- retry/continuation is added. Pause/delete prevent new claims, without canceling
309
- already claimed tasks. Use [history and execution](#schedule-history-and-execution)
404
+ provider retry/continuation is added. Downtime is recorded in compact skipped
405
+ intervals, never replayed minute by minute. Pause/delete prevent new claims,
406
+ without canceling already claimed tasks. Use [history and execution](#schedule-history-and-execution)
310
407
  to inspect recorded work, and [result handling](result-handling.md#scheduled-execution-results)
311
408
  to collect its answer. Schedule reservation release is separate from result
312
409
  publication.
@@ -317,12 +414,12 @@ Delegate workers keep their own budgets; provider-native in-session subagents do
317
414
  not acquire independent Delegate lifetimes. The workflow owns saved progress,
318
415
  worker IDs and deduplication; unknown acknowledgment is not permission to resend.
319
416
 
320
- Interrupting the service joins its admission/control work before releasing its
321
- owner lease. Accepted lifecycle calls settle independently of the stop signal;
417
+ Interrupting the compatibility runtime joins its admission/control work before
418
+ releasing its owner lease. Accepted lifecycle calls settle independently of the stop signal;
322
419
  there is no shutdown-time guarantee. Already admitted tasks continue under their
323
- own supervisors. The
324
- service reports bounded identifiers/codes on stderr; `--json` selects the final
325
- command response, not an event stream or daemon-control protocol. Uncertain task
420
+ own supervisors. The compatibility command reports bounded identifiers/codes on
421
+ stderr; `--json` selects the final command response, not an event stream or
422
+ daemon-control protocol. Uncertain task
326
423
  evidence blocks only its schedule until the existing owners can prove closure.
327
424
 
328
425
  ## Codex review
@@ -166,6 +166,66 @@ asking again, but never infer it from a rejection or silently substitute a
166
166
  destination. Keep the original failed attempt reported as failed; independent
167
167
  requests and explicitly allowed recovery paths retain their existing rules.
168
168
 
169
+ ## Schedule definition and host results
170
+
171
+ Use the installed build's help to check `scheduler serve/status/stop` support.
172
+ Keep three facts separate: the definition was
173
+ saved, the host is ready, and an occurrence produced an accepted provider result.
174
+ Neither saving nor host readiness proves that a task ran.
175
+
176
+ Schedule create/resume report confirmed persistence as `schedule.saved: true`;
177
+ keep `schedule.id` even if the command exits nonzero. The separate top-level
178
+ `scheduler` object carries host observation and guidance:
179
+
180
+ | JSON field | Meaning |
181
+ | --- | --- |
182
+ | `scheduler.state` | Observed lifecycle or availability state, including `foreground` for a current raw `scheduler run`. Read it with `ready` and the process exit. |
183
+ | `scheduler.epoch`, `scheduler.attempt` | Owner generation string and numeric child attempt, when known. Omission does not identify an owner. |
184
+ | `scheduler.ready` | Whether this observation confirms host/child readiness; it is not an occurrence result. |
185
+ | `scheduler.fault` | Optional `true` for a permanent fault reported by the host owner. Do not infer it from degraded state or `last_error`; omission is not proof that the whole command is fault-free. |
186
+ | `scheduler.next_retry_at` | Optional next retry timestamp during recovery. Observation does not reset it. |
187
+ | `scheduler.last_error` | Optional bounded host diagnostic. Keep it alongside pending or readiness facts. |
188
+ | `scheduler.next_action` | Caller guidance, such as `start_required`, `inspect_scheduler` or `stop_foreground_runtime`. |
189
+ | `scheduler.serve_command` | Optional exact argv array for an independent user start. Preserve every element and its argument boundary. |
190
+ | `scheduler.stop_accepted` | Optional boolean for acceptance of this stop request. `true` is accepted, `false` is explicitly not accepted, and omission is unknown. Acceptance does not prove shutdown completed. |
191
+
192
+ For `start_required`, both `schedule.next_action` and `scheduler.next_action`
193
+ carry that guidance. `scheduler.serve_command` is JSON argv, including the
194
+ resolved executable and exact root. Human output also prints JSON argv after
195
+ `run independently (argv):`, for example:
196
+
197
+ ```text
198
+ run independently (argv): ["/installation with spaces/delegate","--root","/state with spaces","scheduler","serve"]
199
+ ```
200
+
201
+ Forward the array intact. It is not an unquoted shell command: do not join its
202
+ elements with spaces or pass the joined text through a shell. The user starts
203
+ serve independently with those exact argument boundaries; the agent must not
204
+ execute it inside its bounded task. An omitted `schedule.saved` does not confirm
205
+ persistence; preserve any ID and follow the reported storage/error guidance.
206
+
207
+ | Response or observation | Next action |
208
+ | --- | --- |
209
+ | Create/resume saved the definition and confirmed a compatible ready host; exit `0` | Keep its schedule ID/root. The host will handle future due work; use history/execution for actual occurrence evidence. |
210
+ | Create/resume returns exit `3`, `schedule.saved: true` and `scheduler.next_action: start_required` | The definition remains saved. Preserve the returned schedule ID/root and give `scheduler.serve_command` unchanged to the user to run in an independent terminal or tmux pane. Never start it inside the agent's bounded task, detach it in the background, or submit another create. |
211
+ | Create/resume saved the definition but reports starting, backoff or pending readiness; exit `3` | Keep the same ID and report its host state and available retry time. Use passive scheduler status for later observation; do not create another definition, start a competing host or reset cooldown. |
212
+ | Create/resume saved the definition but the host is temporarily unreachable; exit `3`, pending guidance and no top-level `error` | Preserve `schedule.saved: true` and the same ID. Use passive status to observe the uncertainty. A transport failure does not establish owner death or a permanent host fault. |
213
+ | Create/resume saved the definition and the host reports `scheduler.fault: true`; exit `1` | Report the permanent fault and available `scheduler.last_error`; retain `schedule.saved: true` and the ID. For an incompatible saved definition, the before-Ready check stops automatic child restart. Repeated create, serve or status calls are not a repair. |
214
+ | Scheduler status observes starting, ready, backoff, degraded, stopping or stopped; exit `0` | Observation completed. Report the observed state; exit `0` does not mean ready or that an occurrence succeeded. Status does not start, migrate, repair or clean resources. |
215
+ | Scheduler stop confirms completed stop; exit `0` | The exact stopped intent has a validated owner-written closure witness and the exact host is absent. The witness follows joined child shutdown and free execution ownership. Independently admitted tasks keep their existing lifetimes. A later host needs a fresh explicit user-run serve command. |
216
+ | Scheduler stop has `scheduler.stop_accepted: true` but completion is pending; exit `3` | Preserve its acceptance and pending state. The host remains control-responsive while joining its child or waiting for a prior execution owner. Host death before the closure witness does not complete stop. Observe the same generation; do not claim stopped, launch a replacement or repeat schedule creation. An omitted `stop_accepted` is unknown, not false. |
217
+ | Scheduler stop has authenticated `scheduler.stop_accepted: true` and a later readback fault; exit `1` | Preserve the accepted fact and report the concrete fault. Readback failure does not revoke acceptance or establish completed shutdown. |
218
+ | Status reports `scheduler.state: foreground`, or stop returns exit `3` with that state, `stop_accepted: false` and `next_action: stop_foreground_runtime` | The current compatibility `scheduler run` owns this generation; an older managed-host receipt cannot hide it. Public stop does not terminate it. Have the user end that invocation with Ctrl-C in its original pane. Prefer managed `scheduler serve` afterward. |
219
+ | Invalid input/state; exit `2`, or concrete operational/compatibility/cleanup fault; exit `1` | Report the error and retain any saved ID or accepted-control fact. A concrete fault joined to pending work remains a fault; it is not a pending-only result. |
220
+
221
+ If the host dies, its pane closes or the machine reboots, the user must start
222
+ serve again. Child crash recovery applies only while that host remains alive.
223
+ An absent heartbeat or unresponsive endpoint is uncertainty, not permission to
224
+ replace an owner. Do not install a service or invoke a detached bootstrap as a
225
+ recovery step. Pause/delete affect future claims and need no live host; they do
226
+ not cancel already admitted occurrences. [Scheduler runtime](command-reference.md#scheduler-runtime)
227
+ owns launch, backoff and calendar behavior.
228
+
169
229
  ## Scheduled execution results
170
230
 
171
231
  Use [schedule history and execution](command-reference.md#schedule-history-and-execution)
@@ -34,17 +34,34 @@ else
34
34
  status_exit=$?
35
35
  fi
36
36
  printf '%s\n' "$status_exit" >"$RESPONSE.status.exit"
37
+ cat "$RESPONSE.status"
38
+ ```
39
+
40
+ Read the saved status JSON and apply
41
+ [Observe and collect](../references/result-handling.md#observe-and-collect)
42
+ before running another command. Run the collection below only when that
43
+ guidance calls for it.
44
+
45
+ ```sh
37
46
  if delegate --root "${DELEGATE_ROOT:-$HOME/delegation-state}" collect TASK_ID --watch 5s --json >"$RESPONSE.collect"; then
38
47
  collect_exit=0
39
48
  else
40
49
  collect_exit=$?
41
50
  fi
42
51
  printf '%s\n' "$collect_exit" >"$RESPONSE.collect.exit"
52
+ cat "$RESPONSE.collect"
43
53
  ```
44
54
 
45
- Continue observing that created task when collection exits `3`. Wait for the
46
- workspace to return to `state: retained` and inspect its final capture. Only
47
- after the Lead explicitly chooses release, run:
55
+ Apply that same decision order to the collection JSON before treating exit `3`
56
+ as pending. Cancellation, `failure.code: "task_cancelled"` or
57
+ `failure.next_action: "stop_and_report"` ends pending polling; do not continue
58
+ the task or dispatch a replacement. Bounded
59
+ [failure diagnosis](../references/result-handling.md#failure-diagnosis)
60
+ remains available. Keep observing the same task with a finite watch only when
61
+ the canonical guidance calls for it.
62
+
63
+ Before release, wait for the workspace to return to `state: retained` and inspect
64
+ its final capture. Only after the Lead explicitly chooses release, run:
48
65
 
49
66
  ```sh
50
67
  if delegate --root "${DELEGATE_ROOT:-$HOME/delegation-state}" workspace release WORKSPACE_ID \
@@ -62,10 +79,11 @@ Follow the same result decisions rather than assuming either response is
62
79
  completed cleanup.
63
80
 
64
81
  Save each response and exit code once. A created task is observed with
65
- `status` first and collected in the foreground. Exit `3` means pending, not
66
- success; continue observing the same task. The Lead reviews the capture and
67
- owns landing any changes. `workspace release` is explicit; no automatic
68
- apply, commit, branch merge, TTL eviction, or provider-CLI fallback occurs.
82
+ `status` first and collected in the foreground, following the canonical
83
+ observation decisions before each next step. Exit `3` alone is not a reason
84
+ to keep polling. The Lead reviews the capture and owns landing any changes.
85
+ `workspace release` is explicit; no automatic apply, commit, branch merge,
86
+ TTL eviction, or provider-CLI fallback occurs.
69
87
 
70
88
  ## Fork from a checkpoint
71
89
 
@@ -3,18 +3,21 @@
3
3
  Use this reference when asked to consult Claude Code Router (CCR), use one of
4
4
  its configured model aliases, or compare its models with other harnesses.
5
5
  CCR runs Claude Code against a configured third-party or local provider.
6
+ `ROOT` below is the exact absolute state root selected for dispatch; use it
7
+ unchanged for model discovery and dispatch.
6
8
 
7
9
  1. Resolve CCR through `delegate providers --json`; its profile is `ccr:print`.
8
10
  2. Preserve an explicitly requested CCR alias as `--model ALIAS`. Do not replace
9
11
  it with an upstream model ID or reject it solely because discovery omitted it.
10
12
  3. If no alias was chosen, run
11
- `delegate models --provider ccr:print --cwd ABSOLUTE_WORKSPACE --json`.
13
+ `delegate --root ROOT models --provider ccr:print --cwd ABSOLUTE_WORKSPACE --json`.
12
14
  Choose a suitable configured alias from the available metadata and report
13
15
  the choice. Clarify when the intended model remains ambiguous. If discovery
14
16
  is unavailable and no alias is known, report the blocker; do not guess.
15
- 4. Dispatch through Delegate with `--provider ccr:print --model ALIAS`, the brief,
16
- workspace, permission, finite budget, and `--json`. Use the normal status,
17
- collect, and continuation procedure from the main skill.
17
+ 4. Dispatch through Delegate with the same `--root ROOT`,
18
+ `--provider ccr:print --model ALIAS`, the brief, workspace, permission, finite
19
+ budget, and `--json`. Use the normal status, collect, and continuation procedure
20
+ from the main skill.
18
21
 
19
22
  CCR requires an explicit alias. Unspecified external collaboration still uses
20
23
  `dispatch --auto`; do not prefer CCR unless the request calls for it. Multiple
@@ -22,7 +22,7 @@ The main skill owns [root selection](../SKILL.md#3-prepare-separate-paths-and-a-
22
22
  | `workspace`, `checkpoint` | [Git resources](workspaces.md) | Helpers, not provider turns |
23
23
  | `teams` | [Optional configuration and Member selection](#teams) | None |
24
24
  | `schedule` | [Recurring definitions](#schedules), [history and execution evidence](#schedule-history-and-execution) | None |
25
- | `scheduler run` | [Independent scheduler](#scheduler-runtime) | Admits due occurrences through normal dispatch |
25
+ | `scheduler serve/status/stop` (when supported), `scheduler run` | [User-started host and compatibility runtime](#scheduler-runtime) | Due occurrences use normal dispatch; status/stop do not launch providers |
26
26
 
27
27
  Prefix every task command with `delegate --root ROOT`, using the same
28
28
  explicit root across invocations.
@@ -186,9 +186,16 @@ not prove admission, provider readiness or successful publication.
186
186
 
187
187
  ## Schedules
188
188
 
189
- The management commands below save and inspect definitions. They do not start
190
- a scheduler, launch a provider, or prove that a task ran. Start the
191
- [scheduler](#scheduler-runtime) separately to execute due occurrences.
189
+ The management commands below save and inspect definitions; they do not start a
190
+ scheduler, launch a provider themselves, or prove that a task ran. On builds with
191
+ [host controls](#scheduler-runtime), create/resume check for a compatible live
192
+ host after saving. When a response includes `scheduler.serve_command`, retain
193
+ the saved ID and give that argv array intact to the user for an independent
194
+ terminal or tmux pane. For run-only builds, use the
195
+ [compatibility instructions](#scheduler-runtime); do not expect those host fields.
196
+ Never start a persistent scheduler inside the agent's bounded task or submit
197
+ another create to obtain a running scheduler.
198
+ See [definition and host results](result-handling.md#schedule-definition-and-host-results).
192
199
 
193
200
  ```text
194
201
  delegate --root ROOT schedule create --brief FILE --cwd ABS \
@@ -235,7 +242,9 @@ delegate --root ROOT schedule delete SCHEDULE_ID --json
235
242
  - Definitions are immutable. Pause blocks future admissions; resume skips the
236
243
  interval from the stored cursor through now without catch-up. A clock behind
237
244
  the cursor leaves that cursor unchanged. Delete is terminal and retains
238
- history. Pause/delete do not cancel an active occurrence.
245
+ history. Pause/delete do not cancel an active occurrence or require a live
246
+ host. Create/resume preserve the saved definition even when the host is
247
+ absent, starting, in backoff or otherwise not confirmed ready.
239
248
  - Only create initializes absent schedule storage. An absent store lists as
240
249
  empty; show/state commands report not found. List defaults to 50 rows, at most
241
250
  100, including paused/deleted definitions. Use the returned cursor to page.
@@ -244,8 +253,11 @@ delegate --root ROOT schedule delete SCHEDULE_ID --json
244
253
  when output or storage reports uncertainty; inspect it with show rather than
245
254
  submitting another create. Reusing an existing ID conflicts.
246
255
 
247
- Handler results use exit `0` for success/advisory warnings, `2` for invalid
248
- input/state transitions and `1` for not-found, conflicts or operational failures.
256
+ Handler results use exit `0` for confirmed completion/advisory warnings, `2` for
257
+ invalid input/state transitions and `1` for not-found, conflicts or operational
258
+ failures. On builds with host controls, create/resume also use exit `3` for saved
259
+ definitions needing user host start or pending host readiness; keep the same ID
260
+ and follow [result handling](result-handling.md#schedule-definition-and-host-results).
249
261
  `--json` applies to handler responses; argument/usage errors retain the CLI's
250
262
  normal stderr behavior. A valid rule with no future occurrence in the supported
251
263
  timestamp range has a distinct range error, not a claim of permanent invalidity.
@@ -282,31 +294,116 @@ for freshness, no-result states, response bounds, exit codes and recovery.
282
294
 
283
295
  ## Scheduler runtime
284
296
 
297
+ Check `delegate help` for the installed build's command surface. Use `serve`,
298
+ `status` and `stop` only when that help advertises them; prefer `serve` for managed
299
+ recovery. The signatures below describe the current command surface. Keep the
300
+ same explicit absolute `ROOT` used by the schedule commands.
301
+
285
302
  ```text
303
+ delegate --root ROOT scheduler serve
304
+ delegate --root ROOT scheduler status
305
+ delegate --root ROOT scheduler stop
286
306
  delegate --root ROOT scheduler run [--pueue-config ABS] [--json]
287
307
  ```
288
308
 
289
- The scheduler requires the automatic managed worker. Use colocated `delegate`
309
+ If installed help offers only `scheduler run`, the user runs
310
+ `delegate --root ROOT scheduler run` in an independent terminal or tmux pane and
311
+ leaves it in the foreground. Ctrl-C in its original pane stops it; it has no
312
+ automatic child restart. Keep the saved schedule ID and inspect
313
+ [history and execution](#schedule-history-and-execution) for actual occurrences.
314
+ Do not issue unsupported `scheduler status` or `scheduler stop` commands, or
315
+ expect `start_required` or `scheduler.serve_command` fields from that build.
316
+ The managed-host controls and response fields below apply only when installed
317
+ help supports them.
318
+
319
+ The user starts one foreground `serve` host per canonical execution root in an
320
+ independent terminal or tmux pane and leaves it running. It manages every saved
321
+ schedule in that root. When returned, agents give the exact
322
+ `scheduler.serve_command` argv array to the user. Agents must not start either
323
+ persistent scheduler command inside their own bounded task. The guard recognizes
324
+ an explicit Delegate task-scope marker and, on Linux, native Delegate
325
+ cgroup membership. It does not reconstruct guardian ownership or detect every
326
+ enclosing ancestor. A successful check or missing marker does not prove
327
+ independent placement; independent user launch remains required. Delegate
328
+ installs no OS service, enables no reboot/login startup and
329
+ does not automatically launch a detached host.
330
+
331
+ When present, `scheduler.serve_command` preserves spaces and shell metacharacters
332
+ as separate arguments. Human output also prints JSON argv, not an unquoted shell string.
333
+ Preserve those boundaries; see the [scheduler response fields](result-handling.md#schedule-definition-and-host-results).
334
+
335
+ Serve requires existing schedule storage; create owns initialization. A second
336
+ host or competing `run` cannot acquire the same root's ownership. The host uses
337
+ its retained launch context and the saved requested provider choices. For
338
+ Team-targeted schedules, new occurrences read the pinned catalog's latest Member
339
+ defaults through normal admission; existing task IDs retain saved settings. Use
340
+ the intended user configuration context, or a different catalog instance fails
341
+ admission even when Team/Member IDs match. Context changes require completed stop
342
+ and a fresh user start; full launch environments are not persisted.
343
+
344
+ While the host lives, it restarts its scheduler child after an unexpected exit,
345
+ including a clean exit while running is still desired. A successful Start needs
346
+ its exact child Wait before replacement; a definitively failed Start that
347
+ created no child may retry without Wait. Retry delays are 1, 2, 4, 8, 16, 30, 60,
348
+ 120 and 300 seconds, capped at five minutes indefinitely. Five continuous healthy
349
+ minutes reset the policy;
350
+ elapsed healthy time and delays use monotonic timing. Create/resume/status do not
351
+ reset cooldown. A live but unready child or uncertain launch is not replaced.
352
+ Before the child reports Ready or scans for due work, the application's
353
+ before-Ready check validates every current saved definition. An incompatible
354
+ definition leaves the host degraded and stops automatic child restart for that
355
+ incompatibility; it does not enter an endless crash/retry loop. Preserve the
356
+ saved definitions and report the compatibility fault.
357
+ If the host, terminal/tmux pane or machine stops, automatic recovery ends; the
358
+ user must run serve again.
359
+
360
+ `scheduler status` is passive: it does not start, migrate, repair or clean
361
+ anything. It observes starting, ready, backoff, degraded, stopping or stopped
362
+ state, or a compatibility runtime's `foreground` generation, and available
363
+ attempt, bounded diagnostic and retry information. Optional
364
+ `scheduler.fault: true` is the host owner's permanent fault decision; degraded state or
365
+ `last_error` alone is not that decision. After a definition is saved,
366
+ transport-only unreachability returns pending exit `3` without a top-level
367
+ `error`; a permanent host fault returns exit `1`, retaining
368
+ `schedule.saved: true` and the same ID.
369
+
370
+ `scheduler stop` persists a stopped fence, interrupts backoff, ends admission and
371
+ joins accepted controls, GoCron shutdown and child Wait. The host remains
372
+ responsive to authenticated status/stop while joining its child or waiting for a
373
+ prior execution owner. Under host ownership, it writes a closure witness once
374
+ execution ownership is free. Completed stop requires that witness and exact
375
+ host absence; acceptance, timeout or host death alone is not completion.
376
+ Authenticated acceptance remains visible even if later readback fails; concrete
377
+ faults remain visible too. SIGINT, SIGTERM and SIGHUP use the same fenced shutdown
378
+ path. Independently admitted tasks retain their own supervisors and budgets.
379
+ See [host result decisions](result-handling.md#schedule-definition-and-host-results).
380
+
381
+ `scheduler run` runs the foreground runtime directly and remains a compatibility
382
+ path without automatic child restart. On builds with host controls, it shares
383
+ root ownership with serve and announces its current foreground generation,
384
+ which an older managed-host stop
385
+ receipt cannot hide. Status reports `scheduler.state: foreground`.
386
+ `scheduler stop` does not terminate the raw invocation: it returns
387
+ `stop_accepted: false` and `next_action: stop_foreground_runtime`. The user ends
388
+ it with Ctrl-C in its original pane; prefer `scheduler serve` for managed
389
+ recovery. The existing manual OS-service hosting option is separate from the new
390
+ foreground host path; see [operator hosting](https://github.com/hishamkaram/delegation-layer/blob/main/docs/cli-reference.md#scheduler-hosting).
391
+
392
+ Serve and run require the automatic managed worker. Use colocated `delegate`
290
393
  and `delegate-run` binaries from the same build and omit the advanced `--runner`
291
394
  override. An override selects custom ownership even when it names the bundled
292
- worker; startup rejects it with exit `2` before opening storage or acquiring a
293
- lease. Ordinary explicit custom-runner dispatch and continuation retain their
395
+ worker. `scheduler run` rejects it with exit `2` before opening storage or
396
+ acquiring a lease. `scheduler serve` checks existing state and schedule storage
397
+ before rejecting the override with exit `2`, so a storage error can take
398
+ precedence. Ordinary explicit custom-runner dispatch and continuation retain their
294
399
  existing compatibility rules. Historical custom-runner claims are not
295
400
  automatically repaired or released.
296
401
 
297
- This foreground command requires existing schedule storage. One process owns
298
- each root; a second fails busy. It uses the service launch environment and the
299
- saved requested provider choices. Saving a definition never starts the service.
300
- For Team-targeted schedules, new occurrences read the pinned catalog's latest
301
- Member defaults through normal admission; existing task IDs retain saved settings.
302
- Use the same intended user configuration context as creation, or a different
303
- catalog instance fails admission even when Team/Member IDs match.
304
- See [operator hosting](https://github.com/hishamkaram/delegation-layer/blob/main/docs/cli-reference.md#scheduler-hosting).
305
-
306
402
  Startup skips past appointments. Expired, overlapping or capacity-limited
307
403
  appointments are skipped with a recorded reason; no catch-up queue or automatic
308
- retry/continuation is added. Pause/delete prevent new claims, without canceling
309
- already claimed tasks. Use [history and execution](#schedule-history-and-execution)
404
+ provider retry/continuation is added. Downtime is recorded in compact skipped
405
+ intervals, never replayed minute by minute. Pause/delete prevent new claims,
406
+ without canceling already claimed tasks. Use [history and execution](#schedule-history-and-execution)
310
407
  to inspect recorded work, and [result handling](result-handling.md#scheduled-execution-results)
311
408
  to collect its answer. Schedule reservation release is separate from result
312
409
  publication.
@@ -317,12 +414,12 @@ Delegate workers keep their own budgets; provider-native in-session subagents do
317
414
  not acquire independent Delegate lifetimes. The workflow owns saved progress,
318
415
  worker IDs and deduplication; unknown acknowledgment is not permission to resend.
319
416
 
320
- Interrupting the service joins its admission/control work before releasing its
321
- owner lease. Accepted lifecycle calls settle independently of the stop signal;
417
+ Interrupting the compatibility runtime joins its admission/control work before
418
+ releasing its owner lease. Accepted lifecycle calls settle independently of the stop signal;
322
419
  there is no shutdown-time guarantee. Already admitted tasks continue under their
323
- own supervisors. The
324
- service reports bounded identifiers/codes on stderr; `--json` selects the final
325
- command response, not an event stream or daemon-control protocol. Uncertain task
420
+ own supervisors. The compatibility command reports bounded identifiers/codes on
421
+ stderr; `--json` selects the final command response, not an event stream or
422
+ daemon-control protocol. Uncertain task
326
423
  evidence blocks only its schedule until the existing owners can prove closure.
327
424
 
328
425
  ## Codex review
@@ -166,6 +166,66 @@ asking again, but never infer it from a rejection or silently substitute a
166
166
  destination. Keep the original failed attempt reported as failed; independent
167
167
  requests and explicitly allowed recovery paths retain their existing rules.
168
168
 
169
+ ## Schedule definition and host results
170
+
171
+ Use the installed build's help to check `scheduler serve/status/stop` support.
172
+ Keep three facts separate: the definition was
173
+ saved, the host is ready, and an occurrence produced an accepted provider result.
174
+ Neither saving nor host readiness proves that a task ran.
175
+
176
+ Schedule create/resume report confirmed persistence as `schedule.saved: true`;
177
+ keep `schedule.id` even if the command exits nonzero. The separate top-level
178
+ `scheduler` object carries host observation and guidance:
179
+
180
+ | JSON field | Meaning |
181
+ | --- | --- |
182
+ | `scheduler.state` | Observed lifecycle or availability state, including `foreground` for a current raw `scheduler run`. Read it with `ready` and the process exit. |
183
+ | `scheduler.epoch`, `scheduler.attempt` | Owner generation string and numeric child attempt, when known. Omission does not identify an owner. |
184
+ | `scheduler.ready` | Whether this observation confirms host/child readiness; it is not an occurrence result. |
185
+ | `scheduler.fault` | Optional `true` for a permanent fault reported by the host owner. Do not infer it from degraded state or `last_error`; omission is not proof that the whole command is fault-free. |
186
+ | `scheduler.next_retry_at` | Optional next retry timestamp during recovery. Observation does not reset it. |
187
+ | `scheduler.last_error` | Optional bounded host diagnostic. Keep it alongside pending or readiness facts. |
188
+ | `scheduler.next_action` | Caller guidance, such as `start_required`, `inspect_scheduler` or `stop_foreground_runtime`. |
189
+ | `scheduler.serve_command` | Optional exact argv array for an independent user start. Preserve every element and its argument boundary. |
190
+ | `scheduler.stop_accepted` | Optional boolean for acceptance of this stop request. `true` is accepted, `false` is explicitly not accepted, and omission is unknown. Acceptance does not prove shutdown completed. |
191
+
192
+ For `start_required`, both `schedule.next_action` and `scheduler.next_action`
193
+ carry that guidance. `scheduler.serve_command` is JSON argv, including the
194
+ resolved executable and exact root. Human output also prints JSON argv after
195
+ `run independently (argv):`, for example:
196
+
197
+ ```text
198
+ run independently (argv): ["/installation with spaces/delegate","--root","/state with spaces","scheduler","serve"]
199
+ ```
200
+
201
+ Forward the array intact. It is not an unquoted shell command: do not join its
202
+ elements with spaces or pass the joined text through a shell. The user starts
203
+ serve independently with those exact argument boundaries; the agent must not
204
+ execute it inside its bounded task. An omitted `schedule.saved` does not confirm
205
+ persistence; preserve any ID and follow the reported storage/error guidance.
206
+
207
+ | Response or observation | Next action |
208
+ | --- | --- |
209
+ | Create/resume saved the definition and confirmed a compatible ready host; exit `0` | Keep its schedule ID/root. The host will handle future due work; use history/execution for actual occurrence evidence. |
210
+ | Create/resume returns exit `3`, `schedule.saved: true` and `scheduler.next_action: start_required` | The definition remains saved. Preserve the returned schedule ID/root and give `scheduler.serve_command` unchanged to the user to run in an independent terminal or tmux pane. Never start it inside the agent's bounded task, detach it in the background, or submit another create. |
211
+ | Create/resume saved the definition but reports starting, backoff or pending readiness; exit `3` | Keep the same ID and report its host state and available retry time. Use passive scheduler status for later observation; do not create another definition, start a competing host or reset cooldown. |
212
+ | Create/resume saved the definition but the host is temporarily unreachable; exit `3`, pending guidance and no top-level `error` | Preserve `schedule.saved: true` and the same ID. Use passive status to observe the uncertainty. A transport failure does not establish owner death or a permanent host fault. |
213
+ | Create/resume saved the definition and the host reports `scheduler.fault: true`; exit `1` | Report the permanent fault and available `scheduler.last_error`; retain `schedule.saved: true` and the ID. For an incompatible saved definition, the before-Ready check stops automatic child restart. Repeated create, serve or status calls are not a repair. |
214
+ | Scheduler status observes starting, ready, backoff, degraded, stopping or stopped; exit `0` | Observation completed. Report the observed state; exit `0` does not mean ready or that an occurrence succeeded. Status does not start, migrate, repair or clean resources. |
215
+ | Scheduler stop confirms completed stop; exit `0` | The exact stopped intent has a validated owner-written closure witness and the exact host is absent. The witness follows joined child shutdown and free execution ownership. Independently admitted tasks keep their existing lifetimes. A later host needs a fresh explicit user-run serve command. |
216
+ | Scheduler stop has `scheduler.stop_accepted: true` but completion is pending; exit `3` | Preserve its acceptance and pending state. The host remains control-responsive while joining its child or waiting for a prior execution owner. Host death before the closure witness does not complete stop. Observe the same generation; do not claim stopped, launch a replacement or repeat schedule creation. An omitted `stop_accepted` is unknown, not false. |
217
+ | Scheduler stop has authenticated `scheduler.stop_accepted: true` and a later readback fault; exit `1` | Preserve the accepted fact and report the concrete fault. Readback failure does not revoke acceptance or establish completed shutdown. |
218
+ | Status reports `scheduler.state: foreground`, or stop returns exit `3` with that state, `stop_accepted: false` and `next_action: stop_foreground_runtime` | The current compatibility `scheduler run` owns this generation; an older managed-host receipt cannot hide it. Public stop does not terminate it. Have the user end that invocation with Ctrl-C in its original pane. Prefer managed `scheduler serve` afterward. |
219
+ | Invalid input/state; exit `2`, or concrete operational/compatibility/cleanup fault; exit `1` | Report the error and retain any saved ID or accepted-control fact. A concrete fault joined to pending work remains a fault; it is not a pending-only result. |
220
+
221
+ If the host dies, its pane closes or the machine reboots, the user must start
222
+ serve again. Child crash recovery applies only while that host remains alive.
223
+ An absent heartbeat or unresponsive endpoint is uncertainty, not permission to
224
+ replace an owner. Do not install a service or invoke a detached bootstrap as a
225
+ recovery step. Pause/delete affect future claims and need no live host; they do
226
+ not cancel already admitted occurrences. [Scheduler runtime](command-reference.md#scheduler-runtime)
227
+ owns launch, backoff and calendar behavior.
228
+
169
229
  ## Scheduled execution results
170
230
 
171
231
  Use [schedule history and execution](command-reference.md#schedule-history-and-execution)