Production checklist
September 6, 2026 ยท View on GitHub
This page is a go-live review for an OMA deployment: the decisions that are easy to leave at a default, where that default is deliberately permissive or deliberately absent, and which page owns the detail. Each item is one or two sentences plus a link. Nothing here restates a linked page, and nothing here is a substitute for reading the one that matters to you.
Every item names a real configuration field or a documented behavior. Items marked default is permissive are the ones most likely to surprise a first production run.
Models and credentials
- Pin a provider and model. Set
providerandmodelper agent, or setdefaultProvider/defaultModelonce on the orchestrator and let agents inherit. A standalonenew Agent(...)has no orchestrator to inherit from, so it must declare its ownmodelunless it runs on an externalbackend. See providers. - Decide where credentials come from. Provider keys resolve from
apiKey/defaultApiKeyor the provider's environment variable. Tool code should readAgentConfig.credentialsthrough the tool context rather than closing over a module-level secret, so each agent holds only what it was assigned. See per-agent tool credentials. - Configure
egressPolicy, or accept that there is none. Default is permissive: omitting it preserves unrestricted behavior. Once set, scopes intersect and a more specific scope can only narrow. Read the enforcement matrix before relying on it: it guards framework-owned LLM requests, not tools, subprocesses, MCP servers, or your own exporters. See egress policy. - Check the runtime and network footprint if you self-host. Dependency surface, which components open sockets, and what an air-gapped deployment requires are enumerated in self-hosting.
Tools and sandbox
- Audit every tool grant. Built-in tools are default-deny: an agent
with neither
toolsnortoolPresetgets zero of them. Confirm that anydefaultToolPresetyou set is intentional, because it widens every agent that declares no grant of its own. See tool configuration. - Accept that tool output reaches your provider. Every tool result is appended to the conversation and sent to the model on the next turn, so file contents, command output, and fetched pages leave your process. Grant read access deliberately.
- Decide the containment story for
bash. Filesystem built-ins resolve insidecwd/defaultCwd, defaulting to<cwd>/.agent-workspace. Grantedbashis contained by nothing OMA owns, and aShellExecutorchanges the execution target rather than adding a boundary. For untrusted commands, use process-level isolation. See sandbox and shell. - Add a per-call gate if a granted name is too coarse. Default is
permissive:
onToolCallis off. When set it runs after input validation and before execution, fails closed on a throw or an invalid decision, and cansuspendfor durable review. It is a policy layer, not containment. See per-call gating. - Treat an MCP server as a separate trust boundary. Argument validation
is delegated to the server, and the server is its own process with its own
network behavior outside
egressPolicy. See MCP tools. - Cap tool output.
maxToolOutputCharson the agent, ormaxOutputCharsper tool, bounds what a single result can push into the context. Neither has a default.
Budgets and limits
- Bound the loop. Set
maxTurns,timeoutMs, andcallTimeoutMsexplicitly. OnlymaxTurnshas a default; without the two timeouts, a stalled provider is bounded only by its SDK. - Set a token or cost ceiling.
maxTokenBudgetworks on its own;maxCostBudgetrequires an application-ownedestimateCost, because OMA ships no price table. Budgets are checked at turn and task boundaries, so treat them as bounds, not exact stops. - Turn on
loopDetectionfor long-running agents. Off by default. It stops a repeating agent beforemaxTurnswould, and its default action warns once before terminating. - Know that two stop conditions look like success. Exhausting
maxTurnsand terminating on a detected loop both returnsuccess: true. Checkresult.loopDetected, and treat a truncated answer as unfinished if that matters.
All four items are detailed in budgets and limits.
Approvals and governance
- Pick one task-level approval mode.
onApproval(round-based) andonTaskDispatch(per ready task) are mutually exclusive and the constructor throws if both are set.onPlanReadygates the coordinator's plan once, before execution. See approval modes and hooks and callbacks. - If a decision must outlive the process, use durable approvals. They
need a
MemoryStorewhosecompareAndSetis atomic across every writer;FileStorehas no cross-process lock, and suspension fails closed withAPPROVAL_ATOMIC_STORE_REQUIREDwhen the store cannot decide atomically.RedactingStoreis unsupported there because its lossiness would break the content hash. See store requirements. - Build the reviewer surface yourself. OMA provides the mechanism and the durable record only: no UI, no CLI command, no transport, no notification. See what the framework provides.
- Declare governance roles when a goal must pass through named agents,
and check the verdict.
governanceIntent: 'required'withrequiredRolesbuilds the topology structurally instead of letting the coordinator choose, and the result'sgovernanceConclusionis what tells you whether it held. See declared governance roles. - Consider
requireConsequentialConfirmation. Default is permissive: it isfalse. See consequential tools.
Recovery and durability
- Enable checkpointing if a run must survive a crash. Off by default.
Choose the store deliberately:
checkpoint: truereuses the team's shared-memory store when one exists and otherwise uses a private in-memory store for that run, neither of which survives the process. See checkpoint. - Understand mid-task recovery before relying on it. A restore replays
committed tool results without re-executing them and conservatively re-runs a
call that has no commit record, reusing the same
toolCallIdso a consequential tool can key on it. External backends checkpoint at task boundaries only. See mid-task tool recovery. - Set
maxRetrieswhere a transient provider failure is expected. Default is permissive in the other direction: retry is off (maxRetries: 0). When enabled it is error-aware, with jittered backoff, and validation, cancellation, and budget exhaustion are terminal. See task retry boundaries and errors. - Decide whether the plan may repair itself. Recovery mode defaults to
'fixed';'repairable'is opt-in and bounded bymaxPlanRevisions(default3) andmaxAddedTasks(default20). See adaptive recovery. - Configure a
runStoreif more than one worker can pick a run up. Off by default, and a checkpoint alone establishes no owner: two processes can restore the same snapshot and both advance it. A run store adds a per-run lease and fencing token, and its writes fail closed rather than degrade to best-effort. Declareatomicity: 'cross-process'only for a backend whose compare-and-set really is atomic across writers โFileStoreandInMemoryStoreare not. See run store. - Rehearse the resume path.
restore()needs the team wiring rebuilt and, for arunTeamrun, the samecoordinatorconfig, because a checkpoint cannot persist a live adapter. Without it, restore falls back to raw per-task output. See resume.
Observability and audit
- Wire progress events, traces, or both.
onProgressgives lifecycle events for logs and live UIs;observability.sinksgives structured records. Neither is on by default. See observability. - Own the sink lifecycle. OMA never shuts down an injected sink,
installs a signal handler, or calls
process.exit(). CallforceFlush()in a serverless invocation andshutdown()before a short-lived process exits, or you will lose the tail of every run. See flush and shutdown. - Accept that telemetry is not execution state. Delivery and export failures never become run failures, and deleting traces never deletes checkpoints or shared memory.
- Know exactly what redaction covers. A shared credential redactor runs
over trace attributes, tool I/O, status messages, task metadata,
bashoutput, process-backend stderr, and evaluation payloads. It is credential-shaped and best-effort: PII is not covered by default, and checkpoints and shared memory are outside it entirely. Wrap every durable store inRedactingStoreif agent output may carry secrets. See redaction, the default privacy boundary, and redacting persisted secrets. - Turn on the run journal if you need to reconstruct what a model saw.
Opt-in, and you supply the backend instance;
verifyRun()then checks offline that every model-visible block is reproducible from the log. See run journal. - Decide how a finished run gets inspected. The Run Viewer is a self-contained offline HTML artifact built from an allowlisted payload, with no remote loads and no write path back into the run. See Run Viewer.
- Add the OpenTelemetry adapter only if you already run an OTel stack.
It is a separate optional package on its own version track, and the
application owns the
TracerProviderand its lifecycle. Seepackages/otel/README.md.
Evaluation
- Have an EvalSet before you have a regression. Offline evaluation runs scorers over cases independently of production traffic. See evaluation.
- Gate CI on a policy, not on a glance at the numbers.
evaluateGate()turns a report plus thresholds and an accepted baseline into a pass/fail verdict a job can act on. See evaluation in CI. - Keep online sampling out of the request path. Sampling, scoring, and
persistence are best-effort and isolated from the business response, and a
scorer failure is recorded as
scorer_errorrather than a zero, so it cannot quietly drag an average down. See scorer failures are not zero scores. - Check
storePayloadsagainst your retention rules. It defaults to'none', so records carry scores and references but no input/output snapshots. A model-based judge still sends the evaluated output to the judge model regardless. See privacy.
External agent boundaries
Skip this section if no agent sets AgentConfig.backend.
- Re-check which controls still apply. Task DAG placement, dependency
cascade, the plan and dispatch gates, shared memory, run and task journal
events, and abort propagation all still work. The
onToolCallgate, the filesystem sandbox,egressPolicy, tool-level journal events, and mid-task checkpoints do not, and no configuration makes them. See control boundary. - Change the ACP permission default. Default is permissive:
permissionis'auto-approve', so every prompt the agent raises is answered yes. Only'reject'or a callback makes it a real gate. - Do not rely on a budget to bound an external agent. A process-backend
agent reports zero tokens and an ACP agent reports none unless it emits
usage_update, so neither is budget-gated in practice. Bound them with their own flags. See ACP token accounting.
Before the first production run
A short smoke pass that exercises the decisions above end to end:
- Run the real goal with
planOnly: trueand read the plan. - Run it once with a deliberately low
maxTokenBudgetand confirm your handler seesbudget_exceededand the skipped tasks. - Kill the process mid-run and resume from the checkpoint.
- Deny one tool call from
onToolCalland confirm the agent adapts instead of crashing. - Flush the sink and confirm the last records actually arrived.
Related pages
- Budgets and limits
- Tool configuration and sandbox and shell
- Egress policy and self-hosting
- Durable approvals and hooks and callbacks
- Checkpoint, run store, adaptive recovery, and task scheduling
- Observability, run journal, and Run Viewer
- Errors for the full error taxonomy
- External agents