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
index.ts
conversations
index.ts
knowledge
index.ts
tables
index.ts
triggers
index.ts
workflows
index.ts
evals
index.eval.ts
agent.config.ts
agent.json

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: {},
})

Models

The defaultModels field controls which LLM your agent uses:

defaultModels: {
  autonomous: "cerebras:gpt-oss-120b",
  zai: "cerebras:gpt-oss-120b",
},
ModelUsed by
autonomousexecute() calls in conversations and workflows
zaiZai 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:

ScopePersists acrossUse for
botAll conversations and usersGlobal counters, shared config
userAll conversations for a given userPreferences, 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"),
  }),
},

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.

Secrets in the Dev Console

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:

Configuration values 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",
},
FieldDescription
idleTimeoutMilliseconds to wait for the agent to respond before timing out
judgeModelModel used for LLM judge assertions