Human Validation
Touba reserves the human.* namespace for two statements, distinct from a tool:
human.approve, a barrier imposed by the program (required_approvalmode);human.review, a review initiated by the logic of askillorstrategy(agent_reviewmode).
In both cases, the runtime suspends execution and resumes only after an explicit human decision. An approved decision remains a runtime decision: it does not become a Verified proof.
Shape
human.approve
with context as reviewed_change
into approval
human.review
with context as analysis
into decision
Common rules:
contextis the only required argument;intois required;- these statements are allowed in
skillandstrategy; - they are forbidden in
function, preserving function purity.
Simple Case
module examples.validation_simple
type ChangeRequest
summary is Text
type AppliedChange
summary is Text
tool ApplyChange
takes request as ChangeRequest
gives AppliedChange
requires filesystem_write
skill ReviewAndApply
takes request as ChangeRequest
gives AppliedChange
uses ApplyChange
do
human.approve
with context as request
into approved
ApplyChange
with request as request
into applied
show
with message as "Change applied"
give applied
human.approve blocks execution before ApplyChange. Without an approved decision, the side-effecting tool (requires filesystem_write) is never reached.
Observable Decisions
A human decision can be provided from a file or inline with
--human-decisions-json. The useful V1 validation values are approved and
rejected.
With approved, the runtime resumes after the human.approve or
human.review point, then continues the do block.
With rejected, the runtime stops the current scope before the next external
effect. The trace contains the decision, the rejection event, then run
completion with a stopped status. The result is null if no other result has
been produced:
human_approval_decided decision=rejected
human_approval_rejected
scope_exited status=stopped
run_completed status=stopped
The approval identifier is produced from the AIR graph. For a deterministic test scenario, you can provide the decision at run start:
touba run program.air.json \
--human-decisions-json '{"approval:graph:skill:examples.review/ReviewAndApply:node:graph:skill:examples.review/ReviewAndApply:1":"rejected"}' \
--output trace
Advanced Case
module examples.validation_advanced
type Analysis
confidence is Float
summary is Text
skill ReviewWhenNeeded
takes analysis as Analysis
gives Analysis
do
if analysis.confidence < 0.8
human.review
with context as analysis
into decision
give analysis
else
give analysis
Here, human.review is triggered only in one branch: the decision to request human review depends on logic computed by the skill, not on an unconditional barrier.
human.approve vs human.review vs request_human_review
human.approve: a static barrier written in the program. The stop condition does not depend on a model decision.human.review: a source statement, but the decision to reach it can depend on conditional logic in askill/strategy.request_human_review: an action that an agentic decision provider may choose during anagentloop, without being written as a statement in source. See Governed Agentic Decision for this separate mechanism.
Roles, deadlines and separate signers
The program can require a role, a deadline and a different signer. The trusted host authenticates people and attests their current roles. Model output never serves as an identity attestation.
human.approve
with context as invoice
with role as "finance"
with timeout_ms as 3600000
with distinct_from as "initiator_and_previous"
into approval
These optional arguments are static literals. role is a non-empty identifier
(up to 128 UTF-8 bytes), timeout_ms is 1..2592000000 ms (30 days), and
distinct_from is "initiator", "previous" or "initiator_and_previous".
Previous signers are those whose approval was already accepted in this run,
including nested calls and parallel branches.
An on expired branch can request another approval. Every path in that branch
must end with give or stop; it never falls through to the protected
continuation. Without this branch, expiration stops the run. At the exact
deadline, expiration wins. A timely accepted decision remains valid for its
one occurrence after restart; each new request checks current rights again.
Opaque signer identities stay in the private checkpoint, not the public trace. See the roles and deadlines tutorial.
Runtime Contract
human.approveandhuman.revieware nottools: they do not go throughAirTool.idand have no handler.- Pauses and resumes are explicit: Touba does not read
stdinimplicitly and does not invent an interactive prompt. - An accepted human decision does not automatically transform a result into a formal proof (
Verified). - Inline implementations, arbitrary
human.*names, and richer human workflow handlers are handled through dedicated interface surfaces.
Resume and External Effects
A typed agent called from a source workflow keeps its own inputs separate from
its caller's values across resume. Identically named parameters cannot replace
the caller's values; only the returned result is bound by into. This remains
true across multiple pauses. An agent-call checkpoint missing either scope
is refused before invoking the provider. Checkpoints can contain business
data: protect their storage; they are not public traces.
--human-decisions injects decisions at the start of a run. Each decision authorizes one occurrence, not future loop iterations or later invocations of the same approval statement. The AIR approval reference remains static; a new encounter requires a new decision for the current checkpoint. This path serves deterministic scenarios. To resume after an external effect has already been produced, use a resume checkpoint.
For an explicit human_approval node or an agentic request_human_review in a sequential stack of source calls and agent-selected capabilities, Touba can write a resume checkpoint:
touba run program.air.json \
--human-checkpoint-out human.checkpoint.json \
--output trace
Resume then consumes that checkpoint and an explicit human decision:
touba run program.air.json \
--human-resume-checkpoint human.checkpoint.json \
--human-decisions-json '{"approval:example":"approved"}' \
--output trace
This checkpoint avoids redispatching already-produced effects in this bounded case. Without a checkpoint, a human pause after external dispatch is refused with HumanApprovalPauseRequiresDurableResume.
Human checkpoints also preserve the source-call stack of skills and strategies, including separate values, types and loop cursors for each invocation. An approval inside a subworkflow, or a review requested by an agent called from that chain, resumes at its saved position and returns through its callers. Completed calls are not replayed; budgets, consumed active time and effect IDs remain run-wide. Errors after resume follow the declared failure paths. Invocation depth is bounded to 64 calls.
The entire stack is validated before any new effect. Only the current V1 format
is accepted, including call_stack and every required scope; incomplete older
states are not converted. Resolved secrets are refused in ancestor scopes too.
A local checkpoint is trusted host state, not a signed attestation.
The stack also preserves agent-selected capabilities, including a subagent requesting review or calling a subworkflow. After the human decision, Touba finishes the pending call, adds its result to the caller's observations and resumes that loop at the next step. It does not ask the model to repeat an already made selection. A single host-selected capability remains a call/return, without adding a model loop. Earlier step ceilings remain effective; a human decision is not reused across invocations.
Human approvals are also supported inside parallel groups: each wait belongs
to one branch occurrence. The group suspends new starts and drains in-flight
calls to serializable boundaries. Its checkpoint preserves completed branches,
continuations, budgets and consumed decisions. A decision does not authorize
other branches. Completed branches are not dispatched again after resume.
The recovery guide distinguishes human continuations, parallel progress checkpoints and the sequential durable-resume profile. None guarantees crash recovery at an arbitrary instruction or universal exactly-once external effects.