Done (newest first)
This morning session · 2026-05-30 (autonomous overnight + operator-paired morning)
9 commits merged to main. 5 root-cause deadlock fixes, 2 new features, 1 verifier queued. All env-var defaults so existing behavior is unchanged until an edge case hits.
✓
5 worker-deadlock root-cause fixes
All 5 in one branch (fix/worker-deadlock-rootcauses). Planner fanout exits immediately on 0 subtasks + 45min wall cap. archive() SIGTERMs subprocess. Workers hard-capped at 60min runtime. Autopilot skips items completed within 1h. Watchdog tracks tool_use idle (15min) separately from any-event idle. Every fix is a default-env-var so existing behavior is unchanged until an edge case hits it.
8430c54, 9ee0c28, 3448031, bebe69b, d5150de · Nyx
apps/moderator/src/planner/orchestrator.ts, worker-manager.ts, queue/autopilot.ts, watchdog.ts
✓
Status pulse (GET /status/pulse)
Token-free system health snapshot. Pure SQL, one sentence, zero LLM in the common path. Returns workers_active, branches_awaiting_critic, last_merge_minutes_ago, stuck_count, queue_pending, queue_in_progress, critic_blocked, and a text summary. Auto-broadcasts on SSE every 20min (NYX_STATUS_PULSE_INTERVAL_MS). haiku escalation only on anomalies (stuck_count > 0, critic_blocked > 5, queue stalled with idle workers). The answer to "what's going on right now" without burning tokens.
0ea8d5b, f475e79 · Nyx
apps/moderator/src/status/pulse.ts, routes/status.ts
✓
Self-improvement reflector (GET /reflection/digest)
Rule-based weekly digest: worker timeouts, revise budget exhaustion, stalled queue items, merge velocity, top critic block reasons. One haiku call synthesizes into 3-sentence narrative. Daily scheduler tick. Fires on SSE topic 'reflection'. The answer to "what could we do better" without burning tokens.
83b7cdd · Nyx
apps/moderator/src/reflection/digest.ts, routes/reflection.ts
Q
Verifier runtime gate (in queue)
Post-Critic, pre-merge: boots the app in the right mode (headless Playwright for web routes, spawn+exit-code for CLI, expect-style stdin/stdout for TUI), exercises only the touched surface area, rule-based assertions (HTTP 200, no console errors, no broken images, clean exit codes), haiku-low for visual judgment capped at 5 calls per run, 8min hard cap. Same verdict shape as Critic. Autopilot will pick it up and dispatch a worker.
queue item szv0cdezfWdM · priority 48
feat/verifier-runtime-gate
Walk-away autonomy session · 2026-05-30 (operator-paired)
Operator's question that drove the whole session: "do I have to keep restarting it?" Answer by end of session: no, ever again. Every manual chore became a self-driving loop. Each item below was diagnosed and patched mid-conversation, then committed to its own branch.
✓
Auto-restart-on-merge (the moderator restarts itself)
After any successful ff or no-ff merge, the daemon checks the diff against apps/moderator/src/**. If touched, schedules a 30s-debounced process.exit(0); keep-alive respawns within ~5s with the new code. Multiple back-to-back merges within the debounce window coalesce into one restart. NYX_AUTO_RESTART_ON_MERGE=0 disables. This is the self-referential cool part: the feature landed by merging, and immediately used itself to restart.
on nyx-feat/auto-restart-on-merge · Nyx
apps/moderator/src/auto-merge/daemon.ts
✓
Planner + parallel fanout + synthesizer
POST /plan {goal, cwd} runs an opus planner that decomposes into N subtasks with explicit file ownership (no two subtasks can claim the same file). Fanout spawns N workers in parallel git worktrees. Synthesizer cherry-picks in plan order (pure git, zero tokens) and only falls back to LLM conflict-resolve on actual conflicts. Migration 011 tracks plans + plan_subtasks. Routes at /plan, /plan/:id, /plan/:id/events SSE.
90c71a5, 777a409 · Nyx
apps/moderator/src/planner/*
✓
Daemon test runner fix (unblocked ~80 branches)
The auto-merge daemon's defaultRunner used pnpm --filter ... test --run, which pnpm 9 treats --run as a pnpm option (errors "Unknown option: 'run'"). The error went to stdout while the daemon captured only stderr, so every blocked branch showed empty stderr_tail and looked like a phantom test failure. Two-line fix: added "test": "vitest run" to the moderator package.json + dropped --run from the runner args.
b00b125 · Nyx
apps/moderator/src/auto-merge/daemon.ts + package.json
✓
Concierge persona unlocked + "On authority" rule
The cached persona was treating side requests as scope creep ("get Ethan to authorize", "doesn't match his shape"). Re-framed project list as "currently in flight, not a fence" and added an explicit ## On authority section killing the false-authority test pattern. Anyone at the operator's keyboard is treated as operator-authorized. Hard rules (no em dashes, no auto-push, push-gate floor) remain the only refusal triggers.
~/.nyx/concierge/CLAUDE.md · Nyx
✓
Go TUI panic fix: streamBuffer pointer
Bubble Tea's Update has a value receiver, so the model struct is copied on every msg. A strings.Builder by value triggers copyCheck panic on the next WriteString. Held as *strings.Builder instead so the copy duplicates the pointer not the Builder. Rebuilt the binary; relaunched cleanly.
4f05578 · Nyx
apps/tui-go/model.go
✓
Headless Playwright MCP default
Workers don't need a visible Chromium; they see the page via screenshots, accessibility snapshots, and DOM queries returned as image/text content blocks. Added --headless to the MCP launch args. Faster, no focus stealing, safe to run while the operator is using the laptop. browser_snapshot and browser_take_screenshot keep working unchanged.
on nyx-feat/tui-claude-feel · Nyx
apps/moderator/src/mcp/installer.ts
✓
nyx symlink path resolution
Installing the launcher as /opt/homebrew/bin/nyx -> .../scripts/nyx broke REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" because $0 resolved to the symlink, making REPO_ROOT /opt/homebrew. Walk the symlink chain manually before computing the root (macOS readlink lacks -f). nyx start/stop/status work from anywhere now.
1d6c72d · Nyx
scripts/nyx
✓
Migration 010 work_queue + teams/voice routes wired
Three pre-existing test failures were silently blocking every auto-merge: nyx-mcp.test.ts hit "no such table: work_queue" (migration was never registered), routes-voice.test.ts and teams.test.ts got 404s (AppDeps had no voice or registry fields and server.ts didn't mount the routes). Added migration 010 to register the work_queue table; added voice?: VoiceRoutesDeps and registry?: TeamRegistry to AppDeps; conditional mounts at /voice and /teams.
d78f31a · Nyx
apps/moderator/src/db/migrations/010 + src/server.ts
✓
docs/how.html: plain-English explainer + role cards + timing chart SVG
"Explain what a daemon is, I wasn't paying attention." Built a new page with role cards for every actor (operator, concierge, moderator, worker, planner, fanout, synthesizer, critic, auto-merge, autopilot, watchdog, scheduler, janitor, auto-revise, self-iter, queue-sync, model probe, CLI updater), a 60-minute timing chart SVG showing each loop firing on its own row, and an end-to-end flow diagram SVG. Wired into the nav across all docs pages. Deployed to orchestrator-docs-51t.pages.dev/how.html.
docs/how.html · Nyx
docs/how.html + nav across 8 pages
✓
Auto-revise loop
When the Critic returns revise, spawn a sonnet fixer in a fresh worktree off the same branch with the critique + original diff. Worker commits v2; daemon picks it up on next sweep. Migration 012 tracks attempts; budget is 3 per branch then quarantined. Eliminates the "branch stuck because critic asked for revisions and nothing does the revisions" failure mode. Auto-revise landed and immediately proved itself: it self-revised the Critic diff-window bump when Critic caught a NaN footgun in the same code.
44ef227 · nyx-feat/auto-revise-loop
✓
Branch janitor
Runs at the start of every auto-merge tick: deletes branches already ancestors of main (already merged), renames branches whose revise budget is exhausted to nyx-stale/*. Stops the daemon from re-evaluating zombie branches every minute. Skips any branch with an active worktree to avoid disturbing in-flight workers. 44 nyx-stale/* branches currently awaiting the next janitor pass.
nyx-feat/branch-janitor · merged
✓
TUI streaming + visual overhaul
Go TUI (nyx-tui) with Bubble Tea + Lipgloss. Per-token streaming, mouse support, multi-worker layout. Binary at apps/tui-go/nyx-tui. Per-token streaming (decouple SSE receive from render, never batch), mouse support (click any item to focus/dispatch), scrollable bubbles/viewport per pane, multi-worker layout (middle column auto-splits as new workers spawn), Lipgloss visual hierarchy with Atlas accent (#6f9bff) on neutral grays.
d907575, c9e14ad · apps/tui-go/nyx-tui
●
Multi-moderator process model (in flight, opus)
Process-per-project isolation with hard caps: max 2 moderators concurrent, max 4 workers per moderator. New nyx project create / start / stop / list / switch CLI commands. Each project on its own port + own SQLite DB at ~/.nyx/projects/<name>/moderator.db. Concierge routes by ?project=. 3rd start refuses with active-slot listing; 5th dispatch returns 429.
aJfSa1o3QGqX · nyx-feat/multi-moderator
●
Concierge auto-invokes planner for big tasks (in flight, opus)
Today, concierge spawns one worker per message. Adding classifyIntent(text): 'single' | 'plan' | 'chat' with a heuristic-first / opus-haiku-fallback approach. Multi-deliverable messages ("build me a 6-page site", "add 5 NPCs") route to POST /plan; chat questions stay in the conversation pane; well-scoped single tasks stay in the single-worker flow.
772PwyL0RmKk · nyx-feat/concierge-uses-planner
✓
Sleep auto-schedule
Sleep mode currently changes only what Tier-2 push gates do (auto-deny vs wait-for-operator-approval). Was a manual toggle; now a 60s scheduler flips it ON during a configurable window (default 23:00 to 07:00 America/New_York) and OFF outside. Operator manual overrides win (state with non-'auto:' reason prefix is never touched by the scheduler).
c870f93 · nyx-feat/sleep-auto-schedule
Afternoon session · 2026-05-29 (operator-paired)
Operator returned to a stuck queue (19 items "in_progress" with no live workers, the overnight orphan signature). The session diagnosed the cause across three layers, shipped fixes for each, then converted the recurring "Nyx spawns Claude for trivial work" anti-pattern into a deterministic-code routing system. Spend dropped from $325/hr to a sustainable rate by routing cherry-pick / rebase / cleanup shapes to pure code.
✓
Deterministic cherry-pick fanout (0 tokens replaces Opus worker)
fanoutCommit(commitHash, branchGlob, opts) iterates matching branches, attempts cherry-pick, runs the test subset, reports per-branch outcomes. Conflicts are aborted cleanly, never half-applied. POST /ops/fanout exposes it; the autopilot's isFanoutItem() routes any queue item titled "cherry-pick X" or "fanout X" to the route instead of spawning Claude. First commit in Nyx history to do meaningful work with zero LLM tokens.
13de104 · Nyx
apps/moderator/src/ops/fanout.ts
✓
Worker-outcome feedback into queue notes
onWorkerExit now calls recordWorkerOutcome which appends "[ts] status after duration: summary" to the originating queue item's notes, bumps fail_count, and re-pends to pending if the worker failed. Retries read their own prior failures. The MAX_FAIL_COUNT ceiling drops reliably-failing items to status=dropped so they cannot spin the queue.
2d1451e · Nyx
apps/moderator/src/queue/outcome.ts
✓
Boot-time zombie agent reaper
Mirror of the session orphan sweep for the agents table. Agents whose every session is failed/succeeded/dropped and whose latest started_at is >1h old get archived_at set, so the snapshot stops showing "23 agents running" when only 3 claude subprocesses exist. Pure SQL, zero LLM.
5f42b1d · Nyx
apps/moderator/src/db.ts
✓
Auto-merge: retry flaky test runs before blocking
NYX_AUTOMERGE_TEST_RETRIES (default 2). A single vitest red no longer permanently blocks merge; the daemon retries up to N times and only blocks if every attempt fails. Audit rows record merge_retry_1_2, merge_retry_2_2 so retry behaviour is measurable.
58d3d28 · Nyx
apps/moderator/src/auto-merge/daemon.ts
✓
Queue auto-enrichment of bare titles
POST /queue {enrich:true} now runs a single haiku call that expands a bare title into a worker-ready brief (goal, files, success criteria, branch name) before insert. The concierge can queue intent without writing the spec; the resulting notes are what the worker reads at dispatch.
7961ebb, 94c027c · Nyx
nyx-feat/queue-spec-enrichment
✓
GET /m mobile status page
Phone-first dashboard with live queue + worker count + last 10 ship events + a big text/voice input box. Web Speech API for browser-side STT, POSTs to /quick-add for enrichment and queueing. No claude.ai/code attachment required; the operator runs Nyx from their phone over Tailscale.
718b5f0 · Nyx
apps/moderator/src/routes/mobile.ts
✓
nyx start/restart drops into the TUI; concierge opt-in
The legacy claude --remote-control concierge subprocess was the default chat surface and burned a Claude Code login slot 24/7. It only provided the claude.ai/code phone URL, which the new /m page replaces. Default is now TUI in the foreground; --with-concierge keeps the legacy path for phone-URL users.
440519a · Nyx
scripts/nyx
✓
Boot-time queue reconciler closes orphan in_progress rows
Three-layer self-healing for the "stuck in_progress" failure mode. Layer 1: onWorkerExit flips in_progress to done on clean exit. Layer 2: boot reconciler scans in_progress items, decides done/pending based on branch state (commits ahead of main = done; no branch = pending + clear dispatch_meta). Layer 3: auto-sync promotes done to succeeded when the branch lands.
ddd22b6, 086ed11 · Nyx
apps/moderator/src/queue/reconciler.ts
✓
Auto-sync uses queue.id as branch prefix when title has no Item N
The 5-minute auto-sync was running but matching nothing: its glob only fired on titles starting with "Item N". The overnight branches were named nyx-feat/reflection, nyx-feat/reasoning-tier, etc. New fallback: derive nyx-feat/<queue.id>* as the pattern when no Item-N marker is present. 7 stuck rows auto-closed on the next tick.
4deb8ce · Nyx
apps/moderator/src/queue/auto-sync.ts
✓
Self-iter joins Opus capability lanes (opus-4-8/medium)
Self-iter diagnoses stuck workers and patches Nyx's own code. The overnight 499-fires-in-14h dribble-livelock proved Sonnet/low was undercooked: the diagnostic kept misreading the same zombie session. Moved to opus-4-8/medium (8k thinking tokens). Self-iter fires rarely, so per-call cost matters less than diagnosis quality.
634167e · Nyx
apps/moderator/src/model-routing.ts
✓
Flip default routine lanes to sonnet-4-6, reserve opus for capability
Overnight burn was $801 Opus 4.8 versus $78 Sonnet 4.6 across 14 hours. moderator, critic, watchdog, research, feature now default to sonnet-4-6; visual-worker, architect, self-iter stay on opus-4-8. Routing table is consulted at every spawn so the flip takes effect on the next worker without a model migration.
3132126, fd838fd · Nyx
apps/moderator/src/model-routing.ts
✓
Autopilot preserves operator notes; skips manual-only items
Two merges. Preserves-notes: dispatch metadata (agent_id, session_id, picked_at, reason) moved from notes into a dedicated dispatch_meta column. The operator's prompt source in notes is no longer clobbered on dispatch. Skip-manual: items with priority >= 9999 are operator-trigger-only and never auto-fired (model-flip-shaped changes the operator must run by hand).
352a054, 097ccec · Nyx
nyx-feat/autopilot-preserves-notes, nyx-feat/autopilot-skip-manual
Overnight build cycle · 2026-05-29
One continuous autonomous run shipped the conduction layer, the Concierge backend, a Telemetry surface, the MCP servers, the supervisor tooling, and a full TUI rewrite. Each item below landed on its own branch and merged after tests and Critic review.
✓
Autopilot: autonomous queue conduction
Pulls pending items off the queue and dispatches them with no operator present, respecting the worker cap and cost guardrails. Turns the queue into a self-draining work plan rather than a manual dispatch list.
93a0b4f · Nyx
nyx-feat/queue-autopilot
✓
Auto-Merge Daemon (item 34)
Sweeps finished nyx-self and nyx-feat branches on a tick, runs the test suite, requests a Critic verdict, and merges only what passes. Records every evaluation in audit_log so the auto-merge rate is measurable. Queue auto-sync (migration 007) flips merged branches to succeeded.
9c32607, e7cecd8 · Nyx
branch-sweeping gate
✓
Sleep Mode
Operator hands the orchestrator full autonomy for a fixed window. Workers dispatch, branches merge through the auto-merge gate, and the operator wakes to a digest instead of a queue of prompts. The hardcoded Push Gate floor still cannot be lifted while asleep.
63b1537 · Nyx
/sleep routes + AppDeps
✓
Concierge backend with persistent memory (item 34.x)
A fast Haiku-backed Concierge answers operator questions, injecting saved memories and recent turns. Persistent memory module over ~/.nyx/memory with CRUD routes (migration 006), and every turn is persisted. Replies stream as readable markdown.
79d38a3, 3601cdb, d805e8d · Nyx
/concierge + /concierge/memory
✓
MCP servers: nyx memory + Codex
The Concierge memory is exposed to workers as the nyx MCP worker addon, so any worker can read and write durable memory. A Codex MCP adds codex_ask, codex_image, and codex_edit with Tier 2 gate routing. Opt-in MCPs now forward through POST /sessions (item 33).
9279e92, 26a01cd, 3b6a2ee · Nyx
worker tool surface
✓
Telemetry surface (/metrics)
One JSON endpoint and a self-contained dashboard derive at-a-glance health from the existing SQLite tables: tokens today, lines shipped today and lifetime, mean time between failures, worker success rate, auto-merge rate, top workers, and a 24h token sparkline. The LOC calc is git-backed and cached for five minutes.
Nyx
routes/metrics.ts
✓
Supervisor tooling + one-command launcher
A launchd plist plus a bash watchdog keep the Moderator alive across crashes (the Moderator never dies). A single launcher starts, stops, restarts, and reports status for the whole stack. An ntfy notify daemon pushes gate prompts and digests to the operator's phone.
6cc7b99, c272f95 · Nyx
supervisor + notify
✓
TUI rewrite in the Claude Code style
Full terminal rewrite with a grouped queue, a dynamic worker grid that grows with concurrency, true token streaming, a live worker filter, DEEP inspection panes, and rendered markdown. Concierge replies stream as styled segments with soft-newline formatting rather than raw objects.
bc8173f, b4bdbe3, 86cdf10 · Nyx
apps/tui
✓
CLI updater + Team audit scaffolding
Auto-detects Claude Code CLI updates (item 32). Team-scoped audit tables are scaffolded (migration 008) for the multi-seat tier, ahead of per-user and per-team memory namespacing.
7947e01 · Nyx
migration 008_team_audit
✓
Item 18: per-role model tier routing
Built by Nyx. ClaudeModelId per role: Critic + Watchdog + research = haiku 4.5, Moderator + workers + self-iter = sonnet 4.6, only big refactors = opus 4.7. Env var override per role (NYX_MODEL_CRITIC=...). Wires through worker.ts, worker-manager.ts, critic.ts, routes/agents.ts, routes/internal.ts. 117 new tests.
6bb41da · Nyx
817 LOC / 12 files
✓
Billing-mode detection + subscription opt-out
CostGuardrails now reads NYX_BILLING_MODE / ANTHROPIC_API_KEY at construction. Subscription mode still records spend_log rows for visibility but never kills tasks or pauses dispatches. Caps are real only in api mode.
2026-05-28 19:01
9 new tests
✓
Item 17: per-task + daily spend guardrails
New spend_log table, per-model USD pricing table, observeUsage hook, kill-on-task-cap, pause-on-day-cap, /cost endpoints. Built by Nyx. Caught a real overrun on the first Item 16 attempt within minutes of going live.
b8ee9fa · Nyx
704 LOC / 10 files
✓
Item 15: idle-based watchdog (Nyx implements Nyx's own rec)
Switched stuck-session detection from age-based (was: any session running > 15min) to idle-based (now: silent for > 10min). Built by Nyx from its own tuning note. Eliminated the false-positive class that triggered self-iter spuriously.
458a118 · Nyx
180 LOC / 2 files
✓
First autonomous self-modification (historic)
On its first boot, Self-Iterator fired against a real watchdog signal. Fix worker created branch, investigated, correctly diagnosed as "long-but-progressing" rather than a code bug, wrote a 104-line tuning note instead of guessing at a fix. Didn't push, didn't merge. Safety pattern: 100% right.
ef37468 · Nyx
on nyx-self/...
✓
Self-Iterator v1 (signal-driven self-edit foundation)
Auto-dispatches a fix worker on worker_failed + watchdog_stuck signals. Loop prevention, mutex, cooldown, branch isolation, protected files, kill switch. 8 dedicated tests.
aa1d457
~700 LOC
✓
Orphan-on-boot sweep
Surfaced by self-iter's first false-positive: sessions stuck as "running" after a moderator crash were flagging the watchdog. Boot now sweeps them to "failed" before Watchdog/SelfIterator start.
c082378
regression test
✓
Yaga.co.za integration into FBM Sniper Pro (full feature, built by Nyx)
One operator sentence: "add yaga to the app." Nyx self-dispatched a discovery worker, found the public JSON endpoint, wrote the scraper, wired it across 13 files (daemon, shared seller-trust, UI shell, 6 UI modules, onboarding step, tests). Desktop build launched first-try.
ec21188 + 0006259
(FBM repo) · Nyx
✓
Phase 6 slice 4: Watchdog
Always-on monitor scanning every 5 min for stuck sessions. Audit-log entry per detection. First-slice age-based detection has since been replaced by idle-based (Item 15).
phase 6 slice 4
✓
Phase 3a: Critic
POST /sessions/:id/review. Spawns short-lived reviewer claude with strict prompt. Verdict: approve / revise / abstain + critique up to 300 words. Manual-trigger first; auto-trigger gated behind a config flag.
phase 3a
✓
Phase 6 slices 1-3: Memory + Skills
Hermes-shaped frozen-snapshot memory (MEMORY.md 2200, USER.md 1375, PROJECT.md 4400 char caps). Skills librarian (~/.orchestrator/skills/) with list/get MCP tool. Auto-loaded into every worker prompt prefix.
phase 6 slices 1-3
✓
Phase 5: Discord bot + Cloudflare Tunnel
DM the bot from your phone, persistent agent per Discord user, long replies auto-chunked. scripts/tunnel.sh for public dashboard URL on demand. The "control from anywhere" layer.
phase 5
✓
Plan 2.5: Error webhook + cron + repo priming
External systems POST errors to /events/error, Nyx auto-investigates. @every / @hourly / @daily scheduled jobs. Workers entering a repo auto-load its CLAUDE.md. Unlocked the FBM Sniper SRE use case.
aff751b + f519b85 + f42602d
✓
Phases 1, 2A, 2B, 2C: Moderator, Push Gate, Dashboard, Trust
Hono server, SQLite WAL, Claude subprocess spawner, three-tier Push Gate (hardcoded floor + blacklist.yml + best-effort normalize), audit log on every decision, React 19 dashboard with mac chrome, multi-tab agents, push-gate bar, audit drawer.
phases 1-2C · ~20 commits