Configuration
Understand your project structure and configure your agent in agent.config.ts.
Project structure
Here are the key files in your project after running adk init:
src
actions
conversations
knowledge
tables
triggers
workflows
evals
The ADK scans src/ and discovers primitives automatically. Each file exports a primitive (a Conversation, Workflow, Action, and so on) and the framework registers it at build time.
agent.json links your project to its production bot. A gitignored agent.local.json is added for your development bot the first time you run adk dev. See Project setup for how those work.
agent.config.ts
You configure your agent in agent.config.ts by calling defineConfig:
import { z, defineConfig } from '@botpress/runtime'
export default defineConfig({
// Identity
name: 'my-agent',
description: 'An AI agent built with Botpress ADK',
// LLM models
defaultModels: {
autonomous: 'cerebras:gpt-oss-120b',
zai: 'cerebras:gpt-oss-120b',
},
// Persistent state
bot: {
state: z.object({}),
},
user: {
state: z.object({}),
},
// Sensitive values (API keys, tokens)
secrets: {},
// Static, deploy-time settings
configuration: {
schema: z.object({}),
},
// Custom events
events: {},
// Test settings
evals: {},
})
Integrations aren’t declared here in ADK 2.0. You manage them with the adk integrations and adk plugins commands instead. See Managing dependencies.
Models
The defaultModels field controls which LLM your agent uses:
defaultModels: {
autonomous: "cerebras:gpt-oss-120b",
zai: "cerebras:gpt-oss-120b",
},
| Model | Used by |
|---|---|
autonomous | execute() calls in conversations and workflows |
zai | Zai operations like zai.extract(), zai.check(), zai.text() |
If you don’t set defaultModels, the ADK uses auto and lets the platform pick a default model for you.
You can pass an array of models for fallback. If the first model fails, the next one is tried:
defaultModels: {
autonomous: ["cerebras:gpt-oss-120b", "openai:gpt-4.1-2025-04-14"],
},
You can also set models from the Dev Console under Settings > LLM Config, or override the model on a single execute() call:
await execute({
model: 'openai:gpt-4.1-2025-04-14',
instructions: 'You are a helpful assistant.',
})
State
The state field defines schemas for data your agent persists. There are two scopes:
| Scope | Persists across | Use for |
|---|---|---|
bot | All conversations and users | Global counters, shared config |
user | All conversations for a given user | Preferences, profile data |
Define state with Zod. The ADK generates TypeScript types from your schemas, so state access is fully typed. Use .default() to set initial values:
bot: {
state: z.object({
totalConversations: z.number().default(0),
}),
},
user: {
state: z.object({
name: z.string().optional().describe("The user's name"),
preferredLanguage: z.string().default("en"),
}),
},
For reading and writing state at runtime, see Manage state.
Tags
Tags are metadata you can attach to bots, users, conversations, messages, and workflows. Declare them per scope:
bot: {
tags: {
plan: { title: "Plan", description: "free or paid" },
},
},
conversation: {
tags: {
priority: { title: "Priority" },
},
},
Tags are useful for filtering and organizing data on the Botpress platform.
Secrets
Secrets store sensitive values like API keys and tokens. You declare them in agent.config.ts, but their values are stored separately and never committed to version control:
secrets: {
STRIPE_KEY: { description: "Stripe API key" },
SENTRY_DSN: { optional: true, description: "Error tracking DSN" },
},
Required secrets, which are the default, must be set before adk dev or adk deploy can start the bot. Optional secrets never block startup or deployment. If a required secret is added while the dev server is already running, the ADK warns until you set it.
Setting values
Set values with adk secret:set. Development and production keep separate values, so your dev keys never reach production:
adk secret:set STRIPE_KEY "sk-test-..." # development value
adk secret:set STRIPE_KEY "sk-live-..." --prod # production value
You can also manage secrets in the Dev Console under Settings > Secrets, for both development and production. Adding or removing a secret here writes the declaration back to agent.config.ts.
Using secrets at runtime
Import secrets from @botpress/runtime and reference them directly:
import { secrets } from '@botpress/runtime'
const res = await fetch('https://api.stripe.com/v1/charges', {
headers: { Authorization: `Bearer ${secrets.STRIPE_KEY}` },
})
if (secrets.SENTRY_DSN) {
Sentry.init({ dsn: secrets.SENTRY_DSN })
}
The secrets import is a typed proxy: required secrets are typed as string, optional ones as string | undefined.
Secret keys must be SCREAMING_SNAKE_CASE, start with an uppercase letter, be at least two characters, have no trailing underscore, and not start with the reserved prefixes SECRET_, BP_, or BOTPRESS_.
Configuration values
The configuration field defines static, deploy-time settings. Unlike secrets, these aren’t sensitive. Unlike state, they’re read-only at runtime:
configuration: {
schema: z.object({
supportEmail: z.string().default("help@example.com"),
maxRetries: z.number().default(3),
enableBeta: z.boolean().default(false),
}),
},
Set values from the CLI, with separate development and production values:
adk config # fill missing values interactively
adk config:set supportEmail "help@mycompany.com" # development value
adk config:set supportEmail "help@mycompany.com" --prod # production value
adk config:get supportEmail # read a value
You can also edit these in the Dev Console:
Read configuration at runtime the same way as secrets:
import { configuration } from '@botpress/runtime'
const email = configuration.supportEmail
const retries = configuration.maxRetries
Custom events
The events field defines custom events your agent can emit and subscribe to:
events: {
orderPlaced: {
description: "Fired when an order is placed",
schema: z.object({
orderId: z.string().describe("The placed order's ID"),
total: z.number().describe('Order total in USD'),
}),
},
},
You can then listen for these events in triggers and conversations. See Set up triggers.
Evals
The evals field configures how your agent’s automated tests run:
evals: {
idleTimeout: 30000,
judgeModel: "openai:gpt-4o",
},
| Field | Description |
|---|---|
idleTimeout | Milliseconds to wait for the agent to respond before timing out |
judgeModel | Model used for LLM judge assertions |