Tab
Agents buy first and pay later, and nobody is trusted to say the money arrived.
https://github.com/user-attachments/assets/9c53db2f-0768-4019-9b2d-b0f44c7bd8da
A Service meters usage into an Open Tab held on Monad.
The Agent settles that tab in USDC or AUSD, with its own keys, whenever it likes.
TabSettlement moves the Asset to the Service and applies the Settlement to the tab in the same transaction, so the transfer and the ledger entry cannot disagree.
The Credit Limit is a pure function of the Settlements the chain has already applied.
No facilitator, oracle, bridge or API key sits between the payment and the ledger entry.
An autonomous agent cannot open a bank account or hold a card, so today every way it pays is a prepayment. Post-paid billing needs a repayment record, and on Monad the payment and the record are the same state change.
The problem, and who it is for
An AI agent that wants a paid tool today has to pay before it gets anything: a funded wallet, an API key bought in advance, or a person approving every charge. No service can bill an agent after delivering, because nothing tells it the bill will be paid. Tab is for services that sell tools, data or APIs to agents (MCP servers, x402 endpoints, any HTTP API) and want to charge after they deliver. It is also for developers building those agents, who want them to call paid tools on credit and settle with their own key.
Built by Emad Qureshi.
Live
Testnet is the free playground, priced in a mintable test token (mUSDC) and in Circle's Testnet USDC.
Mainnet uses real USDC and AUSD, so the Dashboard rate-limits Mainnet trial calls, each of which spends real gas.
How it works
- Authorise. The Agent sets its own ceiling on chain with
TabBook.authorise(serviceId, asset, maxCumulative, expiry). - Call on credit. The Service does the work, returns it, and only then records the charge with
TabBook.recordDelivery, inside the Credit Limit. - Settle on Monad. The Agent calls
TabSettlement.settle(serviceId, asset, amount)with its own key, or signs a Permit2 witness that anyone may submit throughsettleWithPermit2. In the same transactionTabBook.applySettlementlowers the Open Tab, banks any surplus as prepaid credit, and extends the Agent's history commitment. - Credit follows. The next call sees the new headroom in the same block, with nothing pending and nothing to reverse.
Anyone may mark a tab delinquent once its Settlement Window closes, which zeroes the Agent's Credit Limit in that Asset until it settles.
Only the settlement surface wired once at deployment may call TabBook.applySettlement, so no operator, indexer or off-chain process can reduce an Open Tab.
The full walk-through is How the rail works.
Every way an Agent pays
Credit, and what bounds it
A new Agent that authorises a bonded Service starts at min(baseline, 95% of that Service's free Bond), and anything above the baseline is earned by settled history.
To unlock X of credit, a colluding ring must lock strictly more than X in Bonds on Curated Services; the derivation is in the whitepaper.
Architecture
The registry serves a Credit Limit only where its own recomputation agrees with the chain, and the Dashboard asks for a wallet only when you are about to sign.
Technology stack
Built with
Tab builds on these projects and services:
- Contracts: OpenZeppelin Contracts (
SafeERC20), Uniswap Permit2 (its canonical bytecode is used in tests), forge-std and Foundry. - Libraries: ethers, Hono, Next.js, React, fumadocs, the Model Context Protocol SDK, x402 (
@x402/core), Drizzle ORM, postgres.js, zod,@scure/bip32and@scure/bip39, Radix UI, Three.js and React Three Fiber, GSAP, Lenis and lucide. - Monad: the network, its passkey library
@category-labs/mera, Monad's Sourcify verifier and the MonadScan explorer. - Integrations: the MetaMask Agent Wallet CLI, NEAR Intents 1Click, Nansen over x402, Envio HyperSync, ERC-8004, Chainlink CRE, Privy and Kuru.
AI tools used: Claude Code, Kiro, Kane CLI.
Deployed on chain
Every address below is read back off the chain by script/02_VerifyDeployment.s.sol, which holds no key and sends nothing.
MeteringDelegates is wired to nothing, so it was deployed on its own by script/06_DeployMeteringDelegates.s.sol, which checks the recorded address when run again.
Every contract is source-verified through Monad's Sourcify: a full creation and runtime match on Mainnet, a runtime match on Testnet.
The Mainnet contracts are verified on MonadScan as well.
tab.demo prices quote.generate at 0.01 in each Asset, plus the fronted tools apihub.run and nansen.query at one base unit a unit, applied after the registry's 48-hour hold.
Both demo Agent identities are owned by the Agent address 0x3a3B6079e418C81a9dE08414Bb07ea817939e7Ce itself, which is what lets tab.demo write reputation about it.
On Testnet, tab.demo.b and tab.demo.c are registered and bonded with 50 mUSDC each, and the Curated tier for all three is queued with eta 2026-10-02T02:44:06Z.
Every transaction hash and applied change id is in deployments.json, under networks.
On Monad, end to end
Every piece is in the tree and exercised by tests, and none of them changes what a Settlement is. Each has its own section on On Monad.
x402 and Hub payments are prepaid and outside the credit history; the Credit Limit reads only Settlements applied on chain.
What has run live
Status
Nothing is pinned to one network: deployments.json holds one entry per chain id, and MONAD_CHAIN_ID selects it.
Quick start
Node >= 20.10.0, pnpm 9.15.3 (never npm), and Foundry for the Solidity work.
Verify the live Testnet deployment, keylessly:
pnpm install
pnpm env:bootstrap # writes .env from .env.example plus the recorded Testnet addresses
cd packages/contracts && set -a && source ../../.env && set +a && forge script script/02_VerifyDeployment.s.sol:VerifyDeployment --rpc-url monad_testnet --sig "run()"
For Mainnet, node scripts/env-bootstrap.mjs --print --chain 143 prints the same environment, and the same script verifies it with --rpc-url monad.
Put an agent on the rail:
npx -y @tabai/sdk connect # merges an mcpServers.tab entry into your MCP client's config, never a key
npx -y @tabai/sdk doctor # checks the installation against the live deployment, keylessly
npm install @tabai/sdk # or use it as a library
The MCP server gives an agent four tools: tab_discover and tab_status, which need no key; tab_call, a metered call on credit that reports the x402 offer on a refusal; and tab_settle, which spends real funds, directly or monad-relayed through Permit2.
None of them throws; a failure returns ok: false with a category, a code and a message.
With AGENT_ADDRESS and AGENT_PRIVATE_KEY set, a fresh install calls the hosted demo Service and settles its tab with no configuration file.
Run the rail locally:
docker compose up -d db
DATABASE_URL=postgres://tab:[email protected]:5432/tab pnpm --filter @tabai/registry db:apply
DATABASE_URL=postgres://tab:[email protected]:5432/tab node --env-file=.env apps/registry/dist/main.js # :8787
node --env-file=.env apps/gateway/dist/main.js # :8788
node --env-file=.env --import tsx apps/keeper/src/main.ts once # lists overdue tabs
pnpm --filter @tabai/app build:site && pnpm --filter @tabai/app serve # :3000
pnpm --filter @tabai/docs dev # :3001
The guides: packages/sdk/README.md, Integration and Using the Dashboard.
Verify and test
CI runs every one of these.
pnpm build && pnpm typecheck && pnpm lint && pnpm test # 851 TypeScript tests; lint includes the WCAG AA contrast gate
cd packages/contracts && forge test # 179 contract tests, property tests, Permit2 against the canonical bytecode
pnpm coverage # 90% of lines on the money-handling contracts, 75% on the registry and the multisig
pnpm lint:deps # no import points the wrong way through the workspace
pnpm env:check # every process.env read is declared in .env.example
pnpm deployments:check # deployments.json and .env.example describe the same deployment
Contributor detail and the traps worth knowing before you spend gas are in CONTRIBUTING.md.
Security
- Published security scan. Slither 0.11.6 ran all 102 detectors over the core contracts, and every result is triaged in
packages/contracts/audit/slither.md: none is an exploitable vulnerability.pnpm --filter @tabai/contracts audit:slitherre-runs it. - Verified on Monad. Every contract's source is verified through Monad's Sourcify, a full creation and runtime match on Mainnet and a runtime match on Testnet, the Mainnet contracts are verified on MonadScan too, and a keyless script reads every deployed address and setting back from the chain on both networks.
- Checked on every push. A secret scan over the whole git history and the working tree with a pinned, checksum-verified scanner; a dependency audit that reports no known vulnerabilities; property-based fuzz and invariant suites; coverage floors on the money-handling contracts; and a read-only reproduction job that holds no secrets.
- Curation behind a multisig and a timelock. On Mainnet the Curated tier is set by a 2-of-3
CurationMultisig, and every registry change waits 48 hours behind a public event before it applies. - Who is trusted, for what. The threat model and the whitepaper's security analysis.
Repository layout
The terms are defined in the glossary, and the full design is in WHITEPAPER.md.
Author
Emad Qureshi. Design, contracts, off-chain rail, SDK, interfaces and documentation.
License
MIT, for the whole repository: the contracts, the off-chain services, the SDK, the plugin, the Dashboard and the docs. See LICENSE.