@stellar-agent-services/dev-mcp 0.0.0-stage → 0.1.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.
- package/LICENSE +21 -0
- package/README.md +50 -2
- package/dist/docs.d.ts +35 -0
- package/dist/docs.d.ts.map +1 -0
- package/dist/docs.js +92 -0
- package/dist/docs.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +14 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +125 -0
- package/dist/server.js.map +1 -0
- package/package.json +40 -4
- package/repository/AGENTS.md +162 -0
- package/repository/CONTRIBUTING.md +95 -0
- package/repository/IMPLEMENTATION_PLAN.md +548 -0
- package/repository/README.md +78 -0
- package/repository/SECURITY.md +22 -0
- package/repository/apps/wallet/README.md +78 -0
- package/repository/docs/client-integration/README-AI.md +487 -0
- package/repository/docs/client-integration/README.md +137 -0
- package/repository/docs/dx-improvements.md +666 -0
- package/repository/docs/erc-compatibility.md +163 -0
- package/repository/docs/job-recovery.md +201 -0
- package/repository/docs/payment-client.md +258 -0
- package/repository/docs/provider-setup-guide.md +348 -0
- package/repository/docs/provider-standard.md +724 -0
- package/repository/docs/recovery/README-AI.md +288 -0
- package/repository/docs/recovery/README.md +119 -0
- package/repository/docs/standard/README-AI.md +611 -0
- package/repository/docs/standard/README.md +108 -0
- package/repository/docs/verification.md +502 -0
- package/repository/examples/paid-service/README.md +24 -0
- package/repository/examples/python-upstream/README.md +44 -0
- package/repository/llms.txt +64 -0
- package/repository/packages/create-stellar-service/README.md +143 -0
- package/repository/packages/dev-mcp/README.md +51 -0
- package/repository/packages/payment-client/README.md +75 -0
- package/repository/packages/protocol/README.md +15 -0
- package/repository/packages/protocol/schemas/manifest.schema.json +272 -0
- package/repository/packages/protocol/test-vectors/README.md +45 -0
- package/repository/packages/provider-kit/README.md +507 -0
- package/repository/packages/provider-kit/schemas/gateway-config.schema.json +140 -0
- package/repository/packages/verifier/README.md +127 -0
- package/repository/plugins/stellar-agent-services/README.md +31 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for helping. This repository is a standard first and code second, so changes follow the order below.
|
|
4
|
+
AI coding agents should also read [AGENTS.md](AGENTS.md).
|
|
5
|
+
|
|
6
|
+
## The order of a change
|
|
7
|
+
|
|
8
|
+
1. **The spec.** A new behavior, field, error or guarantee starts as a rule in
|
|
9
|
+
[docs/provider-standard.md](docs/provider-standard.md), with an id. v1 is frozen: it only gains optional fields
|
|
10
|
+
and SHOULD rules. A breaking change waits for v2.
|
|
11
|
+
2. **The code that implements it:** `packages/protocol` (types, constants, reference checks, test vectors), then
|
|
12
|
+
`packages/provider-kit` and `packages/payment-client`.
|
|
13
|
+
3. **The verifier:** a check, or a finding in an existing check, that fails a provider breaking the new rule and
|
|
14
|
+
cites its id.
|
|
15
|
+
4. **The docs:** the human summary and the AI reference for the area (`docs/*/README.md`, `docs/*/README-AI.md`),
|
|
16
|
+
the package README's file table, and `llms.txt` if you add a document. Then run `npm run llms`.
|
|
17
|
+
|
|
18
|
+
A fix inside the existing rules skips step 1.
|
|
19
|
+
|
|
20
|
+
## Before you open a pull request
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install
|
|
24
|
+
npm run typecheck
|
|
25
|
+
npm test
|
|
26
|
+
npm run llms:check
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- Tests never touch the network. Use the fakes in each package's `test/support/`.
|
|
30
|
+
- Pin dependency versions exactly.
|
|
31
|
+
- No keys, `.env` files, journals or job databases in commits.
|
|
32
|
+
- Money paths fail closed. If a change touches payment, settlement or recovery, say in the pull request how it
|
|
33
|
+
keeps "never charge twice" (`[J13]`, `[P9]`).
|
|
34
|
+
|
|
35
|
+
## What CI checks
|
|
36
|
+
|
|
37
|
+
[ci.yml](.github/workflows/ci.yml) runs on every pull request. None of it signs or pays, and it uses no secret.
|
|
38
|
+
|
|
39
|
+
| Job | What it checks | Run it here |
|
|
40
|
+
| --- | --- | --- |
|
|
41
|
+
| Typecheck, test, build | The four commands above, the wallet and approval pages, and what each npm package would publish: its files, metadata and shared version | `npm run build && npm run packages:check` |
|
|
42
|
+
| New project, 6 jobs | `create-stellar-service` from this clone, each kind on testnet and on mainnet: the project installs with one copy of the Stellar SDK, builds and starts, and the verifier passes it (C1, C3, C6, C7). A mainnet project must refuse to start without the facilitator's API key. On testnet the project's Dockerfile is built too. The facilitator and the verifier's chain lookup are stand-ins. | `npm run scaffold:check -- --kind typescript --network mainnet` |
|
|
43
|
+
| npm publish rehearsal | Every package published to a throwaway registry (Verdaccio on the runner), installed from it and used: imports, commands, the MCP server's documents, and projects made by the published scaffolder. It warns when a plain install brings two Stellar SDKs or dependencies `npm audit` flags. | `npm run packages:rehearse` |
|
|
44
|
+
| Gateway image | `packages/provider-kit/Dockerfile` builds and runs | `docker build -f packages/provider-kit/Dockerfile .` |
|
|
45
|
+
|
|
46
|
+
The new-project checks and the rehearsal install from the npm registry. Run them after `npm run build`.
|
|
47
|
+
|
|
48
|
+
[live.yml](.github/workflows/live.yml) runs every day and from the Actions tab, never on pull requests, since it
|
|
49
|
+
depends on services outside this repository:
|
|
50
|
+
|
|
51
|
+
- **What the packages expect** on testnet and mainnet: the facilitator, Soroban RPC, Horizon, the USDC contract and
|
|
52
|
+
the Stellar 8004 registries (`npm run live:check`). Read-only.
|
|
53
|
+
- **A paid call on testnet**: a new project, paid once by `provider-kit try --yes` from a throwaway account with test
|
|
54
|
+
money.
|
|
55
|
+
- **A mainnet project against OpenZeppelin's facilitator**, with the repository secret `MAINNET_FACILITATOR_AUTH`
|
|
56
|
+
(`Bearer <key>`, a key from [channels.openzeppelin.com/gen](https://channels.openzeppelin.com/gen)). Nothing is
|
|
57
|
+
paid on mainnet. Without the secret, this job is skipped, and the daily check only confirms the facilitator answers.
|
|
58
|
+
|
|
59
|
+
## Releasing
|
|
60
|
+
|
|
61
|
+
Every package is released together at one version, since a project made by `create-stellar-service` x.y.z depends
|
|
62
|
+
on `provider-kit` x.y.z. A version tag runs [release.yml](.github/workflows/release.yml): every CI check again, then
|
|
63
|
+
the npm packages with provenance, the gateway image at `ghcr.io/algorialabs/provider-kit`, and a GitHub release.
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm run packages:version 0.2.0 # every package and the dependencies between them, and package-lock.json
|
|
67
|
+
git commit -am "Release 0.2.0" && git tag v0.2.0 && git push origin main v0.2.0
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
A version with a suffix, such as `0.2.0-rc.1`, goes to npm under the `next` tag, so `npm install` keeps getting the
|
|
71
|
+
last release. Run the workflow from the Actions tab with "dry run" on to go through every step without publishing.
|
|
72
|
+
|
|
73
|
+
The first release needs three things done once:
|
|
74
|
+
|
|
75
|
+
1. Remove `"private": true` from each package under `packages/`. `npm run packages:check` lists the ones left;
|
|
76
|
+
the publish refuses to start while any is.
|
|
77
|
+
2. Publish the first version with a token, since npm only trusts a workflow for a package that exists: an npm
|
|
78
|
+
granular access token with read and write access to your packages, new ones included, saved as the repository
|
|
79
|
+
secret `NPM_TOKEN`. The `@stellar-agent-services` organization must exist on npm, with you able to publish to it.
|
|
80
|
+
3. Then make npm trust the workflow instead: on npmjs.com, each package's settings → Trusted publishing → GitHub
|
|
81
|
+
Actions, organization `AlgoriaLabs`, repository `stellar-agent-services`, workflow `release.yml`, environment `npm`.
|
|
82
|
+
Delete the `NPM_TOKEN` secret and the token. Later versions publish with no token at all.
|
|
83
|
+
|
|
84
|
+
The `npm` environment can require an approval before each publish (Settings → Environments → npm).
|
|
85
|
+
|
|
86
|
+
## Issues
|
|
87
|
+
|
|
88
|
+
Pick the template that fits: a question about integrating, a proposal to change the standard, or a request to
|
|
89
|
+
verify a provider. Report security problems privately, as [SECURITY.md](SECURITY.md) says.
|
|
90
|
+
|
|
91
|
+
## Wallet and payment adapters
|
|
92
|
+
|
|
93
|
+
Adapters for other wallets or payment methods follow
|
|
94
|
+
[docs/client-integration/README.md](docs/client-integration/README.md). They live in their own packages and pass
|
|
95
|
+
the conformance checks in `@stellar-agent-services/payment-client/conformance`.
|
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
# Stellar Agent Services: Implementation Plan
|
|
2
|
+
|
|
3
|
+
Phase 2 of [Stellar Agent Search](https://github.com/berkingurcan/stellar-agent-search). It covers the Provider
|
|
4
|
+
Standard, Provider Kit, safe Payment Client, verification receipts, Stellar 8004 Validation Registry records and
|
|
5
|
+
Job Recovery, delivered and piloted within one 30-day Instaward sprint.
|
|
6
|
+
|
|
7
|
+
- **Source of truth:** Instawards SOW "Stellar Agent MCP" (submitted 29.09.2026, $4,000, 30 days).
|
|
8
|
+
- **Background:** `stellar-agent-search/docs/provider-network-phase-2.md` and `issues/P3-23-provider-network-phase-2.md`.
|
|
9
|
+
- **Network:** Stellar **testnet** for the whole build. Mainnet is a later, separate decision (see [Open decisions](#10-open-decisions)).
|
|
10
|
+
- **Status:** Week 3. The protocol package, the Provider Kit (library, gateway mode, durable SQLite queue, CLI)
|
|
11
|
+
and the payment client (core, `stellar-pay` CLI and a minimal web approval page) work end to end on testnet.
|
|
12
|
+
Job Recovery is complete in code, reconciliation and the ledger clock included; the recorded testnet demo is
|
|
13
|
+
still to do. The verifier is complete in code: checks C1–C7 with on-chain payment proofs, receipts, badges and
|
|
14
|
+
`validation_response`, and `provider-kit request-validation` asks for it. A first testnet receipt and Validation
|
|
15
|
+
Registry record are next.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 1. What the SOW commits us to
|
|
20
|
+
|
|
21
|
+
| SOW deliverable | Contents | Evidence promised |
|
|
22
|
+
| --- | --- | --- |
|
|
23
|
+
| **D1:** Provider Standard + Safe Payment Client | Provider Standard v1 (purpose, input, output, price, network, job status, result). Payment client that shows payment details, applies spending controls and requires approval. | Public spec, short demo video, screenshots, payment tx link |
|
|
24
|
+
| **D2:** Provider Kit, Verification, Job Recovery | Open-source kit, setup guide, sample service. Provider checks, verification receipts and badges, Stellar 8004 Validation Registry publishing. Job Recovery (create-job, check-status, get-result) without paying twice. | Public repo, setup guide, verification receipt, Validation Registry record, recovery demo |
|
|
25
|
+
| **D3:** Independent Provider Pilot + Public Evidence | Independent providers each complete at least one paid call. Users run the full flow. Job Recovery demo. Pilot report. Incentives included. | Provider links, payment references, screenshots, pilot report, public evidence page |
|
|
26
|
+
|
|
27
|
+
**Out of scope (SOW):**
|
|
28
|
+
- a new registry or protocol
|
|
29
|
+
- the full ERC-8126 specification
|
|
30
|
+
- zero-knowledge proofs
|
|
31
|
+
- a formal audit
|
|
32
|
+
- a consumer marketplace
|
|
33
|
+
- custody
|
|
34
|
+
- guaranteed adoption or availability
|
|
35
|
+
|
|
36
|
+
### 1.1 Inconsistencies in the SOW, and the reading we plan against
|
|
37
|
+
|
|
38
|
+
The SOW gives different numbers in different sections. We plan against the reading that satisfies all of them.
|
|
39
|
+
|
|
40
|
+
| Topic | What the SOW says | We plan for |
|
|
41
|
+
| --- | --- | --- |
|
|
42
|
+
| Providers | "two independent providers" (objective, W4, evidence). "three independent providers" (D3). "not more than two" (out of scope). "three working provider integrations" (W4 output). | **3 integrations = our sample provider + 2 independent providers** |
|
|
43
|
+
| Users | "five users" (D3, W4 output). "two users" (objective, W4 work, evidence). "not more than five" (out of scope). | **5 completed user flows** (this also covers "two") |
|
|
44
|
+
| Where it lives | "add … to Stellar Agent Search" | Phase 2 of Stellar Agent Search, built in this repo. Discovery stays in `stellar-agent-search`. |
|
|
45
|
+
|
|
46
|
+
> Action: confirm this reading with the Ambassador Chapter Lead before the sprint starts.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 2. Principles
|
|
51
|
+
|
|
52
|
+
1. **Discovery holds no keys.** `stellar-agent-search` stays read-only and keyless. Nothing in this repo is
|
|
53
|
+
imported into it except read-only types or schemas.
|
|
54
|
+
2. **The provider runtime holds no keys.** A provider server only knows its `payTo` public address. The
|
|
55
|
+
facilitator verifies and settles. The owner's transactions (USDC trustline, registration, validation requests)
|
|
56
|
+
are signed only in the owner's own wallet, on a local approval page the CLI opens, or with `--source` through
|
|
57
|
+
the Stellar CLI keychain. The CLI never holds a key.
|
|
58
|
+
3. **Signing happens only in the payment client.** The approved payment is signed exactly once, and only after
|
|
59
|
+
the user approves the exact price, recipient, asset and network, or when the payment fits a budget the user
|
|
60
|
+
explicitly granted.
|
|
61
|
+
4. **Never pay twice for one job.** The job identity is fixed before payment. The provider binds it to one
|
|
62
|
+
request and one payment, and recovery never re-sends a payment credential.
|
|
63
|
+
5. **Fail closed.** A failed spending-limit check, an unknown settlement, a mismatched challenge or an
|
|
64
|
+
unreadable journal stops the flow. None of them is ever treated as a pass.
|
|
65
|
+
6. **One network per flow.** A demo, test or pilot run uses testnet from discovery to feedback, never a mix.
|
|
66
|
+
7. **Independent codebase.** No code, schemas or names are taken from Algoria. The foundations are the public
|
|
67
|
+
x402 v2 spec, the `@x402/*` packages, `@stellar/stellar-sdk`, `@trionlabs/stellar8004` and Stellar Agent
|
|
68
|
+
Search's own Phase 1 reference (`examples/x402-demo.ts`).
|
|
69
|
+
8. **Stay compatible with ERC-8126 and ERC-8196.** We don't implement them, because a parallel project does. Our
|
|
70
|
+
identity, Validation Registry, policy and journal formats must not block their Stellar versions. See
|
|
71
|
+
[docs/erc-compatibility.md](docs/erc-compatibility.md).
|
|
72
|
+
9. **Universal standard.** Any service in any language can implement Provider Standard v1. The spec is
|
|
73
|
+
language-neutral and reuses existing standards (x402, JSON Schema, MCP tool fields, IETF Idempotency-Key,
|
|
74
|
+
RFC 9457). The TypeScript kit and its gateway mode make adoption easier but are never required.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## 3. Architecture
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
┌──────────────────────────┐ read-only ┌──────────────────────────────┐
|
|
82
|
+
│ stellar-agent-search │ ─────────────▶ │ Stellar 8004 registries │
|
|
83
|
+
│ (discovery, no keys) │ │ Identity · Reputation · │
|
|
84
|
+
└────────────┬─────────────┘ │ Validation (Soroban) │
|
|
85
|
+
│ finds provider + manifest URL└──────────────▲───────────────┘
|
|
86
|
+
▼ │ validation_request (provider owner)
|
|
87
|
+
┌──────────────────────────┐ create-job (402 → pay) │ validation_response (verifier)
|
|
88
|
+
│ payment-client (keys) │ ───────────────────────────┐ │
|
|
89
|
+
│ approval · limits · │ check-status / get-result │ │
|
|
90
|
+
│ journal · recovery │ ◀──────────────────────────┤ │
|
|
91
|
+
└──────────────────────────┘ ▼ │
|
|
92
|
+
┌──────────────────────────┐
|
|
93
|
+
┌──────────────────────────┐ test calls │ provider (provider-kit) │
|
|
94
|
+
│ verifier (verifier key) │ ────────────▶ │ manifest · x402 server · │
|
|
95
|
+
│ checks · receipt · badge │ │ job store · services │
|
|
96
|
+
└──────────────────────────┘ └────────────┬─────────────┘
|
|
97
|
+
│ verify / settle
|
|
98
|
+
▼
|
|
99
|
+
┌──────────────────────────┐
|
|
100
|
+
│ x402 facilitator │
|
|
101
|
+
│ (fee-sponsored USDC SAC) │
|
|
102
|
+
└──────────────────────────┘
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 3.1 Who holds which key
|
|
106
|
+
|
|
107
|
+
| Actor | Holds | Must never hold |
|
|
108
|
+
| --- | --- | --- |
|
|
109
|
+
| `stellar-agent-search` (discovery) | nothing | any secret |
|
|
110
|
+
| Provider server (`provider-kit` runtime, library or gateway mode) | `payTo` **public** address, facilitator URL; in gateway mode, the upstream API's own credential if it has one | any Stellar secret key |
|
|
111
|
+
| Provider operator (`provider-kit` CLI) | no key: the owner's own wallet signs the USDC trustline, registration and `validation_request` on the local approval page; `--source` uses a Stellar CLI keychain key instead | payer or verifier keys |
|
|
112
|
+
| `payment-client` | the payer's key or wallet connection (§5.6) | provider or verifier keys |
|
|
113
|
+
| `verifier` | verifier key (`validation_response`), plus a dedicated testnet test-payer key for the paid-call check | provider owner keys |
|
|
114
|
+
|
|
115
|
+
### 3.2 Repository layout
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
packages/
|
|
119
|
+
protocol/ Provider Standard v1 as code: types, schemas, header names, job states, receipts,
|
|
120
|
+
canonical JSON, network constants. Shared by every other package.
|
|
121
|
+
provider-kit/ Server toolkit: defineService, createProvider (Fetch-API handler), gateway mode
|
|
122
|
+
(any existing HTTP API), x402 resource server, job store + runner,
|
|
123
|
+
manifest + 8004 registration, operator CLI.
|
|
124
|
+
payment-client/ Buyer side: policy, journal, payment, recovery (§5.6).
|
|
125
|
+
verifier/ Provider checks → verification receipt → badges → Validation Registry response.
|
|
126
|
+
create-stellar-service/
|
|
127
|
+
npm create stellar-service: a new provider project (gateway, library or Python), ready to
|
|
128
|
+
run, try and deploy.
|
|
129
|
+
apps/
|
|
130
|
+
wallet/ Web approval page: static, no backend, the payment-client core in the browser (§5.6).
|
|
131
|
+
examples/
|
|
132
|
+
paid-service/ Sample provider built only with provider-kit (one on-success + one upfront service).
|
|
133
|
+
python-upstream/ An existing Python API made a paid service by gateway mode, with only a config file.
|
|
134
|
+
docs/ Provider Standard v1, setup guide, job recovery, verification, payment client, pilot.
|
|
135
|
+
evidence/ Receipts, payment references, validation records, pilot report (filled during the sprint).
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Tooling:**
|
|
139
|
+
- npm workspaces, matching `stellar-agent-search`, with TypeScript project references (`tsc -b`) and vitest.
|
|
140
|
+
- Node `>=22.13`; `.node-version` pins 24. Node 22.13 is needed for the built-in `node:sqlite` with no native
|
|
141
|
+
dependency and for `@x402/stellar`.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## 4. Network and dependencies (testnet)
|
|
146
|
+
|
|
147
|
+
| Item | Value or source |
|
|
148
|
+
| --- | --- |
|
|
149
|
+
| CAIP-2 | `stellar:testnet` (`STELLAR_TESTNET_CAIP2` from `@x402/stellar`) |
|
|
150
|
+
| Asset | USDC Stellar Asset Contract: import `USDC_TESTNET_ADDRESS` from `@x402/stellar`, never retype it |
|
|
151
|
+
| USDC issuer (trustline check) | `GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5` |
|
|
152
|
+
| Soroban RPC / Horizon | `https://soroban-testnet.stellar.org` / `https://horizon-testnet.stellar.org` |
|
|
153
|
+
| 8004 contracts | `TESTNET_CONFIG` from `@trionlabs/stellar8004`. Validation: `CC5USZRO26MOIAVNYTTJDS63C2OBBLREOAOET4CPF2EZWO3YFKLMO3SL` |
|
|
154
|
+
| Facilitator | `https://x402.org/facilitator`. Confirmed: it supports `stellar:testnet` + `exact` with sponsored fees, and sets no authorization window of its own (the window follows `maxTimeoutSeconds`). |
|
|
155
|
+
| Decimals | 7 (`0.01 USDC = 100000` base units) |
|
|
156
|
+
|
|
157
|
+
| Package | Version | Note |
|
|
158
|
+
| --- | --- | --- |
|
|
159
|
+
| `@x402/core`, `@x402/fetch`, `@x402/stellar` | 2.28.0 | `@x402/stellar` needs `@stellar/stellar-sdk ^16.3.0` |
|
|
160
|
+
| `@stellar/stellar-sdk` | 16.4.1 | Root `overrides` put `@trionlabs/stellar8004` (declares `^15`) on the same copy, and only it: `@creit.tech/stellar-wallets-kit` (approval page, dev only) keeps its `^17`. 16.4.1 is the first 16.x that pins a fixed axios (1.20.0); 16.3.1 pinned a vulnerable 1.18.0. |
|
|
161
|
+
| `@trionlabs/stellar8004` | 0.0.11 | Identity, Reputation and Validation clients; `generateRequestNonce`; metadata helpers |
|
|
162
|
+
| `hono`, `@hono/node-server` | 4.x / 2.x | Example service only. The kit itself is framework-agnostic (Fetch `Request`/`Response`). |
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 5. Components
|
|
167
|
+
|
|
168
|
+
### 5.1 Provider Standard v1 (`docs/provider-standard.md`, `packages/protocol`)
|
|
169
|
+
|
|
170
|
+
The draft spec is in [docs/provider-standard.md](docs/provider-standard.md). It is a thin layer over existing
|
|
171
|
+
standards, so the SOW's "no new protocol" holds, and any language can implement it.
|
|
172
|
+
|
|
173
|
+
| Concern | Standard reused |
|
|
174
|
+
| --- | --- |
|
|
175
|
+
| Payment | x402 v2 `exact` on Stellar; the manifest's payment option uses x402 `PaymentRequirements` field names |
|
|
176
|
+
| Service description | JSON Schema 2020-12 with MCP tool field names (`name`, `title`, `description`, `inputSchema`, `outputSchema`) |
|
|
177
|
+
| Discovery inside the 402 | x402 Bazaar extension |
|
|
178
|
+
| Idempotency | IETF Idempotency-Key draft-07 (422 for a reused key, 409 while in progress) |
|
|
179
|
+
| Long jobs | `202 Accepted` + `Location` + `Retry-After` |
|
|
180
|
+
| Errors | RFC 9457 problem details with a stable `code` |
|
|
181
|
+
| Identity | Stellar 8004 registration `services[]` entry pointing at the manifest |
|
|
182
|
+
|
|
183
|
+
**What the spec adds:** the manifest, the `Job-Token` header, and the rules that bind one job to one request and
|
|
184
|
+
one payment.
|
|
185
|
+
|
|
186
|
+
**Main rules:**
|
|
187
|
+
- The manifest is at `/.well-known/stellar-agent-services.json` by default, or any HTTPS URL the 8004
|
|
188
|
+
registration names. Job endpoints are fixed paths under one `baseUrl` on the same origin.
|
|
189
|
+
- Small required core: `standard`, provider `name`, `baseUrl`, one payment option, and per service `name`,
|
|
190
|
+
`description`, `price.amount`, `inputSchema`, `outputSchema`. Clients ignore unknown fields.
|
|
191
|
+
- No sync/async flag. Each service declares `charge: "on-success" | "upfront"` and `expectedDurationSeconds`.
|
|
192
|
+
- The 402 challenge equals the manifest payment option plus the service price, field by field.
|
|
193
|
+
- Input is validated and capacity checked *before* the 402.
|
|
194
|
+
- Conformance levels: Described (C1, C6), Payable (+ C3, C4), Recoverable (+ C5), plus Registered (C2).
|
|
195
|
+
|
|
196
|
+
**Ways to implement:** gateway mode (any existing HTTP API), the TypeScript library, or natively from the spec,
|
|
197
|
+
checked with `verifier check`. The manifest JSON Schema and language-neutral test vectors are in
|
|
198
|
+
`packages/protocol` (`schemas/`, `test-vectors/`).
|
|
199
|
+
|
|
200
|
+
### 5.2 Job Recovery protocol (`docs/job-recovery.md`)
|
|
201
|
+
|
|
202
|
+
The SOW names three operations.
|
|
203
|
+
|
|
204
|
+
| Operation | HTTP | Notes |
|
|
205
|
+
| --- | --- | --- |
|
|
206
|
+
| **create-job** | `POST {baseUrl}/services/{name}/jobs` | x402-protected. Headers: `Idempotency-Key: <uuid>` (becomes the job id) and `Job-Token: <32 random bytes, base64url>` |
|
|
207
|
+
| **check-status** | `GET {baseUrl}/jobs/{jobId}` | `Job-Token` required. Returns the job view: status, `charged`, receipt and timestamps |
|
|
208
|
+
| **get-result** | `GET {baseUrl}/jobs/{jobId}/result` | `Job-Token` required. Returns the job view with the output |
|
|
209
|
+
|
|
210
|
+
All three return the same job view: `200` when the job has finished, otherwise `202` with `Retry-After`. A client
|
|
211
|
+
that sends neither header (any plain x402 client) gets a provider-generated job id and token in the create-job
|
|
212
|
+
response, without the guarantee for lost responses.
|
|
213
|
+
|
|
214
|
+
**Job states:** `queued → running → succeeded | failed`, plus `payment_uncertain`.
|
|
215
|
+
|
|
216
|
+
**How double-charging is prevented:**
|
|
217
|
+
1. **The client fixes the identity before paying.** It generates `jobId` and the token, then persists both
|
|
218
|
+
together with the binding hash *before* the first request. Because the status URL is a fixed path under
|
|
219
|
+
`baseUrl`, a lost response never loses the handle.
|
|
220
|
+
2. **The provider binds the job.** `jobId → (sha256(JCS({ service, input })), sha256(token))`.
|
|
221
|
+
- Repeating create-job with the same binding returns the existing job, with no new 402 and no new charge.
|
|
222
|
+
- A different binding or token gets `422`; a request while the job is still being claimed or settled gets
|
|
223
|
+
`409` (IETF Idempotency-Key draft-07).
|
|
224
|
+
- A wrong token gets `404`, so the response does not reveal whether the job exists.
|
|
225
|
+
3. **The provider binds the payment.** A unique payment fingerprint (network, payer, signed auth entry)
|
|
226
|
+
means one signed payment can buy at most one job.
|
|
227
|
+
4. **Uncertain means don't pay.** If settlement times out or fails transiently, the job becomes
|
|
228
|
+
`payment_uncertain` and is never re-charged. The provider resolves it from on-chain data after every sweep,
|
|
229
|
+
and operators with `provider-kit reconcile`: the tx hash the facilitator named, or the payer's USDC
|
|
230
|
+
`transfer` events, matched to the job by the payer's signed auth entry and its nonce. "Not settled" needs the
|
|
231
|
+
expiration ledger closed and every ledger the payment could have landed in searched (docs/job-recovery.md).
|
|
232
|
+
5. **Recovery never re-sends `PAYMENT-SIGNATURE`.** It only calls check-status and get-result.
|
|
233
|
+
|
|
234
|
+
**When the user is charged** is set per service with `charge`:
|
|
235
|
+
- `on-success`: verify → run → settle. Work that fails is never charged. The signed payment expires about
|
|
236
|
+
`maxTimeoutSeconds` after signing, so this only suits work well inside that window.
|
|
237
|
+
- `upfront` (default): verify → settle → run. Expensive or long work starts only once it is paid.
|
|
238
|
+
|
|
239
|
+
The **response-loss drill** is test-only, needs an explicit flag, and is off by default. The provider settles and
|
|
240
|
+
persists the result, then drops the response. This is how the SOW recovery demo is produced.
|
|
241
|
+
|
|
242
|
+
### 5.3 Provider Kit (`packages/provider-kit`)
|
|
243
|
+
|
|
244
|
+
| Module | Responsibility |
|
|
245
|
+
| --- | --- |
|
|
246
|
+
| `define-service.ts` | `defineService({ name, title, description, price, charge, expectedDurationSeconds, capacity, inputSchema, outputSchema, examples, handler })`, with schema validation of input (before the 402) and output (before settling) |
|
|
247
|
+
| `provider.ts` | `createProvider(config)` → `{ fetch(request): Promise<Response> }`, which wires every part together |
|
|
248
|
+
| `http/router.ts` | Manifest, create-job, check-status and get-result routes, in the spec's processing order. RFC 9457 errors, body size caps, no redirects. |
|
|
249
|
+
| `gateway/config.ts`, `gateway/upstream.ts` | Gateway mode: a config file describes services whose handler forwards the input to an existing HTTP API in any language |
|
|
250
|
+
| `gateway/openapi.ts` | The gateway config from an existing API's OpenAPI 3 document (`provider-kit init --openapi`): its callable POST endpoints as services, schemas in JSON Schema 2020-12 |
|
|
251
|
+
| `payments/x402-server.ts` | The challenge, built from the manifest, with the Bazaar extension while the header stays under 8 KiB; reading the paid request |
|
|
252
|
+
| `payments/payload-checks.ts` | Local checks run before calling the facilitator: exactly one SAC `transfer(payer → payTo, amount)` on the manifest's asset, authorized by the payer's own signed auth entry and nothing else. The fingerprint is `sha256(JCS({ network, payer, nonce }))`, so re-wrapping one signed auth entry can't buy a second job. Signature validity stays with the facilitator's simulation. |
|
|
253
|
+
| `payments/facilitator.ts` | The kit's own facilitator client: HTTPS-only, no redirects, deadlines (settle: `maxTimeoutSeconds` + 30 s), bounded answers, only the fields the facilitator needs; `checkFacilitator()` at startup (network, `exact`, sponsored fees) |
|
|
254
|
+
| `payments/settlement.ts` | Classifies settlement as `settled` (hash, checked payer and network), `failed` (no hash and a reason from the never-submitted allowlist) or `uncertain` (everything else) |
|
|
255
|
+
| `jobs/store.ts` | `JobStore` contract: atomic claim, compare-and-set transitions that never leave a final state, fingerprint uniqueness, and the queue (admission counts, FIFO starts, worker leases, sweeps); `test/job-store.test.ts` is the contract test |
|
|
256
|
+
| `jobs/memory-store.ts`, `jobs/sqlite-store.ts` | Reference stores. SQLite (`node:sqlite`, WAL, fsync on commit, `BEGIN IMMEDIATE`) is shared safely by several processes on one machine. Providers may add Postgres. |
|
|
257
|
+
| `jobs/runner.ts` | Both charge policies; the output and `settlingSince` are stored before settling; leased upfront workers with renewals and at most 3 starts |
|
|
258
|
+
| `jobs/scheduler.ts` | Capacity (spec §5.8) on the store's queue: admission before the 402 from store counts plus local reservations, the claim under the same lock, FIFO turns for on-success jobs, lease-based workers for upfront jobs, queue positions |
|
|
259
|
+
| `jobs/recovery.ts` | Sweeps at startup and every 30 s: a settlement that never answered becomes `payment_uncertain`; an on-success job whose payment expired (by ledger, or by time) fails uncharged; retention |
|
|
260
|
+
| `jobs/reconcile.ts`, `payments/onchain.ts` | Decides `payment_uncertain` jobs after every sweep [J13]: finds the transaction carrying the payer's auth entry with the job's nonce (the facilitator's hash, else the payer's `transfer` events up to the expiration ledger); settled → queued or succeeded, provably not settled → failed uncharged, anything else waits |
|
|
261
|
+
| `payments/chain.ts` | Soroban RPC reads (`rpc`, default the public testnet RPC) and the ledger clock: on-success deadlines from the payment's expiration ledger, and a create-job check that a signature does not expire too far out |
|
|
262
|
+
| `http/rate-limit.ts` | Optional per-caller limit on create-job: `429` with `Retry-After` |
|
|
263
|
+
| `http/node-server.ts` | `listen()`: Node's HTTP server for a provider, with `/healthz` and graceful close |
|
|
264
|
+
| `manifest.ts` | Builds the manifest and checks it at startup with the JSON Schema and `checkManifestRules()` |
|
|
265
|
+
| `registration.ts` | The 8004 registration file from the manifest [I1], and `checkRegistration()` (I1–I3, read-only), with `inspectRegistration()` also returning the file it read |
|
|
266
|
+
| `validation-request.ts` | The validation request, checked before anything is signed (I1–I3, a signer the registry accepts, a validator that is not the provider itself) and sent as canonical JSON in a `data:` URI |
|
|
267
|
+
| `testing.ts` | `signTestPayment()`: real x402 payments signed offline, for provider and client tests |
|
|
268
|
+
| `cli/` | `serve --config` (gateway mode), `init` (a starter config, or `--openapi` from an OpenAPI document), `check` (self-check, then how agents see the provider: `cli/discovery.ts`), `try` (one paid testnet call from a throwaway payer), `trustline`, `register`, `request-validation`, `reconcile` |
|
|
269
|
+
| `Dockerfile`, `schemas/gateway-config.schema.json` | The gateway image; the config file's JSON Schema |
|
|
270
|
+
|
|
271
|
+
**Developer experience targets (W2 exit criteria):**
|
|
272
|
+
- Library: starting from a clean machine, `npm i`, defining one service and running the server produces a
|
|
273
|
+
working paid testnet request, using only the setup guide.
|
|
274
|
+
- Gateway: an existing non-TypeScript API (a small Python service) becomes a paid service with only a config
|
|
275
|
+
file and `provider-kit serve`, also from the Docker image.
|
|
276
|
+
|
|
277
|
+
### 5.4 Verification, receipts, badges and Validation Registry (`packages/verifier`)
|
|
278
|
+
|
|
279
|
+
**Checks** (each one records evidence):
|
|
280
|
+
|
|
281
|
+
| # | Check | Pass condition |
|
|
282
|
+
| --- | --- | --- |
|
|
283
|
+
| C1 | Manifest | Fetched over HTTPS without redirects, schema-valid v1, size limits respected, no remote `$ref`, examples valid |
|
|
284
|
+
| C2 | Identity | `agentId` exists in the 8004 Identity registry, its registration points to this manifest, and the manifest `payTo` equals the on-chain `agent_wallet` |
|
|
285
|
+
| C3 | Challenge | Invalid input returns `400` before any `402`. Valid unpaid create-job returns `402` whose single `accepts` entry equals the manifest payment option plus the price. `payTo` has a USDC trustline. |
|
|
286
|
+
| C4 | Paid call | Test payer pays → result matches the `output` schema; on-chain USDC `transfer` to `payTo` for the exact amount |
|
|
287
|
+
| C5 | Recovery | Repeating create-job returns the same job with no second transfer; the same key with other input returns `422`; check-status and get-result work with the token and return `404` without it |
|
|
288
|
+
| C6 | Hygiene | No redirects, no secrets in responses, bounded bodies |
|
|
289
|
+
| C7 | Load | A burst of unpaid create-job requests is answered with `402`, `429` or `503` plus `Retry-After`, never another error or a timeout. With `--pay`, `concurrency + 1` paid jobs are each accepted or refused before settlement. |
|
|
290
|
+
|
|
291
|
+
**Conformance levels** (each maps to one badge): Described = C1 + C6, Payable = + C3 + C4,
|
|
292
|
+
Recoverable = + C5, Registered = C2 plus a Validation Registry record, and Load-safe = C7. `verifier check` runs the no-payment
|
|
293
|
+
checks against any URL. With `--dev` it also accepts a local `http://` server (spec [M6]), so providers can test
|
|
294
|
+
themselves before going live.
|
|
295
|
+
|
|
296
|
+
**Verification receipt:**
|
|
297
|
+
- Canonical JSON containing: standard version, provider `agentId`, manifest sha256, network, a status and
|
|
298
|
+
evidence for each check, payment tx hash, verifier address and timestamps.
|
|
299
|
+
- It is stored under `evidence/receipts/` and published through the evidence page (GitHub Pages).
|
|
300
|
+
|
|
301
|
+
**Badges:** SVGs derived **only** from a receipt.
|
|
302
|
+
- Badge set: one per level, `Standard v1`, `Payment verified`, `Recovery verified`; plus `Load-safe` (C7) and
|
|
303
|
+
`8004 validated` (C2 and a Validation Registry record of the receipt, confirmed on chain).
|
|
304
|
+
- Each badge shows the network.
|
|
305
|
+
|
|
306
|
+
**Validation Registry flow** (contract read from `stellar-8004/contracts/validation-registry`):
|
|
307
|
+
|
|
308
|
+
1. **Provider owner** runs `provider-kit request-validation`, which calls
|
|
309
|
+
`validation_request(caller = owner, validator_address = verifier G…, agent_id, request_uri, request_hash)`.
|
|
310
|
+
- `request_uri` is the verification request document.
|
|
311
|
+
- `request_hash = sha256(document)`, the spec-compliant `contentHash` mode of `generateRequestNonce`.
|
|
312
|
+
2. **Verifier** runs the checks and calls
|
|
313
|
+
`validation_response(caller = verifier, request_hash, response = score 0–100, response_uri = receipt URL, response_hash = sha256(receipt), tag = "provider-standard-v1")`.
|
|
314
|
+
3. Anyone can read the result with `get_validation_status(request_hash)` or `get_agent_validations_paginated`.
|
|
315
|
+
|
|
316
|
+
`response` is higher-is-better (ERC-8004: 0 = failed, 100 = passed). Documents are hashed as
|
|
317
|
+
`sha256(RFC 8785 JCS)`. Both rules are shared with the planned Stellar ERC-8126 records, so the two kinds of
|
|
318
|
+
record never get mixed up in `get_summary` (docs/erc-compatibility.md, T2).
|
|
319
|
+
|
|
320
|
+
Mainnet currently reports `totalValidations: 0`, so these will be among the first real Validation Registry
|
|
321
|
+
records. Stellar Agent Search's deferred P3-10 (validation trust axis) can then read them.
|
|
322
|
+
|
|
323
|
+
### 5.5 Example paid service (`examples/paid-service`)
|
|
324
|
+
|
|
325
|
+
The example is built only with the public `provider-kit` API, so it doubles as the template for pilot providers.
|
|
326
|
+
|
|
327
|
+
| Service | Charge | Price | Behavior |
|
|
328
|
+
| --- | --- | --- | --- |
|
|
329
|
+
| `text-stats` | on-success | 0.01 USDC | Deterministic. Answers `200` at once; failed work is never charged. |
|
|
330
|
+
| `delayed-report` | upfront | 0.02 USDC | Configurable delay. Answers `202`. Used for the Job Recovery demo. |
|
|
331
|
+
|
|
332
|
+
It runs on Hono with `@hono/node-server`. The `.env` holds only the `payTo` public address and the facilitator URL.
|
|
333
|
+
|
|
334
|
+
### 5.6 Payment Client: decided
|
|
335
|
+
|
|
336
|
+
**Decided 2026-10-21.** The design is in [docs/payment-client.md](docs/payment-client.md):
|
|
337
|
+
- One core (`packages/payment-client`) that keeps every safety rule.
|
|
338
|
+
- Two strategies behind it (Strategy pattern, built 2026-10-22 with the built-ins only):
|
|
339
|
+
- signers: a local key, browser wallets through Stellar Wallets Kit, then a passkey smart account
|
|
340
|
+
- payment methods: x402 `exact` on Stellar, the only one v1 allows
|
|
341
|
+
- adapters for other projects (such as Eunomia or an ERC-8196 wallet) come later as separate packages that
|
|
342
|
+
must pass the conformance checks
|
|
343
|
+
- Two surfaces: a static web app for everyone and a keyed MCP server for agents.
|
|
344
|
+
- Policy and journal use ERC-8196 field names. Out of the box, every payment needs approval.
|
|
345
|
+
|
|
346
|
+
The core, the local-key signer, the `stellar-pay` CLI and a minimal web approval page (`apps/wallet`) work end to
|
|
347
|
+
end on testnet. Settlement proof checks the `transfer` event against the approved payment ([J16]).
|
|
348
|
+
|
|
349
|
+
### 5.7 Discovery integration (changes in `stellar-agent-search`, not this repo)
|
|
350
|
+
|
|
351
|
+
- **Testnet discovery gap:** the default explorer (`stellar8004.com`) indexes **mainnet only**, and testnet mode
|
|
352
|
+
refuses to start without `EXPLORER_BASE_URL` (P1-07). The full "find → approve → pay → receive" flow on
|
|
353
|
+
testnet therefore needs one of:
|
|
354
|
+
- **(a, recommended)** a keyless direct-registry mode for testnet: resolve allowlisted agent IDs through
|
|
355
|
+
Soroban reads, then fetch their manifest.
|
|
356
|
+
- (b) running a testnet indexer.
|
|
357
|
+
- (c) doing the pilot on mainnet.
|
|
358
|
+
- **Manifest awareness:** when an agent's service points to a Provider Standard manifest, show its price,
|
|
359
|
+
network, recovery support and badges, with the badges taken from Validation Registry reads.
|
|
360
|
+
- These changes stay read-only and keyless, each in its own small PR to that repo.
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## 6. Four-week schedule
|
|
365
|
+
|
|
366
|
+
The sprint start date is still TBD; day 1 is the date the SOW is signed.
|
|
367
|
+
|
|
368
|
+
### Week 1: Standard, payment client, first paid flow (D1)
|
|
369
|
+
|
|
370
|
+
- [x] Day 1:
|
|
371
|
+
- Testnet accounts: provider `payTo` and test payer. The verifier account waits for the verifier (Week 3).
|
|
372
|
+
- USDC trustlines and testnet USDC.
|
|
373
|
+
- Facilitator `getSupported()` probe: `stellar:testnet` + `exact` is supported, and the facilitator adds no
|
|
374
|
+
limit of its own on the payment authorization window, so the spec's 30–300 range stands.
|
|
375
|
+
- [x] Day 1–2: **Payment client design decision** (§5.6).
|
|
376
|
+
- [x] `docs/provider-standard.md` v1 draft.
|
|
377
|
+
- [x] Manifest JSON Schema, test vectors and reference checks in `packages/protocol` (canonical JSON, binding
|
|
378
|
+
hash, manifest rules, challenge check).
|
|
379
|
+
- [x] Remaining protocol types (job view, job states, errors, receipts), with test vectors.
|
|
380
|
+
- [x] Freeze v1 (2026-10-21, open decision 6).
|
|
381
|
+
- [x] Verification receipt format defined (spec only).
|
|
382
|
+
- [x] Thin provider slice: manifest, create-job with an on-success service, x402 resource server, memory store.
|
|
383
|
+
- [x] Payment client, first working version: approval screen, caps, signing, journal.
|
|
384
|
+
- [x] Core, local-key signer and `stellar-pay` CLI (approval prompt, caps, journal, on-chain check).
|
|
385
|
+
- [x] Minimal web approval page (`apps/wallet`), for the D1 video.
|
|
386
|
+
- [ ] One successful testnet payment flow, recorded (tx link, screenshots, short video).
|
|
387
|
+
- [x] Testnet tx links.
|
|
388
|
+
- [ ] Screenshots and the short video.
|
|
389
|
+
- [ ] Start pilot outreach: shortlist 4–5 candidate providers and 6–7 users.
|
|
390
|
+
|
|
391
|
+
**Exit:** spec published, approval-before-payment video, testnet tx link.
|
|
392
|
+
|
|
393
|
+
### Week 2: Provider Kit (D2, part 1)
|
|
394
|
+
|
|
395
|
+
- [x] Full `provider-kit`:
|
|
396
|
+
- `defineService` with schemas, checked at definition time (name, S2, S9) and in the manifest at startup
|
|
397
|
+
- strict payload checks
|
|
398
|
+
- settlement classification
|
|
399
|
+
- SQLite store
|
|
400
|
+
- background runner: leased workers, recovery sweeps, retention
|
|
401
|
+
- both charge policies
|
|
402
|
+
- [x] Gateway mode: `provider-kit serve --config`, a Docker image, tested with a small Python API as upstream.
|
|
403
|
+
- `serve --config`, tested end to end with [examples/python-upstream](examples/python-upstream).
|
|
404
|
+
- Docker image (`packages/provider-kit/Dockerfile`, 295 MB): built and run against the Python API. Real testnet
|
|
405
|
+
facilitator check at startup, a paid call settled once, health check, non-root user, and the job recovered
|
|
406
|
+
from the `/data` volume after a container restart.
|
|
407
|
+
- [ ] Manifest builder and 8004 registration (`provider-kit register`) on testnet.
|
|
408
|
+
- [x] Manifest builder with startup checks; `register` and `check` (reads I1–I3 from the testnet registry).
|
|
409
|
+
- [ ] Run `provider-kit register` for the sample provider on testnet, approved in the owner's wallet.
|
|
410
|
+
- [x] Approving in a wallet: `trustline`, `register` and `request-validation` open a local page (Stellar Wallets
|
|
411
|
+
Kit) where the owner's own wallet signs; `--source` keeps the Stellar CLI keychain for CI. `register` saves the
|
|
412
|
+
new `agentId` to the config. Tested on testnet end to end with `trustline`.
|
|
413
|
+
- [x] `examples/paid-service` with both services, on the SQLite store.
|
|
414
|
+
- [ ] Setup guide (`docs/provider-setup-guide.md`), tested on a clean machine.
|
|
415
|
+
- [x] Written for both paths.
|
|
416
|
+
- [ ] Followed on a clean machine.
|
|
417
|
+
- [x] Payment-safety test suite (§7), provider side.
|
|
418
|
+
- [x] Capacity (spec §5.8): per-service lanes, `429`/`503` before payment and queue positions, on a shared queue
|
|
419
|
+
with worker leases in the store, so queued `upfront` jobs survive a restart [Q4] and workers scale apart from
|
|
420
|
+
the HTTP servers (`runQueuedJobs: false` / `serve --no-workers`).
|
|
421
|
+
|
|
422
|
+
**Exit:** a developer installs the kit from scratch, starts the sample provider and completes a paid request. An
|
|
423
|
+
existing Python API becomes a paid service through gateway mode.
|
|
424
|
+
|
|
425
|
+
### Week 3: Verification and Job Recovery (D2, part 2)
|
|
426
|
+
|
|
427
|
+
- [x] Complete Job Recovery (docs/job-recovery.md):
|
|
428
|
+
- create-job, check-status and get-result
|
|
429
|
+
- `payment_uncertain`
|
|
430
|
+
- reconciliation: automatic after every sweep, and `provider-kit reconcile` (`--dry-run`, `--rpc`)
|
|
431
|
+
- the response-loss drill
|
|
432
|
+
- [ ] Record the recovery demo on testnet: one interrupted job, recovered, with exactly one on-chain transfer.
|
|
433
|
+
- [x] Payment client recovery: resume from the journal, never re-sign.
|
|
434
|
+
- [x] Payment client: treat `409 request_in_progress` on create-job and while polling as "ask again later".
|
|
435
|
+
- [x] A ledger clock, shared by reconciliation and the kit: an on-success job's deadline from its payment's
|
|
436
|
+
expiration ledger rather than from its claim, so a payment resent late [Q8] isn't worked on after it expired.
|
|
437
|
+
It reads Soroban RPC (latest ledger, close time, average ledger duration) rather than Horizon, so one endpoint
|
|
438
|
+
serves the clock and reconciliation.
|
|
439
|
+
- [x] `verifier`: checks C1–C7, conformance levels, receipt, badges, and the no-payment `check` command
|
|
440
|
+
(docs/verification.md). Paid checks prove payments on chain by the signed nonce, and that refused payments never
|
|
441
|
+
landed; receipts are stored under their own SHA-256, the on-chain `response_hash`.
|
|
442
|
+
- [ ] Validation Registry publishing: `request-validation` (provider) and `validation_response` (verifier) on testnet.
|
|
443
|
+
- [x] `verifier publish`: `validation_response` through the Stellar CLI keychain, after checking the request, the
|
|
444
|
+
receipt and the `response_uri`; the request document is defined in docs/verification.md.
|
|
445
|
+
- [x] `provider-kit request-validation`: the request document as a protocol type, JSON Schema and test vectors;
|
|
446
|
+
the command checks the registration, the signer and the validator, then the owner's wallet signs it (or the
|
|
447
|
+
Stellar CLI keychain, with `--source`).
|
|
448
|
+
- [ ] Run both on testnet for the sample provider: the first receipt and Validation Registry record.
|
|
449
|
+
- [ ] Discovery integration, option (a) from §5.7, in `stellar-agent-search`.
|
|
450
|
+
- [ ] Pilot providers start integrating: send them the guide and template.
|
|
451
|
+
|
|
452
|
+
**Exit:**
|
|
453
|
+
- The sample provider has a verification receipt and a Validation Registry record (tx).
|
|
454
|
+
- One interrupted job has been recovered, with exactly one on-chain transfer.
|
|
455
|
+
|
|
456
|
+
### Week 4: Pilot and evidence (D3)
|
|
457
|
+
|
|
458
|
+
- [ ] Two independent providers live: each verified, each with at least one paid call.
|
|
459
|
+
- [ ] Five users complete find → approve → pay → receive, and at least one runs a recovery.
|
|
460
|
+
- [ ] Fix pilot-blocking issues and record them in the pilot report.
|
|
461
|
+
- [ ] Evidence page, demo videos, payment references, validation records, pilot report.
|
|
462
|
+
|
|
463
|
+
**Exit:** every row of the SOW §6.1 evidence table is linked from `evidence/README.md`.
|
|
464
|
+
|
|
465
|
+
---
|
|
466
|
+
|
|
467
|
+
## 7. Testing strategy
|
|
468
|
+
|
|
469
|
+
**Unit:**
|
|
470
|
+
- canonical JSON (key order and whitespace don't change the hash)
|
|
471
|
+
- manifest schema and test vectors
|
|
472
|
+
- challenge ↔ manifest matching
|
|
473
|
+
- settlement classification
|
|
474
|
+
- job state transitions
|
|
475
|
+
|
|
476
|
+
**Payment safety:** these tests must exist before the pilot.
|
|
477
|
+
- [x] A repeated create-job with the same key and input → same job, no facilitator call, no second charge.
|
|
478
|
+
- [x] The same key with different input or token → `422`. A request while still claiming or settling → `409`.
|
|
479
|
+
A wrong token → `404`.
|
|
480
|
+
- [x] Invalid input → `400` before any `402`.
|
|
481
|
+
- [x] One signed payment presented for two jobs → rejected (fingerprint), also re-signed with the same nonce.
|
|
482
|
+
- [x] A facilitator timeout or 5xx → `payment_uncertain`, never `failed`, never re-charged.
|
|
483
|
+
- [x] An `on-success` handler failure or invalid output → no settlement.
|
|
484
|
+
- [x] `on-success` work that outlasts the payment authorization → job failed, nothing charged.
|
|
485
|
+
- [x] A client without `Idempotency-Key` and `Job-Token` → provider-generated id and token, one charge.
|
|
486
|
+
- [x] A challenge whose amount, payTo, asset or network differs from the manifest → the client refuses to sign.
|
|
487
|
+
- [x] A failed spending-limit check → the payment is blocked (fail closed).
|
|
488
|
+
- [ ] A lost response → recovery returns the stored result, with one on-chain transfer. (Provider side and the
|
|
489
|
+
client's `recover()` are tested offline; the on-chain demo is Week 3.)
|
|
490
|
+
- [x] An uncertain settlement is decided from the transaction carrying the job's nonce: another job's equal
|
|
491
|
+
transfer never counts, and "not settled" comes only after the expiration ledger closed and the whole window
|
|
492
|
+
was searched. An RPC outage, a window older than the RPC's history, or a ledger still to come leave the job
|
|
493
|
+
waiting.
|
|
494
|
+
- [x] A `409` while the provider settles → the client follows the job and never signs again.
|
|
495
|
+
|
|
496
|
+
**Integration (testnet, manual or CI-gated):** sample provider + verifier + payment client, end to end.
|
|
497
|
+
|
|
498
|
+
**Test hygiene:** use fixed transaction timebounds in fixtures. This is the lesson from the Phase 1 timebounds
|
|
499
|
+
flake.
|
|
500
|
+
|
|
501
|
+
---
|
|
502
|
+
|
|
503
|
+
## 8. Evidence plan (maps to SOW §6.1)
|
|
504
|
+
|
|
505
|
+
| Deliverable | Evidence | Location |
|
|
506
|
+
| --- | --- | --- |
|
|
507
|
+
| D1 | Provider Standard v1 | `docs/provider-standard.md` |
|
|
508
|
+
| D1 | Video (price, recipient, spending control, approval → payment), screenshots, testnet tx link | `evidence/d1/` |
|
|
509
|
+
| D2 | Public repo, setup guide | this repo, `docs/provider-setup-guide.md` |
|
|
510
|
+
| D2 | Verification receipt + badges | `evidence/receipts/` |
|
|
511
|
+
| D2 | Validation Registry record (request + response tx) | `evidence/validation/` |
|
|
512
|
+
| D2 | Recovery demo (video + single-transfer proof) | `evidence/d2/` |
|
|
513
|
+
| D3 | Provider links, per-provider paid-call references, screenshots | `evidence/pilot/` |
|
|
514
|
+
| D3 | Pilot report (what worked, failed, was fixed) | `evidence/pilot/report.md` |
|
|
515
|
+
| D3 | Public evidence page | GitHub Pages from `evidence/` |
|
|
516
|
+
|
|
517
|
+
Every transaction is listed with network, hash, ledger and explorer link. Testnet evidence is labeled as testnet
|
|
518
|
+
everywhere.
|
|
519
|
+
|
|
520
|
+
---
|
|
521
|
+
|
|
522
|
+
## 9. Risks
|
|
523
|
+
|
|
524
|
+
| Risk | Impact | Mitigation |
|
|
525
|
+
| --- | --- | --- |
|
|
526
|
+
| Payment client design not settled by W1 day 2 | Misses the D1 Week 1 output | Build the design-independent core first: policy, validation, journal |
|
|
527
|
+
| No testnet 8004 indexer | Discovery step of the pilot flow doesn't work on testnet | Direct-registry testnet mode in `stellar-agent-search` (§5.7) |
|
|
528
|
+
| Testnet facilitator unavailable or unsupported | No settlement | Probe on day 1. If needed, look for another facilitator or self-host a settlement path. |
|
|
529
|
+
| Independent providers late or unresponsive | D3 missed | Start outreach in W1, use the template repo, offer incentives (SOW), keep a backup provider |
|
|
530
|
+
| `validation_request` must be signed by the provider owner | Friction for independent providers | One-command `provider-kit request-validation`, approved in the owner's own wallet |
|
|
531
|
+
| A CLI key for `payTo`, then importing it into a browser wallet to use the income | Friction and a secret key on disk | The owner's existing wallet is `payTo` and signs every owner step on a local approval page (`trustline`, `register`, `request-validation`) |
|
|
532
|
+
| `stellar8004` declares stellar-sdk `^15`; x402 needs `^16.3` | Duplicate SDK copies: 18 MB and a vulnerable axios, and an XDR type mismatch if SDK objects ever cross between them | Root `overrides`, which `create-stellar-service` writes into each project. `scaffold:check` fails a project with two copies; the rehearsal warns about a plain install. |
|
|
533
|
+
| Reviewers expect mainnet evidence (Phase 1 was mainnet) | Evidence questioned | Agree on testnet with the Ambassador Chapter Lead up front; mainnet is optional follow-up |
|
|
534
|
+
| Users need testnet USDC | Pilot friction | Pre-fund pilot wallets from the team test account |
|
|
535
|
+
|
|
536
|
+
---
|
|
537
|
+
|
|
538
|
+
## 10. Open decisions
|
|
539
|
+
|
|
540
|
+
| # | Decision | Owner | Needed by |
|
|
541
|
+
| --- | --- | --- | --- |
|
|
542
|
+
| 1 | ~~Payment client design (§5.6)~~ **Decided 2026-10-21:** docs/payment-client.md | Berkin | W1 day 2 |
|
|
543
|
+
| 2 | SOW provider/user counts reading (§1.1) | Berkin + Ambassador Chapter Lead | Before sprint start |
|
|
544
|
+
| 3 | Testnet discovery approach (§5.7) | Berkin | W2 |
|
|
545
|
+
| 4 | Testnet-only evidence accepted, or a final mainnet run | Berkin + Ambassador Chapter Lead | W2 |
|
|
546
|
+
| 5 | npm scope for publishing (placeholder `@stellar-agent-services/*`) | Berkin | W2 (first publish) |
|
|
547
|
+
| 6 | ~~Provider Standard v1 freeze~~ **Decided 2026-10-21, frozen as drafted, except the URL:** `Job-Token` header, manifest path, `maxTimeoutSeconds` range, the URL for the schema `$id` and problem `type` values (`algorialabs.github.io/stellar-agent-services`), plus CORS as SHOULD [J17] | Berkin | W1 |
|
|
548
|
+
| 7 | Shared ERC-8126/8196 conventions: score direction, tags, hashing, policy extensions (docs/erc-compatibility.md) | Berkin + ERC-8126/8196 Stellar team | W1 for hashing, W3 for validation records |
|