Publish a catalog
Register many typed offerings from reviewed YAML or CSV on the Next SDK surface.
@lucid-agents/catalog turns a YAML or CSV file into canonical Lucid
entrypoints. Use it when many offerings share one handler shape and differ in
key, description, price, network, protocol, or metadata.
The package is currently available from this repository, not the Stable npm channel. A Lucid catalog is local application configuration: it does not publish to x402 Bazaar, register an ERC-8004 identity, or create a marketplace.
Define reviewed catalog data
products:
- key: sentiment
name: Sentiment analysis
description: Classify bounded text as positive, negative, or neutral
price: '0.05'
network: 'eip155:84532'
paymentProtocol: x402
metadata:
tier: basic
- key: summarize
name: Summary
description: Return or stream a bounded summary
price:
invoke: '0.10'
stream: '0.15'YAML accepts either a top-level array or a products array. CSV requires a
key column and supports key, name, description, price, network,
paymentProtocol, plus meta_* columns. CSV currently represents only a flat
price; use YAML for separate invoke/stream prices.
Prices are USD decimal strings. Use canonical CAIP-2 network identifiers and
explicitly select x402 or mpp when both rails exist.
Register through the Node-only extension
The file-loading extension uses fs, so import it from the Node subpath:
import type { CatalogItem, HandlerFactory } from '@lucid-agents/catalog';
import { catalog } from '@lucid-agents/catalog/node';
import { fileURLToPath } from 'node:url';
const handlerFactory: HandlerFactory = (item: CatalogItem) => {
return async ({ input }) => ({
output: await fulfillCatalogItem(item, input),
});
};
const runtime = await createAgent(meta)
.use(payments({ config }))
.use(
catalog({
file: fileURLToPath(new URL('./products.yaml', import.meta.url)),
keyPrefix: 'store/',
paymentProtocol: 'x402',
inputSchema: z.object({
params: z.record(z.string(), z.unknown()).optional(),
}),
handlerFactory,
})
)
.use(http())
.build();The extension parses during build and registers generated definitions during
initialization. runtime.catalog?.items exposes the parsed records. If you need
portable/browser parsing, use parseCatalogYaml(), parseCatalogCsv(), and
generateEntrypoints() from the package root and provide the file contents
yourself.
Validation and change control
The built-in schema requires key and name, but application correctness
needs more:
- reject duplicate or route-unsafe keys before deployment;
- require descriptions and bounded input/output schemas for public offerings;
- verify every priced item has an installed matching payment rail, network, destination, and facilitator method;
- treat price, network, protocol, key, and output changes as commercial API changes requiring review;
- sign or review catalog artifacts if they come from another system; and
- keep environment-specific secrets out of catalog metadata.
Do not allow an untrusted tenant to choose arbitrary handler identifiers, recipient addresses, module paths, or outbound URLs through metadata.
Verify generated offerings
In CI, load the production catalog and assert:
- parsing succeeds and keys are unique;
- the expected entrypoint count and key set are present;
- every item appears once in the Agent Card/storefront;
- free items invoke successfully;
- priced items return the expected unpaid
402/MPP challenge; - one low-limit testnet item completes and reconciles; and
- a removed or renamed item follows a documented deprecation plan.
Catalog loading is startup-time, not a live control plane. A file change does not update a running process unless your application rebuilds/restarts it.
See the full catalog package reference, service storefront, and x402 support matrix.