Binding Approval
Cryptographic intent gate with an isSigning state.
Install
npx ax-depute@latest add binding-approvalpnpm dlx ax-depute@latest add binding-approvalyarn dlx ax-depute@latest add binding-approvalbunx ax-depute@latest add binding-approvalOverview
Unlike a standard ApprovalGate used for day-to-day coordination, BindingApproval provides a heavy-duty friction boundary for irreversible, legally binding, or financial actions. It forces explicit acknowledgment of terms and implements a multi-phase isSigning visual state.
Wire Transfer Authorization
Under ReviewAgent requests authorization to execute a $5,000 wire transfer.
Basic Usage
<BindingApproval
title="Wire Transfer Authorization"
description="Execute a $5,000 wire transfer."
impactStatement="$5,000.00 will be transferred immediately."
signerIdentity="alice@company.com"
terms={[
{ id: 't1', text: 'I authorize the transfer of $5,000.00', acknowledged: false },
{ id: 't2', text: 'I understand this action is irreversible', acknowledged: false },
]}
onSign={() => initiateSignature()}
/>Solution Patterns
This primitive replaces ApprovalGate in high-stakes nodes. The internal state expects a clear distinction between reviewing and signing, where isSigning: true disables interaction and renders a deterministic loading state while waiting for the protocol layer to secure the ledger / signature.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Title of the binding action |
description | string | — | Detailed explanation of the action |
impactStatement | string | — | Estimated impact (e.g., "$5,000 will be transferred") |
status | 'reviewing' | 'signing' | 'signed' | 'rejected' | 'expired' | 'reviewing' | Current status |
terms | BindingTerm[] | — | Terms that must be acknowledged |
requireAllTerms | boolean | true | Require all terms acknowledged to sign |
isSigning | boolean | false | Toggles the active signing visual state |
signerIdentity | string | — | Identity of the approver |
timeoutSeconds | number | — | Signing window timeout |
onSign | () => void | — | Called when approved/signed |
onReject | (reason?: string) => void | — | Called when rejected |
Design rationale
When to use ApprovalGate vs BindingApproval:
ApprovalGate | BindingApproval | |
|---|---|---|
| Use when | The action is reversible, operational, or low-to-moderate stakes | The action creates a legal, financial, or cryptographic record |
| Friction level | Quick scoped grant — review and approve | Mandatory term acknowledgment + signing flow |
| State model | pending → approved / rejected | reviewing → signing → signed / rejected |
| Examples | "Send this email", "Deploy to staging", "Run this query" | "Wire $50k", "Sign this contract", "Commit to ledger" |
Use ApprovalGate by default. Escalate to BindingApproval only when the action is irreversible and the user's identity must be cryptographically bound to the decision.
Why isSigning? Normal approvals execute instantly. Cryptographic/financial approvals often require a ledger transaction, hardware wallet interaction, or passkey challenge that takes time. isSigning freezes the component deterministically to prevent duplicate submissions.
Why explicit terms? Click-fatigue trains users to blindly click "Approve." Forcing the user to manually acknowledge explicit terms (e.g. "This action cannot be undone") breaks automatic behavior and captures verifiable intent.