provenance-protocol 0.1.3 → 0.2.1

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,9 +1,59 @@
1
1
  # provenance-protocol
2
2
 
3
- SDK for querying the [Provenance](https://getprovenance.dev) agent identity index.
3
+ The Provenance Protocol: an open standard for declaring and verifying AI agent
4
+ identity — and the reference SDK that implements it.
4
5
 
5
- Drop this into any receiving system — marketplace, API, agent orchestrator —
6
- to verify an AI agent's identity and trust profile before allowing it in.
6
+ ## The standard
7
+
8
+ | | |
9
+ |---|---|
10
+ | [**SPEC.md**](./SPEC.md) | The specification. `PROVENANCE.yml`, the field reference, the capability vocabulary, signing and verification, conformance. |
11
+ | [**schema/provenance-0.1.json**](./schema/provenance-0.1.json) | JSON Schema for validating a declaration. |
12
+ | [**test-vectors/**](./test-vectors/) | Normative signature vectors. Pass these and you interoperate. |
13
+
14
+ The specification is MIT-licensed and free to implement in any language,
15
+ without permission or notification. A declaration can be read, validated and
16
+ cryptographically verified **entirely offline** — no account, no API key, and
17
+ no call to any service, this one included. Indexes, monitors and attesters are
18
+ applications built on the standard, not part of it.
19
+
20
+ ## Offline verification
21
+
22
+ No account, no API key, no call to any service — including this one.
23
+
24
+ ```js
25
+ import { verifyDeclaration } from 'provenance-protocol/verify';
26
+ import YAML from 'yaml';
27
+
28
+ const result = await verifyDeclaration(YAML.parse(fileContents), {
29
+ retrievedFrom: 'https://github.com/alice/research-assistant',
30
+ });
31
+
32
+ result.valid // the signature verifies against the key in the file
33
+ result.location // 'match' | 'mismatch' | 'unchecked'
34
+ result.trustworthy // valid AND served from the location it claims
35
+ result.fingerprint // SHA-256 of the key — store it to detect rotation
36
+ ```
37
+
38
+ A valid signature proves the declaration came from the holder of that private
39
+ key and has not been altered. It does **not** prove who that holder is, that
40
+ the declared capabilities are accurate, or that the declaration is current.
41
+ That is why `trustworthy` also requires the location check: a signature is only
42
+ the project owner's if the file was served from the project it names.
43
+
44
+ Also exported: `verifyChallenge()` for live proof of key control against a key
45
+ you already hold, `verifyRevocation()`, `checkLocation()` and `keyFingerprint()`.
46
+
47
+ Declarations are YAML — parse them with whatever library you already use and
48
+ pass the object. This module has no dependencies.
49
+
50
+ ## The SDK
51
+
52
+ This package is one implementation. It adds what cannot be done offline:
53
+ looking up an agent's current standing — open incidents, revocation, drift —
54
+ before you let it in.
55
+
56
+ Drop it into any receiving system — marketplace, API, agent orchestrator.
7
57
 
8
58
  ```bash
9
59
  npm install provenance-protocol
@@ -21,9 +71,10 @@ const trust = await provenance.check('provenance:github:alice/research-assistant
21
71
  console.log(trust);
22
72
  // {
23
73
  // found: true,
74
+ // identity: 'verified', // 'inferred' | 'declared' | 'verified'
75
+ // identity_verified: true,
24
76
  // declared: true,
25
77
  // age_days: 142,
26
- // confidence: 0.9,
27
78
  // capabilities: ['read:web', 'write:summaries'],
28
79
  // constraints: ['no:financial:transact', 'no:pii'],
29
80
  // incidents: 0,
@@ -39,11 +90,11 @@ The most useful method for receiving systems.
39
90
 
40
91
  ```js
41
92
  const result = await provenance.gate('provenance:github:alice/agent', {
42
- requireDeclared: true, // must have PROVENANCE.yml
93
+ requireDeclared: true, // must have PROVENANCE.yml
94
+ requireVerified: true, // must have identity_verified: true
43
95
  requireConstraints: ['no:financial:transact', 'no:pii'], // must have committed to these
44
- requireClean: true, // no open incidents
45
- requireMinAge: 30, // must be at least 30 days old
46
- requireMinConfidence: 0.7, // classification confidence
96
+ requireClean: true, // no open incidents
97
+ requireMinAge: 30, // must be at least 30 days old
47
98
  });
48
99
 
49
100
  if (!result.allowed) {
@@ -119,35 +170,42 @@ if (result.fallback) {
119
170
  | Field | Type | Description |
120
171
  |---|---|---|
121
172
  | `found` | boolean | Agent exists in Provenance index |
122
- | `declared` | boolean | Has a PROVENANCE.yml file |
173
+ | `identity` | string | `'inferred'` \| `'declared'` \| `'verified'` — see below |
174
+ | `identity_verified` | boolean | Cryptographic key ownership confirmed against a public URL |
175
+ | `declared` | boolean | Agent has a PROVENANCE.yml (or registered via API with full fields) |
123
176
  | `age_days` | number | Days since first indexed |
124
- | `confidence` | number | 0–1 classification confidence |
125
177
  | `capabilities` | string[] | What the agent declares it can do |
126
178
  | `constraints` | string[] | What the agent has publicly committed never to do |
127
179
  | `incidents` | number | Number of open incidents |
128
- | `status` | string | active / suspended / removed |
180
+ | `status` | string | `active` / `suspended` / `removed` |
129
181
  | `model` | object | `{ provider, model_id }` if declared |
130
182
  | `public_key` | string\|null | Base64 Ed25519 public key, if registered |
131
- | `identity_verified` | boolean | Cryptographic proof of key ownership confirmed |
132
183
  | `ajp_endpoint` | string\|null | AJP job endpoint URL, if the agent accepts delegated jobs |
133
184
  | `first_seen` | string | ISO date of first public appearance |
134
185
 
186
+ ### Identity states
187
+
188
+ | State | Meaning |
189
+ |---|---|
190
+ | `inferred` | Indexed by crawler from a public repo. No PROVENANCE.yml, no self-registration. |
191
+ | `declared` | Agent registered itself (or has PROVENANCE.yml) but without cryptographic key verification. |
192
+ | `verified` | Agent registered with a keypair and the public key was confirmed against a publicly fetchable PROVENANCE.yml. **Independently auditable** — anyone can re-verify without trusting the Provenance registry. |
193
+
135
194
  ---
136
195
 
137
196
  ## Registering your own agent
138
197
 
139
- ```js
140
- import { Provenance } from 'provenance-protocol';
141
- import { generateProvenanceKeyPair, signChallenge } from 'provenance-protocol/keygen';
198
+ ### Public repo (GitHub / HuggingFace / npm)
142
199
 
143
- const provenance = new Provenance();
200
+ Push a `PROVENANCE.yml` containing your public key to the repo, then register. The server fetches the file and confirms the key — independently verifiable by anyone.
144
201
 
145
- // One-time: generate a keypair
146
- const { publicKey, privateKey } = generateProvenanceKeyPair();
147
- // Store privateKey as PROVENANCE_PRIVATE_KEY env var — never commit it
202
+ ```js
203
+ import { generateProvenanceKeyPair, signForProvenance, signChallenge } from 'provenance-protocol/keygen';
148
204
 
149
- // Sign proof of key ownership for registration
205
+ const { publicKey, privateKey } = generateProvenanceKeyPair();
150
206
  const provenanceId = 'provenance:github:your-org/your-agent';
207
+
208
+ // Add to PROVENANCE.yml → commit → push, then:
151
209
  const signed_challenge = signChallenge(privateKey, provenanceId, 'REGISTER');
152
210
 
153
211
  await provenance.register({
@@ -158,11 +216,34 @@ await provenance.register({
158
216
  capabilities: ['read:web', 'write:summaries'],
159
217
  constraints: ['no:pii'],
160
218
  public_key: publicKey,
161
- signed_challenge, // proves you control the private key
219
+ signed_challenge,
162
220
  });
163
- // → { created: true, identity_verified: true, confidence: 1.0 }
221
+ // → { created: true, agent: { identity: 'verified', identity_verified: true } }
164
222
  ```
165
223
 
224
+ ### Private agent (no public repo)
225
+
226
+ Use `provenance:custom:` platform. Host your `PROVENANCE.yml` at any public URL you control and pass it as `url` — this makes the identity independently verifiable. Without a `url`, verification is registry-dependent (key control only).
227
+
228
+ ```js
229
+ const provenanceId = 'provenance:custom:your-org/your-agent';
230
+ const signed_challenge = signChallenge(privateKey, provenanceId, 'REGISTER');
231
+
232
+ await provenance.register({
233
+ id: provenanceId,
234
+ url: 'https://yourdomain.com/.well-known/provenance.yml', // optional but recommended
235
+ name: 'Your Agent',
236
+ description: 'What it does',
237
+ capabilities: ['read:web'],
238
+ constraints: ['no:pii'],
239
+ public_key: publicKey,
240
+ signed_challenge,
241
+ });
242
+ // → { created: true, agent: { identity: 'verified', identity_verified: true } }
243
+ ```
244
+
245
+ See [getprovenance.dev/docs#ai-quickstart](https://getprovenance.dev/docs#ai-quickstart) for full automated scripts.
246
+
166
247
  ## Revoking a compromised key
167
248
 
168
249
  ```js
package/SPEC.md ADDED
@@ -0,0 +1,483 @@
1
+ # Provenance Protocol Specification
2
+ **Version 0.1**
3
+
4
+ ---
5
+
6
+ ## What is PROVENANCE.yml?
7
+
8
+ `PROVENANCE.yml` is a single file that lives in the root of any AI agent's
9
+ repository. It tells the world — in a structured, machine-readable,
10
+ human-readable way — what this agent is, what it can do, what it will
11
+ never do, and who is responsible for it.
12
+
13
+ Think of it as the agent's public identity card.
14
+ Voluntary. Simple. Five minutes to add. Zero friction.
15
+
16
+ The filename is unambiguous by design. No existing project will already
17
+ have a file called `PROVENANCE.yml` for any other purpose. When you see
18
+ this file in a repository you know exactly what it is and why it exists.
19
+
20
+ ---
21
+
22
+ ## Why does this exist?
23
+
24
+ The agent internet is growing faster than the infrastructure to understand it.
25
+ Thousands of agents exist publicly — on GitHub, HuggingFace, npm, PyPI,
26
+ ClawMarket — but there is no standard way to answer basic questions:
27
+
28
+ - What does this agent actually do?
29
+ - What can it access? What will it never touch?
30
+ - Who built it and how do I reach them if something goes wrong?
31
+ - What model powers it, and has that changed recently?
32
+ - Has this agent's behavior been consistent over time?
33
+
34
+ `PROVENANCE.yml` makes these questions answerable — automatically, at scale,
35
+ without anyone needing to manually curate anything.
36
+
37
+ It is the `robots.txt` of the agent internet. A simple convention that
38
+ benefits everyone: developers get discoverability, receiving systems get
39
+ trust signals, the ecosystem gets a shared foundation.
40
+
41
+ ---
42
+
43
+ ## The File
44
+
45
+ Place a file named exactly `PROVENANCE.yml` in the root of your repository.
46
+
47
+ ### Minimal valid PROVENANCE.yml
48
+
49
+ ```yaml
50
+ provenance: "0.1"
51
+ name: "Research Assistant"
52
+ description: "Searches the web and summarizes academic papers on a given topic."
53
+ ```
54
+
55
+ Three lines. That is the minimum. Everything else is optional but valuable.
56
+
57
+ ---
58
+
59
+ ### Complete PROVENANCE.yml
60
+
61
+ ```yaml
62
+ # PROVENANCE.yml
63
+ # Provenance Protocol v0.1
64
+ # https://getprovenance.dev/spec
65
+
66
+ provenance: "0.1"
67
+
68
+ # ── Identity ──────────────────────────────────────────────────────────────────
69
+
70
+ name: "Research Assistant"
71
+ version: "1.4.2"
72
+ description: >
73
+ Searches the web, retrieves academic papers, and produces structured
74
+ summaries with citations. Designed for researchers and analysts.
75
+
76
+ # ── Intelligence ──────────────────────────────────────────────────────────────
77
+ # When model changes, Provenance detects behavioral drift automatically
78
+
79
+ model:
80
+ provider: "anthropic"
81
+ model_id: "claude-sonnet-4-5"
82
+
83
+ # ── Capabilities — what this agent CAN do ─────────────────────────────────────
84
+
85
+ capabilities:
86
+ - read:web
87
+ - read:pdf
88
+ - read:arxiv
89
+ - write:summaries
90
+
91
+ # ── Constraints — what this agent will NEVER do ───────────────────────────────
92
+ # These are public commitments. Recorded permanently. Violations are detectable.
93
+
94
+ constraints:
95
+ - no:write:external
96
+ - no:financial:transact
97
+ - no:pii
98
+ - no:delegate:agents
99
+
100
+ # ── Runtime ───────────────────────────────────────────────────────────────────
101
+
102
+ runtime:
103
+ type: "task" # task | persistent | scheduled
104
+ trigger: "api" # api | webhook | schedule | event
105
+
106
+ # ── Contact ───────────────────────────────────────────────────────────────────
107
+
108
+ contact:
109
+ name: "Alice Chen"
110
+ url: "https://alice.dev"
111
+ email: "agent-issues@alice.dev"
112
+
113
+ # ── Skills ────────────────────────────────────────────────────────────────────
114
+ # External skills this agent uses — Provenance tracks these as dependencies
115
+
116
+ skills:
117
+ - id: "web-search-001"
118
+ source: "skillsmp"
119
+ url: "https://skillsmp.com/skills/web-search-001"
120
+
121
+ # ── Provenance ────────────────────────────────────────────────────────────────
122
+ # Links this file to your entry in the Provenance index
123
+
124
+ provenance_id: "provenance:github:alice/research-assistant"
125
+
126
+ # ── Identity — optional, makes this file tamper-evident ───────────────────────
127
+ # Signature covers "<provenance_id>:<public_key>". See Signing and Verification.
128
+
129
+ identity:
130
+ public_key: "MCowBQYDK2VwAyEA..."
131
+ signature: "3n8Kd0vQ..."
132
+ algorithm: "ed25519"
133
+ ```
134
+
135
+ ---
136
+
137
+ ## Field Reference
138
+
139
+ ### Required
140
+
141
+ | Field | Type | Description |
142
+ |---|---|---|
143
+ | `provenance` | string | Spec version. Currently `"0.1"` |
144
+ | `name` | string | Human-readable name for this agent |
145
+ | `description` | string | What this agent does, in plain language |
146
+
147
+ ### Recommended
148
+
149
+ | Field | Type | Description |
150
+ |---|---|---|
151
+ | `version` | string | Semantic version of the agent |
152
+ | `model.provider` | string | `anthropic` `openai` `google` `mistral` `meta` `local` `other` |
153
+ | `model.model_id` | string | Specific model e.g. `claude-sonnet-4-5` |
154
+ | `capabilities` | list | What this agent can do |
155
+ | `constraints` | list | What this agent will never do — public commitment |
156
+ | `contact.name` | string | Who is responsible for this agent |
157
+ | `contact.url` | string | Where to learn more |
158
+ | `runtime.type` | string | `task` `persistent` `scheduled` |
159
+
160
+ ### Optional
161
+
162
+ | Field | Type | Description |
163
+ |---|---|---|
164
+ | `contact.email` | string | Contact for issues or abuse reports |
165
+ | `skills` | list | SkillsMP or other skills this agent depends on |
166
+ | `delegates` | list | Sub-agents this orchestrator spawns |
167
+ | `provenance_id` | string | Links to your Provenance index entry |
168
+ | `runtime.trigger` | string | `api` `webhook` `schedule` `event` |
169
+ | `identity.public_key` | string | Base64 SPKI DER Ed25519 public key |
170
+ | `identity.signature` | string | Base64 Ed25519 signature over `<provenance_id>:<public_key>`. Optional — see Signing and Verification |
171
+ | `identity.algorithm` | string | Always `ed25519` in v0.1 |
172
+
173
+ ---
174
+
175
+ ## Capability Vocabulary
176
+
177
+ Standard capability strings. Provenance indexes and filters by them.
178
+ Custom capabilities allowed — prefix with your domain: `acme:custom-capability`
179
+
180
+ ### Read
181
+ ```
182
+ read:web fetch public web content
183
+ read:files read local files
184
+ read:database query databases
185
+ read:email read email (requires auth)
186
+ read:calendar read calendar (requires auth)
187
+ read:code read code repositories
188
+ read:pdf parse PDF documents
189
+ read:images process images
190
+ read:audio process audio
191
+ ```
192
+
193
+ ### Write
194
+ ```
195
+ write:files write local files
196
+ write:database write to databases
197
+ write:email send email
198
+ write:code modify code
199
+ write:summaries generate written content
200
+ write:external any external system write
201
+ ```
202
+
203
+ ### Execute
204
+ ```
205
+ execute:code run code in a sandbox
206
+ execute:terminal run terminal commands
207
+ execute:browser control a browser
208
+ ```
209
+
210
+ ### Financial
211
+ ```
212
+ financial:read read financial data
213
+ financial:transact initiate financial transactions
214
+ ```
215
+
216
+ ### Delegation
217
+ ```
218
+ delegate:agents can spawn or hire sub-agents
219
+ delegate:humans can request human approval
220
+ ```
221
+
222
+ ### Constraints (no: prefix)
223
+
224
+ Any capability prefixed with `no:` is a public constraint.
225
+ A commitment that this agent will never exercise that capability.
226
+
227
+ ```yaml
228
+ constraints:
229
+ - no:financial:transact # will never initiate transactions
230
+ - no:write:external # will never write to external systems
231
+ - no:delegate:agents # will never spawn sub-agents
232
+ - no:pii # will never collect personal data
233
+ ```
234
+
235
+ **Constraints are the most powerful field in PROVENANCE.yml.**
236
+ A receiving system that requires `no:financial:transact` can filter for it.
237
+ An agent that publicly commits to a constraint and violates it gets a
238
+ permanent incident on its Provenance record. The commitment is real.
239
+
240
+ ---
241
+
242
+ ## Provenance IDs
243
+
244
+ Every agent in the Provenance index has a stable identifier derived from
245
+ where it lives publicly. No registration required — the ID is computed
246
+ deterministically from the public URL.
247
+
248
+ ```
249
+ provenance:github:owner/repo
250
+ provenance:npm:@scope/package-name
251
+ provenance:pypi:package-name
252
+ provenance:huggingface:owner/space-name
253
+ provenance:clawmarket:listing-id
254
+ ```
255
+
256
+ Add `provenance_id` to your PROVENANCE.yml to link your file to your
257
+ index entry and claim your agent profile.
258
+
259
+ ---
260
+
261
+ ## How Provenance uses PROVENANCE.yml
262
+
263
+ When Provenance discovers or crawls an agent repository it:
264
+
265
+ 1. Reads `PROVENANCE.yml` if present
266
+ 2. Hashes the file content — future changes are detectable
267
+ 3. Records the discovery in the tamper-evident public log
268
+ 4. Indexes capabilities and constraints for search
269
+ 5. Monitors for changes — what changed, when, from what to what
270
+ 6. Computes the Provenance ID from the repository URL
271
+ 7. Surfaces the agent in search results for capability queries
272
+
273
+ Without PROVENANCE.yml, Provenance still indexes the agent from code
274
+ signals — framework imports, package keywords, repository topics — but
275
+ with lower confidence. Adding PROVENANCE.yml upgrades the profile from
276
+ inferred to declared.
277
+
278
+ ---
279
+
280
+ ## Signing and Verification
281
+
282
+ A `PROVENANCE.yml` file is readable by anyone, which also means it is
283
+ editable by anyone who re-hosts it. The optional `identity` block makes a
284
+ declaration **tamper-evident**: it proves the file was produced by whoever
285
+ holds a particular private key, and that nobody has altered it since.
286
+
287
+ Verification requires no network access and no account. Any implementation
288
+ can perform it offline.
289
+
290
+ ### The identity block
291
+
292
+ ```yaml
293
+ provenance_id: "provenance:github:alice/research-assistant"
294
+
295
+ identity:
296
+ public_key: "MCowBQYDK2VwAyEA..." # base64 of SPKI DER Ed25519 public key
297
+ signature: "3n8Kd0vQ..." # base64 of raw 64-byte Ed25519 signature
298
+ algorithm: "ed25519" # always ed25519 in v0.1
299
+ ```
300
+
301
+ `public_key` is required when `identity` is present. `algorithm` is optional
302
+ and defaults to `ed25519`; no other value is valid in v0.1.
303
+
304
+ `signature` is optional, and its presence changes what the block means:
305
+
306
+ - **`public_key` alone** advertises the key this agent will use to prove
307
+ control live, through the challenge-response below. The declaration itself
308
+ is not tamper-evident. This is the path for an agent with no public
309
+ repository, where there is no stable location to sign against.
310
+ - **`public_key` with `signature`** additionally makes the declaration
311
+ tamper-evident. This requires `provenance_id`, since the identity is part
312
+ of what gets signed.
313
+
314
+ Prefer the signed form wherever the agent has a public location. A verifier
315
+ that finds a key with no signature has learned which key to challenge, and
316
+ nothing about whether the file has been altered.
317
+
318
+ ### What gets signed
319
+
320
+ The signed message is the UTF-8 encoding of:
321
+
322
+ ```
323
+ <provenance_id>:<public_key>
324
+ ```
325
+
326
+ where `<public_key>` is the same base64 string that appears in
327
+ `identity.public_key`. Concatenating the two binds the key to the identity,
328
+ so a key lifted from one declaration cannot be replayed under a different
329
+ `provenance_id`.
330
+
331
+ Signing a declaration therefore requires `provenance_id` to be present.
332
+
333
+ ### How to verify
334
+
335
+ 1. Read `provenance_id` and the `identity` block.
336
+ 2. Reconstruct the message as `<provenance_id>:<public_key>`.
337
+ 3. Import `public_key` as an Ed25519 SPKI DER key.
338
+ 4. Verify `signature` over the message bytes.
339
+
340
+ Ed25519 is deterministic (RFC 8032), so a correct implementation produces
341
+ byte-identical signatures for the same key and message. The test vectors in
342
+ `test-vectors/signatures-0.1.json` let you confirm this without contacting
343
+ anyone.
344
+
345
+ ### What verification proves — and what it does not
346
+
347
+ A valid signature proves:
348
+
349
+ - the declaration was produced by the holder of that private key, and
350
+ - not one byte of `provenance_id` or `public_key` has changed since.
351
+
352
+ A valid signature does **not** prove:
353
+
354
+ - that the key belongs to any particular person or organisation, or
355
+ - that the declared capabilities or constraints are accurate, or
356
+ - that the declaration is still current.
357
+
358
+ Binding a key to a real-world identity is a separate step. Two mechanisms
359
+ are available, and they compose:
360
+
361
+ **Location.** A declaration fetched from the repository named by its own
362
+ `provenance_id` was placed there by someone with write access to it. A
363
+ declaration whose `provenance_id` does not match where it was found should
364
+ be treated as unverified regardless of its signature — this is the
365
+ re-hosting case the substituted-key test vector covers.
366
+
367
+ **Continuity.** Once a key has been seen for a `provenance_id`, a later
368
+ declaration signed by a different key is a key rotation and must be treated
369
+ as a material change, not a silent update.
370
+
371
+ This is the same division of labour as a machine-readable passport: the
372
+ document proves its own integrity offline, while identity binding and
373
+ current standing are looked up.
374
+
375
+ ### Live proof of key control
376
+
377
+ A signature on a file proves the file's origin. It does not prove that the
378
+ agent running right now controls that key. For that, a receiving system
379
+ issues a nonce and the agent returns a signature over:
380
+
381
+ ```
382
+ <provenance_id>:<nonce>
383
+ ```
384
+
385
+ Nonces must be single-use and unpredictable. The receiving system verifies
386
+ the signature against the public key it already holds for that
387
+ `provenance_id`.
388
+
389
+ ### Revocation
390
+
391
+ A key holder revokes a `provenance_id` by signing:
392
+
393
+ ```
394
+ <provenance_id>:REVOKE
395
+ ```
396
+
397
+ Revocation is the one operation that cannot be verified offline — a verifier
398
+ has no way to know a revocation has been issued without asking. Implementations
399
+ that cache public keys should re-check revocation status on the same cadence
400
+ they would re-check any other freshness signal.
401
+
402
+ ---
403
+
404
+ ## Conformance
405
+
406
+ An implementation of this specification is conformant if it:
407
+
408
+ 1. Accepts every file that validates against `schema/provenance-0.1.json`.
409
+ 2. Treats `provenance`, `name` and `description` as required and everything
410
+ else as optional.
411
+ 3. Ignores unrecognised top-level fields rather than rejecting the file.
412
+ Future spec versions add fields; a `0.1` reader must not break on them.
413
+ 4. Treats `identity.signature` as optional, and an unsigned `identity`
414
+ block as advertising a key rather than attesting the file.
415
+ 5. Reproduces every signature in `test-vectors/signatures-0.1.json` marked
416
+ `valid`, and refuses every one marked `invalid`.
417
+ 6. Treats a declaration whose `provenance_id` does not match its retrieval
418
+ location as unverified.
419
+
420
+ Points 5 and 6 are what make independent implementations agree. An
421
+ implementation that passes the test vectors interoperates with every other
422
+ one that does, with no reference to any particular service.
423
+
424
+ A reference implementation of offline verification ships in this repository as
425
+ `provenance-protocol/verify`. It is one implementation, not the definition —
426
+ the vectors are the definition.
427
+
428
+ ---
429
+
430
+ ## Implementing this specification
431
+
432
+ This specification, its JSON Schema and its test vectors are published under
433
+ the MIT Licence. You may implement them in any language, for any purpose,
434
+ commercial or otherwise, without permission, notification or fee.
435
+
436
+ Nothing in this specification requires contacting any particular service. A
437
+ conformant implementation can read, validate and cryptographically verify a
438
+ declaration entirely offline. Services built on this protocol — indexes,
439
+ monitors, attesters — are applications of the standard, not part of it.
440
+
441
+ ---
442
+
443
+ ## Versioning
444
+
445
+ The `provenance` field records which spec version you are using.
446
+ We commit to backwards compatibility — a `0.1` file will always be
447
+ readable regardless of future spec versions.
448
+ New versions add fields. Existing fields are never removed.
449
+
450
+ ---
451
+
452
+ ## FAQ
453
+
454
+ **Do I have to register anywhere?**
455
+ No. Provenance discovers agents automatically. Adding PROVENANCE.yml
456
+ improves your profile but requires no account, no API key, no permission.
457
+
458
+ **What if I already have a file in my repo I want to keep private?**
459
+ PROVENANCE.yml is only read from public repositories. Private repos
460
+ are not crawled.
461
+
462
+ **What if my constraints are inaccurate?**
463
+ Constraints are public commitments. Be honest. A constraint you declare
464
+ but violate becomes a permanent incident on your record.
465
+
466
+ **Can I use custom capability strings?**
467
+ Yes. Prefix with your domain: `acme:internal-tool`. Standard vocabulary
468
+ recommended for interoperability.
469
+
470
+ **What happens when I change my model?**
471
+ Provenance detects it from the repository commit and from behavioral
472
+ fingerprinting. The change is recorded — not penalized. Transparency
473
+ is the point.
474
+
475
+ **What if my agent is on HuggingFace, not GitHub?**
476
+ Same process. Add PROVENANCE.yml to your Space or model repository root.
477
+ Provenance crawls HuggingFace the same way it crawls GitHub.
478
+
479
+ ---
480
+
481
+ *Provenance Protocol v0.1 — MIT License*
482
+ *https://getprovenance.dev*
483
+ *https://github.com/ilucky21c/provenance-protocol*