Put a gate on the
irreversible step.
An autonomous agent doesn't fail on the 10,000 safe actions — it fails on the one spend, send, publish, or delete it can't take back. guard_action is a $0.02 pre-commit gate you wire into your loop: an independent allow / review / block right before the point of no return — and every decision leaves an Ed25519-signed receipt you can verify forever.
The same action, with and without the gate
Your agent proposes a wire transfer off a scraped invoice. One path has a second opinion at the moment of no return. One doesn't.
Illustrative of a real guard_action quick-tier response. Fail-closed: it won't allow what it can't justify as safe — uncertainty escalates to review, real red flags block. Want to check a real signed receipt yourself? Do it live on /proof →
Wire it in — copy, paste, done
The pattern is the same everywhere: gate every side-effecting call. If Verity doesn't allow, you don't act. Start with the official SDK for your stack — or drop in the raw pattern in any language:
# Python — pip install "verity-guard[x402,langgraph]" from verity_guard import VerityClient from verity_guard.payer import x402_payer # spend-capped + Base-pinned from verity_guard.integrations.langgraph import GuardedToolNode # drop-in for LangGraph's ToolNode: guards every tool call; blocked ones never run v = VerityClient(http=x402_payer(os.environ["WALLET_KEY"])) graph.add_node("tools", GuardedToolNode(tools, v, policy="No new payees without human review.")) # also bundled: OpenAI Agents build_tool_input_guardrail(v), CrewAI + LangChain tools, @guard decorator // Node — npm i @veritylayer/guard @x402/fetch @x402/evm viem import { VerityClient } from "@veritylayer/guard"; import { x402Payer } from "@veritylayer/guard/payer"; import { verityGuardTool } from "@veritylayer/guard/vercel"; const fetchPaid = await x402Payer(process.env.WALLET_KEY); const tools = { verityGuard: verityGuardTool(new VerityClient({ fetch: fetchPaid })) };
// guardedAct.ts — wrap ANY irreversible action. // Needs an x402 v2 fetch + a funded Base wallet, so the $0.02 settles // automatically. VerityLayer holds no key. Use the SCOPED @x402/* (2.x) // packages: the old unscoped "x402-fetch" is the v1 client and reads the // challenge from the body — ours is in the payment-required header. // npm i @veritylayer/guard @x402/fetch @x402/evm viem import { x402Payer } from "@veritylayer/guard/payer"; // Spend-capped ($1.00/call) and chain-pinned (Base) — a hostile 402 // can't name its own price, because the endpoint is not a trust anchor. const fetchPaid = await x402Payer(process.env.WALLET_KEY); const SUITE = "https://suite.veritylayer.dev"; export async function guardedAct(action, doIt, opts = {}) { const r = await fetchPaid(`${SUITE}/check/quick`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ action, ...opts }), }).then((r) => r.json()); // No verdict and a "block" verdict are different facts — both stop you, // but only one of them was ever checked. Never let them read the same. if (!r.decision) throw new Error("VerityLayer NOT CHECKED — no verdict exists. Not an allow."); if (r.decision.trim().toLowerCase() !== "allow") throw new Error(`VerityLayer ${r.decision}: ${r.reasons}. Safer: ${r.safer_alternative}`); return doIt(); // only runs if Verity allowed it — and r.receipt is your signed proof }
# Install once: npx -y @veritylayer/mcp — then put this in your agent's system prompt:
Before ANY irreversible step (spend, send, publish, delete, share), call the
guard_action tool with a plain-language description of what you're about to do.
If the decision is "review" or "block", stop and surface the reasons and the
safer_alternative to the user instead of proceeding.
SIDE_EFFECT_TOOLS = {"send_payment", "send_email", "post_tweet", "run_shell", "delete"}
def pre_tool_hook(tool_name, tool_args):
if tool_name in SIDE_EFFECT_TOOLS:
r = guard_action_quick(action=f"{tool_name}({tool_args})") # your $0.02 call
decision = (r.get("decision") or "").strip().lower()
if not decision: # unreachable, unpaid, malformed: NO verdict exists.
return Interrupt(reason="verity NOT CHECKED — no verdict. Not an allow.")
if decision != "allow": # .lower(): "BLOCK" must never slip past a == "block"
return Interrupt(reason=r.get("reasons"), alternative=r.get("safer_alternative"))
return proceed()
Every decision leaves a receipt
A gate that just says "no" is a filter. A gate that hands you portable, re-verifiable proof of every call it cleared or stopped is an audit trail — the record you keep for compliance, incident review, and proving to anyone what your agent was allowed to do.
Ed25519, self-contained
Each verdict ships a receipt signed by Verity's key. It proves — forever, offline — exactly what was decided for exactly what action. No database, nothing to expire.
Verify without us
Anyone with the receipt + our public key can verify it — offline, or via the free POST /receipt/verify. You never depend on Verity being online to trust a past decision.
A trail that compounds
Every session, every risky step, one more signed record. Rip Verity out and you lose the audit trail — which is exactly why teams leave it wired in.
Honest by construction. allow / review / block are priced identically — no charging more to block you. Fail-closed: it won't allow what it can't justify. Pay-per-call via x402 (USDC on Base). VerityLayer holds no key and never moves your money.
Give your agent a second opinion.
One line in the loop. Two cents a call. A signed receipt every time.