@nomosprotocol/sdk 1.3.0 → 1.3.2

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 (2) hide show
  1. package/README.md +320 -47
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,14 +1,36 @@
1
1
  # @nomosprotocol/sdk
2
2
 
3
- Official TypeScript SDK for [NOMOS](https://www.nomosprotocol.com) — ask a public authority a question from your code and get back a deterministic, cryptographically verifiable verdict.
3
+ Official TypeScript SDK for [NOMOS](https://www.nomosprotocol.com/) — a programmable authority layer for AI agents and software.
4
+
5
+ NOMOS lets software ask a simple question:
6
+
7
+ > **Can I do this?**
8
+
9
+ Give `can()` an authority, an action, and the relevant facts. NOMOS verifies the authority, evaluates its rules, and returns a deterministic verdict:
10
+
11
+ **AUTHORIZED · DENIED · ESCALATED**
4
12
 
5
13
  ```bash
6
14
  npm install @nomosprotocol/sdk
7
15
  ```
8
16
 
9
- ## `nomos.can()` — the keyless primitive
17
+ ## `can()` — one function for authority
18
+
19
+ `can()` is the primary query interface to NOMOS.
20
+
21
+ It abstracts three different authority situations behind one call and one verdict vocabulary:
22
+
23
+ | You have... | Call | API key? |
24
+ | ---------------------------------------------------------- | ------------------------------------------------------------------- | -------: |
25
+ | A public authority published on the NOMOS Exchange | `nomos.can({ authority, ...facts })` | No |
26
+ | Your organization's sealed artifact | `client.can({ artifact_id, ...facts })` | Yes |
27
+ | A sealed artifact presented directly by an agent or system | `nomos.can({ artifact, key_certs, root_public_key_pem, ...facts })` | No |
28
+
29
+ The caller does not need to know which evaluation rail is being used. `can()` routes internally based on what you provide.
10
30
 
11
- Every public authority on the [NOMOS Exchange](https://www.nomosprotocol.com/exchange) is queryable with one call. No API key, no setup — this is the front door.
31
+ ### 1. Public authority
32
+
33
+ Ask a published authority directly:
12
34
 
13
35
  ```ts
14
36
  import { nomos } from "@nomosprotocol/sdk";
@@ -18,101 +40,352 @@ const verdict = await nomos.can({
18
40
  ai_categorises_biometric_data_for_sensitive_attributes: true,
19
41
  });
20
42
 
21
- if (!verdict.allowed) {
22
- console.log(verdict.verdict); // "DENIED"
23
- console.log(verdict.reason); // why
24
- console.log(verdict.query_id); // permanent transcript id
25
- }
43
+ console.log(verdict.verdict);
44
+ // "DENIED"
45
+
46
+ console.log(verdict.reason);
47
+ // explanation from the authority
48
+
49
+ console.log(verdict.query_id);
50
+ // permanent transcript ID
26
51
  ```
27
52
 
28
- Facts can be spread flat alongside `authority` (as above), or passed explicitly:
53
+ No API key or account is required for public Exchange authorities.
54
+
55
+ Facts can also be passed explicitly:
29
56
 
30
57
  ```ts
31
58
  const verdict = await nomos.can({
32
59
  authority: "eu-ai-act.nomos",
33
- inputs: { ai_categorises_biometric_data_for_sensitive_attributes: true },
34
- action: "screen a new feature before launch", // optional, recorded in the transcript
60
+ inputs: {
61
+ ai_categorises_biometric_data_for_sensitive_attributes: true,
62
+ },
63
+ action: "screen a new feature before launch",
64
+ });
65
+ ```
66
+
67
+ If a paid authority has not been purchased, NOMOS throws `NomosPaymentRequiredError` with the price and purchase URL attached.
68
+
69
+ NOMOS never auto-charges on your behalf.
70
+
71
+ ### 2. Your organization's authority
72
+
73
+ Use an authenticated client for artifacts belonging to your organization:
74
+
75
+ ```ts
76
+ import { Nomos } from "@nomosprotocol/sdk";
77
+
78
+ const client = new Nomos("nms_live_...");
79
+
80
+ const verdict = await client.can({
81
+ artifact_id: "loan_approval_v1",
82
+ credit_score: 720,
83
+ loan_amount: 50_000,
84
+ });
85
+
86
+ if (verdict.allowed) {
87
+ // proceed
88
+ }
89
+ ```
90
+
91
+ The same verdict vocabulary is returned.
92
+
93
+ The difference is that the artifact is private and accessed through your authenticated NOMOS account.
94
+
95
+ ### 3. A portable authority presented by an agent
96
+
97
+ This is the keyless, portable authority rail.
98
+
99
+ An agent can carry a sealed `.nomos` artifact with it and present that authority to another system — even if NOMOS has never seen or registered the artifact.
100
+
101
+ ```ts
102
+ const verdict = await nomos.can({
103
+ artifact: presentedArtifact,
104
+ key_certs: [rootToIntermediate, intermediateToLeaf],
105
+ root_public_key_pem: yourPinnedRootKey,
106
+ credit_score: 720,
35
107
  });
36
108
  ```
37
109
 
38
- ### The verdict
110
+ NOMOS performs the entire verification locally:
111
+
112
+ 1. Walk the presented certificate chain from the root key you've pinned.
113
+ 2. Verify each link's signature and check it hasn't expired.
114
+ 3. Check that no key in the chain has been revoked.
115
+ 4. Verify the artifact's own cryptographic seal against the resolved key.
116
+ 5. Evaluate the artifact's rules against the supplied facts.
117
+ 6. Return `AUTHORIZED`, `DENIED`, or `ESCALATED`.
118
+
119
+ (NOMOS-SPEC-006 artifact-version revocation — an issuer withdrawing one specific sealed version — is checked on the Exchange rail today; wiring the same check into this rail is a known gap, not yet done.)
120
+
121
+ No prior artifact lookup is required.
122
+
123
+ This means authority can **travel with the agent**.
124
+
125
+ The relying party does not have to trust the AI vendor, the model, or a pre-existing NOMOS registry entry. It can independently verify the authority presented to it.
126
+
127
+ The root key is deliberately supplied by the relying party. NOMOS does not define a universal default root of trust.
128
+
129
+ This rail is currently a working prototype and is not yet a numbered NOMOS specification. A second independent implementation is still required before treating the wire format as interoperable infrastructure.
130
+
131
+ ## `.nomos` — the portable authority artifact
39
132
 
40
- `nomos.can()` always returns the authority's own verdict, verbatim — nothing invented, nothing paraphrased:
133
+ A `.nomos` file is a sealed, machine-executable representation of institutional authority.
41
134
 
42
- | Field | Type | Meaning |
43
- |---|---|---|
44
- | `allowed` | `boolean` | `true` only when `verdict === "AUTHORIZED"` |
45
- | `verdict` | `"AUTHORIZED" \| "DENIED" \| "ESCALATED"` | The authority's own answer |
46
- | `reason` | `string` | Human-readable explanation |
47
- | `rule` | `string \| null` | The rule id that decided it, if any |
48
- | `query_id` | `string` | Permanent, addressable transcript id |
49
- | `url` | `string` | Path to the transcript's permalink page |
50
- | `authority` | `{ id, title, standing }` | Which authority answered, and its standing |
51
- | `missing_inputs` | `string[]` | Fields the authority needed but didn't get — present on `ESCALATED` |
135
+ It can contain the rules, constraints, permissions, obligations, provenance, issuer information, version, and other governance metadata required to evaluate an action.
52
136
 
53
- `ESCALATED` means the authority needs more facts to decide — not a flat no. Check `missing_inputs` for what to supply.
137
+ The artifact is cryptographically sealed.
54
138
 
55
- Every call mints a permanent, cryptographically sealed transcript — open `query_id` any time at `nomosprotocol.com/queries/<query_id>` to replay exactly what was asked and answered, bound to the exact authority version that responded.
139
+ Changing the authority changes the seal.
56
140
 
57
- ### Error handling
141
+ That makes the authority:
58
142
 
59
- A failed call (unknown authority, network issue, upstream error) rejects with a typed `NomosError` subclass — never a bare `Error` — so you can branch on `instanceof` or the stable `.code` string:
143
+ * **machine-executable** — software can evaluate it;
144
+ * **portable** — it can move between systems;
145
+ * **verifiable** — another party can check its authenticity;
146
+ * **versioned** — the exact authority being evaluated can be identified;
147
+ * **auditable** — decisions can be tied back to the authority that produced them.
148
+
149
+ The important distinction is:
150
+
151
+ > The AI does not have to carry the policy in its prompt and be trusted to obey it.
152
+
153
+ The authority can exist outside the model as a verifiable artifact.
154
+
155
+ The model reasons.
156
+
157
+ **NOMOS determines what the authority permits.**
158
+
159
+ ## The verdict
160
+
161
+ `can()` normalizes every rail into the same core result:
162
+
163
+ | Field | Type | Meaning |
164
+ | ------------------- | ------------------------------------ | -------------------------------------------------------- |
165
+ | `allowed` | `boolean` | `true` only when the verdict is `AUTHORIZED` |
166
+ | `verdict` | `AUTHORIZED \| DENIED \| ESCALATED` | The authority's decision |
167
+ | `reason` | `string` | Human-readable explanation |
168
+ | `rule` | `string \| null` | Rule that determined the result, when applicable |
169
+ | `authority` | `{ id, title, standing, attestation? }` | The authority that answered, its standing, and — when a regulator/auditor/issuer has co-signed this exact version — who, in what role, and their statement |
170
+ | `version` | `string` | Authority version, when declared |
171
+ | `missing_inputs` | `string[]` | Facts required for an `ESCALATED` decision |
172
+ | `obligations` | array | Additional duties triggered alongside the verdict |
173
+ | `revoked` | `boolean` | Whether the evaluated authority version has been revoked |
174
+ | `revocation_reason` | `string` | Reason for revocation, when applicable |
175
+ | `max_age` | `number` | Recommended period before re-checking the verdict |
176
+ | `audit` | `{ hash, timestamp }` | Present only on your own artifact rail — your own provenance record, distinct from the Exchange rail's public transcript |
177
+
178
+ ### `ESCALATED` is not `DENIED`
179
+
180
+ An escalation means the authority does not yet have enough information to decide.
60
181
 
61
182
  ```ts
62
- import { nomos, NomosNotFoundError, NomosNetworkError } from "@nomosprotocol/sdk";
183
+ if (verdict.verdict === "ESCALATED") {
184
+ console.log(verdict.missing_inputs);
185
+ }
186
+ ```
187
+
188
+ This distinction matters in institutional workflows.
189
+
190
+ A missing fact is different from a prohibition.
191
+
192
+ An untrusted issuer is different from a rule saying "no."
193
+
194
+ NOMOS keeps those failure classes separate.
195
+
196
+ ## Authority trust is separate from authorization
197
+
198
+ The portable-authority rail deliberately distinguishes two questions:
199
+
200
+ **"Do I trust this authority?"**
201
+
202
+ and
203
+
204
+ **"Does this authority permit this action?"**
205
+
206
+ If the presented chain cannot be established, NOMOS throws `NomosIssuerNotTrustedError`.
207
+
208
+ It does **not** return `DENIED`.
209
+
210
+ ```ts
211
+ try {
212
+ const verdict = await nomos.can({
213
+ artifact,
214
+ key_certs,
215
+ root_public_key_pem,
216
+ credit_score: 720,
217
+ });
218
+ } catch (err) {
219
+ if (err instanceof NomosIssuerNotTrustedError) {
220
+ // The authority itself was not established as trustworthy.
221
+ }
222
+ }
223
+ ```
224
+
225
+ A `DENIED` verdict means:
226
+
227
+ > **The authority was established, and its rules said no.**
228
+
229
+ An issuer-trust error means:
230
+
231
+ > **The authority itself was not established.**
232
+
233
+ Those are fundamentally different claims.
234
+
235
+ ## Errors
236
+
237
+ NOMOS uses typed errors rather than generic failures:
238
+
239
+ ```ts
240
+ import {
241
+ nomos,
242
+ NomosNotFoundError,
243
+ NomosNetworkError,
244
+ NomosPaymentRequiredError,
245
+ NomosIssuerNotTrustedError,
246
+ } from "@nomosprotocol/sdk";
63
247
 
64
248
  try {
65
- const verdict = await nomos.can({ authority: "eu-ai-act.nomos", ...facts });
249
+ const verdict = await nomos.can({
250
+ authority: "eu-ai-act.nomos",
251
+ ...facts,
252
+ });
66
253
  } catch (err) {
67
254
  if (err instanceof NomosNotFoundError) {
68
- // authority slug/id doesn't exist — err.code === 'not_found'
255
+ // Authority does not exist.
256
+ } else if (err instanceof NomosPaymentRequiredError) {
257
+ // Paid authority that has not been purchased.
258
+ console.log(err.priceUsd);
259
+ console.log(err.purchaseUrl);
260
+ } else if (err instanceof NomosIssuerNotTrustedError) {
261
+ // Portable authority could not be established.
262
+ console.log(err.reason);
263
+ // ISSUER_NOT_RECOGNIZED
264
+ // KEY_REVOKED
265
+ // SEAL_INVALID
69
266
  } else if (err instanceof NomosNetworkError) {
70
- // request timed out or the network failed
267
+ // Network failure or timeout.
71
268
  } else {
72
269
  throw err;
73
270
  }
74
271
  }
75
272
  ```
76
273
 
77
- ### Options
274
+ ## Permanent decision transcripts
275
+
276
+ For public Exchange authorities, every `can()` request produces a permanent transcript.
277
+
278
+ The transcript records what was asked, which authority version answered, and what it decided.
279
+
280
+ The returned `query_id` can be used to retrieve the transcript:
78
281
 
79
282
  ```ts
80
- await nomos.can(
81
- { authority: "...", ...facts },
82
- {
83
- baseUrl: "https://www.nomosprotocol.com", // override for local/staging use
84
- signal: abortController.signal, // cancel the request
85
- },
86
- );
283
+ console.log(verdict.query_id);
284
+ console.log(verdict.url);
87
285
  ```
88
286
 
89
- ## `Nomos` — authenticated client
287
+ The portable and private artifact rails are stateless by design and do not invent a server-side transcript ID.
288
+
289
+ ## What `can()` does — and does not do
90
290
 
91
- For private/custom artifacts, governance generation, and webhook verification, use the authenticated client:
291
+ `can()` answers one question:
292
+
293
+ > **Is this action authorized under this authority, given these facts, right now?**
294
+
295
+ It deliberately does not become the interface for everything NOMOS does. Other capabilities stay on the authenticated client, because they answer different questions:
296
+
297
+ ```ts
298
+ await client.can({ artifact_id, ...facts }) // Is this action authorized?
299
+ await verifyChain({ artifact, key_certs, root_public_key_pem }) // Is this artifact's chain of custody genuine?
300
+ await client.artifacts.list({ band, sort }) // What artifacts are available?
301
+ await client.artifacts.retrieve(id) // What is inside this artifact?
302
+ await client.governance.generate({ policies, decision_logs }) // Create a new sealed artifact.
303
+ await client.governance.detectContradictions({ rules }) // Find conflicts in a rule set.
304
+ ```
305
+
306
+ The simplicity comes from giving each operation one meaning.
307
+
308
+ ## Authenticated client
309
+
310
+ The authenticated `Nomos` client exposes the broader platform:
92
311
 
93
312
  ```ts
94
313
  import { Nomos } from "@nomosprotocol/sdk";
95
314
 
96
- const client = new Nomos("nms_live_..."); // or "nms_test_..." for test mode
315
+ const client = new Nomos("nms_live_...");
97
316
 
98
- const result = await client.decisions.verify({
317
+ // Authorization
318
+ await client.can({
99
319
  artifact_id: "your_artifact_id",
100
- decision_context: { /* facts */ },
320
+ ...facts,
101
321
  });
102
322
 
323
+ // Lower-level decision verification
324
+ await client.decisions.verify({
325
+ artifact_id: "your_artifact_id",
326
+ decision_context: { ...facts },
327
+ });
328
+
329
+ // Discover artifacts
103
330
  for await (const artifact of client.artifacts.listAutoPaging()) {
104
331
  console.log(artifact.id);
105
332
  }
106
333
 
107
- const event = await client.webhooks.constructEvent(payload, signatureHeader, webhookSecret);
334
+ // Verify webhook events
335
+ const event = await client.webhooks.constructEvent(
336
+ payload,
337
+ signatureHeader,
338
+ webhookSecret,
339
+ );
108
340
  ```
109
341
 
110
- See [nomosprotocol.com/docs](https://www.nomosprotocol.com/docs) for full API reference, error types, and webhook event shapes.
342
+ `client.decisions.verify()` remains available when the caller needs the lower-level evaluation response rather than the normalized `can()` result.
343
+
344
+ ## Why this exists
345
+
346
+ AI agents can reason.
347
+
348
+ They can plan.
349
+
350
+ They can call tools.
351
+
352
+ But reasoning about authority is not the same thing as possessing authority.
353
+
354
+ A system prompt can tell an agent:
355
+
356
+ > "You may approve loans below this threshold."
357
+
358
+ That does not independently prove that the instruction is authentic, current, untampered with, or actually authoritative.
359
+
360
+ NOMOS moves that authority outside the model.
361
+
362
+ The authority becomes a machine-readable artifact.
363
+
364
+ The artifact can be verified.
365
+
366
+ The rules can be evaluated deterministically.
367
+
368
+ And the result can be checked independently of the model that requested the action.
369
+
370
+ The long-term goal is simple:
371
+
372
+ > **AI agents should not have to be trusted to understand their authority. Their authority should be something other systems can verify.**
111
373
 
112
374
  ## Requirements
113
375
 
114
- Node.js 18+. Ships as dual ESM/CJS with full TypeScript types.
376
+ * Node.js 18+
377
+ * TypeScript supported
378
+ * ESM and CommonJS builds
379
+ * Full TypeScript declarations
115
380
 
116
381
  ## License
117
382
 
118
383
  MIT
384
+
385
+ ## Links
386
+
387
+ * [NOMOS Protocol](https://www.nomosprotocol.com/)
388
+ * [Documentation](https://www.nomosprotocol.com/docs)
389
+ * [NOMOS Exchange](https://www.nomosprotocol.com/exchange)
390
+ * [NOMOS Specification](https://www.nomosprotocol.com/spec)
391
+ * [GitHub](https://github.com/nomos-spec/spec)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomosprotocol/sdk",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "Official TypeScript SDK for the NOMOS governance runtime",
5
5
  "publishConfig": {
6
6
  "access": "public"