# 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. This is a Grok-Wiki source-grounded repository wiki. Use the complete Markdown link when an agent needs the full repo context. ## Context Links - [Complete Markdown wiki](https://grok-wiki.com/public/wiki/dzhng-duet-agent-82dbe2572d3a/llms-full.txt) - [Complete Markdown alias](https://grok-wiki.com/public/wiki/dzhng-duet-agent-82dbe2572d3a.md) - [Human interactive wiki](https://grok-wiki.com/public/wiki/dzhng-duet-agent-82dbe2572d3a) - [GitHub repository](https://github.com/dzhng/duet-agent) ## Repository - Repository: dzhng/duet-agent - Generated: 2026-05-22T00:33:51.703Z - Updated: 2026-05-22T00:34:49.281Z - Runtime: Claude Code - Format: Mental Model - Pages: 8 ## Pages - [The Mental Model — Three Answers to Process Death](https://grok-wiki.com/public/wiki/dzhng-duet-agent-82dbe2572d3a/pages/01-the-mental-model-three-answers-to-process-death.md): The 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 Protocol](https://grok-wiki.com/public/wiki/dzhng-duet-agent-82dbe2572d3a/pages/02-turnstate-the-command-event-protocol.md): TurnState 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 Relay](https://grok-wiki.com/public/wiki/dzhng-duet-agent-82dbe2572d3a/pages/03-the-five-state-kinds-vocabulary-of-a-relay.md): Every 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 Transitions](https://grok-wiki.com/public/wiki/dzhng-duet-agent-82dbe2572d3a/pages/04-state-machine-execution-flow-how-the-runner-agent-drives-transitions.md): The 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 Rows](https://grok-wiki.com/public/wiki/dzhng-duet-agent-82dbe2572d3a/pages/05-observational-memory-how-transcripts-become-durable-rows.md): Memory 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 Prompt](https://grok-wiki.com/public/wiki/dzhng-duet-agent-82dbe2572d3a/pages/06-recall-the-frozen-context-pack-what-survives-into-every-prompt.md): Every 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 Enforcement](https://grok-wiki.com/public/wiki/dzhng-duet-agent-82dbe2572d3a/pages/07-wire-shaping-model-resolution-context-budget-enforcement.md): wire-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 Rules](https://grok-wiki.com/public/wiki/dzhng-duet-agent-82dbe2572d3a/pages/08-invariants-failure-modes-safe-change-rules.md): A 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. ## Source Files - `evals/context-overflow-recovery.eval.ts` - `evals/memory-reflect.eval.ts` - `evals/outreach-lifecycle.eval.ts` - `evals/prompt-cache.eval.ts` - `evals/recall-memory-cross-session.eval.ts` - `evals/recall-memory-implicit-triggers.eval.ts` - `evals/source-of-truth-first.eval.ts` - `evals/state-machine-interrupt-resume.eval.ts` - `evals/state-machine-real-session-carry-forward.eval.ts` - `evals/state-machine-routing.eval.ts` - `evals/state-machine-tool-call-shape.eval.ts` - `evals/thread-context-loss.eval.ts` - `examples/state-machine.ts` - `README.md` - `src/guardrails/firewall.ts` - `src/guardrails/semantic.ts` - `src/index.ts` - `src/memory/context-pack.ts` - `src/memory/embedding-worker.ts` - `src/memory/embedding.ts` - `src/memory/loader.ts` - `src/memory/migrations.ts` - `src/memory/observation-groups.ts` - `src/memory/observational-prompts.ts` - `src/memory/observational.ts` - `src/memory/pglite.ts` - `src/memory/recall.ts` - `src/memory/session.ts` - `src/memory/storage.ts` - `src/memory/store.ts` - `src/model-resolution/catalog.ts` - `src/model-resolution/duet-gateway.ts` - `src/model-resolution/resolver.ts` - `src/session/session-manager.ts` - `src/session/session.ts` - `src/turn-runner/prompts.ts` - `src/turn-runner/shell-state-handle.ts` - `src/turn-runner/state-compaction.ts` - `src/turn-runner/state-machine-controller.ts` - `src/turn-runner/state-machine-session.ts` - `src/turn-runner/tools.ts` - `src/turn-runner/transient-error.ts` - `src/turn-runner/turn-runner.ts` - `src/turn-runner/turn-state.ts` - `src/turn-runner/usage-accounting.ts` - `src/turn-runner/wire-shaping.ts` - `src/types/protocol.ts` - `src/types/state-machine.ts` - `test/memory-recall.test.ts` - `test/memory-reflect-planner.test.ts` - `test/transient-error.test.ts` - `test/turn-runner-state-machine-agent-events.test.ts`