Skip to content

Observability & Debugging

Invariant exposes two different records:

  • Runtime events are durable facts used to derive execution state.
  • Diagnostic traces explain how handlers, models, and validation boundaries behaved. Traces do not decide execution truth.

Enable Console Tracing

ts
import { consoleTraceSink, invariant } from "@invariant/sdk";

const app = invariant({
  observability: {
    level: "debug",
    sinks: [consoleTraceSink({ level: "debug" })],
    capture: {
      reasoningBoundary: true,
    },
  },
});

debug: true also installs a console sink, but reasoning payloads remain metadata-only by default. Set capture.reasoningBoundary: true only when the sink is approved to receive prompts, projected context, tools, and raw model responses.

What You Can Inspect

Current SDK execution paths emit diagnostics for:

  • Agent and workflow .reason() call start, completion, failure, duration, and available token usage,
  • projected context and provider tool declarations when capture is enabled,
  • Agent action receipt, acceptance, rejection, and validation details,
  • workflow start and input rejection,
  • node entry and completion,
  • capability dispatch, completion, and failure,
  • wait input receipt, validation rejection, and boundary conflict.

Not every event shape exported by the trace type union is emitted by every adapter. Treat the sink output from your chosen execution path as the operational contract.

Debug a Rejected Action

  1. Read the agent.action.rejected or wait rejection trace.
  2. Check the validation code and issues.
  3. Inspect the fresh action surface or active .wait() schema.
  4. Compare the rejected proposal with session.snapshot().
  5. Confirm that execution revision and event history did not change.

Debug Durable Progress

ts
const state = await app.storage?.loadState(runId);
const events = await app.storage?.readEventLog(runId);

console.log(state?.revision, state?.status, state?.currentNodeId);
console.table(events?.map(({ seq, type }) => ({ seq, type })));

Use events to answer “what became true?” Use traces to answer “why did this handler or model produce that proposal?”

Sensitive Data

Projection boundaries should remove secrets and unnecessary PII before model calls. Full reasoning capture is opt-in and can record exactly what crossed that boundary, so production sinks require access controls, retention policy, and redaction appropriate to the application.

Next Steps

Invariant Durable Execution Engine.