Guarding workflows
const workflow = guardWorkflow(monitor, incidentWorkflow)guardWorkflow rewrites both the step map and the execution graph. A committed workflow holds direct step references
in that graph, so replacing the map alone would leave the engine running the originals — a guard that looks installed and
is not.
guardStep does one step at a time, for the case where you want a guard on some steps and not others.
What a step guard adds to a tool guard
Section titled “What a step guard adds to a tool guard”The framework’s own suspension primitive. When a guarded step would violate a rule in suspend, the guard pauses through
the engine’s suspension rather than through anything of its own, so the pause is as durable as any other — it survives a
process restart, and the run can be resumed minutes later by something else entirely.
Asking a human is that flow end to end.
The guarded step’s suspend and resume schemas are widened to admit one extra variant alongside whatever the step already declared. Everything else the step accepts is still validated.
deny on a step
Section titled “deny on a step”deny bails the run rather than returning the violation object. A step’s return value is bound by its output schema, and
there is no equivalent of handing a model something to adapt to — the whole reason deny composes with an agent is that
an agent can read a refusal and try again, and a workflow step cannot.
If you want a step to be stoppable-but-resumable, that is suspend. If you want it to end the run, that is deny or
abort.
A step that suspends for its own reasons
Section titled “A step that suspends for its own reasons”Unaffected. The guard notices the body reached for suspend, records a pause rather than a finish, and does not announce
a second start when it resumes. A workflow that already uses suspension for its own human-in-the-loop steps does not
start double-counting them because a guard was added.