Repository navigation
Description
Decision (Drew, 2026-10-31): tasks assigned the opencode execution lane must be triggered by scheduled tasks on the laptop/OpenChamber side. No Muse cron boots, launches, or hands off to OpenCode. Muse lanes keep claiming and assigning; execution starts without Muse in the loop.
Why: execution already spends only provider-plan quotas, but the triggers and supervision are Muse cron jobs — in the Oct 30 check-in window the conductor burned 96M input and its still-running predecessors (openchamber-dispatcher + openchamber-babysitter) ~199M more, i.e. Muse tokens spent just to start and watch work that runs entirely elsewhere.
Mechanism — OpenChamber scheduled tasks (corrected 2026-10-31, Drew): OpenChamber does have native scheduled tasks, and they are the mechanism for this change: the schedule lives on the OpenChamber side, not in Muse cron and not in OS timers. OpenCode itself lacks the capability — the #2019 investigation (comment 6494101941) audited OpenCode core and the fleet fork and correctly found no scheduler there (upstream request anomalyco/opencode#41906 open), but it did not audit OpenChamber's own feature set; its systemd-timer + opencode run composition is a fallback only, for anything OpenChamber's scheduler genuinely cannot express.
Work:
- OpenChamber-scheduled claimant/executor. An OpenChamber scheduled task on the laptop (any supporting service units defined in the developing-today/code flake — laptop services live there, never in dezren39/nix) that polls the four repo-health queues for tasks whose execution lane is
opencode, and for each: claims/binds it in the lane ledger at launch, with the session id recorded (this closes the launch-binding gap behind the Oct 28 duplicate PRs), launches the session with the route the task packet specifies (Workhorse default; Specialist / Summit for complex work), enforces the 12-session concurrency cap, and records the terminal state (complete / park / block / fail) via the queue helper when the session ends. - Parallel-run gate. Run beside openchamber-conductor for a defined window (24h or the first 20 executions, whichever is later), comparing bindings and completions. The Muse launch path stands down only after the gate passes.
- Stand-down. Disable the conductor's launch role and retire openchamber-dispatcher and openchamber-babysitter. Muse lanes keep claiming/assigning lanes and verifying results from queue + ledger records.
- Supervision. Scheduling is not supervision (investigate: OpenCode native scheduled tasks — creation, route choice, independence from Muse tokens #2019): name how stalled sessions are caught laptop-side (an OpenChamber-scheduled session health check) with Tend's fleet-watchdog reading the ledger as the backstop, and record the choice on this issue.
Acceptance:
- A full day with the Muse launch path disabled and opencode-lane completions continuing at or above the pre-change rate.
- 100% of laptop-side launches have a ledger binding with session id at launch time; zero duplicate PRs attributable to unbound launches during the gate.
- Daily check-in reports the opencode lane's per-item cost before/after the change.
- The Muse token cost of the launch path (conductor + predecessors) goes to ~0 for opencode executions.
Routes, pools and the measurement gate are unchanged — this moves who pulls the trigger, not what the sessions run on.
Acceptance criteria
- An OpenChamber scheduled task on the laptop polls the four repo-health queues for opencode-lane tasks, claims/binds each at launch with the session id recorded in the lane ledger, launches it on the packet's route, enforces the 12-session concurrency cap, and records the terminal state via the queue helper.
- The parallel-run gate (24h or the first 20 executions, whichever is later) passes beside openchamber-conductor: 100% of laptop-side launches bound with session id at launch time, zero duplicate PRs attributable to unbound launches.
- After the gate passes, the Muse launch path stands down: openchamber-conductor's launch role disabled, openchamber-dispatcher and openchamber-babysitter retired.
- A full day with the Muse launch path disabled shows opencode-lane completions continuing at or above the pre-change rate, and the Muse token cost of the launch path at ~0 for opencode executions.
- Laptop-side stall supervision is named and recorded on this issue (OpenChamber-scheduled session health check, fleet-watchdog ledger backstop).
Activity
dezren39 commentedon Oct 31, 2026
Top priority. Drew directed this change 2026-10-31 and it is enqueued for immediate pickup as triage task (see queue) in repo-health-code-pilot at queue priority 20 — only breakage-class work at priority 10 outranks it. The #2019 investigation it builds on is complete (comment 6494101941): no native scheduler exists; the systemd-timer +
opencode runpattern is proven. Note the parallel-run gate in the acceptance criteria: the Muse launch path stands down only after the laptop scheduler proves itself beside the conductor.dezren39 commentedon Oct 31, 2026
Correction (2026-10-31, Drew): the mechanism is OpenChamber's native scheduled tasks. The original framing leaned on #2019, which audited OpenCode (correctly: OpenCode has no scheduler) but never audited OpenChamber's own feature set. The issue body is updated: OpenChamber scheduled tasks are the primary mechanism; #2019's systemd-timer composition is fallback-only. The queue packet was likewise corrected and re-enqueued.
dezren39 commentedon Oct 31, 2026
Agent note — triage verdict: CONFIRMED, routed as a sequence (queue task 4384)
Verified this shift: this issue carries Drew's 2026-10-31 decision in full (no Muse cron boots/hands off to OpenCode; laptop-side scheduled tasks trigger opencode-lane executions), the #2019 investigation it builds on is complete (no native scheduler; systemd timer +
opencode runproven live 2026-10-29 at zero Muse tokens), and the spend evidence is recorded on the issue. No hard-stop labels; priority/high stands.Routing — this is a program, not one packet. The four work items sequence, and each step's completion enqueues the next so nothing waits on rediscovery:
opencode runwith the packet route, 12-session cap, terminal states via the queue helper, shadow mode for the worked example). Enqueued now as queue task 4387 (priority 20, deduperepo-health:v1:fix:developing-today/code:issue:3026).This issue stays open until the stand-down lands; the triage task closes here because the route now exists as live queue work.
dezren39 commentedon Oct 31, 2026
107 remaining items
dezren39 commentedon Nov 2, 2026
🤖 Agent note · picked up
dezren39 commentedon Nov 2, 2026
🤖 Agent note · picked up
dezren39 commentedon Nov 2, 2026
🤖 Agent note · blocked
dezren39 commentedon Nov 2, 2026
Lane-identity + parity gate report — 2026-11-02 (Drew's directive: parity first, then stand the conductor down)
The measuring instrument is live. Migration
0020_lane_identity(Supabase muse-dev,agentschema) added theagent.lanesregistry andtasks.lane_id; every claim now stamps the claiming lane — Muse lanescode-a…code-l,opencode-a,openchamber-a/b,nix-a; OpenChamber lanes stamp their scheduled-task UUID. Verified live within the first hour: OpenChamber lane8ac61616…claimed 5 code-queue tasks carrying its lane_id; a synthetic claim→complete cycle stampedopencode-a; legacy claims without a lane id still work (lane_id NULL = pre-attribution). Helper:repo-queue.py claim --lane(hatch efb7b19e3); lane definitions wired in hatch-personal 1df773f7a.Parity baseline. From
agent.repo_task_lane_ledger, opencode-lane executions over the last 7 days: 36 total, 20 with a session_id recorded = 55.6% launch-time binding (2026-11-02 alone: 5/8 = 62.5%). The acceptance bar for stand-down is 100%.Parallel-run overlap. Zero tasks with more than one execution record across the same 7-day window — OpenChamber-side dispatch and the conductor are coexisting without double-execution.
Gate verdict: STOP at the binding gate. Binding is ~56%, not 100%, so under the directive's own condition the conductor is NOT stood down today.
openchamber-dispatcherandopenchamber-babysitterare already disabled (verified live 2026-11-02, andenabled: falsein their hatch-personal definitions); the only live piece of the Muse launch path isopenchamber-conductor. Stand-down task 5983 stays blocked — now on the binding gate, not on authorization (the 2026-11-02 directive supplies the authorization; the gate supplies the stop).What closes the gap. Every opencode execution path must record the session id bound at launch in the ledger — 16 of the last 36 executions recorded none, spread across assigning paths. With lane_id attribution now live, binding can be re-measured per dispatch path. Proposed re-test window: the next 20 opencode executions or 7 consecutive days, whichever is longer; at 100% binding and zero overlap over that window, the stand-down proceeds (disable
openchamber-conductorvia the git-definition workflow; Muse direct lanes untouched).Bookkeeping note: queue task 4418 (the earlier slice-2 reference) no longer resolves in
agent.tasks; the live tracking chain is 4387 (slice 1, done) → 4408 (parallel-run gate, done 2026-11-02 00:14Z, PASS recorded) → 5983 (stand-down, blocked on the binding gate above).Merge pull request #4461 from developing-today/feat/3026-claimant-lau…
dezren39 commentedon Nov 2, 2026
Claimant wiring FINISHED — the gate's blocker is fixed at the source (2026-11-02)
The parity audit's stop verdict stood on a wiring defect, now root-caused and repaired:
Root cause. The claimant (f1b4a33b, enabled, mode
live,*/10) has launched zero sessions in its entire life. Its candidate discovery (pm-stack/opencode-claimant/poll.py) selects claimed tasks withprogress.lane = 'opencode'and noprogress.session_id— butassign_repo_task_lanewrote the assignment only into the ledger, never intotasks.progress. Discovery therefore saw zero candidates on every fire since enable (2026-10-31), while the conductor kept doing every launch and terminal-time--executionrecording carried a session id only ~47% of the time (48h baseline: 17 opencode executions, 8 bound).Fix (migration 0021, applied; PR #4461 merged
c403aadc5; helper in hatch544626e):assign_repo_task_lanenow stampstasks.progress.lane(atomic with the ledger insert; idempotent path self-heals; one-time backfill for claimed tasks — none were outstanding).bind_repo_task_lane_sessionRPC +repo-queue.py bindverb: one atomic call at launch writes the session id into both the ledger andprogress(session_id,launched_by), and refuses to overwrite a different existing binding — the double-launch guard.record_repo_task_lane_executionalready coalesces, so a launch binding survives terminal records that omit it.poll.py: candidate filter extracted asis_candidate()with tests (20/20 pass); claims by OpenChamber scheduled lanes themselves (UUIDlane_id) are excluded — those lanes are sessions executing their own claims, so a claimant launch would double-execute.bindverb; installer re-run on the laptop (prompt verified live in the OpenChamber store, task still enabled).Synthetic end-to-end proof: task created →
laneassignedopencode(progress stamped{lane: "opencode"}) →bindset ledger + progress session atomically → second bind with a different session id refused (already bound to session ...). Synthetic rows removed after the test.Gate state now: wiring complete; the conductor is NOT yet stood down. What remains is the demonstrated window: organic claimant launches binding at 100% with zero overlap beside the live conductor. Observation is running; the stand-down (task 5983) proceeds only on that evidence, per the directive.
Side finding, filed separately: code#4464 — laptop repo-keeper snapshot commits diverged
~/git/codemain from origin and pm-git-sync is failing every cycle; the claimant deploy used the verified-identical merged content from a worktree instead.Merge pull request #4469 from developing-today/feat/3026-claimant-wor…
Merge pull request #4490 from developing-today/feat/3026-claimant-han…
Merge pull request #4493 from developing-today/feat/3026-claimant-cre…
dezren39 commentedon Nov 2, 2026
STAND-DOWN EXECUTED — conductor retired, dispatch lives in OpenChamber tasks (2026-11-02)
Per Drew's 2026-11-02 directive (parity first, then stand the conductor down), executed end-to-end today:
Parity gate — PASS on the post-hardening window (17:35Z → stand-down).
progress.lane, which nothing wrote).bindRPC that refuses double-binding); post-hardening opencode executions recorded 3/3 bound in the gate window; zero tasks with more than one execution session; zero overlap since the handoff gate.progress.stage = handed_off, instruction §1b) — plus the create-shape pin in PR opencode-claimant: pin the session-create body shape (#3026) #4493.Stand-down actions.
openchamber-conductor: definition setenabled: false(hatch-personalc59246821), live job disabled via cron.update (scheduler reconciled), next run null. Its final pre-disable run (started 11:58 CST) finished its own cycle; nothing follows it.openchamber-dispatcher/openchamber-babysitter: already disabled in definitions and live jobs (verified today; last runs 2026-10-30).Post-cutover observation.
What shipped: migration 0021 (assign stamps
progress.lane; atomicbind_repo_task_lane_session),repo-queue.py bind(hatch544626e), PRs #4461 / #4469 / #4490 / #4493, instruction §1b in all four queue runbooks (hatch-personal3738362ea), claimant prompt reinstalled after each PR. Side finding filed as code#4464 (repo-keeper divergence blocking pm-git-sync; the claimant's poll.py was deployed byte-identical to origin/main as a stopgap).Closing: opencode executions now run from laptop-side scheduled tasks with launch-time binding, and the Muse boot handoff is retired.