examples/safe-node-attempt.ts (excerpt)
promptandmodel, what to ask and which model to ask.tools,allowedToolsandworkspaceMode, the access the process may have.timeoutMs,maxOutputBytesandmaxMemoryBytes, the bounds one turn runs inside.
Run an adapter
Each adapter runs one attempt and returns a result the public validator checks before its parts are used:examples/safe-node-attempt.ts (excerpt)
unknown instead of zero. Run it with
npx tsx safe-node-attempt.ts:
Output
attemptReport keeps the absolute paths. Both
requested and effective identities are recorded. If a CLI reports a
different model, the two records stay separate and the change stays
visible. Each identity records the adapter, adapter version, provider,
model family, model, capabilities and executable: the absolute path a
command adapter selected, or null for an engine with no child process.
When the engine runs with an effort, each identity also records it.
A host that writes an engine’s selection itself names the effort in
the selection, the same way it names the model. The runtime passes that
effort to the engine with each request, preflight checks included. An
effort set on the engine itself still applies to a request that names
none, so an engine built with its own effort under a selection that names
a different one, or none, reports a different requested identity, and the
attempt fails. Name the effort in one place: the selection.
The path identifies the selected wrapper, not its resolved target or file
digest. When no Claude or Codex binary is configured, those plugins search
the inherited PATH once and record the absolute path they select.
Declare access
tools lists the built-in capabilities the CLI may expose. allowedTools
holds the narrower permission rules approved by the host. An adapter that
can’t express the declared access refuses the request before it starts the
process, so no model runs.
The workspace mode is a ceiling. An approval never adds a capability the
mode withholds, and a bypass never goes past it. A reviewer with no way to
read the work is refused rather than run, so a review rests only on
material the seat could open. The example uses workspaceMode: 'none' and
exposes no tools. An evidence-only job can use workspaceMode: 'read' with
declared read tools. A writing job must name its write access and gets a
separate scratch directory for temporary data.
An action decision is made before an effect: allow runs it, wait pauses
it, and deny records a refusal without running it.
Read results and usage
A successful result has ordered parts and exactly one final part. A stopped or truncated turn can keep the parts it produced, including no parts at all, but it’s still a failed attempt. Usage has two states.reported means the engine supplied a valid receipt.
unknown means it didn’t. Unknown usage never becomes a fake zero.
Command adapters set three environment variables before they start a
process, and children inherit them unless they replace their environment:
OBVERSA_HEADLESS=1tells hooks and child tools that the attempt is unattended, so they must not open interactive or desktop prompts.OBVERSA_RUN_IDidentifies the run that owns the process.OBVERSA_ATTEMPT_IDidentifies the exact attempt and lets cleanup find descendants that detach from their parent process.
Failure
- Fallback. One attempt can use one declared fallback after a model becomes unavailable. The failed model stays in the attempt record. Both lanes share one clock, so a fallback receives only the time left by the first lane. The graph executor uses durable events to keep later graph work away from that model.
TIMEOUT.timeoutMsis the work deadline; at that point a command adapter starts stopping its process tree.timeoutGraceMsis teardown time: the adapter asks the processes to stop, waits that long, then force-stops any that remain. The grace doesn’t start more model work. A marked final result returned inside the deadline stays separate from a later transport failure. If cleanup makes the adapter return after the deadline, the attempt fails withTIMEOUTand its parsedresultstaysnull, while the record keeps the returned parts, reported usage, effective engine and transport failure as evidence. The runtime waits up to seven more seconds for that cleanup evidence, and the wait can’t turn the attempt into a success.- Cleanup. The command-adapter kit cleans its process tree on normal
completion, timeout, abort and other handled exits, and the runtime waits
for that cleanup before it records the attempt.
temporaryDirectoryRemovedin the output covers only the example’s fixture files; the package test suite checks child-process cleanup separately.
Limits
- Hosts own two things. Recovery after the supervising process dies, and checks against the CLIs installed on the machine. The supervised runner does both.
Full file
Full file
examples/safe-node-attempt.ts
Next steps
- Supervised local runs: the watchdog that checks engines before the first step and restarts a killed worker.
- Events and artifacts: the stores an attempt’s events and parts land in.
- API: the engine contract every adapter implements.