Skip to main content
Quality checks let a runbook ask a separate model to evaluate whatever the previous step produced — extracted invoice fields, a proposed journal, a calculated NAV — before a human ever sees it. The check result feeds the Tenant UI’s review screen alongside the underlying value, so the accountant reviewing the output sees the AI’s own assessment of “I’m pretty sure I got this right” or “this looks off, please double-check the GL mapping”.

Install

The capability is bundled with the workflow extra.

The API

Returns a structured CheckResult with:

Wiring into a runbook

Quality checks are typically run as a Temporal activity right after the thing they’re checking. Lifted from nav-monthly-journals:
The re-export pattern matters. run_quality_check is implemented in the SDK, but the worker only registers activities it can find via the runbook’s activities.py. Re-exporting run_quality_check (and the other shared activities you need) in __all__ is what wires it into your bundle.load_previous_task_activity is re-exported above because checks frequently want prior-period baselines for MoM deltas. See Task lookups for the full helper.
The actual call site is just await run_quality_check(...) from inside the workflow:
The Tenant UI renders the CheckResult next to the underlying JournalProposal — the accountant sees both the proposed journal and the model’s “I checked the balance, debits = credits, looks balanced” alongside it.

Designing a good check

Quality checks work best when they’re focused. A check that’s “review this entire NAV” is hard to interpret. A check that’s “verify the journal balances and that all GL codes exist in the COA” is actionable. Common shapes: Each slug routes to a check definition in your provider configuration. The same model and prompt setup used by ai.extract backs run_quality_check.

Severity drives routing

The severity field affects how the Tenant UI surfaces the result:
  • info — green check, accountant sees “all clear” and approves quickly
  • warn — yellow flag, accountant sees the finding inline with the value
  • error — red block, the workflow can wait_for_action with must_resolve=True to force a correction before approval
Pair severity == "error" with wait_for_action(must_resolve=True) to guarantee the human can’t approve over the top of a critical issue.

Workflows overview

Where you wire the check into the run via @runbook.step.

Private AI

The same provider plumbing backs both extraction and checks.