- Upgrading: the agent-deck skill is now split into a short
SKILL.mdplusreferences/files. If you installed it with the README's curl loop rather than the plugin, re-run the loop so the new reference files are present (#2429).
Added
agent-deck inbox peek [--json] [<session-id>|self]shows pending records without consuming them, rendered exactly as the prompt-time drain injects them (#2469).agent-deck inbox stats [--json] [--all] [<session-id>|self]reports a parent's communication counters: records by tier, turns suppressed as noise or duplicates, wakeups fired and withheld, records delivered, bytes injected and the last urgent latency (#2469).[inbox]config section (wake_on,max_text_bytes,info_digest_minutes,question_wakes,journal_keep) with a per-conductor override under[conductors.<name>.inbox](#2469).[launch] nest_under_parent = truelinks a session started from inside a sub-session under that sub-session's parent (one hop, with a note on stderr and alaunched-byhint naming the caller); a parent that no longer exists gives a top-level session plus a note. Off by default: a sub-session caller gets a top-level session as before.launch,addand the startup pre-check now share one parent selector, and a plainlaunchfrom inside a sub-session no longer exits 1 at the capacity pre-check (#2440, thanks @AdamiecRadek).- The
*time filter gains a "Last 30 days" step between 7 days and All, with the same rolling window as the 3- and 7-day modes (#2448, thanks @borng). group_sort = "alphabetical"orders the sessions in a group A to Z by title, case-insensitively, with a stable tie-break on creation order;creationandactionableare unchanged and remain the default (#2459, fixes #2451).- Remote sessions nest under their parent in the controller's TUI: when a remote session's
parent_session_idnames another session on the same remote, the parent row comes first and its children are indented one level, as local sub-sessions are; a parent that is missing from the fetched set (archived, filtered out, or an older remote build that does not report the field) leaves the child flat as before. Shift moves among nested remote rows stay among siblings (#2463, fixes #2450). [ui] active_includes_idle = truekeeps idle sessions that still have a live pane in the active section of the active-on-top view, so only stopped, errored and never-started sessions sink to the bottom and the top list stops reshuffling whenever a juggled session goes idle. Off by default (#2468, fixes #2452).[display] hide_default_tool_badge = truedrops the tool badge from rows whose tool is the deck's default tool (an unsetdefault_toolcounts as claude), so only the outliers are labelled; applies to local and classic remote rows (#2445, thanks @borng).- Web UI: session cards and the Overview rail show recall annotation hints.
/api/menu,/api/session/{id},/api/sessionsand the menu event stream carry optionalhintsandtagsper session, read in one bulk query from the profile'sstate.db(read-only, re-opened if the file is replaced), so asession annotateshows up within about two seconds. Sidebar cards show the headline, a coloured status chip and the ticket, behind a default-on "Goal / status hints" toggle; the rail lists every hint and the tags; the sidebar filter matches them. An opt-in Status view (Status | Groups toggle) groups sessions by theirstatushint and pins a conductor's markdown summary on top; the default Groups view and the runtime Running/Waiting/Error/Idle tiles are unchanged (#2447, fixes #2446, thanks @bryant-numeric). agent-deck healthreportsopen_fds_support(sampledorunsupported) next toopen_fds, and the budget line saysdescriptors unsupported on this platforminstead of advertising a check that can never run (#2462, fixes #2427).
Fixed
conductor setup <name>re-run without--agentkeeps the conductor's stored agent instead of resetting it to claude (an explicit--agentstill switches; a corruptmeta.jsonnow refuses the bare re-run instead of silently becoming claude), and the stale-instruction cleanup no longer deletes a hand-editedCLAUDE.md,AGENTS.mdorHERMES.md: a file that still matches the rendered template is removed as before, a diverged one is moved to<file>.bak-<timestamp>with one notice line.--claude-md/--shared-claude-mdwithout--agenton a non-claude conductor now errors instead of switching it (#2465, fixes #2434, #2435).- Attaching to and detaching from a pi, gemini, cursor or hermes session no longer wipes its hook-driven status. The attach-return wipe exists for Claude and Codex, which can exit via
/qwithout a final hook; it is now gated to those tools (and tools declared compatible with them), so the other tools' status dot no longer falls back to pane heuristics after every attach (#2458, fixes #2436). session sendto a Codex session no longer reports "never confirmed submitted" for a message Codex is already working on. The confirmation check now reads Codex's own pane evidence, measured against a capture taken before the send: a new copy of the body in the transcript above an empty composer, or the liveWorking (…)row with the body out of the composer and not in the queued-input list. A body still sitting in the composer with no processing is still reported as typed, not submitted (#2460, fixes #2424).- Light theme: the preview pane now remaps only dark backgrounds to the surface colour and passes light ones through, so a tool that already renders light highlights (OpenCode on Solarized Light, for example) no longer turns into grey stripes while the Codex dark bars stay fixed; the New Session dialog re-applies its surface fill after every inner reset, so the box is uniform on any terminal background. Dark theme is unchanged (#2461, fixes #2449).
- On macOS,
agent-deck healthsamples the process's own descriptor count again. The previous/dev/fdread failed once the Go runtime's kqueue netpoller existed, so every sample stored null and thedescriptors <512budget could never fire; the count now comes fromproc_pidinfo, with nolsofand no filesystem events (#2462, fixes #2427). agent-deck updateleaves a launch agent that is disabled in launchd alone instead of retrying its bootstrap after every update: the hygiene step consultslaunchctl print-disabledonce per run, prints one line naming thelaunchctl enablecommand, drops the label from the pending marker, andupdate --checkreports it asdisabledrather thanbootstrap failed. Enabled agents behave exactly as before (#2464, fixes #2457).- Conductor
NEED:alerts reach Telegram, Slack and Discord again when the OS heartbeat daemon is installed (the default). The bridge used to disable its own loop in that mode, and that loop was the only reader of heartbeat replies; it now runs a read-only scan each half interval, forwards freshNEED:lines with the existing escalate/retire policy, keeps per-conductor counts under the conductor directory, and skips unchanged replies by hash (#2437, fixes #2426, thanks @koenzhao). - Web UI: a stopped session's terminal can be brought back in place. The "Restart session" button on the tmux-not-found banner is clickable again (it sat under xterm's link layer), and the terminal reattaches whenever a start or restart for the open session succeeds from the header, the sidebar, the banner or the CLI, or its status goes live over the event stream; switching sessions is no longer the only way out (#2467, fixes #2432).
Changed
- A child's finished turn is now classified from its transcript before anything reaches the parent (#2469). The notify-daemon used to key a turn on the transcript file size, so every background sub-agent or background Bash completion inside a child (a
<task-notification>turn) looked like a new turn and woke the parent with a text-less record: one conductor was woken 161 times in 160 minutes with nothing to act on. Each turn now gets exactly one record, tieredurgent(completion sentinel, error, a question, or new text in a turn a human or asession sendstarted) orinfo(new text in a turn a background task, a system injection or the child's own inbox/heartbeat prompt started); a turn whose text and state did not change is counted as noise and never recorded. Records carry the child's new text (text, capped by[inbox] max_text_bytes, default 600 B), its hash, the trigger and the turn uuid, so the parent acts on the record instead of re-reading the child;inbox drainprints the text in both modes and the Stop-hook block includes it. Onlyurgentrecords wake an idle parent ([inbox] wake_on, default["urgent"]);inforecords stay durably queued and ride the parent's next turn. A sentinel turn is onefinishedrecord instead of a transition record plus a finished record. Every recorded turn is also appended to a per-child journal underruntime/turn-journal/(bounded by[inbox] journal_keep, default 256 lines). Records from older producers carry no tier and keep today's behaviour. - A parent now receives its pending inbox records at the START of a turn: the
UserPromptSubmithook (installed synchronous from this release, healed on the daemon's next start) drains the durable inbox and injects the records, text included, as[agent-deck inbox]context, so the turn a wake, a heartbeat or a human started already carries every pending record and the model acts with zero tool calls. The wake line itself now names its record ([INBOX] urgent · <title> (<id>): done (ok) — <summary>) instead of a fixed sentence. The Stop-hook block at a turn boundary fires only for urgent records (info waits for the next turn or the digest), and when it fires it carries the queued info too. An idle parent with info waiting longer than[inbox] info_digest_minutes(default 15) is woken once with a digest line. The[agent-deck fleet]snapshot is injected only when it changed since the last prompt (always on SessionStart) and no longer lists a child as completed while it is running again (#2469). - The agent-deck skill loads a short core first and the detail on demand from
references/; the description keeps its trigger terms (session, sub-agent, MCP attach, git worktree) and the#974alias rows are corrected (#2429, thanks @kickinrad).