Activation status: The exact public browser-action refinement is
source-ready, with compatible Worker code deployed. Required production
database activation and authenticated approval canaries remain pending.
Praxa’s existing product approval gates remain live; this page does not claim
that every product gate is exposed through /v1.
The first public approval boundary is deliberately specific. A durable task can
park on an immutable browse_session_act action. Praxa exposes that action only
when it can re-derive the exact instruction or steps, target host, and matching
digest from the stored executor input.
Generic tool approvals, email approvals, configurable approval policy, and
candidate turn approval-resume flows are not available on the public execution
API. mode:"turn" returns 400 invalid_request, and /v1/chat is not routed.
Lifecycle
- A
mode:"task"run reaches an exact browser action that requires approval. - The run projects
status: "awaiting_approval"and apendingApproval. - Its resumable SSE feed emits the same presentation as
approval.required. - Your application renders
summaryexactly as supplied and collects one explicit decision. - Your backend posts the unchanged digest with
approveordeny. - Praxa re-derives the stored presentation and digest before recording the decision and waking the suspended workflow.
- Your application follows the run until a real terminal event.
awaiting_approval, not waiting_approval.
The event envelope uses run_id, not the offline candidate turn schema’s
requestId or toolCallId.
Render == record == gate-match
summary is the canonical public presentation. Do not truncate, paraphrase,
translate, reorder, or reconstruct it. The action the person sees, the action
Praxa recorded, and the action the resume gate validates must remain the same.
The action_digest binds authority to this one action instance. If the action,
host, steps, state, or approval reference changes, an old digest no longer
matches. If Praxa cannot prove the exact presentation, it emits no public
approval, omits pendingApproval, and refuses a decision.
Record a decision
runs:write. The request literal is exactly approve or deny.
The updated run response is not proof that the browser action or the run has
finished. Continue reading the run or its event stream until run.completed,
run.failed, or run.cancelled.
A deny decision never authorizes the action. It may begin cancellation and
close-out processing, so observe the resulting terminal state rather than
inventing one in your UI.
Fail-closed cases
Praxa refuses a decision when the run is foreign, the action is unsupported, the approval is expired or already resolved, the digest is absent or stale, the immutable executor presentation fails validation, or workflow wake-up fails. A stale or mismatched digest returns409 conflict.
The event and pending projection may include expiresAt. Treat it as
authoritative for UI controls, but rely on the server to reject a late decision.
The durable v1 contract does not promise an expired run status or a turn-style
request.failed event; follow the durable run to its actual terminal
projection.
Internal gates versus the public boundary
Praxa already uses fail-closed approvals across purchases, browser actions, connector writes, social posts, credentials, and other product surfaces. Those existing gates are evidence for the safety pattern, not evidence that a unified configurable policy engine or every approval domain is exposed through/v1.
The public boundary starts with the exact browser action above.