Feature Catalog
This page is the detailed capability ledger for agent-doc. It records user-visible capabilities and workflow invariants that are useful for operators, release notes, and implementation audits. It moved here from the project README, which now stays a short introduction.
Instruction-surface rules in AGENTS.md that say to keep
“README.md” aligned with a behavior refer to this catalog (and the
architecture reference) since the move.
Overview by workflow layer
- Document model — template components, backlog archival, exchange boundaries, snapshots, durable captures, and component-aware baseline guards.
- Write and merge pipeline — state-machine intents applied to Lazily current state, typed PID-scoped editor delivery, template patching, exact response replay, strict closeout, and selective git commits.
- Agent orchestration — harness-specific routing for Claude, Codex, and OpenCode, prompt contracts, model attribution, direct-run dispatch, sequential/parallel/DAG orchestration, per-item enqueue markers, and lower-agent job packets with target write scopes plus tsift context/graph acceptance sidecars.
- Queue ownership stays visible — each queue row is continuously projected from durable state:
📥pending/unclaimed,🟡claimed/dispatching,🚧running,📤reported/outbox awaiting coordinator integration,⚠️lost,🔄reconciling, or❔degraded/unknown. Worker-owned rows include the normal-bracket[#owner#N]attempt identity (for example,[#subagent:sdk#2]);🙋 [#request-id]composes with that state when operator input blocks progress. Legacy double-bracket attempt markers remain readable. Manual marker edits repair on preflight/restart, and a strike is terminal only when durable closeout state agrees. - Session memory —
agent-doc memory index/searchrecords backlog, review, done, icebox, and exchange history in.tsift/memory.dbthrough the sharedtsift-memorylibrary for local dedupe and resolved-before checks. - Tmux and editor coordination — route/sync/start/claim, project-controller actor state, session drift repair, startup-miss handling, fast mixed-root exact-visible pane projection, passive sync, stash/rescue, and editor plugins.
- Mid-turn steering — operator edits to
agent:queueand the exchange reach a running turn as they settle: aPostToolUsehook (agent-doc hook steering-post-tool-use, Claude Code and Codex) injects them verbatim after each tool call, each with a typeddispatch(address_nowfor exchange prompts, edits to the current item, and ordinary queue work explicitly sent with Run Agent Doc;drain_after_currentfor passively observed queue work that runs in order after the current item;subagentfor#subagents-tagged work).agent-doc steering <FILE> [--json] [--peek] [--follow]exposes the same surface to other harnesses and monitors. Every settle/delivery decision the typing-completion gate makes is logged with its features tostate.dband labelled premature / late / on-time from what the operator does next (#steergatelog);agent-doc steering dataset --jsonexports it. An online-learned gate (#steergateperceptron, logistic regression over those features, weights per operator instate.db) answers first: send at p >= 0.8, hold at p <= 0.3, the deterministic tier in between. Its seed decides exactly like the deterministic gate, unbalanced delimiters always hold, and the max-hold always delivers;agent-doc steering --explainprints the weights and each feature’s contribution to the latest decision, andagent_doc_steering_learned_gate = falsein.agent-doc/config.tomlturns it off. Each logged decision also keeps the last 280 characters of the item text it judged (text_tail, localstate.dbonly), soscripts/steergate-model-eval --datasetcan score a pretrained end-of-turn text model (Namo, turnsense) against the logged rules+perceptron on the real pause points before any model ships (#steergatenamo); without--datasetit bounds the same comparison on a proxy corpus of the operator’s own submitted prompts. - Operational safety — preflight recovery, session-check guards, hooks, Codex stop-hook recovery, required-SSH/network capability proofs, accretion context, and explicit manual-repair rules.
Session, layout, and supervisor notes
Supervisor freshness warnings are pane-local and refresh on binary-state changes, including child-preserving upgrades, without changing the child’s turn title. Automatic editor layout sync retains proof of outgoing pane assignments across tab switches; layout-reuse invalidation does not erase controller ownership. Renaming a managed document preserves its live pane when the session identity has one unambiguous old-path owner, and editor routes await newer layout state that still covers the routed document instead of racing it with republication.
Full catalog
- Compaction-resistant skill router — installed Claude/Codex/OpenCode
SKILL.mdfiles are generated from one small table of contents. The router survives context compaction and requiressession-cycle.md; that bundled runbook owns the ordered closeout spine and routes branch work to focused runbooks, with coverage tests preserving the former inline invariants. - Template mode — named component regions (
<!-- agent:name -->) updated independently; inline attrs (patch=,max_lines=) >components.toml> built-in defaults - Completed backlog archive — reaped tracked work is stored in canonical
agent:done, or in an explicit repo-relative.done.mdfile viaagent:done archive=...;agent-doc migraterewrites oldagent:backlog-doneandagent:pending-donetags - Review-pending tracked work —
agent:reviewholds code-complete[/]items awaiting human review.--pending-gatemoves backlog items into review,--pending-ungatemoves them back,--doneaccepts review items, and optionalreview_done_guardcan warn or fail when a project requires review before done. - Session memory retrieval —
agent-doc memory index/searchstores current backlog/review/done/icebox items and exchange response summaries in.tsift/memory.db, enabling deterministic local checks for already-tracked or already-resolved work without embedding tsift’s heavy codebase index. - CRDT merge — yrs-based conflict-free merge for concurrent edits between agent writes and user edits; the markdown AST layer also defines a structured
.yrsoverlay schema and node-keyed component mutations so queue/backlog items can be consumed, deduped, reordered, and enqueued by semantic node identity instead of text lines - Lazily-first writes — every edit is a durable named intent applied by compare-and-swap to Lazily current state, then delivered through the registered PID-scoped editor socket. Component patches carry explicit
op/node_idmetadata and target-node source proof, so unrelated operator edits survive rebase while cursor position and undo history remain intact. - Tmux routing — persistent per-document agent sessions;
routedispatches to the correct pane or auto-starts one using the active harness’s trigger shape (/agent-docfor Claude Code, plainagent-docfor Codex); reconciler always runs (no early exits) handling 0/1/2+ panes uniformly - Frontmatter harness changes hand off live — changing
agent:from Claude to Codex, OpenCode, or back is accepted as a safe-boundary handoff. Route never sends the pending prompt into the old harness; the supervisor preserves any active turn, replaces the child at the next idle boundary, and auto-triggers the document on the new harness. Queue pause holds the handoff until resume without requiring a supervisor restart. - Repository-locked issue filing —
agent-doc admin issue --title ... --handling human-only|agent-assistedfiles through the authenticated GitHub CLI intobtakita/agent-doc, adds a visible and machine-readable handling policy, supports bodies from text/files/stdin, labels, JSON, and a no-network dry run. The generic top-levelagent-doc issuename stays reserved for a future caller-repository action. - Controller-backed admin controls —
agent-doc admin inspect,admin queue pause|resume|drain,admin reap,admin handoff, andadmin repair-projectionrun through the project controller instead of editing sidecars directly.admin inspectjoins live editor endpoints with actual CRDT memberships aseditor_replica, so a ready/fresh actor with a missing or flapping replica is visibly unhealthy and includes a remedy. Document-scoped mutations require the observed actor generation; stale requests produce typed rejected receipts.admin reap --all-stale --idle-for 5dadditionally reclaims actors whose document and actor transition have both been idle for five days, including parked live panes. Queue pause/drain state is stored in.agent-doc/state.db, and dispatch reports durablequeue_pausedoractor_busy_drainingbackpressure receipts before any tmux/supervisor input is sent. An acceptedadmin queue pausesuppresses the unattended supervisor idle-queue watch auto-injection on ago-mode queue (#qpausego): the idle-watch stops injecting triggers while the pause is active, andpreflightsurfacesqueue_paused: true,queue_pause_reason, and pause-awarequeue_continuation_guidance. It does NOT stop the attended in-session/loop(which keeps draining real queue work) — usequeue: pausefrontmatter /--- stopfences for that;admin queue resumeclears the pause flag and reason. - Route-owned panes close after successful idle cycles — fresh panes created by
routerunagent-doc start --route-owned, so the supervisor stops and reaps the pane after the first new document cycle commits once the supervisor has stablereadyprompt state or direct pane output shows the harness is back at an idle prompt, and the document has no live backlog, queue, dirty edits, or unresolved exchange-tail prompt. Explicit blocking prompt states still keep the pane alive. If the fresh route never starts a cycle, the startup-miss marker is still recorded, but the just-created idle pane is killed instead of becoming a stranded registered owner. - Ready/busy owned panes reconcile instead of stalling forever — when the actor record, supervisor actor state, and controller lease all say
readybut a stale Codex renderer cue still reports the pane asalive-busy/prompt_ready=falsefrom a queued-draft footer, route-owned completion and the idle-queue watch debounce the conflict for the same short window used by stale-busy idle repair, logowned_pane_ready_busy_conflict, and let queued work continue. Genuine active turns, permission prompts, shell search, hook-review prompts, help screens, and clean-exit prompts remain protected.agent-doc session statusprints the conflict and points to bounded reconcile/clear recovery rather than pane restart. - Managed reroutes keep one tmux submit boundary — once a Claude/Codex session is running under
agent-doc start, route keeps the managed acceptance/queue paths on supervisor IPC, but dispatch-only editor reroutes and file-scoped/clearnow submit through the live pane’s tmux input path instead of mixing direct PTY writes and supervisor-only reopen delivery. Tmux-bound command injects are normalized once and submitted once through the centralized submit profile: Codex, Claude, OpenCode, and default harnesses use normalized text plus a namedEnterkey in one tmuxsend-keys -t <pane> <text> Enteroperation. Literal\r/\nsubmit bytes are reserved for raw child-PTY fallback writes, not tmux. - Queued editor reruns preempt the auto-loop — a dispatch-only editor rerun queued behind a busy actor in
agent:queueis inserted ahead of pending active-loop items (priority preempt,#jb-run-preempt-autoloop-priority): a manualRun Agent Docjumps the queue rather than landing at the tail. Route-owned queue writes are canonical plainagent:queuewrites: they never addauto, and they strip a legacyautoattribute from any queue tag they touch. The priority insert lands after any leading queue directive (preset / start fence) and never supersedes a lone active-loop prompt, so the pending item is preserved (the manual prompt runs first, then the pending item) instead of being replaced. If an explicitRun Agent Docfinds a busy authoritative actor and the document already has an explicitly startable inactive queue head (marker-sidego/start, a start fence, or legacyauto), route promotes that head toqueue_active: trueand syncs the snapshot instead of failing as a silent no-op; unattended continuation after closeout still requiresgomode, neverqueue_active: truealone. Slash-only queue heads such as/clear, ignoring surrounding whitespace, are treated as command handoffs for the supervisor rather than assistant prompts, so preflight/plan/run do not open an exchange response cycle for them. A non-interruptingsession clearon a busy active auto-loop records one deferred queue context-clear projection for the next proven idle boundary; repeated clears before delivery report the existing deferred clear and do not inject another/clear. - Owned PTY output has a real screen model — managed supervisors feed filtered child output into an
alacritty_terminalviewport, and prompt/help/protected-input checks prefer that owned screen state before falling back to the raw byte ring. Cursor rewrites and line clears are interpreted like a terminal instead of tmux scrollback text. - Fresh reroutes keep the new pane authoritative — after route creates a fresh pane for a document, later same-session registry churn cannot hand the reopen back to an older pane and make the new pane disappear from the
agent-docwindow - Late associated-pane proof still fails closed before auto-start — if stale registered-pane cleanup exposes a live legacy associated pane later in the same route pass, the normal route path now stops with explicit inspect/claim guidance instead of silently cold-starting around ambiguous ownership
- Codex forwarded
Ctrl+Cand EOF/Ctrl-D now always hand control back to the operator — after a stdin-forwardedCtrl+Cthat terminates the child, or a forwarded stdin EOF/Ctrl-D, agent-doc returns to an explicit canonicalEnter/qprompt mode even when the parent harness keeps stdin in raw-ish mode. Ctrl+D + Enter resumes the document’s exact conversation; Ctrl+C + Enter remains an explicit fresh restart. - Missing Codex resume sessions recover fresh — when Codex definitively reports that the requested saved-session ID does not exist, agent-doc removes only that matching
resumepointer and immediately starts a fresh session. Safe replica-refresh suffix duplication is normalized in the same authority CAS as pointer removal, so malformed binary scaffolding cannot retain the dead ID and repeat the error on later restarts. If the operator already removed the pointer, the running supervisor notices and discards its cached resume arguments too. Ctrl+C also stops the supervisor during crash backoff instead of being swallowed by raw terminal mode - Only genuinely promptless clean exits auto-recover — if a fresh/fresh-restart Codex child clean-exits before it ever surfaces an idle prompt and no operator
Ctrl+Dwas forwarded, agent-doc still treats that as failed startup provenance and restarts fresh automatically instead of stopping for the quit prompt - Starting actor reroutes promote only dispatch-ready panes — when the controller still reports the authoritative actor as
starting, route polls the current actor generation until the live pane shows a harness-specific dispatch-ready prompt, promotes that same actor toready, and then uses the normal managed or dispatch-only send path. If the pane never becomes dispatch-ready, both route modes fail closed before sending tmux or supervisor input and persist one typed diagnostic with elapsed time, pane id, generation, actor state, supervisor health/runtime state, prompt-ready status, and last lifecycle transition. Repeated reroutes for the same stuck pane/generation coalesce behind that saved timeout instead of writing duplicateroute_authoritative_actor_starting_not_readyrecords. Because that saved timeout is sticky, a reroute that finds a blocked-by-starting-timeout actor polls that same pane/generation for a dispatch-ready prompt up to the harness recovery budget before failing closed — so a healthy but slow-starting harness (for example a heavy Codex model that takes seconds to present its idle composer after a supervisor restart) recovers within the same reroute instead of dead-ending on a single capture. A busy pane never satisfies that proof, so the bounded poll preserves the promote-only-proven-idle rule; when the proof appears, route clears the saved timeout, promotes the actor toready, and continues through the prompt-gated submit path. If the supervisor refreshes the actor toclosedorblockedduring that wait, route stops immediately and reports that terminal state instead of timing out against stalestartingstate. - Dispatch-only reroutes keep editor runs on proven live sessions — after
agent-doc session clear <file>or when a Codex session lacks a fresh capability-proof log event, the next editor-triggeredagent-doc route --dispatch-only --plain-trigger <file>still sends the plainagent-doc <FILE>reopen through that same live pane’s tmux input path when supervisor/runtime state remains healthy. If the authoritative actor’s supervisor is unreachable or missing runtime actor state but the actor pane is still the current registered/live owner, dispatch-only keeps that pane as the recovery target, logsroute_dispatch_only_authoritative_degraded_direct_pane, and only submits after the normal direct-pane readiness checks pass. - Clear Session Context during a running turn is queued, not refused — when the clear guard proves a harness turn live (
harness_turn_live=true) and the document’s supervisor owns that pane,agent-doc session clear <file>types nothing into the turn, queues one clear, and exits 0 withsession_clear queued for ... ui_outcome=queued; the supervisor delivers it when the turn ends, and drops it if a newer prompt starts first, the session restarts, orinterrupt-clearruns (#clearqueuedliveturn). Without an owning supervisor the refusal namesunblocker=wait_for_turn_end_no_supervisor_to_queue_clearand is not filed as a dogfood fix prompt. - Dispatch-only reroutes trust shared Enter delivery across harnesses — if a live Claude Code, Codex, or OpenCode pane accepts
agent-doc route --dispatch-only <file>through the shared tmux text+Enterpath but no stronger dispatch-start proof arrives inside the proof window, route completes withproof=accepted proof_scope=accepted_onlyinstead of returning a hard IDE failure. Codex hook proof and OpenCode pane-state proof are still logged as strongerdispatch_startevidence when available. - Direct pane submit telemetry separates input acceptance from dispatch proof —
route_latency phase=direct_pane_submitrecords whether tmux input acceptance was observed, whileroute_latency phase=dispatch_start_proofrecords harness proof. Empty first captures must stay stable before acceptance so a delayed Codex composer draft can still be seen. If Codex hook tracking later proves the prompt was consumed or submitted, an unobserved direct-pane acceptance is labeledacceptance_unobserved_dispatch_provenand uses the tmux/control-mode acceptance budget instead of reporting a false submit timeout. If Codex later has only accepted-without-dispatch-start proof but the same prompt is visibly drafted, route sends one lateEnterretry and logsroute_submit_late_resubmit. Before appending a new direct-pane trigger, route also detects the same trigger already drafted in a Codex/Claude composer and sends bounded bareEnterretries instead of stacking another copy; stale scrollback is ignored when an idle prompt appears below the trigger. - Run Agent Doc cannot overtake closeout — every routed trigger, including the plain dispatch-only editor action, drains any prior open cycle through the controller projection before tmux submission. An unresolved response or retained component write fails closed, while a settled plain trigger keeps its single-submit transport behavior.
- Plain dispatch-only reopens fail closed on a busy actor instead of silently focusing — an editor
Run Agent Docreopen (no prompt-bearing work) against abusyauthoritative actor focuses the pane but must not return focus-only success, which would report a routed run even though nothing was submitted (#jb-run-agent-doc-command-route-miss). Route fails closed with the busy-not-ready diagnostic (route_dispatch_only_authoritative_actor_busy_focus_only_not_dispatched) carrying thethe authoritative actor is busy did not return to a dispatch-ready promptmessage, and the JetBrains plugin surfaces that as a “session still running” notification immediately rather than after silently re-waiting the ready timeout once per retry. The narrow exception is an explicitly startable inactive queue head; route may activate it, but unattended continuation after closeout still requiresgomode. Only a still-bootingstartingpane is silently retried. - Dispatch-only proof scope is explicit — route ops logs include both
proofandproof_scope; Claude Code dispatch-only routes remainaccepted_only, hook-backed Codex can report consumed/submitteddispatch_startproof, and OpenCode can reportproof=pane_state_changed proof_scope=dispatch_startafter its pane leaves idle chrome - Claude artifact state is shape-classified, not label-classified — a completed artifact attached to an idle composer renders as a generic
⧉ <session-owned label>chip and is skipped while locating the real❯/permissions prompt. The active picker remains blocked only by itsEnter to openplusclaude.ai/code/artifact/...evidence, so arbitrary artifact names never become routing heuristics. - Dispatch-only reroutes now absorb same-file restart handoffs before surfacing a boot-window refusal — if the first starting-pane ready probe times out but the supervisor immediately restarts the same session in-place or hands it to a new pane for the same file, route follows that newer run instead of pinning the stale pane and surfacing a false
still bootingerror to the editor. OpenCode uses a longer harness-specific redraw budget for this startup-window prompt gate so JetBrains reruns do not fail just after the idle splash becomes visible. - Dispatch-only reroutes now fail closed on cross-file pane reuse before any rebind lands — if the candidate pane is still registered to another document, route refuses the reopen instead of transiently superseding that other file’s pane and then repairing the registry afterward
- Optimistic fresh-restart retries stay traceable — if a routed Codex fresh restart never gets back to a dispatch-ready prompt, agent-doc records a
startup_misson the original routed pane with the canonical absolute document path instead of silently redirecting the retry through a replacement pane - Stale startup-miss markers clear from the document’s current owner — if a later pane/session is now the registered owner for the same file,
start,route,sync, andsession-checktreat the older pane’sstartup_missmarker as stale once the current owner logs a newersession_start, even if that handoff rolled the session id - Managed Codex capability proof is explicit and fast-path optimized —
Codex documents opt in with frontmatter
managed_proof: true; omitted or false keeps the gatenot_requiredeven when launch args include network, SSH, or extra writable roots. Enabled proof children are ephemeral, skip project rules, use low reasoning effort, and combine simultaneous network and writable-root checks in onecodex exec --jsoninvocation. OpenCode proof selection and the existing contract fingerprints, retry gate, timings, and status reporting are unchanged. - OpenCode prompt labels stay user-facing —
agent-doc prompt --allreportsPermission requiredfor horizontal OpenCode permission controls when no explicit← ...question line is present, so external prompt consumers never display earlier shell command text or ANSI-literal prompt fixtures as the question. First-party JetBrains and VS Code plugins no longer poll this surface. - Codex hook-review startup chrome blocks dispatch — if Codex starts with a
hook needs review/Open /hooks to review itwarning, route/start readiness treats that as an operator-action blocker and refuses to inject routed input, even when a later managed capability-proof line saysstatus=proven. - Required SSH preflight probes no longer touch shared multiplexing state — when a document declares
required_ssh_targets, the pre-launchssh ... truecapability checks now force isolated probe flags (ControlMaster=no,ControlPath=none,ClearAllForwardings=yes,PermitLocalCommand=no) so proving SSH for a managed session cannot create or reuse shared control sockets that might affect later operator shells - Required SSH drift detection now covers bare socket EPERM too — when a document declares
required_ssh_targets, resumed Codex recovery treatscommand_executionoutput likesocket: Operation not permittedas required-SSH capability drift when the same event proves SSH command context for one of those targets; localhost/CDP EPERM remains on the separate browser-capability retry path - Resumed required-SSH streams now drop stale prelude text before fresh retry — when a resumed Codex turn for an SSH-gated document emits assistant prelude text before the failing SSH command, agent-doc buffers those early resumed-session chunks until required SSH is proven safe or the turn completes, so a required-SSH fresh retry can discard the poisoned prelude instead of leaking it into the committed response
- Passive mixed-root sync stays fail-safe — when
sync --no-autostartleaves any visible file blocked, agent-doc preserves the current visibleagent-docwindow layout and warns instead of collapsing the remaining foreign pane set into a new authoritative layout; if the newly focused file is already visible in that preserved window, sync still reselects its pane - Passive stale-column gating preserves the whole editor surface — when a safe-passive exact-visible pass temporarily excludes any requested column because its supervisor is stale, agent-doc keeps the current tmux layout instead of realizing the admitted subset. The recycle-settled generation retries the complete surface; explicit full/manual sync may still realize a non-empty admitted remainder as part of operator repair
- JetBrains mixed-root editor surfaces have one controller authority — after the plugin successfully republishes a visible surface through a different Project Controller root, it forgets the prior root so two retained layout projections cannot compete for the same tmux window. On plugin restart it recovers candidate roots from the open markdown set and retires projections retained by the previous plugin process. IntelliJ split restoration waits until every editor window has selected a file before publishing, and component focus uses only the targeted pane-selection lane
- JetBrains surface publication cannot retire itself — each published surface is positive liveness evidence even when IntelliJ’s detached-frame window enumeration lags. The plugin adds the current/published surface to an available live-window snapshot before retiring closed siblings; no backend windows remains unknown Remote Dev liveness and retires nothing, so later tab observations in the same generation remain accepted
- Fresh controller routes preserve live multi-pane layouts — when a restarted controller has no retained layout and the project has no
tmux_sessionpin, a one-column editorensureroute resolves the real tmux session from its registered supervisors and merges over every live in-project pane.controller_editor_route_merge_basisreports both the session source and any explicit fall-through reason, so an unobserved layout cannot silently masquerade as a valid one-column basis - Manual Sync Tmux Layout uses the doctor repair path first — full
agent-doc syncdelegates focused session-document repair tosession doctor --repairlogic before reconciling editor panes, so it can close recoverable crash-left commit boundaries where the visible document and snapshot already contain a response thatHEADlacks, recreate0:agent-docfrom a currently selected or explicitly suppliedstashwindow, and normalize adjacentN:stashoverflow; passive--no-autostarteditor sync keeps that repair step explicit - Layout repair re-fits agent-doc windows a manual size pin holds small (GH #244) — tmux’s
resize-window -A(often bound to a “fit window” key) leaves a per-windowwindow-size manual, so a later terminal resize leaves the window small and dot-padded. Layout repair now releases that pin on agent-doc’s ownagent-doc/stashwindows when the window is smaller than every attached client, logginglayout_repair_window_size_pin_released; your own windows, inheritedmanualpolicies and sessions with no attached client are left alone - Manual Sync Tmux Layout creates and routes missing panes atomically — when the requested document has no live pane, the full sync path creates and registers one in the resolved tmux session, waits for its harness composer, and submits the document route before its controller command becomes terminal; JetBrains waits for that outcome and displays pane/start/route failures directly
- Dispatch-only startup submits are prompt-gated — editor reroutes no longer type a bare reopen into a startup-window pane until it shows harness-specific idle evidence; a Codex/OpenCode model/context footer is dispatch-ready only when busy cues and protected prompt input are absent. While route owns that pane-input window, it records
RouteSubmitStarted/RouteSubmitSettled/RouteSubmitBlockedthrough the project-controller route projection instead of marker files, so supervisor idle-queue context resets and visible/clear//newdrafts yield until the submit window settles. - Queue context-clear gates are controller projections — explicit operator clears and queued slash-command clears publish
QueueContextClearStarted/QueueContextClearSettledfacts instead of.agent-doc/context-clear-in-flightmarker files. Busy-loop operator clears publishQueueContextClearDeferredinstead of.agent-doc/deferred-clearsmarker files until idle-watch can submit the clear and promote the projection toStarted. Plain manual clear cooldowns use the same context-clear projection source instead of.agent-doc/queue-cooldownsmarker files. The supervisor idle watch reads the lazily-backed queue projection to avoid stacking another clear or draining an agent-doc trigger into the same composer, and it settles that projection after the cleared pane has been idle for the cooldown window. - Queue drain-stall detection uses controller projections — clean closeouts that still require queue continuation publish
QueueDrainStallContinuationRecordedthrough the project controller instead of writing.agent-doc/drain-stallmarker files. The next preflight reconciles and clears that lazily-backed projection, while supervisor-driven drain progress clears it before it can false-firequeue_stall_detected. - Queue auto-clear between items (
#bgclearpolicy) — an activeagent:queueruns each item in a fresh agent context by default. Bareclearis the positive, discoverable declaration used by the default template; omission remains enabled for existing queues, and legacydisable-auto-clearopts out. After a direct queue item’s proven closeout, the in-session drain (Claude/loop, the Codex Stop hook, OpenCode’s in-turn drain) hands the turn boundary to the document’s ready supervisor. Asubagents/fan-outqueue instead waits for the next safe idle boundary after every in-flight claim settles. The supervisor resets the context once —/cleartyped into the live Claude Code process and/newinto OpenCode, so background agents and shells survive; a fresh restart for Codex, whose/clearexits the process — and dispatches the next head to the fresh agent. It never clears mid-turn, over an unsent composer draft, with operator steering unanswered, or while a subagent claim is in flight; with no ready supervisor the drain simply continues in the same context. Preflight reportsqueue_auto_clear. A clear does not shrink the document: session-accretionblockmeasures the exchange size, which only compaction reduces. - Codex Stop continuations own active auto-queue handoff — Codex’s Stop protocol names every same-turn continuation
Blocked by hook. Healthy auto-queue handoffs therefore lead withQueue continuation, not an error:, name the next queue prompt, and give one terse same-turn persistence instruction; suppressed background context-reset reasons go toops.logonly, never into the operator-visible payload (#codexstopterse). When queue auto-clear hands the boundary to a ready supervisor, the hook allows the stop instead of continuing in-pane. Fresh post-commit queue or exchange steering follows the same receiver-first rule: a ready supervisor reacts at the idle boundary without a Stop continuation, while a missing or stale supervisor keeps the safe in-pane successor fallback (#steeringwake). While that auto queue and Codex turn are active, a dispatch-only editor reopen coalesces behind the Stop hook instead of typing a competing trigger into the composer. - Prompt steering survives an empty abandoned Stop preflight — when an initial Codex Stop attempt fails before capture and owner release abandons that empty preflight, a recursive Stop with unresolved prompt-bearing steering opens a durably marked successor cycle and continues it in-pane (
#stopsteeringafterabandon). The following recursive Stop may close only that successor, so the operator does not need to re-enteragent-doc <FILE>and unrelated recursion remains bounded. - Preflight observes the live document model before surfacing editor-authority failures — when a live editor owns a document but the CRDT relay model is absent or not converged, current-document resolution observes the retained Lazily projection and live relay until they reach a fixed point. It emits no editor republish or re-registration request. A bounded failure is reported as document-model startup/reconciliation guidance while disk remains non-authoritative.
- Controller restarts repair editor replicas even when transport stays up — the controller sends one targeted rebuild signal for every stranded registration, including peer-pull-capable JetBrains editors whose reconnect hook may not run after a transparent restart. The idle watcher adds one bounded missing-replica observation before its 30-second backoff, while high-frequency liveness reconciliation no longer floods
ops.log. - Plain Markdown never enters JetBrains replica retry loops (GH #282) — open-document and local-edit registration paths classify the current text before controller transport. A file without
agent_doc_*frontmatter or an<!-- agent:marker clears any armed registration retry and completes its local splice batch terminally; adding a marker in a later edit is re-evaluated immediately rather than blocked by sticky state. - Editor document switches focus immediately, then reconcile in the background — automatic editor sync first submits a latest-wins Project Controller focus command without waiting on debounce, sync-lock acquisition, prune cleanup, or tmux-router reconciliation; a real selection event still runs the guarded
sync --no-autostart --exact-visiblepass afterward so the selected tab can replace the old pane on that editor side - JetBrains focus projection captures its editor surface on the EDT (GH #291) — automatic focus handoff resolves the active
EditorWindowand its stable surface id while handling the editor event, before scheduling transport work. The background task retains the generation, active-window, lifecycle, and disposal gates without calling IntelliJ’s EDT-onlycurrentWindowor editor-window surface APIs. - Automatic focus recovery shares the route crash circuit breaker — a missing selected-document pane may provision one bounded replacement, but Project Controller
ProvisionOnlyrecovery first records its typed missing-pane observation, then consumes the same persisted recent pane-loss projection as normal routing and fails closed instead of repeatedly rebinding a crashing session; explicit supervisor recovery remains available - JetBrains socket patches compute native results off the EDT — patch delivery captures an immutable document proof on the event thread, performs native replay/component/normalization work on the listener worker, then re-enters the EDT only for the generation-fenced minimal edit before publishing the content receipt
- JetBrains Remote Dev classifies flat backend evidence off the EDT — the zero-backend-window path snapshots remote client editor evidence on the event thread, then classifies it as focus/liveness-only on the generation-fenced surface worker; only an exact connected-frontend vector can change structure
- Controller-local actor proof keeps passive tab sync live — the controller-owned exact-visible sync reads its authoritative SQLite actor row locally and swaps an already-running hidden pane into view; standalone passive sync still avoids a nested Project Controller actor-binding RPC
- Exact visible editor snapshots do not resurrect stale siblings — automatic editor syncs pass
--exact-visiblewith--no-autostartwhen they have the full visible markdown projection, so a one-file editor state remains a one-pane tmux projection instead of expanding from remembered column memory - Passive editor sync skips stash scans before reconcile —
sync --no-autostartstill prunes stale registry rows and retained dead non-stash panes, but it skips stash-window and stash-pane cleanup so tmux-router can detach extra visible panes immediately after a document switch instead of waiting on orphaned stash scans - Passive sync proceeds around open closeouts — when
sync --no-autostartneeds to attach a newly requested pane while an already-visible unwanted pane owns an openpreflight_started/response_captured/write_appliedcycle, agent-doc keeps that closeout pane alive but still allows DETACH to stash it, so the requested document can attach/focus without temporary visible pane growth - Editor sync lock contention is bounded and self-healing — if an older sync process is stuck, later selection/layout sync commands wait only for the contention budget. Safe-passive sync may already have applied the pre-lock pane handoff, then logs the retry marker and returns without further auto-start, tmux reconciliation, or post-lock hidden-pane focus changes; editor plugins treat that marker as deferred and retry only the newest superseding selection instead of marking stale state applied. Lock acquisition blocks in the kernel on
flock(2)(no userspace polling) and is released automatically when the holding process exits, so a dead or orphaned owner can never wedge the lock — autosync/manual layout sync recovers without/procorphan reaping or operator process cleanup - Open closeout panes stay alive during sync reconcile — if an unwanted pane still owns a document with an open
preflight_started,response_captured, orwrite_appliedcycle, sync logs that state but lets tmux-router stash the pane; stashing is non-destructive, so closeout can continue without forcing a third visible pane into a two-document editor projection - Cross-document child routes preserve the editor surface — a no-layout route launched from explicit live process context inside another document’s managed pane may dispatch only to the target’s proven existing pane; it never rescues that pane from stash, changes focus, lazily adopts a pane, or cold-starts one, so background closeout/queue work cannot append a third pane after a two-pane editor projection has converged
- Stashed owner re-entry is background delivery — a queue, supervisor, or hook route launched from a document’s own pane while that pane is parked in
stashmay submit into that existing pane without surfacing it. Route focus obeys the fail-closed predicateselect-pane ⇔ standalone_foreground authority ∧ proven foreground placement; background/controller-owned routes and stash/unproven targets never issue the underlyingselect-window/select-paneeffect, while explicit editor focus remains sequenced by the controller layout plane - Closeout drift noise is narrower — session-check no longer treats plain content-edit drift as an unstarted response cycle, and
content_oursprompt-prefix fallback preserves unprefixed agent response lines already committed inHEADinstead of creating a follow-up normalize commit - Sync now refuses editor-provided non-
agent-doctmux windows — if the editor passes a tmux window target that is not actually anagent-docwindow and the target session has no discoverableagent-docwindow by name, sync fails closed and preserves layout instead of reconciling remembered docs onto the wrong window - Current tmux session resolution is pane-owned — route, sync, preflight, and parallel dispatch resolve the current session from
TMUX_PANEwhen available, so another attached client’s selected session cannot pull the active agent-doc window into the wrong tmux session - Route-owned panes start where a client is watching (GH #243) — with no
TMUX_PANE(the project controller) and notmux_sessionpin, tmux’s ambient session is used only when a client is attached to it; a client-less session yields to the session the most recently active attached client shows. A cross-root editor route keeps its delegated layout lease in the main-window owner through child dispatch, so passive focus churn cannot stash the target in that interval; the owner projects the newest deferred surface when the child releases the lease. A route that still starts or dispatches into a pane no client displays appends a[route] pane-not-visible:notice with the exact attach/reveal command (JetBrains shows it as a warning instead of a silent success), andagent-doc start --forceretires the superseded agent-doc supervisor and its harness instead of leaving them running beside the new one. A foreground route likewise retires any duplicate supervisor pane for the document beside its authoritative actor pane, so one document never has two live harness panes (a bare harness agent-doc did not start is never touched) - Normal route/start/sync never re-elect owners from pane heuristics — the normal path asks the project controller for the authoritative actor binding. Session-log owners, historical rebind events, and generic same-file process-tree matches remain repair diagnostics, not owner-election inputs.
- Project controller IPC is bounded against stalled clients — controller clients time out instead of blocking forever waiting for a response, the server handles accepted clients independently so one idle socket cannot monopolize
.agent-doc/controller.sock, and readiness checks release their socket before issuing follow-up RPCs. - Supervisor lifecycle reports now go through the project controller —
agent-doc startlazy-launches the project controller, records the starting actor generation and supervisor lease, and reports prompt-ready, busy dispatch, waiting-input, blocked, and closed transitions through controller IPC with stale session/pane/generation rejection. A newer register/heartbeat from the same supervisor lease can replace aClosedactor for the same pane, which lets a reopened Codex/OpenCode child in the same route-owned supervisor become authoritative immediately instead of replaying the closed session.session status/doctoralso refresh the controller lease heartbeat from a live supervisor only when the IPC state proves the same actor session, pane, and generation.session status <FILE>additionally prints direct live-pane evidence (alive-idle,alive-busy,closed-clean, orprojection-stale) from tmux current-command and recent output so projected controller state cannot hide a still-running pane; when direct evidence is idle but projections remain busy, status/clear reconcile the actor and controller lease back to ready. File-scoped restart refusesalive-busypanes. Every turn stage independently detects a proven-stale supervisor and writes the same idempotent, CRDT-checkpointed recycle request; the controller waits for a safe idle boundary before replacing the process, and no stale marker is inserted into the document. This integrity recovery applies even when proactive recycle polling is opted out. File-scoped clear is an explicit operator action: it does not refuse solely becausepane_current_commandisagent-doc, but it still refuses protected prompt input and explicit busy cues such as an active Codex turn, hook-review prompt, or help screen.session interrupt-clear <FILE>is the explicit discard path that interrupts the owning pane, waits for idle/closed evidence, then retries clear. Interrupt-clear timeouts include the final blocking state, evidence source, prompt-ready value, current command, and recent pane tail in both ops logs and user-facing errors. - Supervisor recycle gates are controller projections — route/direct/dispatch-only callers no longer poll recycle-in-flight marker files before injecting work. Recycle starts and settles are recorded as lazily-backed
SupervisorRecycleStarted/SupervisorRecycleSettledfacts in the project controller; prompt injection waits on the controller projection so a trigger cannot disappear during supervisorexecve. Self-driving loop yield forstale_binary_drainandstate_flush_drainuses the same projection, so preflight/session-check/queue continuation reportqueue_recycle_yield=truewhile the supervisor is recycling and then continue once the projection settles. - Native upgrades use an explicit safe-adapter policy —
agent-doc lib-install(andmake install) sendsreload_librarythrough PID-scoped endpoints only to adapters explicitly known to support safe hot reload. The same successful install enumerates every liveagent-doc startprocess, resolves relative document arguments against that process’s/proc/<pid>/cwd, and requests one safe-boundary recycle for every open supervisor before recycling controllers. VS Code reloads and re-registers its open replicas. On Linux, JetBrains marshals JNA invocations onto a bounded generation-owned worker pool; document replicas retain FIFO ordering through per-document Kotlin workers and per-replica Rust locks, so one large document cannot head-of-line block every other replica. A queued call timeout cancels only that call, while a native invocation that actually runs beyond its lease still poisons the generation. Reload stops and joins CRDT/listener workers, drains calls, quiesces native replicas, terminates all owner threads so Rust TLS destructors run, closes the JNA handle, and proves the old/proc/self/mapsentry is gone before loading and publishing the replacement shadow. Controller launch from the cdylib goes through a short-lived external helper, so no controller-lifetime child-reaper thread can pin the mapping. Durable reliable-sync SQLite outboxes live only in the project controller; the reloadable cdylib is a thin RPC client and retains nostate.dbconnection. Any failed drain/unmap/ABI proof fails closed without loading a second generation; unsupported hosts and unknown adapters remain restart-required. JetBrains Kotlin packages are dynamically unloadable on compatible builds: their application-service disposal releases plugin-owned project registries, while local byte-identical installs preserve the live files and inodes. On builds that retire plugin classloaders asynchronously, agent-doc deliberately stages every package upgrade and requires an IDE restart; compatible builds may still use JetBrains’ dynamic classloader replacement, with an explicit unload-failure prompt treated as a defect. No broadcast file or watcher exists.agent-doc admin reload-librepeats the policy-aware fan-out and reports projects, endpoints, deliveries, restart requirements, and failures. - tmux-spawn scope stewardship (
#tmuxscopesteward) — tmux built with systemd support (e.g. tmux 3.8 on Arch/CachyOS) moves every pane into its own transienttmux-spawn-<uuid>.scopein the systemd user manager. A pane that exits before systemd attaches it leaves a FAILED unit (result=resources) loaded untilreset-failed, and a process that daemonizes out of a pane keeps its scope running after the pane or tmux server is gone; thousands of such units in the user manager preceded an X11 session crash. Prevention: every Makefile Rust-test target (check,check-fast,test,tmux-ci,sim-medium,sim-net,cross-editor-simworld) exports an unreachableDBUS_SESSION_BUS_ADDRESSto its processes (tests, and every tmux server a test spawns), which makes tmux skip the scope; install and release targets keep the real bus. Ad-hoccargo testruns outsidemakecan opt in by exportingDBUS_SESSION_BUS_ADDRESS=unix:path=/nonexistent/agent-doc-test-no-session-bus(for example from a local, gitignored.cargo/config.toml[env]entry withforce = true). Stewardship: every non-temporary project controller checks once a minute, on its idle tick, whether the host-wide sweep is due (default every 10 minutes per user,AGENT_DOC_TMUX_SCOPE_SWEEP_INTERVAL_SECS;AGENT_DOC_TMUX_SCOPE_SWEEP=0disables it) and runs it off the accept loop. The sweep resets failedtmux-spawn-*scopes; keeps scopes whose launching tmux server and pane process are alive; stops an orphaned scope (launcher gone, or pane process gone) only when its cgroup is empty or every remaining process is proven by/proc/<pid>/exeto be anagent-docbinary rooted in a lexically containedtempfile.tmp*fixture directory that is removed or at least 10 minutes old; and reports every other orphaned scope without signalling it. Each sweep logstmux_scope_sweep ...(counts before/after, reset, stopped, reported) plus bounded per-scope lines toops.log. It is a no-op off Linux or without a systemd user manager.agent-doc admin tmux-scopes [--dry-run] [--json]runs the same sweep on demand. - Controller and supervisor upgrades recycle safely mid-turn (
#recycle-no-boundaries,#midturn-controller-recycle,#midturn-live-child-recycle,#handoffsocketownership) —agent-doc admin recycle <FILE>and install fan-out immediately start a private controller replacement even while durable harness dispatches or controller RPCs remain open. After the replacement hydrates, socket promotion redirects new RPCs; the predecessor drains already-accepted RPCs before retiring. At promotion the predecessor stops its own supervisor watchdog and orphan-queue drain, ends the editor’s document-turn authority streams so the editor reconnects to the successor, and stops answering document reads from relay hubs that froze at the handoff; the drain is bounded by the#drainingpredecessorlease length for open client connections as well as async workers (GH #261). Its outgoing-handoff worker disarms the predecessor’s stranded-controller watchdog through promotion and drain, and the predecessor relinquishes its listener’s pathname-reclamation guard after socket promotion so its exit cannot unlink the successor’s livecontroller.sock. A stale supervisor may also replace its own image during an open turn when it proves the exact child and PTY can be adopted and reaches a drained supervisor-IPC plus atomic PTY-I/O boundary. The swap preserves the child, session, prompt/input stream, terminal-filter boundary, cycle, and closeout owner; it never kills or replays the in-flight turn. Failedexecvekeeps the old image serving, and a child lost on an adopt-only boot is not re-dispatched. Without that continuity evidence, supervisor replacement continues to defer.--forceonly skips the controller debounce; when no live controller answers and the command escalates throughsession restart-supervisor, it additionally permits interrupting a busy pane. A non-stable handoff remains the strict replacement gate. A bare project-root /--project-rootform with no live controller has no document to cold-start and still prints a one-step remedy.--jsonaddsforced(andescalated_cold_starton the single-project arm). - Route re-checks associated-pane evidence immediately before cold-start — stale registered-pane cleanup does not relax the ownership guard. If a legacy associated pane becomes provable only after the earlier recovery branches run, route still fails closed instead of treating auto-start as a safe tie-breaker.
- Passive sync now fails closed on legacy associated panes instead of reclaiming them implicitly — when
sync --no-autostartsees only session-log/process-tree/registry_rebindevidence for a pane, it blocks that file and requires an explicit claim/repair instead of silently re-registering the pane or cold-starting around ambiguous ownership. - Route readiness is binary-owned — prompt detection / trigger acceptance lives in
route.rs, must tolerate shell startup noise, and keys off the actual harness prompt shapes rather than generic shell>echoes; the skill should not try to infer pane readiness from echoed command text - Route progress logging is UTF-8 safe — live reroute diagnostics trim captured tmux lines on char boundaries, so Unicode prompt/status glyphs such as
…or·cannot panic the binary while route is waiting for readiness - Harness-specific arg aliases —
agent_argsis the generic override;claude_args,codex_args, andopencode_argsare harness-specific aliases used only by their matching backends; submodule-hosted Claude/Codex documents also auto-add the superproject working tree plus any external git metadata directories they need (.git/modules/...plus the superproject.git) so workspace-write sessions can patch parent-repo docs and still complete the normal git lifecycle - Streaming — recovery-only partial checkpoints followed by one final CRDT write (
agent-doc stream), with optional chain-of-thought routing - Task orchestration —
agent-doc orchestrate --mode sequential|parallel|daggives one surface for stepwise fresh-agent execution, worktree fan-out, and dependency-aware DAG scheduling; sequential injects each prompt intoexchange, buffers backend streaming outside the document, and publishes one complete response through strictfinalize(including its binary-owned session check) without spawning a redundant companion command; parallel preserves the existing worktree backend, DAG mode honors dependencies in deterministic topological order, and--mode dag --from-queuepersists an auto-DAG schedule plus schedule-backed job packets for active queue batches - Auto-DAG queue scheduling — active
agent:queuebatches can be expanded intoagent-doc-auto-dag-schedule-v1nodes with dependency batches, node state, attempt counts, replay/repair commands, tsift graph/ownership gates, and ops-log guard decisions before child work launches;--resume-schedule <ID>resumes the durable schedule without relaunching complete or failed/gated nodes - Fleet work board —
agent-doc board [ROOT] [--json] [--dag] [--all] [--no-submodules]shows the queue + backlog of every session document across a superproject and its submodules, one section per project, ordered worst-first by state (BLOCKED/STALLED/OPERATOR/DRAINING/READY/CLEAR) with the per-document auto-DAG lane rollup. The load-bearing signal isSTALLED: a drainable queue head with no live actor draining it.admin dashboardshows which controllers are alive;boardshows where the work is and what is not moving - Agent Doc dashboard —
agent-doc dashboard [ROOT] [--json] [--write [PATH]] [--watch]composes the fleet work board with controller/supervisor liveness in one markdown view.--writekeeps a live projection at.agent-doc/dashboard.mdthat the project controller re-renders (debounced) whenever session, queue, or controller state changes; the editor Dashboard action opens it. The projection is never a session document - tsift graph-backed planning — when a materialized
.tsift/graph.dbworks,planandorchestrateattachgraph-db evidencehandles plusconflict-matrixownership summaries to queueddo #idwork and pass bounded<tsift_graph_evidence>context to child/job prompts without writing that context into the session document; if tsift is stale, unavailable, times out, or violates the graph contract, agent-doc warns and continues without graph evidence/manual packets instead of failing the whole turn - Editor plugins — JetBrains and VS Code plugins for hotkey integration and IPC writes
- Watch daemon — auto-submit on file change with debounce and reactive mode for stream documents; watched markdown sessions also emit node-keyed
document_node_eventsbatches for AST insert/remove/replace/move/strike/unstrike changes - Linked resources —
linksfrontmatter field for local files and URLs; URL content fetched, converted HTML→markdown viahtmd, cached, and diffed on each preflight - Session logging — persistent logs at
.agent-doc/logs/<session-uuid>.logfor debugging session crashes and restarts - Preflight gate —
agent-doc preflightauto-recovers openresponse_captured/write_appliedcycles, treatsstaged snapshot already matches HEADas an already-committed no-op closeout instead ofcommit_failed, repairs stalepreflight_startedlocks when the recorded snapshot/file hashes still match exactly, otherwise still requires a real pending/capture replay before auto-closingpreflight_started, fails closed when an emptypreflight_startedcycle has unresolved prompt-bearing drift and no response capture to replay, fails closed on unrecoverablepreflight_starteddrift instead of snapshot-committing over newer live content, also fails closed on hidden uncommitted closeout drift (snapshot != HEAD/ visible bypassed### Re:with no recoverable cycle) before diffing, preserves ordinary post-exchange HTML comments as user scratch content, does not auto-compact exchanges during preflight, emitswarnings[]such asharness_mismatchwhen frontmatteragent:differs from the detected active harness andstale_installwhen installed/builtagent-docartifacts predate the latest source commit (#install-stale-guard, dogfood/dev only), and emitseffective_tier,required_tier,suggested_tier,model_switch(_tier),agent_model, plus boundedsession_accretionwarnings when exchange/log heuristics show churn-heavy growth - Bounded recent-context packs — when resumed prompt targets land in a warn/block accretion session,
run/stream/orchestratekeep the full document on disk but replace the full exchange tail in the agent prompt with a bounded pack containing prompt targets, session summary, backlog head, a lightweight live+archive response TOC, and the### Re:turns anchored to those prompt positions inexchange(the enclosing response for inline edits, or the immediately previous response for tail prompts), plus a reminder to ask for older turns or useagent-doc response-fetchwhen no clean anchor exists or more neighboring history is required - Accretion advisory —
session_accretionstill summarizes exchange growth, closeout churn, and restart-heavy reopen signals so prompts can choose bounded recent-context packs or suggest compaction/restart when useful. These signals remain advisory:agent-doc planmust not turn exchange-size accretion or repeated no-op closeout churn into acompacthandoff unless the prompt or document explicitly requests compaction. Claude skill auto-update uses restart by default;/compactreload is allowed only with explicitagent_doc_auto_compactfrontmatter or project.agent-doc/config.tomlopt-in. A Codex skill-version mismatch installs without a reload request, re-reads the installed skill completely, and continues the active turn in place (#codex-skill-reload-in-place). - Durable response capture — every final response is persisted in the
state.dbstate-machine ledger before canonical application, so interrupted cycles resume the same intent instead of regenerating it. Streaming may emit cold recovery checkpoints, but those projections never become normal read authority. - Backbone closeout facts — accepted cycle-state transitions append typed Lazily state-backbone facts (
PreflightStarted,ResponseCaptured,WriteApplied,CommitObserved,CycleAbandoned) using stable event ids. Lifecycle re-entry,session-check, and preflight read thestate.dbprojection exclusively; there is no JSON cycle-state compatibility authority. - Git-owned commit proof — real commits and already-current no-op closeouts append an exact
HEADSHACommitObservedfact into the closeout projection, superseding the cycle-state bridge’s compatibility content-hash observation when git proof is available - Bidirectional transport proof — maintained editor plugins publish lazily transport receipt facts (
EditorPatchApplied/EditorPatchRejected) alongside binary write intent / expected response hash and visible-buffer hash facts; ACK-only plugins are incompatible and closeout reads the lazily projection instead of treating whole-buffer sidecars as snapshot authority - Template exchange guard — template writes fail closed when prompt/response content escapes either below
<!-- /agent:exchange -->or into the gap before later agent components such as backlog; explicit repair/compaction still normalize the safe escaped-conversation shapes, while comment-only notes without escaped conversation headings stay outside and ambiguous mixed structure is rejected - Boundary singleton guard — outside fenced examples, a session document may contain exactly one
agent:boundarymarker and it must occupy its own tail line; ordinary write/finalize paths reject inline or duplicate markers before mutation, while explicit legacy repair collapses them after preserving complete exchanges - IPC timeout ordering guard — timeout fallbacks and
repairnow normalize stale-boundary response placement so multi-paragraph prompt text stays before the assistant response and the boundary closes the completed turn; if that order cannot be proven, closeout fails closed instead of committing a split prompt - Backlog prompt cleanup — when a template/CRDT closeout answers prompt-target text typed directly inside
agent:backlog/ legacyagent:pending, the write path removes those resolved raw prompt lines after merging the exchange response while preserving ordinary backlog edits and pending state changes - Operator-authoritative backlog deletion — deleting an open backlog row in the visible document no longer wedges the next preflight/session-check when the deletion is proven by captured editor operations or by an idle command-entry cut that is still present in committed history; unexplained open-cycle or committed loss remains fail-closed
- Prompt presets — frontmatter
prompt_presets:(or its shorter aliaspresets:) defines reusable prompts that#name/preset namereferences expand; optional.agent-doc/project.mdfrontmatter supplies live project-wide defaults without copying them into session documents, while an exact-name session declaration overrides or masks the inherited value; project preset bodies may interpolate effective values such as#project(bare hashtags substitute only declared keys, while explicit{{#project}}references require a definition), recursive chains resolve live without restarting agent-doc, and cycles or unset references fail closed; binary frontmatter writes keep whichever spelling the operator used, and a document spelling both merges them withprompt_presetswinning a name collision - Cross-document backlog capture — prompt presets or user instructions that name another backlog file must close through
--pending-add-to <target-file> "<item>", so the item is added to the named document instead of the current session. The write path fails closed when the target is missing or lacks anagent:backlog/agent:pendingcomponent. - Respect manual cleanup — if a user deletes that escaped conversation tail by hand in a template doc,
agent-doc repairnow discards the stale captured response and advances the snapshot to the repaired file instead of failing on a capture-baseline mismatch or reapplying the removed tail repaircloses git-backed recovery immediately — directagent-doc repair(legacy alias:recover) now runs the normal commit boundary after replaying or deduping a pending response in git, instead of leaving repaired assistant content uncommitted until a laterpreflight- Hard response commit boundary — every appended response should cross a commit boundary unless the operator explicitly wants it left open; the normal happy path is
agent-doc finalize <file>, while missed-patchback repair usesagent-doc write --commit <file> - Explicit no-followup closeout — pass
--no-followups(alias--no-pending-capture) on the firstfinalizeattempt when the response intentionally creates no actionable follow-up work. The runtime records that intent as transient pending-capture evidence for retry/pre-commit checks and removes it from the visible and committed document; agents do not need to search for or inject the internal guard marker. - Manual repo commit ordering keeps the session doc on the finalize path — when an
agent-docturn includes ordinary repocommit + push, manual git commits should stage only the intended non-session repo files, stop immediately on any stage failure, verify the staged diff still matches that intended path set, and commit only that validated set. The session document itself still closes throughagent-doc finalize <file>oragent-doc write --commit <file>, and the push happens after that closeout commit lands so the response commit is included - Harness-native entrypoints are binary-owned workflow starts —
/agent-doc <file>in Claude Code,agent-doc <file>in Codex/OpenCode/direct-exec, and equivalent harness-native entry forms must be treated as the start of the binary-managed response cycle, not as permission to patch the document manually and later say “not committed” - Session-document
write --commitis strict — whenwrite --commitis used to patch back a response into a real session document (agent_doc_session/ legacysession), it now requires git before mutation and only succeeds once the cycle reachescommitted; best-effort--commitremains only for non-session docs and--pending-onlymaintenance - Mode-aware bare/run entrypoint —
agent-doc <file>andagent-doc run <file>now share the same document-mode-aware path: template docs use template patchback, append docs use inline blocks, and missing format defaults to template - Direct run dispatch is bounded and foreground-safe — after
runopens its freshpreflight_startedcycle, the agent child has a bounded wait (AGENT_DOC_RUN_AGENT_TIMEOUT_SECS, default 1800s). Timeout or recursive Codex-in-owning-pane invocation records a recoverablepreflight_startedtimeout event with cycle/pane/actor diagnostics instead of leaving the CLI silent afterSubmitting to codex.... Whenrunis invoked with terminal stderr inside a tmux pane owned by a Codex/OpenCode parent harness, routine run/diff/commit stderr is redirected to.agent-doc/logs/run-stderr.logunless verbose input diagnostics are enabled, so progress output cannot paint over the foreground TUI after a restart - Owner-pane self-invocation preserves the unresolved prompt (
#codex-owned-pane-prompt-miss) — when a Codex-owned pane re-invokesagent-doc <file>for the document it already owns and an unresolved exchange prompt is still pending,runnow fails closed before pre-commit and before opening a cycle. The diagnostic names the unresolved prompt and the in-pane recovery path (answer it in this owner pane’s turn, then persist withagent-doc finalize/write --commit) and tells the operator not to re-run the same direct command from the same pane. Because the early guard bails before pre-commit, the prompt stays uncommitted and executable instead of being baselined intoHEADby the older late recursive-deadlock guard (which still abandons the empty cycle for the no-prompt / queue-only case).session-checkis the backstop: an abandonedrecursive_direct_invocation_blockedcycle with an unresolved exchange prompt still remaining is reported as a missed-prompt recovery, not accepted as terminal closeout - A headless run never resumes the live session that launched it (
#runchildresumesowner) —agent-doc <file>/agent-doc run <file>/agent-doc stream <file>refuse before any document, git, or cycle effect when the document’sresumeid is the harness session the command is running inside (a subagent inherits its coordinator’s id). TheUnansweredEditPendingcommit refusal now tells an in-harness caller to end the turn rather than run the document again, and a commit retry commits the closing cycle’s own late status/strike/handoff projections when they land together instead of calling them an operator edit. - Direct run never dispatches an already-committed repair diff — if pre-commit repair proves the only diff was an already-committed missed patchback and no new response body exists,
runrechecks the diff, stops before invoking the child agent, and points the operator toagent-doc write --commit <file> - Run closeout is durable before commit — once
runhas written the final response (and anyresumeupdate), it recordswrite_appliedbefore the post-write commit so interrupted runs can be finished deterministically bypreflight; git-backedrunnow shares the same strict post-write closeout helper asfinalize,write --commit,repair, and the Codex Stop-hook, so success also requires the snapshot/HEADproof plussession-check - Binary-owned finalize path —
agent-doc finalize <file>is the strict happy-path response command: it reuses the normal write pipeline but requires the document to live in git and fails unless the cycle reaches a terminal committed state - FlowCore closeout diagnostics — strict pre-write/pre-commit guard blocks, document-mutation patchback parse outcomes, repair recovery boundaries, committed-cycle late fallback rejection, and commit completion now emit typed
flow_eventrecords soagent-doc ops summarycan group closeout failures by stage instead of relying on ad hoc proof strings - Ops bug clusters —
agent-doc ops summaryranks closeout/captured-response drift, route/start replay gaps, Codex manifest warning storms, SQLite correlation counts, cross-harness markers, session-review guardrails, and working-tree drift with example lines plus file/session/cycle/thread correlation keys - Direct-exec post-write guard — the direct-exec Codex and OpenCode instruction path runs
agent-doc session-check <file>afterfinalizeor manualwrite --commit, and a nonzero check blocks success reporting until recovery finishes; it flags likely direct response patchbacks (### Re:/## Assistant) that bypassedagent-doc, names the exact recovery path without attributing ambient worktree dirt to the current cycle, directs invalid pending captures throughagent-doc repairrather than a forbidden response write, fails closed when committed-cycle exchange drift appends a prompt+response pair or other response content, fails closed when prompt-bearing user edits exist with no newer cycle start or when the live exchange tail is still prompt-only with no assistant response, and still self-heals already-committed historical response drift whenHEADproves the response is no longer out-of-band, including committed prompt+response pairs that precede newer local drift as long as that later drift did not add another assistant patchback - Managed closeout is turn-reactive (
#sessioncheckturnreactive) — connected clients consume the successfulagent_doc_finalizeresult as the terminal closeout report, including any next queue continuation, and do not invoke a secondagent_doc_session_check. Managed orchestration likewise stops at strictfinalize. The next turn’s admit/preflight resolves the current document and applies the same open-cycle, prompt-only-tail, and bypassed-patchback guards before opening work. Opening a newer cycle clears the older cycle’s closeout owner immediately, so an outstanding diagnostic for turn N is superseded by turn N+1 instead of holding a lease until a clock expires. The explicit session-check command remains for direct-exec distrust checks and operator debugging. - Closeout followers observe lease expiry without polling — a follower still wakes immediately on terminal-cycle and explicit owner-release facts, and now schedules the incumbent lease boundary as well. The timer only publishes that clock edge into a keyed controller-owned Lazily source; the shared Computed closeout gate decides whether the owner remains blocking. That eventless stopgap can no longer turn a short retained recovery into a full 30-second wait followed by another manual status retry.
- Codex empty cursor is not an operator draft — dispatch-only reroutes recognize Codex’s exact idle
› |composer rendering as empty and may submit into it, while populated composer text remains protected. - Repeated Run Agent Doc coalesces its own Codex queued input — when Codex’s queued-input surface already contains exactly the reopen trigger requested by a dispatch-only route, the route reports successful existing acceptance without typing or submitting again. Different queued input, including the trigger plus operator text, remains protected and fails closed.
- No hot-path sidecar authority — cycle, capture, queue deletion, continuation, turn scope, editor operation capture, transport health, and controller cooldown state are transactional
state.dbfacts. Snapshot/CRDT files are recovery projections only and cannot override Lazily current state or the ledger. - Codex admission, Stop-hook, and repair replay guard —
agent-doc skill installfor Codex writes the consequential lifecycle hooks once into user-level$CODEX_HOME/hooks.json, retires only agent-doc’s duplicate commands from project hook files, enablesfeatures.hooks = true, and sets[mcp_servers.agent-doc] default_tools_approval_mode = "approve". The single user-level owner remains visible across nested submodules and worktrees without double-running preflight when a project hook also loads. The installedUserPromptSubmitcommand atomically makes active-document tracking durable and runs binary preflight for a validagent-doc <FILE>trigger—even when injected AGENTS/instruction preambles precede it—then emits the cycle contract, trailing success marker, and an explicit in-pane no-shell-reinvocation directive as Codex turn context. Tracking or preflight failures emit no success marker and therefore fail admission closed. A refused admission receipt fencesStopbefore it can capture the refusal explanation or continue an older queue; Stop retires that denied binding, and ordinary later prompts cannot inherit another pane’s open cycle as writeback debt. Only a new explicitagent-doc <FILE>trigger attempts admission again. For an admitted turn,Stopfirst tries to finish the response cycle deterministically fromlast_assistant_messageonly when that payload validates as a single assistant closeout; tracked state survives nested.agent-docroot / CWD drift and later-stop turn drift within the same Codex session, while transcript-shaped or full-document payloads are kept as diagnostics and blocked instead of being replayed. The shared pending-response adapter applies the same replay-shape guard before every capture source, so direct-run and hook adapters cannot bypass it. Guard comments such as<!-- no-pending-capture -->may wrap an otherwise valid patch response, and plain progress commentary before the first patch is stripped before replay. Direct template writes use the same guard when unmatched text surrounds an exchange patch, so progress prose is not appended intoagent:exchange. Iflast_assistant_messageis empty because Codex stopped after a tool-only/authentication step such as an MCP OAuth /authenticateflow, the hook still fails closed, saves a diagnostic record with the tracked prompt, and forces the turn back through the normalfinalize/session-checkrecovery boundary.agent-doc repairquarantines and retires legacy transcript-shaped captures and abandons their poisoned cycle, preserving the prompt for a fresh response instead of replaying the dump or leaving admission permanently refused. - Bounded Codex lifecycle hooks — installed Codex
UserPromptSubmitandStopentries carry explicit outer timeouts. Stop performs at most one opportunistic captured-closeout resume and returns a valid fail-closed response within its shorter binary budget; the route-owned supervisor, not the hook, owns continued retries. After strict repair replay, Stop and repair reuse the terminal closeout proof only for the same committed cycle/capture and unchanged live, snapshot, and Git content; later edits or missing proof require full closeout. - Single-flight Compact Exchange outcomes — controller RPCs distinguish
committedfromretained_pendingandalready_pending. A retained target never produces the “now in HEAD” note: the initiatingretained_pendingresult is an accepted asynchronous success (exit 0) that says editor delivery will commit automatically and must not be rerun, while a repeated action receives nonzeroalready_pendingwith the bounded-timeout rerun guidance and reuses the existing continuation without composing another compact write. skill-harnessintegration is downstream-owned —agent-doc-skill-harnessimplementsSkillHarnessPluginwithout a dependency on the deletedagent-doc-core. Register it withregister_agent_doc_plugin(&mut registry), or useregistry_with_agent_doc(). A supervisedAGENT_DOC_SESSIONtakes priority over nested Claude/Codex/OpenCode detection and resolves skills to.agent-doc/plugins/<name>/SKILL.md; Agent Doc’s own harness bootstrap skill remains at.claude/skills/agent-doc,.codex/skills/agent-doc, or.opencode/skills/agent-doc.- Malformed patchback guard — template write paths reject responses that contain patch/replace markers but no closed patch blocks parsed, logging marker counts, patch counts, unmatched length, response hash, and source before failing. Socket IPC attempts also log payload shape and lazily visible-write receipt hashes/lengths so live corruption reports can identify whether the fault was malformed parsing, editor projection drift, or a stale fallback writer.
- Normal maintenance covers stale starting actors —
preflight,start, andsyncclose stalestartingcontroller actors older than one hour unless a live supervisor PID still has a fresh heartbeat for that generation. A live but non-heartbeatingagent-doc startprocess does not keep a record instartingforever. The heavier orphan-file GC and old diagnostic pruning remain on a daily throttle stored in.agent-doc/state.db. - MCP auth is a sub-step, not a closeout boundary — bundled harness instructions now state explicitly that browser/authenticate pauses inside an
agent-docturn do not satisfy the response boundary; after the auth step, the same turn must still close through connectedagent_doc_finalize(orfinalize/write --commitplussession-checkon direct exec), or fail closed. - Explicit repair no longer false-passes blocked post-commit drift — when
agent-doc repair <file>finds no pending artifact butsession-checkwould still interrupt the document, the command now surfaces that interruption instead of printingNo pending response found. That keeps the committed-historical-patchback-plus-later-prompt shape fail-closed until a real new cycle starts. - Stale empty preflight cycles preserve unresolved prompts — if a prior pane died after
preflight_startedwith no response capture,repairabandons the stale empty cycle after the timeout instead of writing a placeholder response. The unresolved prompt stays in the document and the next preflight starts a fresh cycle for it; recent empty cycles still fail closed to protect live work. - Response persistence is the close-out boundary — the instruction surface now requires requested implementation / verification / build-install work to finish before
finalizeorwrite --commit; after that point only a required direct-exec distrust check, recovery, and final reporting remain - Imperative document edits execute work — bundled Claude/Codex/OpenCode instructions explicitly treat document-local directives like
do #id,go ...,push ...,run tests,build + install,commit + push, resolved authorizing presets such as#auth, and pending-item task text that starts with an imperative verb (for example[#id] Fix the cross-repo ...) as authorization to perform that repo work from the session document itself; the agent should execute the work without asking for the same directive, confirmation, or preset again, or stop on a concrete blocker. Task authorization remains distinct from harness-native tool permission. The binary rejects status-only/meta-onlyrun/finalizeresponses for those directive diffs unless they include concrete execution evidence or a blocker. - Harness-owned tiered verification —
make check-fastvalidates the affected package/reverse-dependency scope during iteration; release validation runs cheap version/editor-parity checks first, then independently reuses matching full-suite and tmux-CI receipts keyed only by repository bytes and toolchains - Tmux CI review for test turns — when an agent turn runs or changes tests, it should inspect the latest CI tmux leg with
gh run list --workflow CI --limit 1; failures after runner startup should be reproduced locally withmake tmux-ci, while queued/in-progress runs should be recorded without blocking the turn for CI completion. Empty-step/no-log jobs that GitHub never started, such as billing/spending-limit exhaustion, are external CI-start blockers to record alongside local verification evidence - Model-attributed response headers —
### Re:headings should carry the resolved model short name (gpt-5,opus-4-7), not the harness label (codex,claude). For Claude Code, theopusalias resolves to the current concrete Claude Code opus id before attribution. The agent authors the attribution and local timestamp from preflight; strict closeout preserves the complete heading on the production write path. - Git integration — auto-commit each run; squash history with
agent-doc clean - Commit self-heal —
agent-doc commitcan absorb a narrowly-scoped missed agent patchback (status,### Re:response-block insertion, pending-ID superset) into the snapshot before staging, while still leaving plain user prompts uncommitted; when the snapshot lags behind an already-committed response inHEAD,commitnow repairs the snapshot up to that committedHEADstate before later local drift can no-op closeout, as long as the later drift did not add another assistant patchback, so stale snapshots cannot rewind the document; when the snapshot already matchesHEADbut the working tree has later local edits,commitnow classifies that as post-commit local drift and explains that those edits remain uncommitted instead of vaguely implying a missed patchback, and the follow-up case recordspost_commit_user_follow_upinstead of missed-response or out-of-band-write markers; aHEAD-current staged snapshot still closes the cycle as an explicit no-op instead of a falsecommit_failed - Zero-live-editor capture recovery terminates — when an explicitly rejected editor endpoint has been unregistered and controller authority has zero live replicas,
session-checknamesagent-doc commitas the stranded-write recovery. Commit now adopts the exact response-bearing authoritative cut only when the durable capture matches and no newer unanswered prompt or unproved typed-component edit would be consumed. Otherwise it fails closed with the same-capture resume remedy instead of prescribingcommitagain; it never requires response resubmission or a forced disk write. - Extreme-drift guard stays conservative — if a tracked document’s snapshot is badly stale,
commitwarns but does not re-sync the snapshot from the live file wholesale; bootstrap scaffold auto-resync is limited to files with noHEADentry yet so unanswered prompts cannot be swallowed into a commit - Clean post-commit cleanup — commit strips transient
(HEAD)markers from the staged snapshot so the committed blob stays clean, and post-commit cleanup now collapses snapshot/editor state back to the same clean boundary shape instead of leaving marker-only working-tree churn behind - Manual repair guidance is explicit across harnesses — bundled skill/runbook content now distinguishes missing-user-prompt insertion from missed-response repair for both Claude Code and Codex: once the prompt is already present, the default documented repair path is
agent-doc write --commit <file>, not direct file patching or a bare write-back that stops before commit - Generated harness instructions stay aligned — installed Claude/Codex/OpenCode hot-path instructions are rendered from one shared source surface and parity-tested so completion-boundary guidance cannot silently drift between
.claude/skills/agent-doc/SKILL.md,.codex/skills/agent-doc/SKILL.md, and.opencode/skills/agent-doc/SKILL.md; bundled runbooks and OKF concept files are installed beside those surfaces as dynamic context resources;audit-docsfails generated managed skill surfaces that no longer match the running binary and rejects retired generated rootAGENTS.md/.codex/AGENTS.mdsurfaces while preserving custom root instructions, audits installed runbook bundles the same way (a stale or missing runbook, unbundled Markdown in a harness runbook directory, a surviving retired.codex/runbooks/mirror, and drift in askill_runbook_mirrorsproject mirror all block), audits both the superproject install root and the submodule checkout by default from submodule checkouts (bare root resolution prefers the superproject, so submodule-local copies are otherwise only ever version-stamped and never content-checked), still honors explicit--root DIR, and reports broad mtime freshness only as an advisory - Bulk resync — validates session state and fixes stale/orphaned panes in 2 subprocess calls instead of ~20-40;
--fix --session <name>relocates WrongSession panes via join-pane instead of killing them - Column memory — project
state.dbremembers column→agent-doc mapping; preserves a 2-pane tmux layout when one editor column switches to a non-agent file, without a file sidecar - Stash + rescue — replaced panes are stashed (alive in background); stash rescue brings them back when the user switches to that document again
- Startup lock —
.agent-doc/starting/<hash>.lockwith 5s TTL prevents double-spawn when sync fires twice in quick succession - Component-aware baseline guard — detects stale baselines by comparing append-mode components only; user edits to replace-mode components (status, pending) don’t trigger false positives
- Hook system — cross-session event coordination via
agent-doc hook fire/poll/listen/gc;post_write/post_commitevents now includecapture_idandresponse_sha256when a durable capture exists, the system integrates with Claude Code hooks viaPostToolUse, and Codex installs one user-levelUserPromptSubmit/Stopbridge through$CODEX_HOME/hooks.json - Slash command dispatch —
preflightextracts slash commands from user-added diff lines (parse_slash_commands); the SKILL executes them before responding; guards exclude code fences, blockquotes, and non-added lines. In routed editor sessions, a bare exchange slash-command line such as/clearis prompt-bearing even without a❯prefix and is queued for the idle supervisor instead of being answered as a normal agent-doc turn. - No filesystem delivery inbox — editor delivery uses PID-scoped sockets and Lazily receipts; startup has no alternate payload source to rediscover or replay.