hedera-curb 0.4.1 → 0.4.3

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.
Files changed (3) hide show
  1. package/README.md +85 -21
  2. package/dist/cli.js +21 -3
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,8 +1,12 @@
1
1
  # hedera-curb
2
2
 
3
- **Verifiable spend-control for Hedera AI agents.** Drop-in [Hedera Agent Kit](https://github.com/hashgraph/hedera-agent-kit-js) hooks that govern every payment your agent makes — per-task & rolling-24h budgets, a counterparty allowlist, and single-use human approval — and write every decision immutably to the Hedera Consensus Service.
3
+ **Verifiable spend-control for Hedera AI agents.** Drop-in [Hedera Agent Kit](https://github.com/hashgraph/hedera-agent-kit-js) hooks that govern every payment your agent makes — per-task & rolling-24h **budgets**, a counterparty **allowlist**, and single-use **human approval** — and write every decision immutably to the **Hedera Consensus Service**.
4
4
 
5
- > ProveAI proves the model; Curb proves the spend.
5
+ > Agents can pay now. `hedera-curb` makes sure they can't overspend, pay a stranger, or move money without a record.
6
+
7
+ **[🌐 Live demo](https://hedera-curb.vercel.app) · [📖 Docs](https://hedera-curb.vercel.app/docs) · [📚 API reference](https://hedera-curb.vercel.app/docs#api) · [💻 GitHub](https://github.com/Madhav-Gupta-28/Curb)**
8
+
9
+ ---
6
10
 
7
11
  ## Install
8
12
 
@@ -15,38 +19,93 @@ npm i hedera-curb @hashgraph/hedera-agent-kit @hiero-ledger/sdk
15
19
  ```ts
16
20
  import { createCurb } from 'hedera-curb';
17
21
 
18
- const curb = await createCurb({ client, agentAccountId }); // auto-creates audit + HCS-2 policy topics
22
+ const curb = await createCurb({ client, agentAccountId });
19
23
  new HederaAIToolkit({ client, configuration: { context: { hooks: curb.hooks } } });
20
24
  ```
21
25
 
22
- `createCurb` defaults the store to in-memory, auto-provisions the audit topic and an HCS-2 policy registry (owner-only writes), publishes the starting policy, and returns `{ hooks, config, store, auditTopicId, policyTopicId }`. Override anything:
26
+ That's it every governed transfer your agent attempts now passes the budget, allowlist, and approval policies **before** it executes, and every decision lands on your Hedera audit topic.
27
+
28
+ ```
29
+ agent tries to pay
30
+
31
+
32
+ ┌─────────────────────────────────────────────┐
33
+ │ curb.hooks │
34
+ │ 1. allowlist → not vetted? ✗ block │
35
+ │ 2. spend limits → over a cap? ✗ block │
36
+ │ 3. approval tier → large? ⏸ human │
37
+ └─────────────────────────────────────────────┘
38
+ │ │
39
+ ✓ allowed every decision
40
+ ▼ ▼
41
+ payment executes 📜 HCS audit topic
42
+ ```
43
+
44
+ ## `createCurb(opts)`
45
+
46
+ The one-call setup. It auto-provisions the audit topic + an HCS-2 policy registry, defaults the store, publishes your starting policy, and returns ready-to-use hooks.
47
+
48
+ **What you pass:**
49
+
50
+ | Option | Type | Default | |
51
+ | --- | --- | --- | --- |
52
+ | `client` | `Client` | **required** | A `@hiero-ledger/sdk` operator client |
53
+ | `agentAccountId` | `string` | **required** | The account the agent pays from |
54
+ | `perTask` | `number` | `10` | Max value of a single payment |
55
+ | `perDay` | `number` | `25` | Rolling-24h cap |
56
+ | `autoUnder` | `number` | `3` | Below this, payments auto-approve |
57
+ | `approveUnder` | `number` | `10` | At/above this, an approval is flagged high-value |
58
+ | `currency` | `'HBAR' \| 'USDC'` | `'HBAR'` | Display currency |
59
+ | `store` | `CurbStore` | in-memory | Bring your own (Redis/Postgres) for production |
60
+ | `auditTopicId` | `string` | auto-created | Reuse an existing HCS topic |
61
+ | `policyTopicId` | `string \| false` | auto-created | Reuse a registry, or `false` to skip versioning |
62
+
63
+ **What you get back:**
23
64
 
24
65
  ```ts
25
- await createCurb({ client, agentAccountId, perDay: 25, store: myRedisStore, auditTopicId, allowlist });
66
+ const { hooks, config, store, auditTopicId, policyTopicId } = curb;
67
+ // └ drop into the kit └ resolved caps └ for /verify └ HCS-2 registry
26
68
  ```
27
69
 
28
- ### Or provision from the terminal (no code)
70
+ Override anything inline:
71
+
72
+ ```ts
73
+ await createCurb({ client, agentAccountId, perDay: 25, autoUnder: 3, store: myRedisStore });
74
+ ```
75
+
76
+ ## Provision from the terminal (no code)
77
+
78
+ Creates the topics and prints your `.env` — handy for CI or a one-time setup:
29
79
 
30
80
  ```bash
31
81
  npx hedera-curb init --network testnet
32
- # ✓ Audit topic: 0.0.x ✓ Policy topic: 0.0.y (HCS-2, owner-only)
82
+ # ✓ Audit topic: 0.0.x
83
+ # ✓ Policy topic: 0.0.y (HCS-2, owner-only writes)
33
84
  ```
34
85
 
35
- ### Advanced: wire it yourself
86
+ ## Advanced wire it yourself
87
+
88
+ Prefer to assemble the pieces? `buildCurbHooks` returns the ordered policy + audit stack:
36
89
 
37
90
  ```ts
38
91
  import { buildCurbHooks, InMemoryCurbStore } from 'hedera-curb';
92
+
39
93
  const store = new InMemoryCurbStore();
40
94
  store.allowAccount(AGENT_ID, PROVIDER_ID);
41
- const cfg = { agentAccountId: AGENT_ID, auditTopicId: TOPIC_ID, currency: 'HBAR' as const, perTask: 10, perDay: 25, autoUnder: 3, approveUnder: 10 };
42
- // context: { hooks: buildCurbHooks({ cfg, store }) }
43
- ```
44
95
 
45
- Now every governed transfer passes the budget, allowlist, and approval policies **before** it executes, and every decision lands on your HCS audit topic.
96
+ const cfg = {
97
+ agentAccountId: AGENT_ID,
98
+ auditTopicId: TOPIC_ID,
99
+ currency: 'HBAR' as const,
100
+ perTask: 10, perDay: 25, autoUnder: 3, approveUnder: 10,
101
+ };
102
+
103
+ // configuration: { context: { hooks: buildCurbHooks({ cfg, store }) } }
104
+ ```
46
105
 
47
106
  ## Production storage
48
107
 
49
- `InMemoryCurbStore` is for tests / single-instance apps. For production, implement the `CurbStore` interface against Redis, Postgres, etc. Spend is a rolling-24h window split into **committed** (executed) and short-lived **holds** (atomic reservations) so two concurrent payments can't both slip under the cap:
108
+ `InMemoryCurbStore` is perfect for tests and single-instance apps. For production (multi-instance / serverless), implement the `CurbStore` interface against Redis, Postgres, etc. Spend is a rolling-24h window split into **committed** (executed) spend and short-lived **holds** (atomic reservations), so two concurrent payments can't both slip under the cap:
50
109
 
51
110
  ```ts
52
111
  interface CurbStore {
@@ -61,17 +120,22 @@ interface CurbStore {
61
120
  }
62
121
  ```
63
122
 
64
- ## Beyond budgets
123
+ ## Exports
65
124
 
66
- The [full project](https://github.com/Madhav-Gupta-28/Curb) is a trust ladder: off-chain hooks (this package) → HCS audit + an HCS-2 **versioned policy registry** → an on-chain **`CurbVault`** contract that enforces caps + allowlist *in Hedera consensus* → non-custodial allowance / scheduled-transaction approvals. Pick how much to trust the server.
125
+ | | |
126
+ | --- | --- |
127
+ | `createCurb(opts)` | One-call setup — topics, store, hooks |
128
+ | `buildCurbHooks(deps)` | The ordered policy + audit stack for `context.hooks` |
129
+ | `SpendLimitPolicy`, `CounterpartyAllowlistPolicy`, `ApprovalTierPolicy`, `CurbAuditHook` | The individual policies, composable on their own |
130
+ | `createAuditTopic`, `createPolicyRegistry`, `publishPolicyVersion`, `readPolicyVersions`, `currentPolicy` | HCS-2 policy versioning |
131
+ | `InMemoryCurbStore`, `extractPayment`, `paymentKey`, `writeRecord` | Store + helpers |
132
+ | `CurbStore`, `CurbConfig`, `CurbRecord`, `PolicyVersion`, … | Types |
67
133
 
68
- ## Exports
134
+ **Every export is documented with parameters, types, and examples → [hedera-curb.vercel.app/docs](https://hedera-curb.vercel.app/docs)**
135
+
136
+ ## Beyond budgets — the trust ladder
69
137
 
70
- - `createCurb(opts)` one-call setup (topics, store, hooks).
71
- - `buildCurbHooks(deps)` — the ordered policy + audit stack for `context.hooks`.
72
- - `SpendLimitPolicy`, `CounterpartyAllowlistPolicy`, `ApprovalTierPolicy`, `CurbAuditHook`.
73
- - `createAuditTopic`, `createPolicyRegistry`, `publishPolicyVersion`, `readPolicyVersions`, `currentPolicy` — HCS-2 policy versioning.
74
- - `CurbStore` + `InMemoryCurbStore`, `extractPayment`, `paymentKey`, `writeRecord`, and the `CurbConfig` / `CurbRecord` types.
138
+ This package is **L0** of a [larger trust ladder](https://github.com/Madhav-Gupta-28/Curb): off-chain hooks (here) → **L1** an HCS-2 versioned policy registry + a `/verify` that recomputes spend from the on-chain log → **L2** an on-chain **`CurbVault`** contract that enforces the caps + allowlist *in Hedera consensus*, so even a fully-compromised agent key can't overspend. Plus fully non-custodial flows (HIP-336 allowances + HIP-423 scheduled approvals). Pick how much to trust the server.
75
139
 
76
140
  ## License
77
141
 
package/dist/cli.js CHANGED
@@ -6,9 +6,24 @@ import { createAuditTopic } from './audit.js';
6
6
  import { createPolicyRegistry, publishPolicyVersion } from './policy-registry.js';
7
7
  import { DEFAULT_CONFIG } from './config.js';
8
8
  const flag = (name) => {
9
- const i = process.argv.indexOf(`--${name}`);
9
+ const eq = process.argv.find((a) => a.startsWith(`--${name}=`)); // support --name=value
10
+ if (eq)
11
+ return eq.slice(name.length + 3);
12
+ const i = process.argv.indexOf(`--${name}`); // and --name value
10
13
  return i >= 0 ? process.argv[i + 1] : undefined;
11
14
  };
15
+ // a numeric flag must parse to a positive, finite number — otherwise we'd publish a garbage policy (NaN caps).
16
+ const num = (name, def) => {
17
+ const raw = flag(name);
18
+ if (raw === undefined)
19
+ return def;
20
+ const n = Number(raw);
21
+ if (!Number.isFinite(n) || n <= 0) {
22
+ console.error(`Invalid --${name}: "${raw}" (expected a positive number).`);
23
+ process.exit(1);
24
+ }
25
+ return n;
26
+ };
12
27
  function parseKey(s) {
13
28
  for (const parse of [PrivateKey.fromStringECDSA, PrivateKey.fromStringED25519, PrivateKey.fromStringDer]) {
14
29
  try {
@@ -29,6 +44,9 @@ async function init() {
29
44
  console.error('Missing credentials. Pass --account and --key, or set HEDERA_OPERATOR_ID / HEDERA_OPERATOR_KEY.');
30
45
  process.exit(1);
31
46
  }
47
+ // validate all input (flags + key) BEFORE any on-chain work, so bad input never creates topics
48
+ const perTask = num('per-task', DEFAULT_CONFIG.perTask);
49
+ const perDay = num('per-day', DEFAULT_CONFIG.perDay);
32
50
  console.log(`Provisioning Curb on ${network}…`);
33
51
  const client = Client.forName(network).setOperator(account, parseKey(key));
34
52
  const auditTopicId = await createAuditTopic(client);
@@ -37,8 +55,8 @@ async function init() {
37
55
  agentAccountId: agent,
38
56
  auditTopicId,
39
57
  ...DEFAULT_CONFIG,
40
- perTask: Number(flag('per-task') ?? DEFAULT_CONFIG.perTask),
41
- perDay: Number(flag('per-day') ?? DEFAULT_CONFIG.perDay),
58
+ perTask,
59
+ perDay,
42
60
  };
43
61
  await publishPolicyVersion(client, config, policyTopicId, 'initial policy').catch(() => { });
44
62
  console.log(`\n✓ Audit topic: ${auditTopicId}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedera-curb",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "Verifiable spend-control policies for Hedera AI agents — drop-in Hedera Agent Kit hooks for budgets, allowlists, human approval, and an immutable HCS audit trail.",
5
5
  "license": "MIT",
6
6
  "type": "module",