Lucid Agents
Getting Started

Quickstart

Build and run your first Lucid agent in 5 minutes.

This guide walks you through creating a working agent in under 5 minutes.

Create your agent

Run the CLI to scaffold a new project:

bunx @lucid-agents/cli my-agent

Select the following options when prompted:

  1. Adapter: hono (lightweight HTTP server)
  2. Template: blank (minimal starter)
  3. Configuration: Enter your agent name and description

Or use inline configuration:

bunx @lucid-agents/cli my-agent \
  --adapter=hono \
  --template=blank \
  --AGENT_NAME="My First Agent"

Start the development server

cd my-agent
bun run dev

Your agent is now running at http://localhost:3000.

Test your agent

Open a new terminal and try these commands:

View the agent manifest

curl http://localhost:3000/.well-known/agent.json

This returns the Agent Card describing your agent's capabilities, entrypoints, and metadata.

List available entrypoints

curl http://localhost:3000/entrypoints

Invoke an entrypoint

For the blank template, invoke the echo entrypoint:

curl -X POST http://localhost:3000/entrypoints/echo/invoke \
  -H "Content-Type: application/json" \
  -d '{"input": {"text": "Hello, Lucid Agents!"}}'

Understanding the project structure

The CLI generates a project with this structure:

my-agent/
├── src/
│   ├── agent.ts        # Agent definition and entrypoints
│   └── index.ts        # HTTP server bootstrap
├── .env                # Environment variables
├── package.json
└── tsconfig.json

Open src/agent.ts to see your agent definition:

src/agent.ts
import { z } from 'zod';
import { createAgent } from '@lucid-agents/core';
import { http } from '@lucid-agents/http';
import { payments, paymentsFromEnv } from '@lucid-agents/payments';

const agent = await createAgent({
  name: process.env.AGENT_NAME ?? 'my-agent',
  version: process.env.AGENT_VERSION ?? '0.1.0',
  description: process.env.AGENT_DESCRIPTION,
})
  .use(http())
  .use(payments({ config: paymentsFromEnv() }))
  .build();

agent.entrypoints.add({
  key: 'echo',
  description: 'Echo back a message',
  input: z.object({
    text: z.string(),
  }),
  output: z.object({
    echoed: z.string(),
    timestamp: z.string(),
  }),
  async handler({ input }) {
    return {
      output: {
        echoed: input.text,
        timestamp: new Date().toISOString(),
      },
    };
  },
});

Add a streaming entrypoint

You can add streaming behavior after the scaffold is up. Add this after the existing entrypoint:

src/agent.ts
agent.entrypoints.add({
  key: 'status-stream',
  description: 'Streams a few status updates',
  input: z.object({
    topic: z.string(),
  }),
  output: z.object({
    completed: z.boolean(),
  }),
  streaming: true,
  async stream({ input }, emit) {
    await emit({
      kind: 'delta',
      delta: `Starting work on ${input.topic}\n`,
      mime: 'text/plain',
    });
    await emit({
      kind: 'delta',
      delta: 'Still working...\n',
      mime: 'text/plain',
    });
    return { output: { completed: true } };
  },
});

Test it:

curl -X POST http://localhost:3000/entrypoints/status-stream/stream \
  -H "Content-Type: application/json" \
  -d '{"input": {"topic": "a quick demo"}}'

Response events will stream over Server-Sent Events, followed by the final result payload.

What's next?

You now have a working agent. From here you can:

When you're ready to add more capabilities:

On this page