@paybond/kit 0.7.1 → 0.9.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # `@paybond/kit`
2
2
 
3
- Paybond Kit for TypeScript is the npm package for tenant-bound Paybond integrations. It opens hosted Gateway sessions, verifies capability tokens, signs intent and evidence payloads, uses Stripe Connect or x402 / USDC-on-Base settlement rails, and reads tenant-scoped Signal, fraud, ledger, protocol, and A2A data.
3
+ Paybond Kit for TypeScript is the npm package for tenant-bound Paybond integrations and delegated agent spend controls. It opens hosted Gateway sessions, verifies capability tokens, authorizes tool-call spend, signs intent and evidence payloads, uses Stripe Connect or x402 / USDC-on-Base settlement rails, reads tenant-scoped Signal, fraud, ledger, protocol, and A2A data, and includes agent-runtime integrations.
4
4
 
5
5
  ## Install
6
6
 
@@ -59,6 +59,45 @@ try {
59
59
  }
60
60
  ```
61
61
 
62
+ ## Agent spend controls
63
+
64
+ Use Paybond Kit when an agent workflow needs delegated spend guardrails, tool-call budget checks, paid API or vendor action approval, evidence, release/refund logic, disputes, or audit-ready receipts.
65
+
66
+ ```ts
67
+ import { Paybond } from "@paybond/kit";
68
+
69
+ const paybond = await Paybond.open({
70
+ apiKey: process.env.PAYBOND_API_KEY!,
71
+ expectedEnvironment: "sandbox",
72
+ });
73
+
74
+ const created = await paybond.intents.create({
75
+ // principal, payee, budget, predicate, evidence schema, deadline...
76
+ allowedTools: ["travel.book_hotel"],
77
+ settlementRail: "stripe_connect",
78
+ });
79
+
80
+ const intentId = String(created.intent_id);
81
+ const capabilityToken = String(created.capability_token ?? "");
82
+ if (!capabilityToken) {
83
+ throw new Error("fund the intent before guarding tools");
84
+ }
85
+
86
+ const guard = paybond.spendGuard(intentId, capabilityToken);
87
+ const guardedTool = guard.guardTool(
88
+ { operation: "travel.book_hotel", requestedSpendCents: 20_000 },
89
+ async (input) => bookHotel(input),
90
+ );
91
+ ```
92
+
93
+ The `paybond.harbor` client is created by `Paybond.open(...)` and bound to the tenant resolved from the service-account API key. Normal integrations read `capability_token` from `paybond.intents.create(...)`, or from `paybond.intents.fund(...)` after an `x402_usdc_base` payment challenge is satisfied.
94
+
95
+ Scaffold a wrapper:
96
+
97
+ ```bash
98
+ npx -p @paybond/kit paybond-init --framework provider-agnostic --out paybond-spend-guard.ts
99
+ ```
100
+
62
101
  ## What the package includes
63
102
 
64
103
  Core SDK:
@@ -67,6 +106,9 @@ Core SDK:
67
106
  - `HarborClient` for capability verification, intent creation, x402 funding, evidence submission, and ledger reads
68
107
  - `paybond.signal` and `paybond.fraud` on `Paybond` sessions opened from one service-account API key
69
108
  - `PaybondIntents` helpers for principal-signed intent creation, x402 funding, and payee-signed evidence submission
109
+ - `PaybondSpendGuard`, `authorizeSpend`, and `guardTool` for spend-named wrappers around capability verification
110
+ - Runtime-neutral and framework aliases: `paybondAgentToolSpendGuard`, `paybondRuntimeNeutralToolSpendGuard`, `paybondLangGraphToolSpendGuard`, and `paybondMCPToolSpendGuard`
111
+ - `paybondRuntimeToolCallAdapter` for agent SDKs and custom runtimes that expose a tool-call object plus an application-owned executor
70
112
 
71
113
  Gateway and trust helpers:
72
114
 
@@ -74,6 +116,7 @@ Gateway and trust helpers:
74
116
  - `GatewayFraudClient` and `ServiceAccountFraudSession` for tenant-scoped fraud assessments, review queues, review events, metrics, and release-gate config
75
117
  - Protocol-v2 helpers for mandate verification, replay-safe recognition proof verification, receipt reads, and A2A discovery
76
118
  - `paybond-mcp-server` for tenant-bound MCP tool exposure to any MCP-compatible host
119
+ - `paybond-init` for generating a small spend guard wrapper
77
120
 
78
121
  Agent-facing surfaces are model-provider agnostic. Paybond verifies tool operations and tenant scope, not whether a tool call came from OpenAI, Anthropic, Gemini, a local model, or another runtime.
79
122
 
@@ -92,7 +135,7 @@ Gateway-backed protocol helpers throw `ProtocolHttpError` with parsed `errorCode
92
135
  ## What it does not include
93
136
 
94
137
  - No operator-tier settlement or console workflows
95
- - No model-provider-specific TypeScript agent wrapper; use the documented app-side wrapper pattern with `PaybondCapabilityBinding`
138
+ - No model-provider-specific TypeScript agent wrapper; use the documented app-side wrapper pattern with `paybond.spendGuard(...)`
96
139
  - No model-provider-specific MCP wrapper; the MCP server is host-agnostic and works with any MCP-compatible runtime
97
140
 
98
141
  ## Docs
package/dist/index.d.ts CHANGED
@@ -652,7 +652,52 @@ export declare class PaybondCapabilityBinding {
652
652
  readonly intentId: string;
653
653
  readonly capabilityToken: string;
654
654
  constructor(harbor: Pick<HarborClient | GatewayHarborClient, "tenantId" | "verifyCapability">, intentId: string, capabilityToken: string);
655
+ verifySpendCapability(input: PaybondSpendAuthorizationInput): Promise<VerifyCapabilityResult>;
656
+ authorizeSpend(input: PaybondSpendAuthorizationInput): Promise<VerifyCapabilityResult>;
655
657
  }
658
+ export type PaybondSpendGuardInit = {
659
+ harbor: Pick<HarborClient | GatewayHarborClient, "tenantId" | "verifyCapability">;
660
+ intentId: string;
661
+ capabilityToken: string;
662
+ };
663
+ export type PaybondSpendAuthorizationInput = {
664
+ operation: string;
665
+ requestedSpendCents?: number;
666
+ };
667
+ export declare class PaybondSpendDeniedError extends Error {
668
+ readonly result: VerifyCapabilityResult;
669
+ constructor(result: VerifyCapabilityResult);
670
+ }
671
+ export type PaybondToolHandler<TArgs extends unknown[], TResult> = (...args: TArgs) => TResult | Promise<TResult>;
672
+ export type PaybondGuardedToolHandler<TArgs extends unknown[], TResult> = (...args: TArgs) => Promise<Awaited<TResult>>;
673
+ export declare class PaybondSpendGuard {
674
+ readonly harbor: Pick<HarborClient | GatewayHarborClient, "tenantId" | "verifyCapability">;
675
+ readonly intentId: string;
676
+ readonly capabilityToken: string;
677
+ constructor(init: PaybondSpendGuardInit | PaybondCapabilityBinding);
678
+ verifySpendCapability(input: PaybondSpendAuthorizationInput): Promise<VerifyCapabilityResult>;
679
+ authorizeSpend(input: PaybondSpendAuthorizationInput): Promise<VerifyCapabilityResult>;
680
+ assertSpendAuthorized(input: PaybondSpendAuthorizationInput): Promise<VerifyCapabilityResult>;
681
+ guardTool<TArgs extends unknown[], TResult>(input: PaybondSpendAuthorizationInput, handler: PaybondToolHandler<TArgs, TResult>): PaybondGuardedToolHandler<TArgs, TResult>;
682
+ }
683
+ export declare function authorizeSpend(source: PaybondSpendGuardInit | PaybondCapabilityBinding, input: PaybondSpendAuthorizationInput): Promise<VerifyCapabilityResult>;
684
+ export declare function guardTool<TArgs extends unknown[], TResult>(source: PaybondSpendGuardInit | PaybondCapabilityBinding, input: PaybondSpendAuthorizationInput, handler: PaybondToolHandler<TArgs, TResult>): PaybondGuardedToolHandler<TArgs, TResult>;
685
+ export declare const paybondAgentToolSpendGuard: typeof guardTool;
686
+ export declare const paybondRuntimeNeutralToolSpendGuard: typeof guardTool;
687
+ export declare const paybondLangGraphToolSpendGuard: typeof guardTool;
688
+ export declare const paybondMCPToolSpendGuard: typeof guardTool;
689
+ export type PaybondRuntimeOperation<TCall> = string | ((call: TCall) => string);
690
+ export type PaybondRuntimeSpendCents<TCall> = number | ((call: TCall) => number | undefined);
691
+ export type PaybondRuntimeToolExecutor<TCall, TResult> = (call: TCall) => TResult | Promise<TResult>;
692
+ export type PaybondRuntimeDenyHandler<TCall, TResult> = (result: VerifyCapabilityResult, call: TCall) => TResult | Promise<TResult>;
693
+ export type PaybondRuntimeToolCallAdapterInit<TCall, TResult> = {
694
+ source: PaybondSpendGuardInit | PaybondCapabilityBinding;
695
+ operation: PaybondRuntimeOperation<TCall>;
696
+ execute: PaybondRuntimeToolExecutor<TCall, TResult>;
697
+ requestedSpendCents?: PaybondRuntimeSpendCents<TCall>;
698
+ onDeny?: PaybondRuntimeDenyHandler<TCall, TResult>;
699
+ };
700
+ export declare function paybondRuntimeToolCallAdapter<TCall, TResult>(init: PaybondRuntimeToolCallAdapterInit<TCall, TResult>): (call: TCall) => Promise<Awaited<TResult>>;
656
701
  export type PaybondOpenOptions = {
657
702
  apiKey: string;
658
703
  gatewayBaseUrl?: string;
@@ -701,6 +746,18 @@ export declare class HarborClient {
701
746
  operation: string;
702
747
  requestedSpendCents?: number;
703
748
  }): Promise<VerifyCapabilityResult>;
749
+ verifySpendCapability(input: {
750
+ intentId: string;
751
+ token: string;
752
+ operation: string;
753
+ requestedSpendCents?: number;
754
+ }): Promise<VerifyCapabilityResult>;
755
+ authorizeSpend(input: {
756
+ intentId: string;
757
+ token: string;
758
+ operation: string;
759
+ requestedSpendCents?: number;
760
+ }): Promise<VerifyCapabilityResult>;
704
761
  /**
705
762
  * POST `/intents` with a principal-signed `CreateIntentRequest` JSON body.
706
763
  *
@@ -787,6 +844,18 @@ export declare class GatewayHarborClient {
787
844
  operation: string;
788
845
  requestedSpendCents?: number;
789
846
  }): Promise<VerifyCapabilityResult>;
847
+ verifySpendCapability(input: {
848
+ intentId: string;
849
+ token: string;
850
+ operation: string;
851
+ requestedSpendCents?: number;
852
+ }): Promise<VerifyCapabilityResult>;
853
+ authorizeSpend(input: {
854
+ intentId: string;
855
+ token: string;
856
+ operation: string;
857
+ requestedSpendCents?: number;
858
+ }): Promise<VerifyCapabilityResult>;
790
859
  createIntent(body: Record<string, unknown>, options: GatewayHarborMutationOptions): Promise<Record<string, unknown>>;
791
860
  fundIntent(intentId: string, options: GatewayHarborMutationOptions & {
792
861
  paymentSignature?: string;
@@ -962,6 +1031,9 @@ export declare class PaybondIntents {
962
1031
  create(params: PaybondCreateIntentParams & {
963
1032
  idempotencyKey?: string;
964
1033
  }): Promise<Record<string, unknown>>;
1034
+ createSpendIntent(params: PaybondCreateIntentParams & {
1035
+ idempotencyKey?: string;
1036
+ }): Promise<Record<string, unknown>>;
965
1037
  /**
966
1038
  * Advance Harbor `/intents/{id}/fund` for x402 / USDC-on-Base intents.
967
1039
  */
@@ -993,6 +1065,13 @@ export declare class Paybond {
993
1065
  static open(init: PaybondOpenOptions): Promise<Paybond>;
994
1066
  /** Reserved for future HTTP client cleanup; safe to call after work completes. */
995
1067
  aclose(): Promise<void>;
1068
+ spendGuard(intentId: string, capabilityToken: string): PaybondSpendGuard;
1069
+ authorizeSpend(input: {
1070
+ intentId: string;
1071
+ token: string;
1072
+ operation: string;
1073
+ requestedSpendCents?: number;
1074
+ }): Promise<VerifyCapabilityResult>;
996
1075
  }
997
1076
  export { normalizeJson, jsonValueDigest } from "./json-digest.js";
998
1077
  export { buildSignedCreateIntentBody, intentCreationSignBytesRaw, type BuildSignedCreateIntentParams, type SettlementRail, } from "./principal-intent.js";
package/dist/index.js CHANGED
@@ -156,6 +156,99 @@ export class PaybondCapabilityBinding {
156
156
  this.intentId = intentId;
157
157
  this.capabilityToken = capabilityToken;
158
158
  }
159
+ async verifySpendCapability(input) {
160
+ return this.harbor.verifyCapability({
161
+ intentId: this.intentId,
162
+ token: this.capabilityToken,
163
+ operation: input.operation,
164
+ requestedSpendCents: input.requestedSpendCents,
165
+ });
166
+ }
167
+ async authorizeSpend(input) {
168
+ return this.verifySpendCapability(input);
169
+ }
170
+ }
171
+ export class PaybondSpendDeniedError extends Error {
172
+ result;
173
+ constructor(result) {
174
+ const reason = result.message ?? result.code ?? "denied";
175
+ super(`Paybond spend authorization denied: ${reason}`);
176
+ this.name = "PaybondSpendDeniedError";
177
+ this.result = result;
178
+ }
179
+ }
180
+ export class PaybondSpendGuard {
181
+ harbor;
182
+ intentId;
183
+ capabilityToken;
184
+ constructor(init) {
185
+ this.harbor = init.harbor;
186
+ this.intentId = init.intentId;
187
+ this.capabilityToken = init.capabilityToken;
188
+ }
189
+ async verifySpendCapability(input) {
190
+ return this.harbor.verifyCapability({
191
+ intentId: this.intentId,
192
+ token: this.capabilityToken,
193
+ operation: input.operation,
194
+ requestedSpendCents: input.requestedSpendCents,
195
+ });
196
+ }
197
+ async authorizeSpend(input) {
198
+ return this.verifySpendCapability(input);
199
+ }
200
+ async assertSpendAuthorized(input) {
201
+ const result = await this.authorizeSpend(input);
202
+ if (!result.allow) {
203
+ throw new PaybondSpendDeniedError(result);
204
+ }
205
+ return result;
206
+ }
207
+ guardTool(input, handler) {
208
+ return async (...args) => {
209
+ await this.assertSpendAuthorized(input);
210
+ return await handler(...args);
211
+ };
212
+ }
213
+ }
214
+ export async function authorizeSpend(source, input) {
215
+ return new PaybondSpendGuard(source).authorizeSpend(input);
216
+ }
217
+ export function guardTool(source, input, handler) {
218
+ return new PaybondSpendGuard(source).guardTool(input, handler);
219
+ }
220
+ export const paybondAgentToolSpendGuard = guardTool;
221
+ export const paybondRuntimeNeutralToolSpendGuard = guardTool;
222
+ export const paybondLangGraphToolSpendGuard = guardTool;
223
+ export const paybondMCPToolSpendGuard = guardTool;
224
+ function resolveRuntimeOperation(operation, call) {
225
+ const value = typeof operation === "function" ? operation(call) : operation;
226
+ const trimmed = String(value).trim();
227
+ if (!trimmed) {
228
+ throw new Error("Paybond operation must be a non-empty string");
229
+ }
230
+ return trimmed;
231
+ }
232
+ function resolveRuntimeSpendCents(requestedSpendCents, call) {
233
+ if (requestedSpendCents === undefined) {
234
+ return undefined;
235
+ }
236
+ return typeof requestedSpendCents === "function" ? requestedSpendCents(call) : requestedSpendCents;
237
+ }
238
+ export function paybondRuntimeToolCallAdapter(init) {
239
+ const guard = new PaybondSpendGuard(init.source);
240
+ return async (call) => {
241
+ const operation = resolveRuntimeOperation(init.operation, call);
242
+ const requestedSpendCents = resolveRuntimeSpendCents(init.requestedSpendCents, call);
243
+ const result = await guard.authorizeSpend({ operation, requestedSpendCents });
244
+ if (!result.allow) {
245
+ if (init.onDeny) {
246
+ return await init.onDeny(result, call);
247
+ }
248
+ throw new PaybondSpendDeniedError(result);
249
+ }
250
+ return await init.execute(call);
251
+ };
159
252
  }
160
253
  /**
161
254
  * HTTP client for Harbor: capability verify, intents, evidence, and tenant-scoped ledger reads
@@ -329,6 +422,12 @@ export class HarborClient {
329
422
  message: body.message,
330
423
  };
331
424
  }
425
+ async verifySpendCapability(input) {
426
+ return this.verifyCapability(input);
427
+ }
428
+ async authorizeSpend(input) {
429
+ return this.verifyCapability(input);
430
+ }
332
431
  /**
333
432
  * POST `/intents` with a principal-signed `CreateIntentRequest` JSON body.
334
433
  *
@@ -653,6 +752,12 @@ export class GatewayHarborClient {
653
752
  message: body.message,
654
753
  };
655
754
  }
755
+ async verifySpendCapability(input) {
756
+ return this.verifyCapability(input);
757
+ }
758
+ async authorizeSpend(input) {
759
+ return this.verifyCapability(input);
760
+ }
656
761
  async createIntent(body, options) {
657
762
  const { res, text, url } = await this.postJSON("/harbor/intents", body, this.mutationHeaders("createIntent", options));
658
763
  if (!res.ok) {
@@ -1642,6 +1747,9 @@ export class PaybondIntents {
1642
1747
  });
1643
1748
  return this.harbor.createIntent(body, { idempotencyKey, recognitionProof });
1644
1749
  }
1750
+ async createSpendIntent(params) {
1751
+ return this.create(params);
1752
+ }
1645
1753
  /**
1646
1754
  * Advance Harbor `/intents/{id}/fund` for x402 / USDC-on-Base intents.
1647
1755
  */
@@ -1715,6 +1823,12 @@ export class Paybond {
1715
1823
  async aclose() {
1716
1824
  await Promise.resolve();
1717
1825
  }
1826
+ spendGuard(intentId, capabilityToken) {
1827
+ return new PaybondSpendGuard({ harbor: this.harbor, intentId, capabilityToken });
1828
+ }
1829
+ async authorizeSpend(input) {
1830
+ return this.harbor.authorizeSpend(input);
1831
+ }
1718
1832
  }
1719
1833
  export { normalizeJson, jsonValueDigest } from "./json-digest.js";
1720
1834
  export { buildSignedCreateIntentBody, intentCreationSignBytesRaw, } from "./principal-intent.js";
package/dist/init.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export declare function main(argv?: string[]): Promise<number>;
package/dist/init.js ADDED
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env node
2
+ const FRAMEWORKS = new Set([
3
+ "generic",
4
+ "provider-agnostic",
5
+ "openai",
6
+ "claude",
7
+ "anthropic",
8
+ "gemini",
9
+ "google-ai",
10
+ "vercel-ai",
11
+ "langgraph",
12
+ "mcp",
13
+ ]);
14
+ const FRAMEWORK_NOTES = {
15
+ generic: "Wrap the returned function around any side-effecting tool handler.",
16
+ "provider-agnostic": "Use the guarded handler with OpenAI, Gemini, Claude/Anthropic, local models, or any custom runtime.",
17
+ openai: "Call the guarded handler before the OpenAI tool call performs paid or external work.",
18
+ claude: "Call the guarded handler before the Claude tool-use action performs paid or external work.",
19
+ anthropic: "Call the guarded handler before the Anthropic tool-use action performs paid or external work.",
20
+ gemini: "Call the guarded handler before the Gemini function call performs paid or external work.",
21
+ "google-ai": "Call the guarded handler before the Google AI function call performs paid or external work.",
22
+ "vercel-ai": "Call the guarded handler from your Vercel AI SDK tool execute function.",
23
+ langgraph: "Call the guarded handler from the LangGraph JS node or tool wrapper that performs paid work.",
24
+ mcp: "Call the guarded handler inside the MCP tool implementation before paid or external work runs.",
25
+ };
26
+ function usage() {
27
+ return [
28
+ "Usage: paybond-init [--framework generic|provider-agnostic|openai|claude|anthropic|gemini|google-ai|vercel-ai|langgraph|mcp] [--out paybond-spend-guard.ts] [--force]",
29
+ "",
30
+ "Scaffolds a Paybond spend guard wrapper for delegated agent spend controls.",
31
+ ].join("\n");
32
+ }
33
+ function parseArgs(argv) {
34
+ let framework = "generic";
35
+ let out = "paybond-spend-guard.ts";
36
+ let force = false;
37
+ for (let i = 0; i < argv.length; i += 1) {
38
+ const arg = argv[i];
39
+ if (arg === "--help" || arg === "-h") {
40
+ process.stdout.write(`${usage()}\n`);
41
+ process.exitCode = 0;
42
+ return { framework, out, force };
43
+ }
44
+ if (arg === "--force") {
45
+ force = true;
46
+ continue;
47
+ }
48
+ if (arg === "--framework") {
49
+ const raw = argv[i + 1];
50
+ i += 1;
51
+ if (!raw || !FRAMEWORKS.has(raw)) {
52
+ throw new Error("invalid --framework");
53
+ }
54
+ framework = raw;
55
+ continue;
56
+ }
57
+ if (arg === "--out") {
58
+ const raw = argv[i + 1];
59
+ i += 1;
60
+ if (!raw || raw.startsWith("-")) {
61
+ throw new Error("invalid --out");
62
+ }
63
+ out = raw;
64
+ continue;
65
+ }
66
+ throw new Error(`unknown argument: ${arg}`);
67
+ }
68
+ return { framework, out, force };
69
+ }
70
+ function template(framework) {
71
+ return `import { Paybond, type FundIntentResult } from "@paybond/kit";
72
+
73
+ type ToolInput = {
74
+ city: string;
75
+ maxPriceCents: number;
76
+ };
77
+
78
+ type FundedIntent = {
79
+ intentId: string;
80
+ capabilityToken: string;
81
+ };
82
+
83
+ export async function openPaybond(): Promise<Paybond> {
84
+ return Paybond.open({
85
+ apiKey: process.env.PAYBOND_API_KEY!,
86
+ expectedEnvironment: "sandbox",
87
+ });
88
+ }
89
+
90
+ export function fundedIntentFromCreate(created: Record<string, unknown>): FundedIntent {
91
+ const intentId = String(created["intent_id"] ?? "");
92
+ const capabilityToken = String(created["capability_token"] ?? "");
93
+ if (!intentId) {
94
+ throw new Error("intent create response missing intent_id");
95
+ }
96
+ if (!capabilityToken) {
97
+ throw new Error("intent is not funded yet; call paybond.intents.fund(...) before guarding tools");
98
+ }
99
+ return { intentId, capabilityToken };
100
+ }
101
+
102
+ export function fundedIntentFromFund(funded: FundIntentResult): FundedIntent {
103
+ if (!funded.capabilityToken) {
104
+ throw new Error("intent funding did not return a capabilityToken yet");
105
+ }
106
+ return { intentId: funded.intentId, capabilityToken: funded.capabilityToken };
107
+ }
108
+
109
+ async function bookHotel(input: ToolInput): Promise<{ confirmation: string }> {
110
+ // Put the side-effecting tool call here.
111
+ return { confirmation: \`demo-\${input.city}-\${input.maxPriceCents}\` };
112
+ }
113
+
114
+ export async function buildGuardedHotelTool(params: {
115
+ paybond: Paybond;
116
+ intentId: string;
117
+ capabilityToken: string;
118
+ }): Promise<(input: ToolInput) => Promise<{ confirmation: string }>> {
119
+ if (!params.capabilityToken.trim()) {
120
+ throw new Error("fund the intent before guarding tools");
121
+ }
122
+ const guard = params.paybond.spendGuard(params.intentId, params.capabilityToken);
123
+
124
+ // ${FRAMEWORK_NOTES[framework]}
125
+ return guard.guardTool(
126
+ {
127
+ operation: "travel.book_hotel",
128
+ requestedSpendCents: 20_000,
129
+ },
130
+ bookHotel,
131
+ );
132
+ }
133
+ `;
134
+ }
135
+ async function writeScaffold(out, body, force) {
136
+ // @ts-expect-error Node builtins are available in the published CLI runtime.
137
+ const fs = await import("node:fs/promises");
138
+ try {
139
+ await fs.stat(out);
140
+ if (!force) {
141
+ throw new Error(`${out} already exists; pass --force to overwrite`);
142
+ }
143
+ }
144
+ catch (err) {
145
+ if (!(err && typeof err === "object" && "code" in err && err.code === "ENOENT")) {
146
+ if (!force) {
147
+ throw err;
148
+ }
149
+ }
150
+ }
151
+ await fs.writeFile(out, body, "utf8");
152
+ }
153
+ export async function main(argv = process.argv.slice(2)) {
154
+ let parsed;
155
+ try {
156
+ parsed = parseArgs(argv);
157
+ }
158
+ catch (err) {
159
+ process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n\n${usage()}\n`);
160
+ return 1;
161
+ }
162
+ if (argv.includes("--help") || argv.includes("-h")) {
163
+ return 0;
164
+ }
165
+ await writeScaffold(parsed.out, template(parsed.framework), parsed.force);
166
+ process.stdout.write(`Created ${parsed.out}\n`);
167
+ return 0;
168
+ }
169
+ main().then((code) => {
170
+ process.exitCode = code;
171
+ }, (err) => {
172
+ process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
173
+ process.exitCode = 1;
174
+ });
@@ -364,6 +364,8 @@ export class PaybondMCPServer {
364
364
  version: SERVER_VERSION,
365
365
  },
366
366
  instructions: "This MCP server is tenant-bound to the configured Paybond service-account API key. " +
367
+ "Use paybond_create_spend_intent or paybond_fund_intent to obtain the intent_id and " +
368
+ "capability_token, then call paybond_authorize_agent_spend before side-effecting tools. " +
367
369
  "It works with any MCP-compatible host and does not assume a specific model provider.",
368
370
  },
369
371
  };
@@ -447,10 +449,37 @@ export class PaybondMCPServer {
447
449
  },
448
450
  {
449
451
  name: "paybond_verify_capability",
450
- description: "Verify a capability token for one tenant-bound Harbor intent through the gateway compatibility route.",
452
+ description: "Verify a capability token returned by a created or funded Paybond intent for one tenant-bound Harbor intent.",
451
453
  inputSchema: objectSchema({
452
454
  intent_id: { type: "string", description: "Canonical Harbor intent UUID." },
453
- token: { type: "string", description: "Capability token to verify." },
455
+ token: {
456
+ type: "string",
457
+ description: "Capability token returned by paybond_create_spend_intent or paybond_fund_intent.",
458
+ },
459
+ operation: { type: "string", description: "Delegated operation or tool name." },
460
+ requested_spend_cents: {
461
+ type: "integer",
462
+ description: "Optional requested spend in cents for this tool call.",
463
+ },
464
+ }, ["intent_id", "token", "operation"]),
465
+ call: async (args) => this.runtime.verifyCapability({
466
+ intentId: uuidArg(args.intent_id, "intent_id"),
467
+ token: stringArg(args.token, "token"),
468
+ operation: stringArg(args.operation, "operation"),
469
+ requestedSpendCents: args.requested_spend_cents === undefined
470
+ ? 0
471
+ : intArg(args.requested_spend_cents, "requested_spend_cents"),
472
+ }),
473
+ },
474
+ {
475
+ name: "paybond_authorize_agent_spend",
476
+ description: "Provider-agnostic spend gate: verify the funded intent's capability token before a side-effecting tool, paid API, vendor action, or settlement workflow executes.",
477
+ inputSchema: objectSchema({
478
+ intent_id: { type: "string", description: "Canonical Harbor intent UUID." },
479
+ token: {
480
+ type: "string",
481
+ description: "Capability token returned by paybond_create_spend_intent or paybond_fund_intent.",
482
+ },
454
483
  operation: { type: "string", description: "Delegated operation or tool name." },
455
484
  requested_spend_cents: {
456
485
  type: "integer",
@@ -630,9 +659,23 @@ export class PaybondMCPServer {
630
659
  idempotencyKey: optionalString(args.idempotency_key),
631
660
  }),
632
661
  },
662
+ {
663
+ name: "paybond_create_spend_intent",
664
+ description: "Create a signed Paybond spend intent through the gateway /harbor route. Use this when an agent workflow needs bounded budget, allowed operations, evidence, and settlement review. If the selected rail funds immediately, use the returned intent_id and capability_token with paybond_authorize_agent_spend.",
665
+ inputSchema: objectSchema({
666
+ body: { type: "object", additionalProperties: true },
667
+ recognition_proof: { type: "object", additionalProperties: true },
668
+ idempotency_key: { type: "string" },
669
+ }, ["body", "recognition_proof"]),
670
+ call: async (args) => this.runtime.createHarborIntent({
671
+ body: ensureObject(args.body, "body"),
672
+ recognitionProof: ensureObject(args.recognition_proof, "recognition_proof"),
673
+ idempotencyKey: optionalString(args.idempotency_key),
674
+ }),
675
+ },
633
676
  {
634
677
  name: "paybond_fund_intent",
635
- description: "Advance Harbor funding through the gateway /harbor path with a replay-safe recognition proof.",
678
+ description: "Advance Harbor funding through the gateway /harbor path with a replay-safe recognition proof. When funding succeeds, use the returned capability_token with intent_id in paybond_authorize_agent_spend.",
636
679
  inputSchema: objectSchema({
637
680
  intent_id: { type: "string" },
638
681
  recognition_proof: { type: "object", additionalProperties: true },
@@ -662,6 +705,22 @@ export class PaybondMCPServer {
662
705
  idempotencyKey: optionalString(args.idempotency_key),
663
706
  }),
664
707
  },
708
+ {
709
+ name: "paybond_submit_spend_evidence",
710
+ description: "Submit signed evidence for a Paybond spend intent so release, refund, review, and receipt generation use the same audit-ready record.",
711
+ inputSchema: objectSchema({
712
+ intent_id: { type: "string" },
713
+ body: { type: "object", additionalProperties: true },
714
+ recognition_proof: { type: "object", additionalProperties: true },
715
+ idempotency_key: { type: "string" },
716
+ }, ["intent_id", "body", "recognition_proof"]),
717
+ call: async (args) => this.runtime.submitHarborEvidence({
718
+ intentId: uuidArg(args.intent_id, "intent_id"),
719
+ body: ensureObject(args.body, "body"),
720
+ recognitionProof: ensureObject(args.recognition_proof, "recognition_proof"),
721
+ idempotencyKey: optionalString(args.idempotency_key),
722
+ }),
723
+ },
665
724
  {
666
725
  name: "paybond_confirm_settlement",
667
726
  description: "Confirm Harbor settlement through the gateway /harbor path with a replay-safe recognition proof.",
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@paybond/kit",
3
- "version": "0.7.1",
4
- "description": "Paybond Kit for TypeScript: hosted Gateway sessions, capability verification, signed intent/evidence flows, and Stripe Connect or x402 / USDC-on-Base settlement.",
3
+ "version": "0.9.0",
4
+ "description": "Paybond Kit for TypeScript: agent spend controls, hosted Gateway sessions, capability verification, signed intent/evidence flows, and Stripe Connect or x402 / USDC-on-Base settlement.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
8
8
  "types": "dist/index.d.ts",
9
9
  "bin": {
10
+ "paybond-init": "dist/init.js",
10
11
  "paybond-mcp-server": "dist/mcp-server.js"
11
12
  },
12
13
  "exports": {
@@ -41,6 +42,14 @@
41
42
  "kit",
42
43
  "agents",
43
44
  "agent-runtime",
45
+ "agent-spend-controls",
46
+ "ai-agent-budget",
47
+ "delegated-spend",
48
+ "spend-guardrails",
49
+ "tool-call-spend-limits",
50
+ "gemini",
51
+ "claude",
52
+ "anthropic",
44
53
  "agent-payments",
45
54
  "escrow",
46
55
  "intent-escrow",