The pre-commit gate · guard_action

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.

Without a gate
agent · about to actsend_payment(to="0x9a3f…c012", amount="$4,000", memo="invoice #221")
▼ executes immediately
Sent · irreversibleThe funds are gone. The address was never seen before, the invoice was injected into a scraped page — but nothing checked before the transaction settled. You find out after.
With guard_action in the loop
agent · about to actguard_action(action="wire $4,000 to 0x9a3f…c012 (invoice #221)", policy="no new payees without review")
▼ $0.02 · ~1s · independent check
Decision: blockrisk 0.92. Recipient address unseen in the last 30 days; invoice originates from untrusted scraped content; amount exceeds the standing policy for new payees. Safer alternative: hold for human confirmation and verify the payee out-of-band.
↳ returned with a signed receipt · key_id ed25519:ea7c47db…39a8 · verifiable forever

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:

1 · Official SDK — one linepip install verity-guard · npm i @veritylayer/guard
# 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 })) };
2 · The universal wrapperany language · no SDK · ~8 lines
// 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
}
3 · MCP hostClaude Desktop · Cursor · any MCP client
# 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.
4 · Raw pre-tool hookany tool-calling agent · no SDK
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.

SIGNED

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.

FREE TO CHECK

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.

YOURS TO KEEP

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.

npx -y @veritylayer/mcp