@lucid-agents/core
Protocol-agnostic agent runtime with a dependency-ordered extension system.
@lucid-agents/core owns agent metadata, the canonical entrypoint registry,
manifest composition, and extension lifecycle. Protocol capabilities such as
HTTP, payments, identity, and A2A are installed as separate extensions.
Installation
bun add @lucid-agents/core @lucid-agents/httpBasic usage
import { createAgent } from '@lucid-agents/core';
import { http } from '@lucid-agents/http';
import { z } from 'zod';
const runtime = await createAgent({
name: 'my-agent',
version: '1.0.0',
description: 'An AI-powered assistant',
})
.use(http())
.addEntrypoint({
key: 'echo',
input: z.object({ text: z.string() }),
handler: async ctx => ({ output: { text: ctx.input.text } }),
})
.build();Runtime contract
Every built runtime exposes the protocol-neutral core services. Extensions add their own typed slices directly to the same object.
runtime.agent; // metadata and canonical registry controller
runtime.entrypoints.add(...);
runtime.entrypoints.list(); // serializable entrypoint summaries
runtime.entrypoints.snapshot();
runtime.manifest.build('https://agent.example.com');
await runtime.close();
runtime.http.handlers; // contributed by http()
runtime.http.routes; // canonical adapter-neutral route plan
runtime.payments; // contributed by payments()runtime.agent.config.meta contains the metadata passed to createAgent.
Use runtime.entrypoints for registration and discovery; protocol adapters do
not maintain separate registries.
AgentBuilder
createAgent(meta) returns an AgentBuilder with three primary operations:
const builder = createAgent(meta)
.use(extension)
.addEntrypoint(definition);
const runtime = await builder.build();use(extension)adds a typed runtime capability.addEntrypoint(definition)queues an entrypoint before build.build()orders extensions, initializes them, registers queued entrypoints, and returns the completed runtime.
Extension lifecycle
Extensions declare hard dependencies with requires and optional ordering with
before or after. The builder topologically orders them and rejects missing
dependencies, cycles, duplicate names, and runtime-property collisions.
import type { Extension } from '@lucid-agents/types/core';
const metrics = (): Extension<{ metrics: { count: () => number } }> => ({
name: 'metrics',
after: ['http'],
build: () => ({ metrics: { count: () => 0 } }),
initialize: async runtime => {
// All runtime slices are available here.
},
onEntrypointAdded: (entrypoint, runtime) => {
// React to both queued and dynamically added entrypoints.
},
onManifestBuild: (manifest, runtime) => manifest,
dispose: async runtime => {
// Released once, in reverse dependency order, by runtime.close().
},
});If build or initialization fails, already-built extensions are disposed in reverse order before the error is returned.
Entrypoints
Entrypoints can be registered before or after build:
runtime.entrypoints.add({
key: 'status-stream',
async stream(ctx, emit) {
await emit({
kind: 'delta',
delta: `Starting ${ctx.input.topic}\n`,
mime: 'text/plain',
});
return { output: { completed: true } };
},
});Duplicate keys are rejected by the single core registry. Adding an entrypoint also invalidates the manifest cache and notifies installed extensions.
Public exports
export {
AgentBuilder,
buildAgentManifest,
createAgent,
validateAgentMetadata,
} from '@lucid-agents/core';
export type {
AgentConfig,
EntrypointDef,
EntrypointHandler,
EntrypointStreamHandler,
StreamEnvelope,
StreamPushEnvelope,
StreamResult,
} from '@lucid-agents/core';Shared runtime, manifest, and extension contracts live at
@lucid-agents/types/core; AgentCore and createAgentCore are not public
core-package exports.