spendctl 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,83 @@
1
+ spendctl Proprietary Software License
2
+
3
+ Copyright (c) 2026 Mirai Studio, Inc. (株式会社みらいスタジオ), Tokyo, Japan.
4
+ All rights reserved.
5
+
6
+ This software and its documentation (the "Software") are licensed, not sold.
7
+ By installing or running the Software you agree to these terms. If you do not
8
+ agree, do not install or run it.
9
+
10
+ 1. Grant. Subject to these terms and to the spendctl Terms of Service
11
+ (https://spendctl.dev/terms), Mirai Studio grants you a non-exclusive,
12
+ non-transferable, non-sublicensable, revocable licence to install and run
13
+ the Software, in the form distributed by Mirai Studio (for example through
14
+ the npm registry or a container image), on systems you control, solely to
15
+ use the spendctl service within the limits of your plan.
16
+
17
+ 2. Restrictions. Except as expressly permitted by Mirai Studio in writing or
18
+ by applicable law notwithstanding this restriction, you may not:
19
+ (a) copy, modify, translate, adapt or create derivative works of the
20
+ Software;
21
+ (b) distribute, publish, sublicense, sell, rent, lease, lend or otherwise
22
+ make the Software available to third parties;
23
+ (c) reverse engineer, decompile, disassemble or otherwise attempt to derive
24
+ the source code of the Software;
25
+ (d) remove, obscure or alter any proprietary notice in the Software;
26
+ (e) circumvent or disable licence keys, plan limits, usage metering or
27
+ security measures in the Software;
28
+ (f) use the Software to build or train a product that competes with
29
+ spendctl.
30
+
31
+ 3. Third-party components. The Software incorporates third-party components
32
+ under their own licences. Their notices are provided with the distributed
33
+ package (THIRD_PARTY_NOTICES). Nothing in this licence limits your rights
34
+ under those licences. The spendctl client SDKs are separately licensed
35
+ under the Apache License 2.0 (https://github.com/miraistudio/spendctl-sdk).
36
+
37
+ 4. Ownership. The Software is protected by copyright and other laws. Mirai
38
+ Studio and its licensors retain all right, title and interest in the
39
+ Software. No rights are granted except those expressly stated here.
40
+
41
+ 5. Your data and keys. The Software signs payments with a wallet you control
42
+ and keeps its ledger on systems you control. The Software may send
43
+ licence-validation and billing metadata to Mirai Studio as described in
44
+ the documentation; it does not send private keys, signed payment
45
+ authorizations, request bodies or response bodies to Mirai Studio.
46
+
47
+ 6. Feedback. If you send suggestions about the Software, Mirai Studio may use
48
+ them without obligation to you.
49
+
50
+ 7. Term and termination. This licence remains in effect until terminated. It
51
+ terminates automatically if you breach these terms or if your plan ends.
52
+ On termination you must stop using and delete the Software. Sections 2,
53
+ 4, 8, 9 and 10 survive termination.
54
+
55
+ 8. Disclaimer of warranty. THE SOFTWARE IS PROVIDED "AS IS" AND "AS AVAILABLE"
56
+ WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING WARRANTIES OF
57
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
58
+ NON-INFRINGEMENT. Spend policies are a safeguard, not a guarantee: Mirai
59
+ Studio does not warrant that the Software will prevent every unauthorised,
60
+ unintended or erroneous payment, that sellers or facilitators will behave
61
+ correctly, or that any blockchain or payment network will be available.
62
+ You remain responsible for the policies you configure and for the wallets
63
+ you connect.
64
+
65
+ 9. Limitation of liability. TO THE MAXIMUM EXTENT PERMITTED BY LAW, MIRAI
66
+ STUDIO SHALL NOT BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
67
+ CONSEQUENTIAL OR PUNITIVE DAMAGES, OR FOR ANY LOSS OF FUNDS, PROFITS, DATA
68
+ OR GOODWILL, ARISING OUT OF OR RELATED TO THE SOFTWARE, EVEN IF ADVISED OF
69
+ THE POSSIBILITY. MIRAI STUDIO'S TOTAL LIABILITY UNDER THIS LICENCE SHALL
70
+ NOT EXCEED THE AMOUNT YOU PAID FOR THE SPENDCTL SERVICE IN THE TWELVE
71
+ MONTHS BEFORE THE CLAIM. Nothing here limits liability that cannot be
72
+ limited under applicable law.
73
+
74
+ 10. Governing law. This licence is governed by the laws of Japan. The Tokyo
75
+ District Court has exclusive jurisdiction in the first instance over any
76
+ dispute arising from it.
77
+
78
+ 11. Export and sanctions. You may not use the Software in violation of
79
+ applicable export-control or sanctions laws.
80
+
81
+ 12. Entire agreement. This licence and the Terms of Service are the entire
82
+ agreement about the Software. If any provision is unenforceable, the rest
83
+ remains in effect.
package/README.md CHANGED
@@ -1,3 +1,221 @@
1
- # Temporary Holding Version
1
+ <p align="center"><img src="https://spendctl.dev/demo.gif" alt="spendctl demo: an agent pays for three API calls, hits its daily budget, waits for a human, gets approved, and the receipts are exported" width="860"></p>
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ <h1 align="center"><picture><source media="(prefers-color-scheme: dark)" srcset="https://spendctl.dev/brand/spendctl-lockup-dark.svg"><img src="https://spendctl.dev/brand/spendctl-lockup-light.svg" alt="spendctl" height="44"></picture></h1>
4
+
5
+ <p align="center"><b>A corporate card and expense policy for your AI agents.</b><br>
6
+ spendctl is the spend-policy control plane for AI agents: budgets, approvals, receipts and chain tracing across every wallet and every HTTP&nbsp;402 protocol — enforced in a sidecar you run, never by holding your keys or funds.</p>
7
+
8
+ <p align="center"><a href="https://spendctl.dev/ja/">日本語</a> · <a href="https://spendctl.dev/zh-cn/">简体中文</a> · <a href="https://spendctl.dev/docs">Docs</a> · <a href="https://spendctl.dev/#pricing">Pricing</a></p>
9
+
10
+ ---
11
+
12
+ - **What it is:** a local sidecar your agents send HTTP requests through. When a seller answers `402 Payment Required` ([x402](https://www.x402.org), [MPP](https://mpp.dev)), spendctl checks the agent's policy, asks a human if needed, signs with *your* wallet, and writes the receipt to a ledger.
13
+ - **Why it exists:** agents can now pay per request, but the protocols leave buyer-side budgets to "the implementation", the SDK guardrails run inside the agent's own process, and wallet vendors only govern the wallet they hold. Per-agent caps are free everywhere; what is missing is one policy, one approval flow and one ledger across all of them.
14
+ - **What you get:** per-agent budgets (per request / hour / day / week / month), host allowlists, recipient pinning, approval thresholds, price-jump and first-payment checks, agent→agent chain limits, dry-run, CSV/JSON export, MCP tools, a dashboard. Non-custodial: signing happens in the sidecar you run, against a wallet you own — a Coinbase CDP server wallet or your own key. spendctl never holds keys or funds.
15
+
16
+ ## Why a sidecar
17
+
18
+ > "Hard limits (validation, approval gates) and anything else that comes up mid-conversation (e.g. memory lookup) move into the **tools**."
19
+ > — Anthropic, [*Building agents: When to fold subagents into your main agent loop*](https://claude.com/resources/articles/building-agents-when-to-fold-subagents-into-your-main-agent-loop)
20
+
21
+ spendctl is that tool for money. **The agent can be talked into asking. It cannot be talked into paying.** The key, the policy and the ledger live in a separate process the model cannot edit; refusals come back as plain sentences the model can read.
22
+
23
+ Where spendctl fits:
24
+
25
+ | | Where it runs | Per-payment cap | Time-window budgets | Human approval | Exportable ledger | Host/endpoint budgets + price pinning | Your wallet, your sidecar (non-custodial) | Wallet- & protocol-neutral |
26
+ |---|---|---|---|---|---|---|---|---|
27
+ | x402 SDK `spendControls` (`@x402/core` 2.28) | inside the agent | ✓ (`$1` default) | — | hook only | — | — | your wallet, in-process | x402 only |
28
+ | CDP SDK x402 spend controls (≥ 1.53) | inside the agent | ✓ | ✓ rolling, in-memory by default | — | — | — | CDP wallet, in-process | CDP + x402 |
29
+ | Wallet-bundled caps (Coinbase Agentic Wallet, AWS AgentCore payments) | wallet UI / Bedrock | ✓ free | per session | — | some | — | one or two wallet providers | their rails |
30
+ | Wallet policy engines (Privy, Turnkey, Circle, CDP Policies…) | wallet vendor | ✓ | some | some | some | — | their wallet | own keys only |
31
+ | Hosted agent-payment platforms (Catena, Locus, xpay, Nevermined…) | their cloud | ✓ | ✓ | some | ✓ | some | their wallet or proxy | their rails |
32
+ | **spendctl** | **your sidecar** | ✓ | ✓ per agent | ✓ CLI / webhook / link | ✓ CSV / JSON | ✓ + payee pinning, price-jump | ✓ any signer you already have | ✓ any EVM signer; x402 v1/v2, MPP |
33
+
34
+ Hosted platforms govern the wallet they hold; spendctl governs the wallets you already have — one policy, one approval flow and one ledger in front of whichever wallet and payment protocol your agents meet. The x402 v2 spec lists *"Client-side budget management"* as out of scope, and builders are hitting it: [x402#3703](https://github.com/x402-foundation/x402/issues/3703) (a cumulative budget can't be built correctly on the client hooks), [x402#3866](https://github.com/x402-foundation/x402/issues/3866) (the official client paid a server that inflated its price ×10).
35
+
36
+ ## Quickstart (5 minutes, no keys, no chain)
37
+
38
+ Requires Node.js 22.13+ (or Bun 1.1+).
39
+
40
+ ```bash
41
+ mkdir spend-demo && cd spend-demo
42
+ npx spendctl init # writes spendctl.yaml + .spendctl/ (git-ignored)
43
+ npx spendctl mock # terminal 1: mock facilitator + two paid APIs
44
+ npx spendctl start # terminal 2: the sidecar on 127.0.0.1:8402
45
+ ```
46
+
47
+ In a third terminal, be the agent:
48
+
49
+ ```bash
50
+ npx spendctl fetch "http://localhost:4021/weather?city=Tokyo" --agent researcher
51
+ # ✔ 200 paid $0.01
52
+ npx spendctl fetch "http://localhost:4021/weather?city=Tokyo" --agent researcher # 2nd, 3rd …
53
+ # the 4th call exceeds the $0.03/day budget → the request is held for a human:
54
+ npx spendctl pending
55
+ npx spendctl approve --latest
56
+ npx spendctl ledger
57
+ npx spendctl export --format csv --out receipts.csv
58
+ ```
59
+
60
+ `spendctl mock` never touches a chain: its facilitator verifies real EIP-712 signatures and fakes settlement. When you're ready for testnet money, see [Real payments](#real-payments-base-sepolia). Full walkthrough: [spendctl.dev/docs/quickstart](https://spendctl.dev/docs/quickstart/).
61
+
62
+ ## The policy
63
+
64
+ ```yaml
65
+ # spendctl.yaml
66
+ version: 1
67
+ signer:
68
+ type: cdp # Coinbase CDP server wallet: keys stay in CDP
69
+
70
+ approvals:
71
+ timeout: 10m # nobody answered → denied
72
+ webhooks:
73
+ - url: https://hooks.slack.com/services/T000/B000/XXXX
74
+ format: slack # json | slack | discord (HMAC-signed with secretEnv)
75
+
76
+ defaults:
77
+ networks: ["eip155:84532"] # Base Sepolia only until you opt in
78
+ assets: ["USDC"]
79
+ maxChainDepth: 3 # agent → agent → agent, then stop
80
+ priceJumpFactor: 3 # >3× the last price paid for an endpoint → human
81
+ firstPaymentMax: "0.05" # first payment to a new recipient above this → human
82
+
83
+ agents:
84
+ researcher:
85
+ budget: { perRequest: "0.05", daily: "1.00", monthly: "20.00" }
86
+ onBudgetExceeded: approve # deny | approve
87
+ requireApprovalAbove: "0.50"
88
+ allow: ["api.weather.dev", "*.search.dev/v1/*"]
89
+ deny: ["*.casino.example"]
90
+ payTo:
91
+ "api.weather.dev": ["0x209693Bc6afc0C5328bA36FaF03C514EF312287C"] # refuse recipient swaps
92
+ ```
93
+
94
+ Every rule fails closed: unknown agent, unknown asset, unsupported scheme or flow → denied, with a reason.
95
+
96
+ ## How it works
97
+
98
+ ```mermaid
99
+ sequenceDiagram
100
+ participant A as Agent (no keys)
101
+ participant S as spendctl sidecar
102
+ participant H as Human
103
+ participant API as Paid API
104
+ A->>S: GET https://api.weather.dev/forecast
105
+ S->>API: GET /forecast
106
+ API-->>S: 402 + payment requirements (x402 v1/v2 or MPP)
107
+ S->>S: policy: allowlist, budgets, payee, price, chain depth
108
+ alt over a limit with onBudgetExceeded: approve
109
+ S->>H: webhook / CLI / review link
110
+ H->>S: spendctl approve apr_…
111
+ end
112
+ S->>S: reserve budget (SQLite BEGIN IMMEDIATE), sign once
113
+ S->>API: GET /forecast + payment header
114
+ API-->>S: 200 + settlement (tx hash)
115
+ S-->>A: 200 response + x-spendctl-* headers
116
+ ```
117
+
118
+ The payment path stays in your network. Pro and Team will sync policies, approvals and ledgers to the spendctl control plane (in development); there is no round trip to us on the payment path, and the hosted service never relays a signature.
119
+
120
+ ## What is guaranteed
121
+
122
+ Each rule has an end-to-end scenario that runs real HTTP servers (mock sellers, mock facilitator, sidecar). Every scenario runs **twice** on every CI run.
123
+
124
+ | # | Rule |
125
+ |---|---|
126
+ | S01 | A payment inside every limit is signed once, settled, and recorded with its tx hash. |
127
+ | S02 | Spending exactly up to the daily budget is allowed. |
128
+ | S03 | A payment that would exceed a budget is never signed. |
129
+ | S04 | Over-budget spend with `onBudgetExceeded: approve` waits for a human and pays only after approval. |
130
+ | S05 | If nobody approves in time, the payment is denied. |
131
+ | S06 | Hosts outside the allowlist are never paid. |
132
+ | S07 | When a recipient is pinned for a host, a 402 naming another recipient is refused. |
133
+ | S08 | A seller that suddenly inflates its price (×10, as in x402#3866) needs a human before it is paid. |
134
+ | S09 | An agent cannot attach or replay a payment header itself; only spendctl signs. |
135
+ | S10 | A retried request with the same `Idempotency-Key` is not paid twice. |
136
+ | S11 | Payments deeper than `maxChainDepth` in an agent→agent chain are refused; parents are recorded. |
137
+ | S12 | When settlement fails, spendctl never retries a signed payment and stops paying that host (circuit breaker). |
138
+ | S13 | A payment the seller could not settle does not consume budget. |
139
+ | S14 | Concurrent requests can never overspend a budget, not even by one payment. |
140
+ | S15 | Dry-run records the decision and never signs. |
141
+ | S16 | An agent cannot approve its own payment; approvals need the admin token. |
142
+ | S17 | Agents that are not in the policy cannot spend. |
143
+ | S18 | Only allowed networks and assets are paid; the cheapest acceptable option is chosen. |
144
+ | S19 | Schemes spendctl cannot budget safely (e.g. `upto`) are refused with a readable reason. |
145
+
146
+ ## Integrations
147
+
148
+ | How your agent talks to spendctl | Use it when |
149
+ |---|---|
150
+ | **Gateway URL** — `http://127.0.0.1:8402/https://api.example.com/path` + `X-Spendctl-Agent` | any language, any HTTP client |
151
+ | **`wrapFetch()`** from `@spendctl/client` (Apache-2.0) | TypeScript/JavaScript agents (zero dependencies) |
152
+ | **MCP server** — `spendctl mcp` (tools `pay`, `check_budget`, `list_receipts`) | Claude Code, Claude Desktop, Cursor, any MCP client |
153
+ | **`spendctl run --agent A -- <cmd>`** — sets `HTTP_PROXY` | plain-HTTP tools; HTTPS is tunnelled unpaid (use the gateway for paid HTTPS) |
154
+
155
+ Framework examples (Claude Agent SDK, OpenAI Agents SDK, LangGraph), typechecked against the real SDKs: [spendctl.dev/docs/integrations](https://spendctl.dev/docs/integrations/).
156
+
157
+ ```ts
158
+ import { wrapFetch, readRefusal } from "@spendctl/client";
159
+
160
+ const pay = wrapFetch({ agent: "researcher" }); // talks to the sidecar, holds no keys
161
+ const res = await pay("https://api.weather.dev/forecast?city=Tokyo");
162
+ const refusal = await readRefusal(res); // { error, message, approval?, reasons }
163
+ ```
164
+
165
+ MCP (Claude Code):
166
+
167
+ ```bash
168
+ claude mcp add spendctl -e SPENDCTL_AGENT=researcher -- npx spendctl mcp
169
+ ```
170
+
171
+ Protocols: **x402 v1 and v2** (`exact` on EVM — Base, Base Sepolia, any EIP-3009 token), **MPP** (`charge` intent via a pluggable credential provider; parsing, policy and receipts today, no live MPP payment yet).
172
+
173
+ ## Real payments (Base Sepolia)
174
+
175
+ ```bash
176
+ npx spendctl init --signer cdp --force # then fill .env (see .env.example)
177
+ npx spendctl wallet fund # 1 testnet USDC from the CDP faucet
178
+ npx spendctl start
179
+ ```
180
+
181
+ The CDP server wallet signs EIP-712 authorizations; the private key never exists in your process. A live run against the official `@x402/hono` middleware and the public x402.org facilitator is documented at [spendctl.dev/docs/real-payments](https://spendctl.dev/docs/real-payments/) ([tx on BaseScan](https://sepolia.basescan.org/tx/0x40d06e55d7d516080593b9f3a62e255edaca17f69ec64a472e0e6402077f9124)).
182
+
183
+ ## Commands
184
+
185
+ ```
186
+ spendctl init | start [--dry-run] | mock
187
+ spendctl fetch <url> --agent A [--dry-run] | run --agent A -- <cmd> | mcp | token <agent>
188
+ spendctl pending | approve <id>|--latest|--all | deny <id>
189
+ spendctl budget | ledger | export --format csv|json | trace <id> | resolve <id> --settled|--failed
190
+ spendctl dashboard [--open] | wallet [address|fund] | license [set <key> | remove]
191
+ ```
192
+
193
+ ## Security model
194
+
195
+ - Agents never hold keys or the admin token. Approvals require the admin token (CLI, dashboard) or an HMAC-bound review link that only acts on POST.
196
+ - Budgets are reserved inside SQLite `BEGIN IMMEDIATE` transactions before signing; failed settlements release them; unknown outcomes count until reconciled.
197
+ - The ledger stores no headers or bodies and drops query strings.
198
+ - The sidecar binds to `127.0.0.1`. Run agents as a different OS user (or container) if they have shell access, so they can't read `.spendctl/admin.token`.
199
+
200
+ Full security model and threat notes: [spendctl.dev/docs/security](https://spendctl.dev/docs/security/). Report vulnerabilities to security@spendctl.dev.
201
+
202
+ ## Pricing
203
+
204
+ Every enforcement feature above is in the Free tier. Paid tiers add the spendctl control plane — policy sync across sidecars, pooled budgets, Slack/Discord approvals, SSO/RBAC, hosted ledger retention and a fleet dashboard — still non-custodial. The control plane is in development; Pro and Team are founding pre-orders until it ships. The sidecar enforces the Free limits itself — 2 agents, checked at `spendctl start`, and 1,000 governed payments per month; refusals and the mock sandbox never count — and reads a licence key for Pro and Team ([how it works](https://spendctl.dev/docs/plans/)).
205
+
206
+ | Tier | Price | Includes |
207
+ |---|---|---|
208
+ | **Free** | $0, no card | 2 agents, 1 policy, 1,000 governed payments/month, local ledger + CSV/JSON export, 7-day hosted ledger copy, CLI/webhook approvals, 1 seat, local sandbox |
209
+ | **Pro** | $29/mo (founding $19) | 10 agents, 25k events/month, 90-day hosted ledger, Slack/Discord approvals, scheduled exports + accounting templates, 3 seats |
210
+ | **Team** | $249/mo (founding $149) | unlimited agents, 500k events/month, 1-year immutable ledger, SSO/RBAC, pooled budgets, chain trace across sidecars, policy-as-code CI, region pinning (US/EU/JP) |
211
+ | **Enterprise** | contact us | SIEM export, SCIM, custom retention (up to 7 years), private control plane, four-eyes approvals, SLA |
212
+
213
+ Overage $5 per 100k events (Pro, Team); 14-day Team trial without a card. Founding members: the first 100, price locked for 12 months from GA, full refund if GA slips past 2027-03-31. No percentage of spend, ever. [Join the waitlist →](https://spendctl.dev/#pricing)
214
+
215
+ ## Status
216
+
217
+ v0.1 — early. Tested: unit + integration (57), golden scenarios (19 × 2), one live Base Sepolia payment. Not yet: Solana signing, `upto`/`batch-settlement` schemes, live MPP payments, HTTPS interception for `HTTP_PROXY` mode, and the control plane (in development). Docs: [spendctl.dev/docs](https://spendctl.dev/docs).
218
+
219
+ ## License
220
+
221
+ spendctl — the sidecar, CLI and MCP server published on npm — is proprietary software, distributed as bundled JavaScript under its own licence terms; there is no public source repository for it. The thin client `@spendctl/client` is Apache-2.0 and lives at [github.com/miraistudio/spendctl-sdk](https://github.com/miraistudio/spendctl-sdk). © Mirai Studio, Inc. (株式会社みらいスタジオ), Tokyo.