Chisle
The coding-agent plugin that bills 52% of a bare model across 20 live tasks. Terse persona + tool-output compressor + context diet.
翻訳待ち
Kage (npm kage-x402): AI agents pay HTTP 402s in shielded Zcash, inside a spend policy you write in code. Merchants verify each payment with an incoming viewing key that can't spend.
翻訳待ち
開発ツールRust · HTMLGitHub @nicolasholmanオンライン所有者未確認
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Kage: private API payments for AI agents using shielded Zcash and x402, with spending policies and human approvals. Zcash testnet.
翻訳待ち
Loading the full README.
Read the full README ↗AI agents are starting to pay for the APIs they use. On a public chain every one of those payments is a public record: who paid, whom, how much, how often. That's an agent's whole strategy, its suppliers and its budget, readable by anyone. And an agent with a wallet and no limits is one bad prompt away from draining it.
Kage fixes both. Agents pay HTTP 402s with shielded Zcash, so amounts and parties stay private, and every payment passes a spend policy you write in code (daily cap, which APIs may be paid, human approval above a threshold) before any transaction exists. Merchants verify payments with an incoming viewing key: their server can confirm "I was paid" but can't spend a coin.
It speaks the x402 wire format (402 → pay → X-PAYMENT → 200), so it fits the
agent-payments stack that already exists, with Zcash's privacy underneath.
npm install kage-x402
import { createKage } from 'kage-x402/agent';
const kage = await createKage({
wallet: { seed: process.env.KAGE_AGENT_SEED!, birthday: 4_548_499, dir: '.kage/agent' },
policy: {
dailyCap: '0.008 ZEC', // hard budget per UTC day
allowedHosts: ['api.example.com'], // the only APIs it may pay
approvalThreshold: '0.003 ZEC', // a human approves anything this big
},
onApproval: async (p) => askHuman(`Pay ${p.amount} ZEC to ${p.host}?`),
});
const res = await kage.fetch('https://api.example.com/v1/zec/price'); // 402 → policy → pay → 200
kage.fetch pays the 402 from the agent's own shielded wallet, waits for the block, presents the
payment and returns the paid response. A refusal throws KageError with a code and paid: false:
nothing was built or broadcast.
import express from 'express';
import { kagePaywall, kagePaywallEnv } from 'kage-x402';
const pay = kagePaywall(kagePaywallEnv()); // KAGE_PAY_TO, KAGE_FACILITATOR_URL/TOKEN, KAGE_RECEIPT_PUBKEY
const app = express();
app.get('/v1/zec/price', pay('0.001 ZEC'), (req, res) => res.json(livePrice()));
app.get('/v1/zec/report', pay('0.005 ZEC'), (req, res) => res.json(report()));
The server holds no keys. The Kage facilitator checks each payment with the merchant's incoming viewing key and signs a receipt; the paywall accepts only that receipt, once per payment.
kage wallet new --role merchant # seed → 0600 file, prints address + incoming viewing key
kage wallet new --dir .kage/agent # the agent's own wallet
kage keys check <key> # is this a UIVK (safe), a UFVK (too much) or an address?
| Key | Held by | Can |
|---|---|---|
| Agent seed (spending key) | the agent, from your secret store | spend the agent's wallet, nothing else |
| Merchant seed | offline, never on a server | spend the merchant's income |
| Merchant UIVK (incoming viewing key) | the facilitator | see payments received: amount and memo. Can't spend, can't see what the merchant sends |
| UFVK (full viewing key) | nobody | would also reveal outgoing payments; Kage refuses it (assertIncomingOnly) |
A viewing key can't be revoked once shared: treat it as permanent read access to incoming payments, and move to a new account if it leaks.
| Field | Type | Meaning |
|---|---|---|
dailyCap | "0.008 ZEC" or zat bigint | most the agent spends per UTC day, counting every broadcast payment (an unknown broadcast outcome counts too) |
allowedHosts | string[] | hosts it may pay: api.example.com, *.example.com, 127.0.0.1:4300. Checked before the first request |
approvalThreshold | ZEC, optional | at or above this, onApproval decides. No handler = refused |
allowInsecureHttp | boolean | plain http beyond loopback (default off) |
The policy runs inside the engine, under a file lock, before a transaction exists. Approvals reach
the engine over a per-process secret, so an LLM driving the agent can't approve its own payments.
Every decision lands in a ledger sealed at rest (kage.ledger()).
KageError.code | When | Money moved? |
|---|---|---|
CAP_EXCEEDED | price over what's left today | no |
HOST_NOT_ALLOWED | host not in allowedHosts (no request is even made) | no |
APPROVAL_REQUIRED / APPROVAL_DENIED | over the threshold with no handler / the human said no | no |
INSUFFICIENT_FUNDS | wallet too low (the message names the address to fund) | no |
PAYMENT_REJECTED | the merchant refused the payment | yes (paid: true) |
SETTLEMENT_TIMEOUT | broadcast, block not seen in time; fetch again resumes, never pays twice | yes |
SETUP_REQUIRED | missing seed, engine or config, named in the message | no |
Events for logs and UIs: request, approval_requested, approved, refused, broadcast
(txid + explorer link), waiting, settled.
examples/agent-chat: an LLM research agent with its own wallet. Ask "what's
ZEC doing this week?" and watch it buy data, pay, wait for the block and answer, with the policy
stopping what it shouldn't buy.examples/market-api: the paid API it buys from — live ZEC price (0.001 ZEC)
and a 7-day report (0.005 ZEC), real CoinGecko and Blockchair data, ~60 lines.x402z-mcp) for Claude, opencode or any MCP client.This is the beginning of the README. Read the rest at the original. Read the full README ↗