Lucid Agents v3 runtime migration
Move from adapter-owned application behavior to extension-owned runtime contracts.
Lucid Agents v3 in this repository makes the completed runtime the single owner of entrypoints, HTTP authorization, payments, tasks, and manifest composition. The public Stable channel remains v2.5.0 until the v3 package set is published.
Migrate in a branch with a pinned lockfile. Do not upgrade one package at a time across Stable and Next.
Before you change code
Inventory:
- every
@lucid-agents/*and x402 dependency/version; - adapter-local route, paywall, manifest, entrypoint, and task code;
- public base paths and Agent Card URLs;
- wallet/payment/identity environment variables;
- payment, SIWX, idempotency, task, and scheduler storage;
- client retry keys and expected error bodies; and
- on-chain/provider side effects that cannot be rolled back.
Capture a v2 contract test for health, discovery, free invoke, unpaid 402,
paid result/receipt, stream envelopes, and any task/client behavior before
changing the implementation.
Build one runtime
import { a2a } from '@lucid-agents/a2a';
import { createAgent } from '@lucid-agents/core';
import { http } from '@lucid-agents/http';
import { payments, paymentsFromEnv } from '@lucid-agents/payments';
const paymentConfig = paymentsFromEnv();
if (!paymentConfig) throw new Error('Payment configuration is required');
const runtime = await createAgent(meta)
.use(payments({ config: paymentConfig }))
.use(
a2a({
tasks: { store: taskStore },
})
)
.use(
http({ basePath: '/api/agent', idempotency: { store: idempotencyStore } })
)
.build();Register capabilities through runtime.entrypoints.add() or on the builder
before build(). Adapter addEntrypoint helpers delegate to this registry for
compatibility. Duplicate keys now fail at the canonical registry and dynamic
additions invalidate manifest caches.
Delegate framework routes
- Hono and Express bind
runtime.http.routes. - TanStack and generated Next.js modules delegate to
runtime.http.handlers. - Remove adapter-local paywalls, task stores, manifests, and registries.
- Preserve the original request body/headers; do not run a body parser or second x402 middleware before the canonical handler.
Compare the public route plan and Agent Card before and after migration, including configured base paths and compatibility discovery aliases.
Move configuration to owning extensions
Use paymentsFromEnv(), walletsFromEnv(), identityFromEnv(), and
mppFromEnv() deliberately. There is no global runtime config merge. Prices
stay on entrypoints as USD decimal strings and one priced entrypoint selects
one payment rail.
The current environment/alias matrix is documented in Environment variables. Remove obsolete generic price/private-key variables only after updating deployment secrets.
Use server-only subpaths
Portable imports stay at package roots. Node-only storage and provider drivers use their declared subpaths, for example:
import { createPostgresPaymentStorage } from '@lucid-agents/payments/storage/postgres';
import { createSQLitePaymentStorage } from '@lucid-agents/payments/storage/sqlite';Payment, SIWX, x402 batch channels, MPP challenges, and Tempo sessions have shipped SQLite/Postgres adapters. HTTP idempotency, Lucid tasks, and scheduler state still require custom durable ports. Do not translate a v2 database setting into an adapter that the owning package does not export.
Review protocol changes separately
- x402 is v2 fixed-price
exact; follow the separate x402 v2 migration. - Lucid Agent Cards/tasks are not the official A2A v1 binding.
- AP2 currently emits v0.1 role metadata only, while upstream has moved.
- ERC-8004 remains Draft and validation is not initialized by default.
- MPP is an active individual Internet-Draft subset tied to the repository's
mppxversion.
Do not combine a runtime migration with an interoperability claim unless the corresponding protocol tests pass.
Verify the migration
Run:
- clean install, package type-check, unit tests, and build;
- adapter contract tests for every deployed framework;
- health/card/entrypoint snapshot comparison;
- free invoke plus invalid input/output errors;
- unpaid
402, paid settlement, same-key replay, and wrong-key conflict; - stream admission, disconnect, and terminal envelope behavior;
- task ownership, cancellation, worker crash, and lease recovery;
- process restart/new replica with every durable state surface; and
runtime.close()resource disposal during graceful shutdown.
Test a low-limit testnet canary through the production proxy and reconcile the output, receipt/transaction, and durable record.
Rollout and rollback
Use expand/contract storage changes so v2 and v3 can coexist during a canary. Keep the prior immutable build and its secret/config set. Route only a small allowlisted capability to v3, stop new paid admission on a mismatch, preserve staged settlements and idempotency records, then reconcile before routing back.
Rollback cannot undo an on-chain settlement or identity registration. Do not drop new storage columns/records until the maximum retry, task-retention, and reconciliation windows have expired.
See Release channels, Configuration, and the production checklist.