Daemon stdlib
Harn’s daemon builtins wrap the existing agent_loop(..., {daemon: true})
runtime so scripts can manage long-lived assistants without hand-assembling
snapshot paths and resume options.
Builtins
daemon_spawn(config)
Start a daemon-mode agent and return a daemon handle dict.
Required config:
taskorpromptpersist_pathorstate_dir
Useful optional config:
namesystemprovider,model,tools,max_iterations, and otheragent_loopoptionswake_interval_mswatch_pathsidle_watchdog_attemptsevent_queue_capacity(default1024)
Example:
let reviewer = daemon_spawn({
name: "reviewer",
task: "Watch for trigger events and summarize the change.",
system: "You are a careful code reviewer.",
provider: "mock",
persist_path: ".harn/daemons/reviewer",
watch_paths: ["src/"],
wake_interval_ms: 30000,
event_queue_capacity: 256,
})
daemon_trigger(handle, event)
Queue a trigger event for a running daemon. Events are delivered FIFO, one daemon wake at a time, and the queue is durably persisted in the daemon’s metadata so a stop/resume or crash/recovery cycle does not lose pending work.
If the queue is full, the builtin throws VmError::DaemonQueueFull.
daemon_trigger(reviewer, {
kind: "file_changed",
path: "src/lib.rs",
})
daemon_snapshot(handle)
Return the latest persisted daemon snapshot plus live queue metadata:
pending_eventspending_event_countinflight_eventqueued_event_countevent_queue_capacity
The rest of the payload mirrors agent_loop daemon snapshots, including
daemon_state, recorded_messages, total_iterations, and saved_at.
daemon_stop(handle)
Stop a daemon and preserve its state on disk. The runtime waits briefly for an
idle boundary when possible; if the daemon is still mid-turn, the current
in-flight trigger is re-queued so daemon_resume(...) can replay it safely.
daemon_resume(path)
Resume a daemon from its persisted state directory. The path is the same root
directory you passed as persist_path / state_dir to daemon_spawn(...),
not the inner daemon.json snapshot file.
If the daemon stopped with queued or in-flight trigger events, they are restored and replayed after resume.
Delivery semantics
- Trigger events are FIFO.
- The queue is bounded by
event_queue_capacity. - Trigger payloads are handed to the daemon only from an idle boundary, so a persisted snapshot always reflects the pre-trigger or post-trigger state and never an ambiguous half-consumed queue.
- Forced stop/restart is intentionally at-least-once: an in-flight trigger is re-queued on stop/resume instead of being dropped silently.