Agent-readable wiki
duet-agent Mental Model Wiki
duet-agent is a TypeScript agent harness for jobs that outlive a single chat session: it combines a five-state relay state machine, PGlite-backed observational memory, and a protocol-first TurnRunner so any process—serverless function, cron job, or interactive TUI—can resume exactly where the last one stopped.
Pages
- The Mental Model — Three Answers to Process DeathThe simplest accurate model of what duet-agent is and why its three subsystems (relay state machine, observational memory, TurnState snapshot) are one coherent answer to the same problem: work that must survive a dead process.
- TurnState & the Command/Event ProtocolTurnState is the only thing that must survive between process boundaries. This page traces the lifecycle of a TurnState from creation through prompt/answer/wake commands, terminal events (complete, ask, sleep, interrupted), and what each field owns—agent messages, stateMachine session, usage accounting, and todos.
- The Five State Kinds — Vocabulary of a RelayEvery relay is built from exactly five state kinds: agent (sub-agent with a prompt), script (shell command), poll (recurring external check), timer (pure wall-clock delay), and terminal (named business outcome). This page explains the invariants, input schema templating, and what each kind can and cannot do—including why integrations like GitHub or email are always script/poll states, never engine primitives.
- State Machine Execution Flow — How the Runner Agent Drives TransitionsThe runner agent—not a config file—selects the next state every turn. This page traces how state-machine-controller.ts dispatches a state, records audit events in StateMachineSession.history, emits sleep for poll/timer states, handles interruptions, and runs a terminal acknowledgment turn. Includes the carry-forward invariant and the mid-session start rule.
- Observational Memory — How Transcripts Become Durable RowsMemory and compaction are the same primitive. After each turn an observer model reads the transcript and appends Observation rows to PGlite; when rows grow beyond a threshold a reflector condenses them. Embeddings run in a background worker (embedding-worker.ts) so foreground turns never block. This page covers the observe → reflect → embed pipeline, trigger conditions, failure isolation, and the image-to-text path that keeps screenshots recallable.
- Recall & the Frozen Context Pack — What Survives Into Every PromptEvery turn is prefixed with a frozen two-layer memory pack: global cross-session observations ranked by recency half-life, and local session compaction. The pack rebuilds only on three specific events (initial load, reflector replacement, wire-shaping eviction) so the provider's prompt cache survives turn-over-turn. recall_memory tool uses hybrid RRF retrieval (pgvector cosine + tsvector keyword) to surface anything that missed the pack. This page explains pack structure, rebuild triggers, cache stability invariant, and RRF fusion.
- Wire Shaping & Model Resolution — Context Budget Enforcementwire-shaping.ts enforces a byte budget (15 MB trigger, 80% target) and a token budget (200k default effectiveContext) on the dispatched message list. Eviction advances the WireGuardHorizon, trimming oldest messages in one block to minimize prompt-cache invalidations. Images get a fixed 1,600-token estimate to prevent base64 byte inflation from triggering early eviction. Model resolution (resolver.ts, catalog.ts, duet-gateway.ts) abstracts Anthropic/OpenAI/OpenRouter/Duet Gateway behind a single resolveModelName call. This page explains the two-gate eviction system, cache-miss cost model, and BYOK/BYOC model routing.
- Invariants, Failure Modes & Safe-Change RulesA synthesis of the core invariants that hold across all subsystems, the failure modes that break them, and how to change the codebase safely. Covers: TurnState as the only cross-process contract; memory pack rebuild triggers (the three-event rule); prompt-cache stability conditions; state machine history append-only guarantee; PGlite cross-process lock; transient-error retry scope; and which files are safe to change in isolation versus which touch multiple invariants.
Complete Markdown
The complete agent-readable Markdown files are published separately from this HTML page.