Skip to main content
An engine-backed node attempt is one fresh engine call doing one piece of work. Command adapters use one fresh CLI process; data-only attempts use no engine process. The runtime records what was requested, what actually ran, what came back, and whether token usage was reported or unknown. The graph executor connects attempts to graph dispatch. Hosts coordinate checks against installed CLIs and process cleanup after runner death.

Run the example

From an Obversa checkout, run:
The report prints the stub executable paths relative to the temporary directory. The exported attemptReport keeps the absolute paths from the adapter results. The example uses local scripted executables. It does not call a model or the network. Grok returns a native structured result. OpenCode returns one marked text part, which the job-owned parser reads. Both adapter results pass through the public result validator before their final parts are used. OpenCode deliberately omits a valid usage receipt, so the runtime keeps its usage as unknown instead of zero.

Source

The output records both requested and effective identities. If a CLI reports a different model, the two records stay separate instead of hiding the change. Each identity records the adapter, adapter version, provider, model family, model, capabilities, and executable. Command adapters record the absolute path they selected. An engine with no child executable uses null. 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. temporaryDirectoryRemoved covers only this example’s fixture files. The package test suite separately checks child-process cleanup on handled exits.

Headless process markers

Command adapters set three environment variables before they start a process:
  • OBVERSA_HEADLESS=1 tells hooks and child tools that the attempt is unattended, so they must not open interactive or desktop prompts.
  • OBVERSA_RUN_ID identifies the run that owns the process.
  • OBVERSA_ATTEMPT_ID identifies the exact node attempt and lets cleanup find descendants that detach from their parent process.
Child processes inherit these values unless they replace their environment.

Keep results and usage honest

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 remains a failed attempt. Usage has two states. reported means the engine supplied a valid receipt. unknown means it did not. Unknown usage never becomes a fake zero.

Declare access before the process starts

tools lists the built-in capabilities the CLI may expose. allowedTools holds the narrower permission rules approved by the host. The selected adapter rejects a rule it cannot express before it starts the process. 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.

Keep fallback and cleanup visible

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. timeoutMs is the work deadline. At that point a command adapter starts stopping its process tree. timeoutGraceMs is teardown time: the adapter asks the processes to stop, waits for that grace, then force-stops any that remain. The grace does not start more model work. A marked final result returned inside the final-result deadline stays separate from a later transport failure. If process cleanup makes the adapter return after that deadline, the attempt fails with TIMEOUT and its parsed result stays null. The record still keeps the returned parts, reported usage, effective engine, and transport failure as evidence. After the deadline, the runtime waits up to seven more seconds for that cleanup evidence. This fixed wait cannot turn the attempt into a success. The command-adapter kit cleans its process tree on normal completion, timeout, abort, and other handled exits. The runtime waits for that cleanup before it records the attempt. Recovery after the supervising process dies, and checks against installed CLIs, are separate host responsibilities.