Tillwarden $TILL Open app
Workshop

Build a careful agent.

One npm package, tillwarden: an SDK, a CLI and an MCP server. The agent key stays with the agent and signs locally. The engine only ever sees signatures.

Checking npm…HTTP APIllms.txt

Before you start

1

Open an account

In the app: a Safe with the module, your rules, and an agent address.

2

Make an agent key

npx tillwarden keygen, or generate it in the app. The private key goes to the agent only.

3

Issue an API key

In the app, the owner signs one message and gets an API key for that agent. Shown once.

SDK

// npm i tillwarden
import { Tillwarden } from 'tillwarden';

const tw = new Tillwarden({
  baseUrl: 'https://tillwarden.fun',                 // or env TILLWARDEN_URL
  apiKey: process.env.TILLWARDEN_API_KEY,         // issued in /app
  agentKey: process.env.TILLWARDEN_AGENT_KEY,     // signs locally, never sent
});

// Ask first. No API key needed; uses the demo account unless you pass safe.
const v = await tw.check({ to, amount: '2.5', token: 'USDG', context: invoiceText });
// v.verdict: 'allow' | 'needs_approval' | 'block', v.checks[], v.simulation

// Pay. Always pass the text that made the agent decide to pay.
const r = await tw.pay({ to, amount: '2.5', token: 'USDG', memo: 'invoice 1042', context: invoiceText });
// r.status: 'paid' | 'pending_approval' | 'blocked', r.txHash, r.verdict

await tw.me();              // account, limits left, balances
await tw.receipts({ limit: 20 });
await tw.verifyReceipt(id);  // hash chain + signature
The SDK re-checks what it signs. Before signing, it compares the typed data from the engine with what the agent asked for (payee, amount, token). A tampered intent is refused.

CLI

npx tillwarden check --to 0x… --amount 12 --token USDG --context @invoice.txt
npx tillwarden examples                # the five playground scenarios
npx tillwarden example prompt-injection-drain
npx tillwarden pay --to 0x… --amount 12 --token USDG --memo "data export"
npx tillwarden me
npx tillwarden receipts --limit 20
npx tillwarden verify <receiptId>
npx tillwarden keygen

# options: --url <base> (env TILLWARDEN_URL) · --json
# env: TILLWARDEN_API_KEY, TILLWARDEN_AGENT_KEY

MCP server

Any MCP client can give its model five tools. The model never sees the agent key; the server signs locally.

tillwarden_payPay someone. Checked first; returns paid, pending_approval or blocked with the reason.
tillwarden_checkRun the firewall only. Nothing is signed or sent.
tillwarden_balanceBalances and what is left today and this week.
tillwarden_rulesThe rules the owner set for this agent.
tillwarden_receiptsRecent signed receipts, in and out.
{
  "mcpServers": {
    "tillwarden": {
      "command": "npx",
      "args": ["-y", "-p", "tillwarden", "tillwarden-mcp"],
      "env": {
        "TILLWARDEN_URL": "https://tillwarden.fun",
        "TILLWARDEN_API_KEY": "…",
        "TILLWARDEN_AGENT_KEY": "…"
      }
    }
  }
}

Plain HTTP

No package needed for checks. The firewall answers anyone, rate limited per IP.

curl -s https://tillwarden.fun/api/firewall/check \
  -H 'content-type: application/json' \
  -d '{"to":"0x…","amount":"2.5","token":"USDG","context":"Invoice 1042, amount due 2.50 USDG"}'

Every endpoint is listed in the docs.