Jobs and Schedules¶
Schedules deliver future mesh messages. Jobs represent durable tracked work that can be created, inspected, updated, completed, or canceled through CLI and MCP surfaces.
Schedules¶
Use schedules for reminders, future asks, and recurring check-ins:
repowire schedule self 10m "check CI"
repowire schedule cron orchestrator "@daily" "review open jobs"
Scheduling is message-oriented: a delivery can be a fire-and-forget notification or a tracked ask that requires an ack.
Jobs¶
Jobs are durable work records. They are useful when an orchestrator or human needs to track status, result, cancellation, and recurring worker templates across turns.
repowire jobs create "Daily brief" --path .repowire/agents/daily-brief --backend codex --cron "@daily" --prompt "Prepare the brief."
The MCP surface is job_create(..., path=..., backend=..., cron=...); schedule_cron
is only for recurring mesh messages to an existing peer, not durable executor
jobs.
For unassigned path/backend jobs, each run uses a short-lived executor process
by default. Recurring jobs use continuity=resume to keep the backend-native
runtime session id as the continuity handle for the next fire; one-shot jobs
default to continuity=fresh. The process is released after terminal job
completion.
Fire lifecycle: structural completion¶
A job fire's result is captured by the daemon, not self-reported by the
executor. The dispatch prompt (sent as an ask from the built-in @jobs
service peer) embeds job_id/attempt_id markers; the Stop hook posts the
executor's turn pair as chat turns, and the daemon correlates them:
- The user-role turn carrying the marker arms the fire (
running/ phaseturn_started). - The next assistant-role turn from the executor completes it: the turn's
final message becomes
result_summary(full text inresult_data.final_message), the dispatch ask is auto-closed, and the per-fire executor is released. - An executor that dies with an in-flight fire (terminal peer offline,
daemon-restart reconcile) fails it with
executor_died.
One fire = one turn. A job that needs a peer's answer must wait inside its
turn with wait_on_ack, never by ending the turn. The executor contract is
spelled out in the dispatch prompt: there is no human at the terminal, and the
turn ending ends the fire.
job_update is optional enrichment — progress notes and structured
result_data. The one escape hatch: a fire blocked on something outside the
mesh can hold itself open across turns with job_update state=running and an
explicit phase; it must then terminal-report itself.
Only the runner's own dispatching phase is lease-bounded. A delivered
fire belongs to the executor and is never reaped by a wall clock — executor
death is the liveness signal.
Observability¶
Every work state transition emits a job_state_changed event. Terminal
states additionally send a best-effort one-line notify from @jobs to the
job's owner — owner_peer_id, falling back to the creator, then the circle's
orchestrator. Jobs never depend on any of those being alive: cron fires
regardless, and the durable work row (job_status / job_result) is the
source of truth whenever someone comes asking.