@agentcash/discovery 1.6.5 → 1.7.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.
@@ -0,0 +1,270 @@
1
+ # Agentcash Discovery Specification
2
+
3
+ Version: v1.0
4
+
5
+ Status: Public draft for implementation and feedback.
6
+
7
+ ## 1. Introduction
8
+
9
+ Agentcash Discovery is a discovery profile for agent-facing HTTP APIs that charge for or
10
+ authenticate access to individual resources.
11
+
12
+ The protocol defines how an origin advertises:
13
+
14
+ - which resources exist
15
+ - how each resource is addressed
16
+ - which auth or payment mode an agent should expect
17
+ - which payment protocols are supported
18
+ - where larger schemas and guidance can be fetched on demand
19
+
20
+ Discovery metadata is advisory. Runtime execution MUST verify auth and payment truth from the
21
+ live endpoint response, including HTTP 402 challenges.
22
+
23
+ ## 2. Conformance
24
+
25
+ The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL are
26
+ to be interpreted as described in BCP 14 when they appear in uppercase.
27
+
28
+ An implementation conforms to v1 when it implements the OpenAPI profile in this document and
29
+ preserves the resource identity rules below.
30
+
31
+ ## 3. Terminology
32
+
33
+ - Origin: scheme plus host plus optional port, with no path, query, fragment, or trailing slash.
34
+ - Resource: one callable HTTP operation identified by origin, method, and path.
35
+ - Resource key: the stable identity string for a resource.
36
+ - Auth hint: advisory discovery-time classification of the auth/payment behavior.
37
+ - Payment info: advisory pricing and protocol metadata declared in OpenAPI.
38
+
39
+ ## 4. Resource Identity
40
+
41
+ Resource identity is always:
42
+
43
+ ```text
44
+ ${origin} ${method} ${path}
45
+ ```
46
+
47
+ Rules:
48
+
49
+ - `origin` MUST be normalized to `scheme://host[:port]`.
50
+ - `method` MUST be an uppercase HTTP method.
51
+ - `path` MUST start with `/`.
52
+ - `path` MUST exclude query strings and fragments.
53
+ - `path` MUST NOT have a trailing slash except for `/`.
54
+
55
+ Clients SHOULD use `resourceKey` for dedupe, caching, display, and audit joins.
56
+
57
+ ## 5. Discovery Order
58
+
59
+ Origin discovery proceeds in this fixed order:
60
+
61
+ 1. Caller-supplied OpenAPI override URL, when provided.
62
+ 2. `GET /openapi.json`.
63
+
64
+ If no OpenAPI spec is found, discovery returns not found. Legacy `/.well-known/x402`,
65
+ `/.well-known/mpp`, and DNS `_x402` records are no longer parsed; implementations MAY probe their
66
+ presence to emit a single `LEGACY_WELL_KNOWN_FOUND` migration warning.
67
+
68
+ ## 6. Canonical OpenAPI Profile
69
+
70
+ OpenAPI is the canonical machine-readable discovery source.
71
+
72
+ Required top-level fields:
73
+
74
+ - `openapi`
75
+ - `info.title`
76
+ - `info.version`
77
+ - `paths`
78
+
79
+ Required per-operation fields:
80
+
81
+ - `summary` or `description`
82
+ - an effective OpenAPI `security` declaration
83
+ - `responses`
84
+
85
+ Authentication MUST use OpenAPI `security`. Use `security: []` to explicitly declare that an
86
+ operation has no API authentication requirement. Payment is declared independently with
87
+ `x-payment-info`.
88
+
89
+ SIWX is represented as a security scheme with an agentcash marker because OpenAPI has no native
90
+ SIWX scheme type:
91
+
92
+ ```json
93
+ "components": {
94
+ "securitySchemes": {
95
+ "WalletAuth": {
96
+ "type": "apiKey",
97
+ "in": "header",
98
+ "name": "SIGN-IN-WITH-X",
99
+ "x-agentcash-auth-kind": "siwx"
100
+ }
101
+ }
102
+ }
103
+ ```
104
+
105
+ Discovery auth hints are derived from OpenAPI `security` plus `x-payment-info`:
106
+
107
+ | Effective security | `x-payment-info` | Derived auth hint |
108
+ | ------------------ | ---------------- | ----------------- |
109
+ | `[]` | absent | `unprotected` |
110
+ | `[]` | present | `paid` |
111
+ | API key | absent | `apiKey` |
112
+ | API key | present | `apiKey+paid` |
113
+ | SIWX scheme | absent | `siwx` |
114
+ | SIWX scheme | present | `paid` |
115
+
116
+ Implementations MAY recognize a security scheme literally named `siwx` for compatibility, but new
117
+ providers SHOULD use `x-agentcash-auth-kind: "siwx"` on the security scheme.
118
+
119
+ ## 7. Payment Metadata
120
+
121
+ Paid operations SHOULD declare `x-payment-info`.
122
+
123
+ Canonical structured shape:
124
+
125
+ ```json
126
+ {
127
+ "x-payment-info": {
128
+ "price": {
129
+ "mode": "fixed",
130
+ "currency": "USD",
131
+ "amount": "0.02"
132
+ },
133
+ "protocols": [{ "x402": {} }]
134
+ }
135
+ }
136
+ ```
137
+
138
+ Dynamic pricing MAY include bounded or unbounded hints:
139
+
140
+ ```json
141
+ {
142
+ "x-payment-info": {
143
+ "price": {
144
+ "mode": "dynamic",
145
+ "currency": "USD",
146
+ "min": "0.01",
147
+ "max": "2.50"
148
+ },
149
+ "protocols": [
150
+ { "x402": {} },
151
+ { "mpp": { "method": "tempo", "intent": "charge", "currency": "USD" } }
152
+ ]
153
+ }
154
+ }
155
+ ```
156
+
157
+ Rules:
158
+
159
+ - `price.mode` MUST be `fixed` or `dynamic`.
160
+ - `fixed` prices MUST include `amount`.
161
+ - `dynamic` prices SHOULD include `min` and `max` when an agent can safely pre-authorize a bound.
162
+ - `currency`, when present, SHOULD be an ISO 4217 uppercase code.
163
+ - `protocols` SHOULD list protocol objects; unknown protocol keys MUST be ignored by clients.
164
+
165
+ Legacy flat `x-payment-info` MAY be parsed for compatibility. v1-conformant providers
166
+ SHOULD emit the structured shape.
167
+
168
+ ## 8. Guidance And Provenance
169
+
170
+ OpenAPI carries machine metadata. Freeform agent guidance is fetched separately, typically
171
+ from `llms.txt`.
172
+
173
+ Canonical optional OpenAPI extensions:
174
+
175
+ ```json
176
+ {
177
+ "x-agentcash-provenance": {
178
+ "ownershipProofs": ["..."]
179
+ },
180
+ "x-agentcash-guidance": {
181
+ "llmsTxtUrl": "https://api.example.com/llms.txt"
182
+ }
183
+ }
184
+ ```
185
+
186
+ Rules:
187
+
188
+ - `ownershipProofs` SHOULD be short strings or URLs to proof artifacts.
189
+ - `llmsTxtUrl` SHOULD point to concise domain-level guidance.
190
+ - Short inline OpenAPI guidance SHOULD use `info.x-guidance`.
191
+ - `info.guidance` is a deprecated compatibility fallback.
192
+ - Clients SHOULD keep first-pass discovery token-light and fetch large guidance only on demand.
193
+
194
+ ## 9. Warning Codes
195
+
196
+ Warning codes are public API. Implementations MUST NOT rename or reuse codes in a minor or
197
+ patch release.
198
+
199
+ Severity values are:
200
+
201
+ - `error`
202
+ - `warn`
203
+ - `info`
204
+
205
+ A single legacy detection warning is emitted when `/.well-known/x402` or `/.well-known/mpp` is
206
+ present at an origin: `LEGACY_WELL_KNOWN_FOUND`. agentcash-discovery does not parse these
207
+ documents; the warning exists to tell publishers to migrate to OpenAPI.
208
+
209
+ ## 10. Extensibility And Adjacent Standards
210
+
211
+ This profile is narrow in scope. It discovers resources, auth/payment hints, and schema
212
+ pointers. It does not define agent identity, capability grants, or approval flows.
213
+
214
+ Future extensions SHOULD use namespaced OpenAPI extension fields or objects such as:
215
+
216
+ - `x-agentcash-auth-kind`
217
+ - `x-agentcash-provenance`
218
+ - `x-agentcash-guidance`
219
+ - `x-agentcash-capabilities`
220
+ - `x-agentcash-agent-auth`
221
+
222
+ Clients MUST ignore unknown extension fields and unknown protocol objects.
223
+
224
+ Agent identity standards such as Agent Auth can compose with this profile by advertising their
225
+ authorization server, capability mapping, or registration metadata in a namespaced OpenAPI
226
+ extension while keeping resource identity unchanged.
227
+
228
+ ## 11. Minimal Example
229
+
230
+ ```json
231
+ {
232
+ "openapi": "3.1.0",
233
+ "info": {
234
+ "title": "Example Commerce API",
235
+ "version": "1.0.0"
236
+ },
237
+ "x-agentcash-guidance": {
238
+ "llmsTxtUrl": "https://api.example.com/llms.txt"
239
+ },
240
+ "paths": {
241
+ "/search": {
242
+ "post": {
243
+ "summary": "Search purchasable records",
244
+ "security": [],
245
+ "x-payment-info": {
246
+ "price": { "mode": "fixed", "currency": "USD", "amount": "0.02" },
247
+ "protocols": [{ "x402": {} }]
248
+ },
249
+ "requestBody": {
250
+ "content": {
251
+ "application/json": {
252
+ "schema": {
253
+ "type": "object",
254
+ "required": ["query"],
255
+ "properties": {
256
+ "query": { "type": "string" }
257
+ }
258
+ }
259
+ }
260
+ }
261
+ },
262
+ "responses": {
263
+ "200": { "description": "Result" },
264
+ "402": { "description": "Payment Required" }
265
+ }
266
+ }
267
+ }
268
+ }
269
+ }
270
+ ```
@@ -0,0 +1,117 @@
1
+ # Validation Diagnostics Design (2026-03-03)
2
+
3
+ ## Goal
4
+ Eliminate recurring discovery/x402 validation bugs by moving protocol validation and policy diagnostics into `@agentcash/discovery` and making all consumers render one canonical issue contract.
5
+
6
+ ## Constraints
7
+ - Unify discovery/validation across all surfaces.
8
+ - Surface actionable errors for wrong chain/network, missing `accepts`, missing schema, and missing metadata.
9
+ - Keep compatibility support while making strict mode deterministic.
10
+ - Keep package lean and avoid UI/runtime scraping concerns in core validation.
11
+
12
+ ## Ownership Boundary
13
+
14
+ ### Lives in `@agentcash/discovery`
15
+ - x402 payload parsing/normalization.
16
+ - Network policy (including Solana CAIP + alias handling).
17
+ - Schema policy checks.
18
+ - Metadata completeness diagnostics (validation only; no scraping).
19
+ - Stable issue taxonomy and strictness matrix.
20
+ - Regression fixtures and snapshot tests.
21
+
22
+ ### Lives in Consumer App (`x402scan`)
23
+ - Probing strategy and retries.
24
+ - Data persistence.
25
+ - UI rendering/grouping of issue codes.
26
+ - Metadata scraping before calling validator.
27
+
28
+ ## Canonical API
29
+
30
+ ```ts
31
+ validatePaymentRequiredDetailed(payload, options) => {
32
+ valid: boolean,
33
+ version?: 1 | 2,
34
+ parsed?: Record<string, unknown>,
35
+ normalized?: {
36
+ version: 1 | 2,
37
+ accepts: NormalizedAccept[],
38
+ hasInputSchema: boolean,
39
+ hasOutputSchema: boolean,
40
+ },
41
+ issues: ValidationIssue[],
42
+ summary: {
43
+ errorCount: number,
44
+ warnCount: number,
45
+ infoCount: number,
46
+ byCode: Record<string, number>,
47
+ },
48
+ }
49
+ ```
50
+
51
+ ## Validation Pipeline
52
+ 1. Coinbase structural gate via `@x402/core/schemas` (`parsePaymentRequired`).
53
+ 2. Map Coinbase Zod issues into canonical `ValidationIssue` entries (`COINBASE_SCHEMA_INVALID`).
54
+ 3. Apply product policy overlay checks (network policy, schema quality checks, metadata completeness).
55
+ 4. Compute summary + validity from merged issues.
56
+
57
+ ## Issue Taxonomy
58
+ - `X402_*`: shape/version/accept-entry errors.
59
+ - `NETWORK_*`: CAIP/network policy errors.
60
+ - `SCHEMA_*`: input/output schema checks.
61
+ - `METADATA_*`: title/description/favicon/og checks.
62
+
63
+ ## Strictness Matrix
64
+
65
+ | Code family | compat=`on` | compat=`strict` |
66
+ |---|---|---|
67
+ | `COINBASE_SCHEMA_INVALID` | error | error |
68
+ | `X402_*` | error | error |
69
+ | `NETWORK_CAIP2_INVALID` | error | error |
70
+ | `NETWORK_SOLANA_ALIAS_INVALID` | error | error |
71
+ | `NETWORK_REFERENCE_UNKNOWN` | error | error |
72
+ | `NETWORK_SOLANA_ALIAS_COMPAT` | warn | warn |
73
+ | `SCHEMA_INPUT_MISSING` | error | error |
74
+ | `SCHEMA_OUTPUT_MISSING` | warn | error |
75
+ | `METADATA_*` | warn | warn |
76
+
77
+ ## Solana Policy
78
+
79
+ ### Accepted canonical refs (v2)
80
+ - `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` (mainnet)
81
+ - `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` (devnet)
82
+ - `solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z` (testnet)
83
+
84
+ ### Compatibility aliases (warn)
85
+ - `solana:mainnet`
86
+ - `solana:devnet`
87
+ - `solana:testnet`
88
+
89
+ ### Invalid aliases (error)
90
+ - `solana-mainnet-beta`
91
+ - Unknown `solana:<ref>`
92
+
93
+ ## Confidence Plan
94
+ - Unit tests for each bug class and strictness behavior.
95
+ - Regression fixtures for known incidents.
96
+ - Consumer contract tests asserting `issues[]` is present on all relevant APIs.
97
+ - UI tests mapping issue codes to checklist rows with unknown-code fallback.
98
+
99
+ ## UI Rendering Contract
100
+ - UI must use `issues[]` as source of truth.
101
+ - No string parsing of free-form errors.
102
+ - Unknown codes render as generic warning/error rows so display never breaks.
103
+
104
+ ## Package Bloat Controls
105
+ - Validation module is isolated (`src/validation/*`) and tree-shakable via root exports.
106
+ - No scraping or heavy runtime dependencies in validator.
107
+ - Test fixtures remain test-only (not shipped in package output).
108
+
109
+ ## Deprecation Timeline
110
+ - `2026-03-03`: Introduce canonical `issues[]` contract in package.
111
+ - `2026-03-10`: Consumer apps return `issues[]` + legacy string errors in parallel.
112
+ - `2026-03-24`: Remove legacy string-only validation transport from consumers.
113
+
114
+ ## Immediate Follow-ups
115
+ 1. Expand fixture matrix with additional malformed network/schema combinations.
116
+ 2. Add OpenAPI operation-level schema policy checks to pair static + runtime diagnostics.
117
+ 3. Publish migration note for consumers adopting canonical `issues[]`.
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "@agentcash/discovery",
3
- "version": "1.6.5",
3
+ "version": "1.7.0",
4
4
  "description": "Canonical OpenAPI-first discovery runtime for the agentcash ecosystem",
5
+ "homepage": "https://github.com/merit-systems/agentcash-discovery#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/merit-systems/agentcash-discovery/issues"
8
+ },
5
9
  "type": "module",
6
10
  "main": "./dist/index.cjs",
7
11
  "module": "./dist/index.js",
8
12
  "types": "./dist/index.d.ts",
9
- "bin": "./bin/discovery.js",
10
13
  "exports": {
11
14
  ".": {
12
15
  "import": {
@@ -27,21 +30,12 @@
27
30
  "types": "./dist/schemas.d.cts",
28
31
  "default": "./dist/schemas.cjs"
29
32
  }
30
- },
31
- "./flags": {
32
- "import": {
33
- "types": "./dist/flags.d.ts",
34
- "default": "./dist/flags.js"
35
- },
36
- "require": {
37
- "types": "./dist/flags.d.cts",
38
- "default": "./dist/flags.cjs"
39
- }
40
33
  }
41
34
  },
42
35
  "files": [
43
36
  "dist",
44
37
  "bin",
38
+ "docs",
45
39
  "README.md",
46
40
  "LICENSE",
47
41
  "AGENTS.md"
@@ -51,10 +45,15 @@
51
45
  },
52
46
  "keywords": [
53
47
  "agentcash",
48
+ "agentic-commerce",
54
49
  "discovery",
55
50
  "x402",
56
- "openapi"
51
+ "mpp",
52
+ "openapi",
53
+ "payments",
54
+ "agents"
57
55
  ],
56
+ "sideEffects": false,
58
57
  "license": "MIT",
59
58
  "repository": {
60
59
  "type": "git",
@@ -66,19 +65,19 @@
66
65
  "dependencies": {
67
66
  "dereference-json-schema": "^0.2.2",
68
67
  "neverthrow": "^8.2.0",
69
- "zod": "^4.0.0"
68
+ "zod": "^4.4.3"
70
69
  },
71
70
  "devDependencies": {
72
- "@changesets/cli": "^2.29.8",
71
+ "@changesets/cli": "^2.31.0",
73
72
  "@eslint/js": "^10.0.1",
74
- "@types/node": "^22.18.0",
73
+ "@types/node": "^22.19.19",
75
74
  "@vitest/coverage-v8": "^3.2.4",
76
- "eslint": "^10.0.0",
77
- "knip": "^5.85.0",
78
- "prettier": "^3.8.1",
79
- "tsup": "^8.5.0",
80
- "typescript": "^5.9.2",
81
- "typescript-eslint": "^8.43.0",
75
+ "eslint": "^10.4.0",
76
+ "knip": "^5.88.1",
77
+ "prettier": "^3.8.3",
78
+ "tsup": "^8.5.1",
79
+ "typescript": "^5.9.3",
80
+ "typescript-eslint": "^8.59.4",
82
81
  "vitest": "^3.2.4"
83
82
  },
84
83
  "scripts": {
@@ -94,5 +93,8 @@
94
93
  "audit:registry:quick": "pnpm build && node scripts/audit-registry.mjs --origin-limit 50 --resource-limit 500",
95
94
  "knip": "knip",
96
95
  "check": "pnpm format:check && pnpm lint && pnpm knip && pnpm typecheck && pnpm build && pnpm test"
96
+ },
97
+ "bin": {
98
+ "discovery": "./bin/discovery.js"
97
99
  }
98
100
  }
package/dist/flags.cjs DELETED
@@ -1,44 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/flags.ts
21
- var flags_exports = {};
22
- __export(flags_exports, {
23
- DEFAULT_COMPAT_MODE: () => DEFAULT_COMPAT_MODE,
24
- LEGACY_SUNSET_DATE: () => LEGACY_SUNSET_DATE,
25
- STRICT_ESCALATION_CODES: () => STRICT_ESCALATION_CODES
26
- });
27
- module.exports = __toCommonJS(flags_exports);
28
- var LEGACY_SUNSET_DATE = "2026-03-24";
29
- var DEFAULT_COMPAT_MODE = "on";
30
- var STRICT_ESCALATION_CODES = [
31
- "LEGACY_WELL_KNOWN_USED",
32
- "LEGACY_DNS_USED",
33
- "LEGACY_DNS_PLAIN_URL",
34
- "LEGACY_MISSING_METHOD",
35
- "LEGACY_INSTRUCTIONS_USED",
36
- "LEGACY_OWNERSHIP_PROOFS_USED",
37
- "INTEROP_MPP_USED"
38
- ];
39
- // Annotate the CommonJS export names for ESM import in node:
40
- 0 && (module.exports = {
41
- DEFAULT_COMPAT_MODE,
42
- LEGACY_SUNSET_DATE,
43
- STRICT_ESCALATION_CODES
44
- });
package/dist/flags.d.cts DELETED
@@ -1,6 +0,0 @@
1
- declare const LEGACY_SUNSET_DATE = "2026-03-24";
2
- type CompatibilityMode = 'on' | 'off' | 'strict';
3
- declare const DEFAULT_COMPAT_MODE: CompatibilityMode;
4
- declare const STRICT_ESCALATION_CODES: readonly ["LEGACY_WELL_KNOWN_USED", "LEGACY_DNS_USED", "LEGACY_DNS_PLAIN_URL", "LEGACY_MISSING_METHOD", "LEGACY_INSTRUCTIONS_USED", "LEGACY_OWNERSHIP_PROOFS_USED", "INTEROP_MPP_USED"];
5
-
6
- export { type CompatibilityMode, DEFAULT_COMPAT_MODE, LEGACY_SUNSET_DATE, STRICT_ESCALATION_CODES };
package/dist/flags.d.ts DELETED
@@ -1,6 +0,0 @@
1
- declare const LEGACY_SUNSET_DATE = "2026-03-24";
2
- type CompatibilityMode = 'on' | 'off' | 'strict';
3
- declare const DEFAULT_COMPAT_MODE: CompatibilityMode;
4
- declare const STRICT_ESCALATION_CODES: readonly ["LEGACY_WELL_KNOWN_USED", "LEGACY_DNS_USED", "LEGACY_DNS_PLAIN_URL", "LEGACY_MISSING_METHOD", "LEGACY_INSTRUCTIONS_USED", "LEGACY_OWNERSHIP_PROOFS_USED", "INTEROP_MPP_USED"];
5
-
6
- export { type CompatibilityMode, DEFAULT_COMPAT_MODE, LEGACY_SUNSET_DATE, STRICT_ESCALATION_CODES };
package/dist/flags.js DELETED
@@ -1,17 +0,0 @@
1
- // src/flags.ts
2
- var LEGACY_SUNSET_DATE = "2026-03-24";
3
- var DEFAULT_COMPAT_MODE = "on";
4
- var STRICT_ESCALATION_CODES = [
5
- "LEGACY_WELL_KNOWN_USED",
6
- "LEGACY_DNS_USED",
7
- "LEGACY_DNS_PLAIN_URL",
8
- "LEGACY_MISSING_METHOD",
9
- "LEGACY_INSTRUCTIONS_USED",
10
- "LEGACY_OWNERSHIP_PROOFS_USED",
11
- "INTEROP_MPP_USED"
12
- ];
13
- export {
14
- DEFAULT_COMPAT_MODE,
15
- LEGACY_SUNSET_DATE,
16
- STRICT_ESCALATION_CODES
17
- };