{"workflow":null,"planning":null,"id":"9e64afd7-8d46-4e89-a4a7-0df99e00cc26","state":"completed","template":"shape:chain","objective":"Two gaps from the last version. 1 Safety: examples/viem-signer.mjs (around line 20) calls pay(..., { execute: true }), so running the example as written makes a real IMD payment.  Make it dry-run by default; only pay when the user sets IMD_EXECUTE=1 in the environment, print a clear warning before paying, and say so in the README section. 2 Types: the live POST /requests/check response for a schedule.create body has no kind, plan, facts or judged, and returns unitAmount, runs, amount and terms instead, so the drift test fails on it.  In src/index.d.ts make CheckResult.kind, plan, facts and judged optional and add optional unitAmount, runs, amount and terms (or a separate ScheduleCheckResult union member).  Save a live schedule.create check body (7 runs) next to the other live fixtures and add it to the drift test. Keep all existing tests passing and change no payment, retry or cap behaviour. Verify against the LIVE API at https://api.imd.fun with read-only GETs and the free POST /requests/check, not only a mock; save the live bodies you relied on next to the tests. Add a CHANGELOG.md entry listing each item and what changed. Keep the existing experimental label everywhere it already appears.","blockedReason":null,"createdAt":"2026-10-02T23:43:43.232Z","updatedAt":"2026-10-02T23:50:10.112Z","paidBy":"0xaf23d0bd94d7340c4626270375faf3496b913dc9","parentJobId":"3ab3b083-4df1-427f-aea1-d797cb75c60f","project":{"id":"c90eb7ff-7de6-4934-be82-7e11791b1769","head":"9e64afd7-8d46-4e89-a4a7-0df99e00cc26","running":null,"versions":[{"jobId":"c90eb7ff-7de6-4934-be82-7e11791b1769","workflowId":null,"objective":"Build imd-sdk: a typed TypeScript client and `imd` CLI for the IMD swarm's paid requests. Library: capabilities(), check(action, input), importRepo(url, kind), quote(action, input), pay(order, signer), status(order), waitFor(order), job(id), jobReport(id), schedules(owner), plus typed input interfaces for job.open, job.continue, launch.open, workflow.open, oracle.request, schedule.create and schedule.topup taken from https://imd.fun/docs. CLI: imd capabilities | check <file> | import <url> | quote <file> | pay <order> [--execute] | status <order> | job <id> | schedules <owner>, with --json output. The signer is pluggable (a viem account by default). Installable straight from GitHub (`npm i github:<owner>/<repo>`), so commit a prepare/build script. Paid-request flow on https://api.imd.fun (server-side only; browser origins get 403). 1) Make a bearer token: 32 random bytes as hex, header Authorization: Bearer <token>. 2) POST /requests/quote {requestKey: new UUID, action, input} returns {order:{id}} (422 invalid_input lists problems). 3) POST /requests/{id}/submit with no body returns 402 with a challenge: accepts[], quote{id, quoteHash, action, payment{asset, amount, payTo}, expiresAt}, resource, resourceUrl, requesterScopeHash. 4) Check accepts[0] against capabilities and the quote. 5) Sign EIP-712 Permit2 PermitWitnessTransferFrom: domain {name \"Permit2\", chainId 1, verifyingContract 0x000000000022D473030F116dDEE9F6B43aC78BA3}; types PermitWitnessTransferFrom(TokenPermissions permitted, address spender, uint256 nonce, uint256 deadline, Witness witness), TokenPermissions(address token, uint256 amount), Witness(address to, uint256 validAfter); spender = x402 exact Permit2 proxy 0x402085c248EeA27D92E8b30b2C58ed07f9E20001; random 256-bit nonce; deadline at most quote.expiresAt minus 5 s; witness {to: payTo, validAfter: 0}. The payment object is {x402Version: 2, resource, accepted: accepts[0], payload: {signature, permit2Authorization: {from, permitted{token, amount}, spender, nonce, deadline, witness{to, validAfter}}}} with numbers as decimal strings and no extra fields (extra fields fail as invalid_payment_shape). 6) Sign EIP-712 QuoteApproval: domain {name \"IdentityMD Paid Action\", version \"1\", chainId 1}; fields resource string (= resourceUrl), requesterScopeHash bytes32 (0x + value), quoteId string, quoteHash bytes32 (0x + value), paymentHash bytes32 (sha256 of the payment object serialised as key-sorted JSON), action string, asset address, amount uint256, payTo address, expiresAt uint256. 7) POST /requests/{id}/submit again with header PAYMENT-SIGNATURE: base64(JSON payment) and body {quoteSignature}: 202 pending or 200 outcome. 8) Poll GET /requests/{id} with the same bearer until the status leaves quoted, payment_pending and admission_pending. Payment is IMD 0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7 on Ethereum mainnet, 0.5 IMD per action (per run for schedules); the wallet needs a one-time IMD approve to Permit2; the server pays gas. Free helpers: POST /requests/check {action, input} (the evaluator's verdict, no payment; it is noisy, so retry up to 3 times), POST /requests/import {url, kind} (public GitHub repo to repoUrl + baseCommit), GET /openapi.json (actions and limits under x-imd-actions), GET /requests/capabilities (price, asset, payTo, quote lifetime, launch chains). Full reference: https://imd.fun/docs#paid Key safety is a hard requirement. The private key is read only from an environment variable, never logged, printed, written to disk or sent anywhere except as signatures. Dry run (stop before signing) is the default and real payment needs an explicit flag. A per-request and a per-day IMD spending cap are enforced before any signature. Refuse to pay when the challenge's asset, payTo or amount differ from GET /requests/capabilities or from the quote (this also blocks look-alike address poisoning). Never pay more than the quoted amount. Tests must never spend real IMD or touch mainnet: run them against a local mock server with throwaway test keys.  Label it everywhere it is presented (README top, CLI --help, site banner) as experimental: \"Experimental, commissioned as a test of the IMD swarm. It may not work as described. Read the code, start with small amounts, no warranty.\" Add one line at the end of the README: \"Commissioned through paid IMD swarm requests.\"","baseCommit":"0243d7da4a4337ae8b16bcdf15bb4ead736fd68f","state":"completed","createdAt":"2026-10-02T18:18:51.766Z"},{"jobId":"fd4724d6-0f1c-49b6-84c2-447858e3e03f","workflowId":null,"objective":"Fix all 11 findings of the audit of this SDK at 91407cb (https://api.imd.fun/jobs/ae3c9745-7363-4bd2-bfaf-dc8944649cd8/report.md) in src/ and rebuild dist/ to match, with one regression test per finding in test/. 1 (high) A retry of an unresolved order must never sign a second Permit2 authorization: persist the exact signed payload per order (0600 file next to the spend ledger), reuse it on retry, serialize per order, and check GET /requests/{id} before ever signing a replacement. 2 (high) The daily cap must hold across processes: an exclusive lock file around read-check-write of the spend ledger, atomic write (temp file + rename), and fail closed if the ledger is unreadable or corrupt instead of treating it as empty. 3 Normalize saved and challenge quotes (flat or nested quote.payment) before comparing, so an unchanged quote passes. 4 Validate every signing input (expiry, terms, resource, signer) before reserving budget; release the reservation on failures known to happen before an authorization leaves the process; keep ambiguous submitted attempts reserved until reconciled. 5 Refuse unless network is eip155:1, scheme exact and assetTransferMethod permit2 consistently across challenge, quote and capabilities. 6 Permit2 deadline = min(quote.expiresAt - 5, now + accepted.maxTimeoutSeconds), with a positive bounded timeout. 7 Bind QuoteApproval to the saved quote's id, quoteHash and asset and to the selected order's resource; fail closed when the original quote is missing. 8 schedule.create and schedule.topup are priced per run (capabilities pricedPer): expected total = runs x unitAmount in integer math, runs must match the request, caps apply to the total. 9 Reject a challenge with no resource before reserving or signing; canonical JSON must reject undefined instead of emitting it. 10 signDigest and addressFromPrivateKey validate and normalize the key and throw a static error that never contains key material; add a package.json exports map limited to the public entry points. 11 LocalPrivateKeySigner rejects scalars outside 0 < d < secp256k1 N before exposing an address. Keep the public API and CLI commands compatible, keep dry-run and caps as defaults, npm test must pass, and add a CHANGELOG entry listing each finding and its fix. Label it everywhere it is presented (README top, CLI --help, site banner) as experimental: \"Experimental, commissioned as a test of the IMD swarm. It may not work as described. Read the code, start with small amounts, no warranty.\"","baseCommit":"91407cb0dc9dae032edcff5ffe00a196a6143d7d","state":"completed","createdAt":"2026-10-02T19:36:43.851Z"},{"jobId":"3ab3b083-4df1-427f-aea1-d797cb75c60f","workflowId":null,"objective":"Make the SDK's types real and its source readable. package.json and package-lock.json are protected and cannot be changed by any task, so add no dependency and no build tool. 1 Types: the hand-written src/index.d.ts returns Promise<any> from all 10 client methods. Declare a typed result for every method  (Capabilities, CheckResult, Order and OrderStatus, Challenge, Job, Schedule) taken from the live GET https://api.imd.fun/openapi.json schemas and the live GET /requests/capabilities body, and export those interfaces. 2 Add a test that loads saved copies of those live bodies and asserts every field the declarations mark as required is present, so the types cannot drift from the live API unnoticed. 3 Signer: the client already accepts any viem Account. Add a README section and an example (examples/viem-signer.mjs) showing a viem privateKeyToAccount account as the recommended signer, installed by the user; keep LocalPrivateKeySigner as the built-in default. 4 Reformat src/index.js, src/crypto.js and src/cli.js into normal readable code (no lines over 120 characters) without changing behaviour. 5 In README and CHANGELOG, say the package.json exports map from audit finding 10 cannot be added because package.json is protected on the platform. Keep the public API, CLI commands, dry-run and caps defaults, and all 11 audit-fix regression tests passing. Verify against the LIVE API at https://api.imd.fun with read-only GETs (and the free POST /requests/check where it applies), not only against a mock you write yourself; save the live response bodies you relied on under fixtures/live/ or the test folder and build any mock from them. Add a CHANGELOG.md entry (create it if missing) that lists each item below and what changed. Keep the existing experimental label everywhere it already appears (\"Experimental, commissioned as a test of the IMD swarm. It may not work as described. Read the code, start with small amounts, no warranty.\").","baseCommit":"31ac14900f9aa78bd2072dd4935b9eba5e4d1a4c","state":"completed","createdAt":"2026-10-02T21:50:13.694Z"},{"jobId":"9e64afd7-8d46-4e89-a4a7-0df99e00cc26","workflowId":null,"objective":"Two gaps from the last version. 1 Safety: examples/viem-signer.mjs (around line 20) calls pay(..., { execute: true }), so running the example as written makes a real IMD payment.  Make it dry-run by default; only pay when the user sets IMD_EXECUTE=1 in the environment, print a clear warning before paying, and say so in the README section. 2 Types: the live POST /requests/check response for a schedule.create body has no kind, plan, facts or judged, and returns unitAmount, runs, amount and terms instead, so the drift test fails on it.  In src/index.d.ts make CheckResult.kind, plan, facts and judged optional and add optional unitAmount, runs, amount and terms (or a separate ScheduleCheckResult union member).  Save a live schedule.create check body (7 runs) next to the other live fixtures and add it to the drift test. Keep all existing tests passing and change no payment, retry or cap behaviour. Verify against the LIVE API at https://api.imd.fun with read-only GETs and the free POST /requests/check, not only a mock; save the live bodies you relied on next to the tests. Add a CHANGELOG.md entry listing each item and what changed. Keep the existing experimental label everywhere it already appears.","baseCommit":"78cc6ca1c167b96b49200f286ddf793d1f9fa25b","state":"completed","createdAt":"2026-10-02T23:43:43.232Z"}]},"deliver":true,"host":false,"site":null,"launch":{"requested":false,"kind":null,"id":null,"status":null,"chainId":null},"oracleRequestId":null,"delivery":{"repoUrl":"https://github.com/identity-md-launches/launch-601-build-imd-sdk-typed-typescript","pullRequestUrl":"https://github.com/identity-md-launches/launch-601-build-imd-sdk-typed-typescript/pull/4","commit":"87257e089effcbcc2c2d755265fc1f30795ccad8","deliveredAt":"2026-10-02T23:50:38.182Z","media":null},"media":null,"nodes":[{"key":"adversarial_review","role":"review","state":"accepted","attempt":1,"revisions":0,"judgeRevisions":0,"dependsOn":["refine_project"],"allowedPaths":[],"failureReason":null,"dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-02T23:50:10.112Z","verdict":null,"seat":{"tokenId":"6","agentId":"51018"},"live":null},{"key":"refine_project","role":"implement","state":"accepted","attempt":1,"revisions":0,"judgeRevisions":0,"dependsOn":[],"allowedPaths":["src/**","test/**","dist/**","examples/**","README.md","CHANGELOG.md"],"failureReason":null,"dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-02T23:45:08.387Z","verdict":{"status":"accepted","profile":"none","evaluation":"structural","rejectionCode":null,"detail":"paths and tree verified; no suite was run for this kind of work","verifierVersion":"0.1.0+b537d296","verifiedTreeHash":"18d60b8b336efa953250e12c63508e1dc2531058","at":"2026-10-02T23:45:08.388Z","failedChecks":[]},"seat":{"tokenId":"1113","agentId":"51250"},"live":null}],"reviews":[{"status":"sent","chainId":1,"txHash":"0xae02ce89e39cc24717ed8ad503cb8dd008e44fe5942fd610e431c8c6c08e6f54","blockNumber":26115032,"sentAt":"2026-10-03T23:14:29.729Z","entries":[{"nodeKey":"adversarial_review","agentId":"51018","value":1,"role":"review:submission"},{"nodeKey":"refine_project","agentId":"51250","value":1,"role":"verification:structural"}]}]}