Background Daemon
Commit-triggered background codegen with isolated jobs, a change journal, and an agent guard hook.
You want spec changes to rebuild themselves in the background while you keep
working, and you want to review the result before it lands. jaunt daemon does
that. You (or your coding agent) commit spec changes, and the daemon rebuilds
what went stale in an isolated job. By default it parks the green result as a
reviewable proposal — you land it explicitly with jaunt jobs land. Opt into
auto-committing green jobs with [daemon] auto_commit = true.
Start / Stop / Status
jaunt daemon start # run the daemon (foreground; Ctrl-C to stop)
jaunt daemon status # is it running? what is it doing? which landing mode?
jaunt daemon stopThe daemon polls the repository HEAD (every [daemon] poll_interval seconds).
When a commit changes specs, it launches an isolated worktree job that rebuilds
the stale modules and runs validation. On green, what happens next depends on the
landing mode (see below). Failed or conflicted jobs are parked instead of
landed. jaunt daemon status reports the active landing mode
(landing: propose-only or landing: auto-commit).
Landing modes
- Propose-only (default,
auto_commit = false). A green job ends in thePROPOSEDstate: its diff is captured as a patch artifact under.jaunt/jobs/<id>.patchalongside the recorded spec digest and provenance commit message. No commit is created — you review and land it explicitly. A newer proposal for the same module automatically supersedes an older pending one. - Auto-commit (
auto_commit = true). A green job flows straight into a provenance commit with no review step. Jaunt's own repo runs its dogfooding daemon this way.
Landing a proposal
jaunt jobs land <id> # land one parked proposal as a provenance commit
jaunt jobs land --all # land every fresh proposal, in job-creation order
jaunt jobs discard <id> # drop a proposal you don't wantjaunt jobs land re-validates before committing: it recomputes the module's spec
digest at HEAD and refuses (marking the proposal SUPERSEDED) if the spec moved
since generation — the daemon will propose a fresh build. It also refuses if the
current branch differs from the job's branch, if the patch's target paths are
dirty in your working tree, or if the patch no longer applies cleanly (a 3-way
conflict supersedes the proposal). There is no --force: regeneration is the
honest resolution for any land-time doubt. On success it creates the same
provenance commit auto-commit mode would have, marks the job LANDED with the
commit sha, and appends the journal line.
jaunt jobs land --all lands every still-fresh PROPOSED job in job-creation
order (the daemon queues jobs in dependency order), prints a per-job outcome, and
exits 0 only when every attempted land succeeded (else 4).
Jobs
jaunt jobs # job records + would-rebuild preview + heartbeat
jaunt jobs show <id> --full # one record, with the full local detail log
jaunt jobs retry <id> # retry landing a parked job (--force if the spec moved on)
jaunt jobs land <id> # land a parked proposal as a provenance commit
jaunt jobs land --all # land every fresh proposal (job-creation order)
jaunt jobs discard <id> # discard a parked proposal
jaunt jobs wait --timeout 1800
jaunt jobs wait <id> --timeout 1800 --json --progress plainjaunt jobs wait blocks until a target job finishes — or, without an id, until
the daemon is idle. --settle N controls the idle race-guard window (default:
2 × poll_interval). Exit codes make it loopable: 0 green, 4 a job failed
or parked, 5 timeout. A parked proposal (PROPOSED) counts as terminal-green,
so jaunt jobs wait returns 0 on it — a proposal is a successful build
awaiting your landing decision.
The canonical agent loop under the default propose-only mode is wait-then-land:
git commit -m "feat: tighten slugify contract" && \
jaunt jobs wait --timeout 1800 && jaunt jobs land --allWith auto_commit = true the daemon commits green jobs itself, so the loop is
just the wait:
git commit -m "feat: tighten slugify contract" && jaunt jobs wait --timeout 1800The Change Journal (jaunt log)
Build, test, and daemon runs append to a JAUNT_LOG journal at the project
root (scaffolded by jaunt init). Tail it with:
jaunt log # last 20 entries
jaunt log -n 0 # everything
jaunt log --module my_app.specs
jaunt log --jsonGuarding Generated Code (jaunt guard)
jaunt guard is a PreToolUse hook for coding agents: it reads the hook payload
on stdin and warns (with a pointer to the owning spec) when a tool call is
about to touch __generated__/**. Wire it into Claude Code via
.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|MultiEdit|Write|Read|NotebookEdit",
"hooks": [{ "type": "command", "command": "jaunt guard" }]
}
]
}
}For harnesses without hook support, the barrier is advisory:
jaunt instructions states the rule.
Configuration
[daemon]
poll_interval = 2.0 # seconds between HEAD polls
max_jobs = 0 # 0 -> build.jobs
notify_command = "" # optional shell command run on landed/parked/failed jobs
auto_commit = false # false (default): park green jobs as proposals; true: auto-commitauto_commit defaults to false: green jobs are parked as proposals you land
explicitly. Set it to true to auto-commit on green. (If you're coming from an
older setup, see Upgrading for the default change.)
notify_command is the push-notification seam: point it at a script that pings
Slack, notify-send, or your agent loop. It fires on proposed, landed, parked,
and failed jobs.
Build, propose, land, discard, and supersede events are all recorded in the
JAUNT_LOG journal, so it stays a complete audit trail whether or not
auto-commit is on. The job-propose and job-discard lines are appended
uncommitted (union-merge-safe); a landing carries the standard build/refreeze
journal line committed alongside its provenance commit.
Next: Gating Generated Code in CI.