type: meta

topic: P3 — harnessd daemon A1, decision inbox A5, notifications W9, trust ramp W10, budgets V2, digest V1, queues/windows X1/X4/X6, handoff bundles X11, run reports X12, control-api token auth

exec_mode: ship

scheduler: sequential

land_mode: merge-to-main

base_branch: main

gate0_mode: strict

status_enum: BLOCKED PENDING WORKING WRITTEN REVIEWED COMMITTED

truth_rule: this file is ground truth for INTENT (goals/task list); git is ground truth for DONE-NESS — reconcile statuses against git, never trust a COMMITTED line with no commit

report_rule: at session end emit brief: done / blocked / deferred / canceled


type: goal

text: babysitter eliminated: daemon owns launch→monitor→resolve→resume→escalate→report; full chaos suite green end-to-end unattended incl. crash-resume and pre-authorized default decision; soak clean


type: anchor

what: canonical spec — state machine, tick loop, sockets, inbox, re-attach, auth, tests


what: READ FIRST — library+CLI-first seam; daemon is a scheduler of library calls


what: plan — pinned per-task contracts (### Task N)


type: intent

text: after this plan lands, W13 dogfooding governs: P4+ (DAG scheduler, lesson loop, message bus, UI, adapters, self-improvement P5.6) are authored as runplan plans and executed BY the harness at autonomy level 1


type: gated

status: RESOLVED

source: author

category: policy

needs: approve engine-src whitelist for this run

why: P2b protected-path gate quarantines any task touching engine src/ when the target repo IS the harness; this entire plan modifies engine src/ — operator must whitelist at preflight per V1 (never at run time)

resolved_by: user


category: input

needs: notification channel config: ntfy topic URL + token, or generic webhook URL — written to ~/.harness/config.json before Task 4 dispatch

why: W9 needs a real operator-owned channel; no default exists and inventing one would silently drop escalations

answer: ntfy


type: task

seat: coder

tier: high

desc: daemon core bin/harnessd + src/daemon.js per spec/DAEMON.md: state machine every edge, 8-step idempotent tick loop, stateless I8, re-attach; resolver called as library (plan Task 1)

status: PENDING

requires_decision: g-protected-whitelist


desc: decision inbox src/inbox.js per spec § Decision inbox: payloads verbatim, d-<seq> ids, first-answer-wins 409, default auto-answer only level ≥2, bundle-before-notification (plan Task 2)


desc: daemon control socket verbs + runplan --unattended submit client + runplan answer; foreground mode unchanged; supervisor socket untouched (plan Task 3)

blocker: waiting on wave 1


tier: medium

desc: notifications src/notify.js per spec: config via resolveConfig, ntfy actions with auth header, notify.failed + retry ×3 → give up, never blocks decisions (plan Task 4)


desc: control-api token auth per spec auth paragraph: ~/.harness/token 0600, Bearer required, timingSafeEqual, 401, localhost/Tailscale bind only; proxy answer+status (plan Task 5)

blocker: waiting on w2.t1


desc: systemd user units (harnessd.service Restart=on-failure, daily timer) + systemd-run scoped agent spawns with setsid/ulimit fallback probed at startup (plan Task 6)


desc: W10 trust ramp submit gate + V2 budget enforcement in tick (task→budget-exceeded, run→pause+decision) + V1 digest src/digest.js + W5 status cache + W12 backup in timer (plan Task 7)

blocker: waiting on wave 3


desc: X1 meta-plan dep queue (cycle detection, accept_partial, blocked-on-dep escalation) + X6 run windows (--now override) + X4 maintenance ladder with preemption (plan Task 8)

blocker: waiting on w4.t1


desc: X11 escalation handoff bundles (before notification, linked) + X12 run report from the SAME journal reducer, committed with landing (plan Task 9)

blocker: waiting on w5.t1


desc: ungate P3 chaos (daemon-kill re-attach, unattended end-to-end, default decision) + soak N cycles zero orphans — epic definition of done (plan Task 10)

blocker: waiting on w6.t1