7.2 KiB
examples/ — Minimal runnable examples for integrators
This folder contains three self-contained, copy-pasteable starters that demonstrate how to talk to the coordinator API, submit jobs, poll status, and (optionally) verify signed receipts.
examples/
├─ explorer-webexplorer-web/ # (docs live elsewhere; not a runnable example)
├─ quickstart-client-python/ # Minimal Python client
├─ quickstart-client-js/ # Minimal Node/Browser client
└─ receipts-sign-verify/ # Receipt format + sign/verify demos
Conventions: Debian 12/13, zsh, no sudo, run as root if you like. Keep env in a
.envfile. Replace example URLs/tokens with your own.
1) quickstart-client-python/
What this shows
- Create a job request
- Submit to
COORDINATOR_URL - Poll job status until
succeeded|failed|timeout - Fetch the result payload
- (Optional) Save the receipt JSON for later verification
Files Windsurf should ensure exist
main.py— the tiny client (≈ 80–120 LOC)requirements.txt—httpx,python-dotenv(andpydanticif you want models).env.example—COORDINATOR_URL,API_TOKENREADME.md— one-screen run guide
How to run
cd examples/quickstart-client-python
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# Prepare environment
cp .env.example .env
# edit .env → set COORDINATOR_URL=https://api.local.test:8443, API_TOKEN=xyz
# Run
python main.py --prompt "hello compute" --timeout 60
# Outputs:
# - logs to stdout
# - writes ./out/result.json
# - writes ./out/receipt.json (if provided by the coordinator)
Coordinator endpoints the code should touch
POST /v1/jobs→ returns{ job_id }GET /v1/jobs/{job_id}→ returns{ status, progress?, result? }GET /v1/jobs/{job_id}/receipt→ returns{ receipt }(optional)
Keep the client resilient: exponential backoff (100ms → 2s), total wall-time cap from --timeout.
2) quickstart-client-js/
What this shows
- Identical flow to the Python quickstart
- Two variants: Node (fetch via
undici) and Browser (nativefetch)
Files Windsurf should ensure exist
node/package.json—undici,dotenvindex.js— Node example client.env.exampleREADME.md
browser/index.html— minimal UI with a Prompt box + “Run” buttonapp.js— client logic (no build step)README.md
How to run (Node)
cd examples/quickstart-client-js/node
npm i
cp .env.example .env
# edit .env → set COORDINATOR_URL, API_TOKEN
node index.js "hello compute"
How to run (Browser)
cd examples/quickstart-client-js/browser
# Serve statically (choose one)
python3 -m http.server 8080
# or
busybox httpd -f -p 8080
Open http://localhost:8080 and paste your coordinator URL + token in the form.
The app:
POST /v1/jobs- polls
GET /v1/jobs/{id}every 1s (with a 60s guard) - downloads
receipt.jsonif available
3) receipts-sign-verify/
What this shows
- Receipt JSON structure used by AITBC examples
- Deterministic signing over a canonicalized JSON (RFC 8785-style or stable key order)
- Ed25519 signing & verifying in Python and JS
- CLI snippets to verify receipts offline
If the project standardizes on another curve, swap the libs accordingly. For Ed25519:
- Python:
pynacl- JS:
@noble/ed25519
Files Windsurf should ensure exist
spec.md— human-readable schema (see below)python/verify.py—python verify.py ./samples/receipt.json ./pubkeys/poolhub_ed25519.pubrequirements.txt—pynacl
js/verify.mjs—node js/verify.mjs ./samples/receipt.json ./pubkeys/poolhub_ed25519.pubpackage.json—@noble/ed25519
samples/receipt.json— realistic samplepubkeys/poolhub_ed25519.pub— PEM or raw 32-byte hex
Minimal receipt schema (for spec.md)
{
"version": "1",
"job_id": "string",
"client_id": "string",
"miner_id": "string",
"started_at": "2025-09-26T14:00:00Z",
"completed_at": "2025-09-26T14:00:07Z",
"units_billed": 123, // e.g., “AIToken compute units”
"result_hash": "sha256:…", // hex
"metadata": { "model": "…" }, // optional, stable ordering for signing
"signature": {
"alg": "Ed25519",
"key_id": "poolhub-ed25519-2025-09",
"sig": "base64url…" // signature over canonicalized receipt WITHOUT this signature object
}
}
CLI usage
Python
cd examples/receipts-sign-verify/python
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python verify.py ../samples/receipt.json ../pubkeys/poolhub_ed25519.pub
# exit code 0 = valid, non-zero = invalid
Node
cd examples/receipts-sign-verify/js
npm i
node verify.mjs ../samples/receipt.json ../pubkeys/poolhub_ed25519.pub
Implementation notes for Windsurf
- Canonicalize JSON before hashing/signing (stable key order, UTF-8, no trailing spaces).
- Sign bytes of
sha256(canonical_json_without_signature_block). - Reject if
completed_at < started_at, unknownalg, or mismatchedresult_hash.
Shared environment
All quickstarts read the following from .env or in-page form fields:
COORDINATOR_URL=https://api.local.test:8443
API_TOKEN=replace-me
# Optional: REQUEST_TIMEOUT_SEC=60
HTTP headers to include:
Authorization: Bearer <API_TOKEN>
Content-Type: application/json
Windsurf checklist (do this automatically)
-
Create folders & files
quickstart-client-python/{main.py,requirements.txt,.env.example,README.md}quickstart-client-js/node/{index.js,package.json,.env.example,README.md}quickstart-client-js/browser/{index.html,app.js,README.md}receipts-sign-verify/{spec.md,samples/receipt.json,pubkeys/poolhub_ed25519.pub}receipts-sign-verify/python/{verify.py,requirements.txt}receipts-sign-verify/js/{verify.mjs,package.json}
-
Fill templates
- Implement
POST /v1/jobs,GET /v1/jobs/{id},GET /v1/jobs/{id}/receiptcalls. - Poll with backoff; stop at terminal states; write
out/result.json&out/receipt.json.
- Implement
-
Wire Ed25519 libs
- Python:
pynaclverify(public_key,message,signature) - JS:
@noble/ed25519verifySync
- Python:
-
Add DX niceties
.env.exampleeverywhereREADME.mdwith copy-paste run steps (no global installs)- Minimal logging and clear non-zero exit on failure
-
Smoke tests
- Python quickstart runs end-to-end with a mock coordinator (use our tiny FastAPI mock if available).
- JS Node client runs with
.env. - Browser client works via
http://localhost:8080.
Troubleshooting
- 401 Unauthorized → check
API_TOKEN, CORS (browser), or missingAuthorizationheader. - CORS in browser → coordinator must set:
Access-Control-Allow-Origin: *(or your host)Access-Control-Allow-Headers: Authorization, Content-TypeAccess-Control-Allow-Methods: GET, POST, OPTIONS
- Receipt verify fails → most often due to non-canonical JSON or wrong public key.
License & reuse
Keep examples MIT-licensed. Add a short header to each file:
MIT © AITBC Examples — This is demo code; use at your own risk.