Quickstart

Gate an action, sign the receipt, verify it.

Every code block on this page was run against the published package before it shipped here. Copy, paste, run. You should reach a verified, tamper-evident receipt in about ten minutes.

npm @agentguard-run/[email protected] · PyPI agentguard-spend 0.15.2
Step 1

Install

The SDK ships for both runtimes. It has no provider lock-in: you bring your own OpenAI, Anthropic, or Bedrock client, or call the core policy and receipt functions directly as shown here.

npm install @agentguard-run/spend
pip install agentguard-spend  # requires Python 3.10+
Step 2

Evaluate a policy, sign the decision, verify it

This is the whole primitive: a policy with a per-call cap, a money-moving call evaluated against it, the resulting decision signed into an Ed25519 hash-chained receipt, then verified clean and verified after tampering. Save the file and run it.

// quickstart.mjs  (run: node quickstart.mjs)
import * as ed from '@noble/ed25519';
import {
  evaluatePolicy, signDecision, verifyEntry, verifyChain,
  InMemorySpendStore, GENESIS_PREVIOUS_HASH,
} from '@agentguard-run/spend';

// 1) A keypair the customer holds. The private key never leaves your runtime.
const privateKey = ed.utils.randomSecretKey();
const publicKey  = await ed.getPublicKeyAsync(privateKey);

// 2) Policy: block any single call projected over $5.00 (500 cents).
const policy = {
  id: 'refund-agent-v1', name: 'Refund agent caps',
  scope: { tenantId: 'acme' },
  caps: [{ amountCents: 500, window: 'per_call', action: 'block' }],
  mode: 'enforce', requiredCapability: 'payment_initiate',
  version: 1, effectiveFrom: new Date().toISOString(),
};

// 3) Evaluate the agent's "refund $40" action against the policy.
const store = new InMemorySpendStore();
const decision = await evaluatePolicy(policy, {
  provider: 'anthropic', model: 'claude-sonnet-4',
  inputTokens: 1200, outputTokens: 300,
  scope: { tenantId: 'acme' },
  label: 'refund customer #8831 $40.00',
  capabilityClaim: 'payment_initiate',
}, store);
console.log('decision.action =', decision.action);

// 4) Sign the decision into a tamper-evident receipt.
const entry = await signDecision({
  sequence: 0, decision, previousHash: GENESIS_PREVIOUS_HASH,
  privateKey, publicKey,
});

// 5) Verify clean (true), then tamper a field and verify again (false).
console.log('verifyEntry (clean)   =', await verifyEntry(entry, publicKey));
console.log('verifyChain (clean)   =', (await verifyChain([entry], publicKey)).ok);
const tampered = structuredClone(entry);
tampered.decision.action = 'allow';
console.log('verifyEntry (tampered)=', await verifyEntry(tampered, publicKey));
Actual output
decision.action = block verifyEntry (clean) = true verifyChain (clean) = true verifyEntry (tampered)= false

@noble/ed25519 is already a dependency of the SDK, so no extra install is needed. The cap is in cents and the projected cost is computed locally; an unpriced model defaults to block (fail-closed), which is why this call is blocked.

# quickstart.py  (run: python quickstart.py)
import asyncio, dataclasses
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization
import agentguard_spend as ag


async def main():
    # 1) Customer-held keypair. The private key never leaves your runtime.
    sk = Ed25519PrivateKey.generate()
    priv = sk.private_bytes(serialization.Encoding.Raw,
                            serialization.PrivateFormat.Raw,
                            serialization.NoEncryption())
    pub = sk.public_key().public_bytes(serialization.Encoding.Raw,
                                       serialization.PublicFormat.Raw)

    # 2) Policy: block any single call projected over $5.00 (500 cents).
    policy = ag.SpendPolicy(
        id="refund-agent-v1", name="Refund agent caps",
        scope=ag.SpendScope(tenantId="acme"),
        caps=[ag.SpendCap(amountCents=500, window="per_call", action="block")],
        mode="enforce", requiredCapability="payment_initiate",
        version=1, effectiveFrom="2026-06-19T00:00:00Z",
    )

    # 3) Evaluate the agent's "refund $40" action against the policy.
    store = ag.InMemorySpendStore()
    decision = await ag.evaluate_policy(policy, ag.CallContext(
        provider="anthropic", model="claude-sonnet-4",
        inputTokens=1200, outputTokens=300,
        scope=ag.SpendScope(tenantId="acme"),
        label="refund customer #8831 $40.00",
        capabilityClaim="payment_initiate",
    ), store)
    print("decision.action =", decision.action)

    # 4) Sign the decision into a tamper-evident receipt.
    entry = await ag.sign_decision(
        sequence=0, decision=decision,
        previous_hash=ag.GENESIS_PREVIOUS_HASH,
        private_key=priv, public_key=pub,
    )

    # 5) Verify clean (True), then tamper a field and verify again (False).
    print("verify_entry (clean)   =", await ag.verify_entry(entry, pub))
    print("verify_chain (clean)   =", (await ag.verify_chain([entry], pub)).ok)
    tampered = dataclasses.replace(
        entry, decision=dataclasses.replace(entry.decision, action="allow"))
    print("verify_entry (tampered)=", await ag.verify_entry(tampered, pub))


asyncio.run(main())
Actual output
decision.action = block verify_entry (clean) = True verify_chain (clean) = True verify_entry (tampered)= False

cryptography is installed automatically with the SDK. An unpriced model defaults to block (fail-closed), which is why this call is blocked.

Step 3

Or verify from the command line

The npm package ships an agentguard binary. demo writes a signed receipt to ~/.agentguard/demo/latest-receipt.json; verify re-checks the signature, the canonical-JSON entry hashes, and the chain pointer. No code required.

npx agentguard demo
npx agentguard verify --trace latest
Actual output (verify)
entries 1 sequence 0 policy agentguard-demo-policy-v1 action block ✓ full chain valid ✓ entry hashes match canonical JSON ✓ signatures match supplied public key

You can also paste a receipt's JSON into the hosted verifier at agentguard.run/verify. It recomputes the canonical-JSON entry hash and checks the Ed25519 signature against the embedded public key, the same logic the SDK runs locally.

On cross-language receipts. Each SDK fully verifies the receipts it signs, and the JavaScript SDK's receipts verify on the hosted /verify endpoint. The two SDKs use the same Ed25519 keys and the same hash chain, but they are not yet byte-identical across languages: the Python SDK serializes some unset optional decision fields explicitly, so a Python-signed receipt is verified by the Python verifier (or any verifier given the receipt as written), not by pasting it into the JavaScript verifier unchanged. Verify a receipt with the same SDK that signed it. We call this out plainly rather than imply drop-in cross-language verification we have not shipped.

What stops an agent from lying about its tier or amount?

Nothing inside the model. AgentGuard is a decision function, not an interceptor: it gates and signs based only on the inputs it is given (the capability claim, the projected amount, the scope), and it holds no data plane: your prompts, completions, and provider keys never pass through it. The enforcement happens at the integrator's tool boundary. You wire the SDK's allow or block decision so that it is the gate in front of the real money-moving call: the refund API, the charge, the transfer. If the decision is block, your code does not make the call. If an agent claims a higher capability tier or a smaller amount than reality, that mismatch is a problem for the boundary you control (the tool wrapper, your identity provider, your ledger), not something the SDK can detect on its own. What AgentGuard guarantees is that whatever decision was made, on whatever inputs, is recorded in a tamper-evident, independently verifiable receipt, so a false claim cannot be quietly rewritten after the fact.

All terminology and labels used in AgentGuard materials are descriptive of software functionality only, not legal definitions or guarantees of compliance. Terms like receipt, audit log, evidence, audit trail, and attestation refer solely to cryptographic data structures produced by the software. AgentGuard is patent-pending technology of Dunecrest Ventures Inc.