Skip to content

Project Setup

An ADL project is any directory with adl.config.* at its root — that’s the one thing the CLI, inspection UI, and loadAdlProject() all need to find it. The recommended way to create one is adl init, which scaffolds everything below for you.

Adding ADL to an existing project instead, or want to know exactly what’s required versus just conventional? See Manual Setup.

Terminal window
bunx @agent-dev-lab/cli@latest init my-research
# or: npx @agent-dev-lab/cli@latest init my-research
cd my-research
bun install
cp .env.example .env # then set OPENAI_API_KEY
Terminal window
bunx adl workflow list
bunx adl agent list
bunx adl agent run assistant --input "What is Agent Dev Lab?"
bunx adl workflow run demo-counter --input '{"steps":3}'
bunx adl workflow run ask --input '{"question":"What is Agent Dev Lab?"}'
bunx adl dashboard
  • adl init — scaffolds a project with SQLite-backed src/adl.ts, a README and tsconfig, demo-counter, a sample ask workflow, and @agent-dev-lab/web for adl dashboard.
  • adl workflow run (adl w run) — loadAdlProject()getWorkflow(id).run(input)
  • adl agent run (adl a run) — loadAdlProject()getAgent(id).run({ user }) (--input is a string, not JSON)
  • adl dashboardinspection UI; sets ADL_PROJECT_ROOT. Registry edits (agents, workflows, templates) hot-reload; restart after .env* edits, or when running --serve, which doesn’t watch at all.
my-research/
package.json # imports["#adl"] → ./src/adl.ts
tsconfig.json # paths["#adl"] → ./src/adl.ts
adl.config.ts # registry + metadata; sets config.adl
.env.example
src/
adl.ts # createAdlRuntime() — recommended runtime module
model.ts
agents/
assistant.ts
workflows/
demo-counter.ts
ask.ts
PieceRole
adl.config.tsRegistry (agents[], workflows[], …) and adl reference for tooling
src/adl.tscreateAdlRuntime({ stores, observers }) — keeps config free of store wiring
#adl aliasRegistry modules import { adl } from "#adl" instead of a relative path

That’s the recommended layout, not a requirement — see Manual Setup for the minimum ADL actually needs and how the pieces wire together, useful if you’re restructuring or adding ADL to an existing project.

loadAdlProject() (and the inspection UI / CLI, which all go through it) loads .env* files from the ADL project root — the directory that contains adl.config.*, not the process cwd.

Direct #adl imports (for example bun run start) should call loadAdlEnv() before reading process.env at module load — the scaffold does this in src/model.ts. createAdlRuntime({ loadEnv }) also loads env by default (false to opt out).

Precedence matches Next.js (highest first). Values already set in the process environment are never overwritten:

FileWhen it loads
.env.[mode].localAlways, for that mode
.env.localAll modes except test
.env.[mode]development, production, or test
.envAlways

mode is NODE_ENV when it is development / production / test, otherwise development (so adl workflow run still loads .env.local). Variable expansion ($VAR, ${VAR}) is supported.

Put provider keys in .env or .env.local at the project root:

Terminal window
OPENAI_API_KEY=sk-...
ADL_MODEL=gpt-4o-mini
VariablePurpose
OPENAI_API_KEYProvider key for @ai-sdk/openai (sample agent)
ADL_SQLITE_PATHSQLite file; relative paths resolve from the project root
ADL_PROJECT_ROOTOverride project discovery
DEBUG=adlPrint CLI stack traces

ADL_MODEL isn’t one of these — the framework doesn’t read it. It’s used in the scaffold’s own src/model.ts to set ADL’s default model.

See Project Config and Runtime for API detail.

adl.createTemplate renders markdown with Handlebars after Zod validates the input. Use {{var}}, {{#each}}, and friends. File templates need from: import.meta.url so relative paths resolve.

See Gotchas for sharp edges worth knowing about before they surprise you.