ntro.workflow is the orchestration surface every runbook subclasses. For the concept-level walkthrough of authoring a runbook, see Build runbooks. This page is the API reference.
Install
[workflow] extra brings in Temporal, all ntro.capabilities.* modules, ntro.events, ntro.accounting, and ntro.data — everything a runbook needs at runtime.
Surface
| Symbol | Kind | Purpose |
|---|---|---|
NtroWorkflow | class | Base class for all runbooks. Subclass + decorate with @runbook.defn. |
runbook | facade object | Mirrors temporalio.workflow — decorators (.defn, .run, .signal, .query, .step) and runtime helpers (.execute_activity, .wait_condition, .info, .now, .logger). |
activity | facade object | Mirrors temporalio.activity — .defn decorator, .info(), .logger. |
WorkflowError | exception | Raised inside activities to fail the workflow. non_retryable=True flags deterministic-input failures so retries don’t loop. |
await_signal_with_action | method on NtroWorkflow | Block until a predicate is satisfied; advertise the pending action via current_pending_action. |
wait_for_action | method on NtroWorkflow | Block on a HITL approve / reject / correct signal from the Tenant UI. |
run_child_workflow | method on NtroWorkflow | Dispatch another runbook by slug. Children appear as nested progress trees in the UI. |
previous | function | Load committed-document context from a prior task. See ntro.workflow.task. |
Runtime backends
runbook and activity dispatch to whichever backend is auto-selected at first attribute access:
| Backend | Selected when | Behaviour |
|---|---|---|
| TemporalRuntime | temporalio is importable AND TEMPORAL_HOST is set — i.e. inside an ntro-worker pod | Every facade call passes straight through to temporalio.workflow.X / temporalio.activity.X. Production behaviour, unchanged from pre-N-102. |
| LocalRuntime | Anywhere else — local dev, CI smoke jobs, Claude MA sandbox | Activities run as direct await fn(...) coroutines; child workflows run on the same event loop; signals are plain method calls; wait_condition polls at 50ms granularity. No durability, no retries, no replay — exceptions bubble up immediately. |
ntro.workflow.set_runtime(...) before importing any runbook module. Otherwise the auto-selection runs once and is cached.
NtroWorkflow
| Name | Kind | Returns / accepts | Purpose |
|---|---|---|---|
current_pending_action | query | {action, display_hint} | What is the workflow waiting for? Polled by Tenant UI. |
current_steps | query | list[{id, title, status, icon}] | The @runbook.step ladder + per-step status. |
current_ui_state | query | combined snapshot | One-shot read for UI rendering. |
user_action | signal | {action, payload} | UI dispatches approve / reject / correct here. |
tb_submitted, document_submitted, …) as needed.
@runbook.step
| Arg | Type | Purpose |
|---|---|---|
name | str | Stable step id (used in current_steps, snapshots, child-workflow ids). |
title | str | Display name in the Tenant UI breadcrumb. |
icon | str | Lucide icon name. |
_current_step_id, _steps_completed) tracks automatically. Class-definition order is breadcrumb order in the UI sidebar.
wait_for_action
Block on a HITL signal. The display_hint tells the Tenant UI which review component to render.
| Arg | Type | Purpose |
|---|---|---|
payload | Any (pydantic-serialisable) | What the user is reviewing — rendered by the UI component. |
display_hint | dict | UI component selector + config. |
reason | str | One-line description shown in the pending-action chip. |
UserAction(action, payload, corrections). corrections is workflow-specific (e.g. row-level edits to an extracted document).
await_signal_with_action
Block until a predicate is true. Advertises the pending action via current_pending_action so the UI knows what to surface.
@runbook.signal handler that mutates the predicate’s state.
run_child_workflow
Dispatch another runbook. Children get their own progress tree under the parent’s step.
| Arg | Type | Purpose |
|---|---|---|
slug | str | The child runbook’s slug (registered with the worker). |
input | pydantic model | Child workflow input. Must match the child’s declared Context model. |
step_id | str | Parent step id this child belongs to — drives UI nesting. |
many (fan-out): call run_child_workflow in a loop; awaits join.
WorkflowError
Raised inside an activity to fail the workflow. Replaces the legacy from temporalio.exceptions import ApplicationError import.
| Arg | Type | Purpose |
|---|---|---|
message | str | Human-readable failure message. |
type | str | None | Error type tag — the worker interceptor uses this to discriminate deterministic-input failures (e.g. "VALIDATION") from infra failures. |
non_retryable | bool | When True, the worker marks the failure as non-retryable so the workflow fails fast rather than re-attempting the activity. Use for deterministic-input failures where retrying can’t change the outcome. |
TemporalRuntime, WorkflowError subclasses temporalio.exceptions.ApplicationError so the ntro-worker’s existing non-retryable interceptor catches it unchanged. Under LocalRuntime it subclasses Exception directly — non_retryable has no effect (there are no retries to suppress) and the exception bubbles up to whoever awaited the activity.
For Temporal’s ActivityError wrapping pattern (used in the journal-proposer’s HITL-vs-propagate discrimination), also re-exported:
LocalRuntime both alias to WorkflowError so the except (ActivityError, ApplicationError) clause parses — though no exception is actually wrapped in ActivityError under LocalRuntime, the ApplicationError branch picks up WorkflowError directly.
Running locally
ntro.workflow.run_local(cls, arg, *, workflow_id=..., task_queue=...) is the entry helper for python -m runbooks.X-style scripts. Instantiates the runbook, sets up the WorkflowInfo contextvar, and awaits cls().run(arg).
See Running locally for the full walkthrough — when LocalRuntime is selected, what works and what doesn’t, and how to force a specific runtime from test fixtures.
Related
Build runbooks (concept)
Worked walkthrough of authoring a runbook from scratch.
ntro.workflow.task
Load context from prior task executions.
ntro.workflow.agents
Invoke a registered external agent from inside a
@runbook.step.Running locally
Run a runbook end-to-end in-process under
LocalRuntime — no Temporal cluster, sub-second feedback.UI and Temporal signals
How Tenant UI actions reach workflows end-to-end.