@odingard/guardian-sdk 0.1.0 → 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.
Files changed (50) hide show
  1. package/README.md +252 -17
  2. package/dist/contracts.js +9865 -0
  3. package/dist/index.js +12976 -1787
  4. package/dist/public-catalog.v1.json +6915 -0
  5. package/dist-dts/catalog.d.ts +14 -0
  6. package/dist-dts/client.d.ts +51 -1
  7. package/dist-dts/contracts/action-pack.d.ts +464 -0
  8. package/dist-dts/contracts/action-registry.d.ts +91 -1
  9. package/dist-dts/contracts/action.d.ts +1408 -17
  10. package/dist-dts/contracts/agent-state.d.ts +386 -0
  11. package/dist-dts/contracts/approval.d.ts +224 -5
  12. package/dist-dts/contracts/assurance.d.ts +60 -0
  13. package/dist-dts/contracts/authority-graph.d.ts +294 -0
  14. package/dist-dts/contracts/authority-state.d.ts +17 -2
  15. package/dist-dts/contracts/authority.d.ts +31 -5
  16. package/dist-dts/contracts/billing.d.ts +32 -0
  17. package/dist-dts/contracts/calendar.d.ts +6 -6
  18. package/dist-dts/contracts/denial.d.ts +648 -0
  19. package/dist-dts/contracts/evidence.d.ts +73 -16
  20. package/dist-dts/contracts/execution.d.ts +449 -55
  21. package/dist-dts/contracts/identifiers.d.ts +16 -0
  22. package/dist-dts/contracts/index.d.ts +22 -0
  23. package/dist-dts/contracts/intent.d.ts +335 -0
  24. package/dist-dts/contracts/lineage.d.ts +218 -0
  25. package/dist-dts/contracts/local.d.ts +101 -0
  26. package/dist-dts/contracts/multi-principal.d.ts +292 -0
  27. package/dist-dts/contracts/multiparty.d.ts +169 -0
  28. package/dist-dts/contracts/obligation.d.ts +196 -0
  29. package/dist-dts/contracts/plan.d.ts +67 -0
  30. package/dist-dts/contracts/policy-simulation.d.ts +681 -0
  31. package/dist-dts/contracts/prerequisite.d.ts +147 -0
  32. package/dist-dts/contracts/protected-data.d.ts +67 -0
  33. package/dist-dts/contracts/receipt.d.ts +3126 -0
  34. package/dist-dts/contracts/resource-claims.d.ts +146 -0
  35. package/dist-dts/contracts/runtime.d.ts +111 -0
  36. package/dist-dts/contracts/safety-envelope.d.ts +287 -0
  37. package/dist-dts/contracts/sequence.d.ts +132 -0
  38. package/dist-dts/contracts/sources.d.ts +191 -0
  39. package/dist-dts/contracts/tools.d.ts +50 -5
  40. package/dist-dts/contracts/transaction.d.ts +360 -0
  41. package/dist-dts/contracts-entry.d.ts +1 -0
  42. package/dist-dts/embedded.d.ts +58 -0
  43. package/dist-dts/evidence/evidence.d.ts +25 -0
  44. package/dist-dts/evidence/receipt.d.ts +61 -0
  45. package/dist-dts/index.d.ts +5 -1
  46. package/dist-dts/lifecycle.d.ts +25 -0
  47. package/dist-dts/proposal.d.ts +16 -0
  48. package/dist-dts/receipts.d.ts +37 -0
  49. package/package.json +12 -6
  50. package/dist-dts/__tests__/client.test.d.ts +0 -1
package/README.md CHANGED
@@ -1,11 +1,22 @@
1
+ <p align="center">
2
+ <img src=".github/assets/guardian-logo.png" alt="Guardian — human authority for AI" width="640" />
3
+ </p>
4
+
1
5
  # @odingard/guardian-sdk
2
6
 
3
- Guardian agent SDK — let an AI agent request governed capabilities and execute
4
- consequential actions under human authority. The agent proposes; the human
5
- decides. Every decision is deterministic (`ALLOW` / `ASK` / `DENY`) and every
7
+ [![npm version](https://img.shields.io/npm/v/@odingard/guardian-sdk)](https://www.npmjs.com/package/@odingard/guardian-sdk)
8
+ [![npm downloads](https://img.shields.io/npm/dm/@odingard/guardian-sdk)](https://www.npmjs.com/package/@odingard/guardian-sdk)
9
+ [![MCP registry](https://img.shields.io/badge/MCP_registry-guardian--mcp-blue)](https://registry.modelcontextprotocol.io/)
10
+ [![Guardian MCP server on mcprush](https://mcprush.com/badge/odingard-guardian-mcp/card.svg)](https://mcprush.com/to/odingard-guardian-mcp?ref=badge)
11
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)
12
+
13
+ **Human Authority Infrastructure for Autonomous AI.** The agent proposes; the human
14
+ decides. This SDK lets an AI agent request governed capabilities and execute
15
+ consequential actions under human authority. Every decision is deterministic (`ALLOW` / `ASK` / `DENY`) and every
6
16
  execution produces a tamper-evident receipt.
7
17
 
8
- Hosted Guardian: https://guardian.odingard.com
18
+ Hosted Guardian: [guardian.odingard.com](https://guardian.odingard.com) — free tier for developers
19
+ (1 agent, 1 connection, 50 protected actions/month), no card required.
9
20
 
10
21
  ## Install
11
22
 
@@ -13,15 +24,15 @@ Hosted Guardian: https://guardian.odingard.com
13
24
  npm install @odingard/guardian-sdk
14
25
  ```
15
26
 
16
- Requires Node.js >= 20.
27
+ Requires Node.js >= 22 (receipt verification uses `node:crypto` Ed25519; browser runtimes are not supported in 0.2).
17
28
 
18
29
  ## Quickstart
19
30
 
20
31
  ```ts
21
- import { createGuardianClient } from "@odingard/guardian-sdk";
32
+ import { classifyRequestResult, createGuardianClient } from "@odingard/guardian-sdk";
22
33
 
23
34
  const guardian = createGuardianClient({
24
- baseUrl: "https://api.guardian.odingard.com",
35
+ baseUrl: "https://guardian-api.odingard.com",
25
36
  credential: process.env.GUARDIAN_AGENT_CREDENTIAL!, // gac1.… issued per agent
26
37
  });
27
38
 
@@ -33,19 +44,23 @@ const result = await guardian.request({
33
44
  arguments: { orderId: "ord_123" },
34
45
  });
35
46
 
36
- if (result.ok && result.decision === "ALLOW") {
47
+ const d = classifyRequestResult(result); // the one fail-closed reading
48
+
49
+ if (d.decision === "ALLOW") {
37
50
  // 2. Guardian minted a single-use capability. Execute it.
38
51
  const execution = await guardian.execute({
39
- requestId: result.requestId,
40
- capabilityToken: result.capabilityToken!,
52
+ requestId: d.requestId,
53
+ capabilityToken: d.capabilityToken,
41
54
  });
42
55
  console.log(execution.ok ? execution.receipt : execution.reasonCode);
43
- } else if (result.ok && result.decision === "ASK") {
44
- // A human approves in the Guardian console, then:
45
- const granted = await guardian.claim(result.requestId);
46
- // …then execute as above once the capability arrives.
56
+ } else if (d.decision === "ASK") {
57
+ // Held for a human. Keep d.requestId; after the human approves:
58
+ const granted = classifyRequestResult(await guardian.claim(d.requestId));
59
+ // …execute as above once granted.decision === "ALLOW".
47
60
  }
48
- // decision === "DENY" → refused before execution, with a reason code.
61
+ // d.decision === "DENY" → refused before execution, with d.reasonCode.
62
+ // Ambiguity (ALLOW without a token, unreachable Guardian, unknown shape)
63
+ // is always DENY.
49
64
  ```
50
65
 
51
66
  ## What the agent can and cannot do
@@ -57,12 +72,232 @@ if (result.ok && result.decision === "ALLOW") {
57
72
  - `receipts(requestId)` returns the machine-readable proof of what happened,
58
73
  who authorized it, and what authority version applied.
59
74
 
75
+ ## Lifecycle and governed actions (0.2)
76
+
77
+ | Result from `request` / `claim` | `classifyRequestResult` | What to do |
78
+ |---|---|---|
79
+ | `{ ok: true, decision: "ALLOW", capabilityToken }` | `ALLOW` | `execute({ requestId, capabilityToken })` |
80
+ | `{ ok: true, decision: "ASK" }` or `{ ok: false, reasonCode: "APPROVAL_REQUIRED", requestId }` | `ASK` | keep `requestId`; `claim(requestId)` after the human decides |
81
+ | anything else (DENY, `SERVICE_UNAVAILABLE`, ALLOW without token) | `DENY` | do not run the effect |
82
+
83
+ A held ASK always carries its `requestId` (fixed in 0.2 — 0.1 dropped it).
84
+
85
+ Invocation types: `tool.invoke`, `mcp.install`, `mcp.enable` (typed), and the
86
+ governed pass-through actions `api.request`, `protected_data.derive|transform|export`,
87
+ `agent.message`, `agent.share_context`, `agent.share_memory`,
88
+ `agent.transfer_task`, `agent.transfer_capability` (you supply
89
+ `materialParameters`; Guardian validates them). Optional provenance:
90
+ `purpose`, `intentId`, `planId`, `parentActionId`, `sourceEffectId`. The wire
91
+ schemas are exported from `@odingard/guardian-sdk/contracts`, synced from
92
+ Guardian's canonical contracts.
93
+
94
+ ## Portable receipts — verify without an account
95
+
96
+ ```ts
97
+ import { fetchReceiptVerificationKeys, verifyReceiptOffline, verifyReceiptOnline } from "@odingard/guardian-sdk";
98
+
99
+ const { receipt } = await guardian.portableReceipt(requestId); // greceipt.v1
100
+ const keys = await fetchReceiptVerificationKeys("https://guardian-api.odingard.com"); // public
101
+ verifyReceiptOffline(receipt, keys.keys);
102
+ // → { valid: true, decision: "ALLOW", effect: "verified", subject } — or { valid: false, reasonCode }
103
+ ```
104
+
105
+ Offline verification checks the Ed25519 signature over the
106
+ `guardian-canonical-json.v1` body and re-derives every embedded record against
107
+ the receipt's evidence chain. It needs no credential, plan or Guardian service
108
+ once you hold the keys, and is never billed. `verifyReceiptOnline` asks a
109
+ Guardian deployment to do the same over the public `POST /v1/receipts/verify`.
110
+
111
+ ## Embedded approvals — humans only
112
+
113
+ `createEmbeddedApprovalClient({ baseUrl, sessionToken })` lets your own UI list,
114
+ view, approve/deny and revoke pending approvals. It requires a **human** session
115
+ token. Agent credentials (`gak_…`, `gac1.…`) and capability tokens (`gcap.…`)
116
+ are refused locally (`HUMAN_SESSION_REQUIRED`) before any request is sent, and
117
+ the server independently accepts only human sessions on these routes. Agent
118
+ credentials can never approve, create grants or revoke.
119
+
120
+ ## Catalog metadata (declarative)
121
+
122
+ `guardianCatalog` (also `@odingard/guardian-sdk/catalog.json`) is generated from
123
+ Guardian's canonical catalog: 62 verticals, 25 agent systems, 48 agent roles,
124
+ 221 entities, each vertical with its tier and maturity. It grants nothing:
125
+ every action is still decided at runtime under a human's policy. Current
126
+ honest status: 3 verticals `governed`, 58 `integration-ready` (governed
127
+ decision path; external adapters declared, not built), 1
128
+ `production-integrated` (recorded external-system proof). Maturity L1 = built-in
129
+ governed, L2 = modeled/decidable, L3 = production-integrated with recorded proof.
130
+ `verticalsForAction("tool.invoke")` lists verticals using an action.
131
+
132
+ ## Guardian for Steel — `@odingard/guardian-steel`
133
+
134
+ Browser-agent checkout governed by Guardian: the agent can only propose
135
+ `steel.checkout.submit`; ALLOW/ASK/DENY happens before the order; the Steel
136
+ session and merchant credential stay on the protected executor side. See
137
+ [`packages/steel/README.md`](packages/steel/README.md) for the boundary and
138
+ current maturity.
139
+
140
+ ## Maturity of what this SDK reaches
141
+
142
+ | Path | Status |
143
+ |---|---|
144
+ | Decision + capability + execute for `api.request`, Gmail, Calendar, tool/MCP connections | LIVE on hosted Guardian |
145
+ | Portable receipt retrieval + offline/online verification | LIVE (staging and production publish keys) |
146
+ | Embedded human approvals | LIVE routes; needs a human session from your Guardian sign-in |
147
+ | Steel checkout | agent side published; protected executor proven in-process, not yet injected into hosted Guardian |
148
+ | Framework `inProcess` mode | decision-gated only — see below |
149
+
150
+ ## MCP server
151
+
152
+ No code needed for MCP-native agents — `@odingard/guardian-mcp` is a stdio
153
+ MCP server exposing `guardian_invoke_tool`, `guardian_claim` and
154
+ `guardian_receipt`. Listed on the official MCP registry as
155
+ `io.github.Odingard/guardian-mcp` — see [mcp-server/README.md](mcp-server/README.md).
156
+
157
+ ```bash
158
+ npm install -g @odingard/guardian-mcp
159
+ ```
160
+
161
+ ```json
162
+ {
163
+ "mcpServers": {
164
+ "guardian": {
165
+ "command": "guardian-mcp",
166
+ "env": {
167
+ "GUARDIAN_BASE_URL": "https://guardian-api.odingard.com",
168
+ "GUARDIAN_AGENT_CREDENTIAL": "gac1.…",
169
+ "GUARDIAN_CONNECTION_ID": "con_…"
170
+ }
171
+ }
172
+ }
173
+ }
174
+ ```
175
+
176
+ ## Plans and limits
177
+
178
+ Guardian is free for individuals — no card required, with the same core
179
+ authority protections on every plan. Usage is metered per month on
180
+ protected actions (the consequential things an agent can cause); reading
181
+ receipts and requests is never metered.
182
+
183
+ | Plan | Price | Connections | Agents | Protected actions / month |
184
+ |------|-------|-------------|--------|---------------------------|
185
+ | Free | $0 | 1 | 1 | 50 |
186
+ | Guardian Personal | $19/month or $190/year | 10 | 25 | 50,000 |
187
+ | Guardian Family | $39/month or $390/year | 50 | 250 | 500,000 |
188
+ | Guardian Developer | $99/month plus protected-action usage | 250 | 1,000 | 5,000,000 |
189
+
190
+ Over a limit, the API returns `403 PLAN_LIMIT_EXCEEDED` naming your plan,
191
+ the limit, and current usage. Upgrade in the console → Billing
192
+ (`POST /v1/billing/checkout` with `{plan, interval}` issues a Stripe
193
+ Checkout URL; monthly and annual billing are both offered).
194
+
195
+ ## Framework adapters
196
+
197
+ Drop-in wrappers that put an agent framework's tool calls behind the same
198
+ ALLOW / ASK / DENY triad — nothing runs before a decision, and no tool
199
+ ever runs without a capability issued for that exact call.
200
+
201
+ Two execution modes, per tool or per wrapper (`mode` / `modes` options):
202
+
203
+ - `remote` (default): the tool name is a registered Guardian catalog
204
+ entry — a bounded HTTP(S) call Guardian performs itself on `ALLOW`.
205
+ `client.execute` IS the execution; the call resolves to the ALLOW
206
+ receipt and the local impl never runs.
207
+ - `inProcess` (opt-in): the local impl IS the tool. It runs only after
208
+ the capability is issued, then `client.execute` redeems + records the
209
+ evidence — needs a `transport: "record"` catalog entry, auto-installed
210
+ via `mcp.install` on first use (WO-021 control plane required).
211
+
212
+ ### `remote` vs `inProcess` — read this
213
+
214
+ `remote` (default): Guardian holds the effect. Nothing local runs; after ALLOW
215
+ the SDK calls `execute` and Guardian's adapter performs the action.
216
+
217
+ `inProcess`: your local tool body runs **after an ALLOW decision but before the
218
+ capability is redeemed**. Redemption-time checks (revocation, expiry,
219
+ single-use) therefore land after the effect, and the effect itself is not
220
+ mediated by Guardian. It is decision-gated, not pre-execution enforcement. If
221
+ redemption then fails, `GuardianExecutionFailed.localEffectRan === true` —
222
+ treat it as an incident. Use `remote` wherever Guardian must hold the effect.
223
+
224
+ ### Vercel AI SDK — `@odingard/guardian-vercel-ai`
225
+
226
+ ```bash
227
+ npm install @odingard/guardian-vercel-ai
228
+ ```
229
+
230
+ ```ts
231
+ import { createGuardianClient } from "@odingard/guardian-sdk";
232
+ import { GuardianApprovalPending, GuardianDenied, withGuardian }
233
+ from "@odingard/guardian-vercel-ai";
234
+
235
+ const guardian = createGuardianClient({ baseUrl, credential });
236
+ const tools = withGuardian({ refund_order, send_email }, {
237
+ client: guardian,
238
+ connectionId: "con_…",
239
+ agentName: "billing-agent",
240
+ modes: { refund_order: "inProcess" }, // send_email stays remote
241
+ });
242
+
243
+ // ALLOW remote: client.execute performs the catalog call, call resolves
244
+ // to the ALLOW receipt. ALLOW inProcess: local impl runs, then
245
+ // execute redeems + records it, call resolves to the impl output.
246
+ // ASK: GuardianApprovalPending carries requestId — approve in Guardian,
247
+ // then `await pending.resume()`. DENY: GuardianDenied carries
248
+ // reasonCode; nothing executes. onAsk/onDeny: "result" returns a
249
+ // serializable decision to the model instead of throwing.
250
+ ```
251
+
252
+ ### LangChain.js — `@odingard/guardian-langchain`
253
+
254
+ ```bash
255
+ npm install @odingard/guardian-langchain
256
+ ```
257
+
258
+ ```ts
259
+ import { createGuardianClient } from "@odingard/guardian-sdk";
260
+ import { GuardianApprovalPending, GuardianDenied, guardianTool }
261
+ from "@odingard/guardian-langchain";
262
+
263
+ const guardian = createGuardianClient({ baseUrl, credential });
264
+ const refundOrder = guardianTool(refundOrderTool, {
265
+ client: guardian,
266
+ connectionId: "con_…",
267
+ mode: "inProcess",
268
+ });
269
+
270
+ // Same triad + modes: the wrapped tool keeps its name, description,
271
+ // schema and returnDirect flag, so it drops into bindTools / LangGraph
272
+ // unchanged. On ASK, catch GuardianApprovalPending in your node and
273
+ // interrupt() — pending.resume() claims the capability and completes
274
+ // the call after the human approves.
275
+ ```
276
+
277
+ ## Examples
278
+
279
+ Runnable examples live in [`examples/`](examples/). Each prints its label:
280
+ `SIMULATED` = a local demo policy stands in for Guardian (nothing real
281
+ happens); `LIVE` = real hosted Guardian (set `GUARDIAN_BASE_URL`,
282
+ `GUARDIAN_AGENT_CREDENTIAL`, `GUARDIAN_CONNECTION_ID`) or real published keys.
283
+
284
+ ```bash
285
+ cd examples && npm install
286
+
287
+ node verify-receipt.mjs # LIVE, no account: verify a real staging receipt offline, then tamper
288
+ node demo-classes.mjs # the 7 demo classes (email, delegation, vendor payment, PHI, deploy, CRM, robot stop)
289
+ node steel-checkout.mjs # Steel checkout → ASK → resume
290
+ node shopping-agent.mjs # purchase → ASK, human approves, receipt
291
+ node prompt-injection-deny.mjs # injected "export contacts" → DENY
292
+ node coding-agent-ask.mjs # consequential command → ASK
293
+ ```
294
+
60
295
  ## License
61
296
 
62
297
  Apache-2.0
63
298
 
64
299
  ## Provenance
65
300
 
66
- Canonical development happens in the Odingard Guardian monorepo; this
67
- repository is the standalone open-source distribution of the agent SDK
301
+ Canonical development happens in the [Odingard Guardian monorepo](https://github.com/Odingard/guardian);
302
+ this repository is the standalone open-source distribution of the agent SDK
68
303
  (source mirrored, Apache-2.0). Issues and contributions welcome here.