* docs: add multi-agent configuration reference Document the agents[] YAML config, per-agent options, migration path from single to multi-agent, and known limitations (#219, #220, #221). Written by Cameron ◯ Letta Code "Documentation is a love letter that you write to your future self." -- Damian Conway * docs: fix channels required claim and soften isolation wording - channels is not strictly required per-agent (validation is global) - isolation has known exceptions, don't claim "fully isolated" Written by Cameron ◯ Letta Code "Clear is kind." -- Brene Brown
11 KiB
Configuration Reference
Complete reference for LettaBot configuration options.
Config File Locations
LettaBot checks these locations in order:
LETTABOT_CONFIGenv var - Explicit path override./lettabot.yaml- Project-local (recommended)./lettabot.yml- Project-local alternate~/.lettabot/config.yaml- User global~/.lettabot/config.yml- User global alternate
For global installs (npm install -g), either:
- Create
~/.lettabot/config.yaml, or - Set
export LETTABOT_CONFIG=/path/to/your/config.yaml
Example Configuration
# Server connection
server:
mode: cloud # 'cloud' or 'selfhosted'
apiKey: letta_... # Required for cloud mode
# Agent settings (single agent mode)
# For multiple agents, use `agents:` array instead -- see Multi-Agent section
agent:
name: LettaBot
model: claude-sonnet-4
# id: agent-... # Optional: use existing agent
# Channel configurations
channels:
telegram:
enabled: true
token: "123456:ABC-DEF..."
dmPolicy: pairing
slack:
enabled: true
botToken: xoxb-...
appToken: xapp-...
dmPolicy: pairing
discord:
enabled: true
token: "..."
dmPolicy: pairing
whatsapp:
enabled: true
selfChat: true # IMPORTANT: true for personal numbers
dmPolicy: pairing
signal:
enabled: true
phone: "+1234567890"
selfChat: true
dmPolicy: pairing
# Features
features:
cron: true
heartbeat:
enabled: true
intervalMin: 60
# Polling (background checks for Gmail, etc.)
polling:
enabled: true
intervalMs: 60000 # Check every 60 seconds
gmail:
enabled: true
account: user@example.com
# Voice transcription
transcription:
provider: openai
apiKey: sk-... # Optional: falls back to OPENAI_API_KEY
model: whisper-1
# Attachment handling
attachments:
maxMB: 20
maxAgeDays: 14
# API server (health checks, CLI messaging)
api:
port: 8080 # Default: 8080 (or PORT env var)
# host: 0.0.0.0 # Uncomment for Docker/Railway
# corsOrigin: https://my.app # Uncomment for cross-origin access
Server Configuration
| Option | Type | Description |
|---|---|---|
server.mode |
'cloud' | 'selfhosted' |
Connection mode |
server.apiKey |
string | API key for Letta Cloud |
server.baseUrl |
string | URL for self-hosted server (e.g., http://localhost:8283) |
Self-Hosted Mode
server:
mode: selfhosted
baseUrl: http://localhost:8283
Run Letta server with Docker:
docker run -v ~/.letta/.persist/pgdata:/var/lib/postgresql/data \
-p 8283:8283 \
-e OPENAI_API_KEY="..." \
letta/letta:latest
Agent Configuration (Single Agent)
The default config uses agent: and channels: at the top level for a single agent:
| Option | Type | Description |
|---|---|---|
agent.id |
string | Use existing agent (skips creation) |
agent.name |
string | Name for new agent |
agent.model |
string | Model ID (e.g., claude-sonnet-4) |
For multiple agents, see Multi-Agent Configuration below.
Multi-Agent Configuration
Run multiple independent agents from a single LettaBot instance. Each agent gets its own channels, state, cron, heartbeat, and polling services.
Use the agents: array instead of the top-level agent: and channels: keys:
server:
mode: cloud
apiKey: letta_...
agents:
- name: work-assistant
model: claude-sonnet-4
# id: agent-abc123 # Optional: use existing agent
channels:
telegram:
token: ${WORK_TELEGRAM_TOKEN}
dmPolicy: pairing
slack:
botToken: ${SLACK_BOT_TOKEN}
appToken: ${SLACK_APP_TOKEN}
features:
cron: true
heartbeat:
enabled: true
intervalMin: 30
- name: personal-assistant
model: claude-sonnet-4
channels:
signal:
phone: "+1234567890"
selfChat: true
whatsapp:
enabled: true
selfChat: true
features:
heartbeat:
enabled: true
intervalMin: 60
Per-Agent Options
Each entry in agents: accepts:
| Option | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Agent name (used for display, creation, and state isolation) |
id |
string | No | Use existing agent ID (skips creation) |
model |
string | No | Model for agent creation |
channels |
object | No | Channel configs (same schema as top-level channels:). At least one agent must have channels. |
features |
object | No | Per-agent features (cron, heartbeat, maxToolCalls) |
polling |
object | No | Per-agent polling config (Gmail, etc.) |
integrations |
object | No | Per-agent integrations (Google, etc.) |
How it works
- Each agent is a separate Letta agent with its own conversation history and memory
- Agents have isolated state, channels, and services (see known limitations for exceptions)
- The
LettaGatewayorchestrates startup, shutdown, and message delivery across agents - Legacy single-agent configs (
agent:+channels:) continue to work unchanged
Migrating from single to multi-agent
Your existing config:
agent:
name: MyBot
channels:
telegram:
token: "..."
features:
cron: true
Becomes:
agents:
- name: MyBot
channels:
telegram:
token: "..."
features:
cron: true
The server:, transcription:, attachments:, and api: sections remain at the top level (shared across all agents).
Known limitations
- Two agents cannot share the same channel type without ambiguous API routing (#219)
- WhatsApp/Signal session paths are not yet agent-scoped (#220)
- Heartbeat prompt and target are not yet configurable per-agent (#221)
Channel Configuration
All channels share these common options:
| Option | Type | Description |
|---|---|---|
enabled |
boolean | Enable this channel |
dmPolicy |
'pairing' | 'allowlist' | 'open' |
Access control mode |
allowedUsers |
string[] | User IDs/numbers for allowlist mode |
DM Policies
Note: For WhatsApp/Signal with selfChat: true (personal number), dmPolicy is ignored - only you can message via "Message Yourself" / "Note to Self".
For dedicated bot numbers (selfChat: false), onboarding defaults to allowlist:
allowlist(default for dedicated numbers): Only specified phone numbers can messagepairing: New users get a code, approve withlettabot pairing approveopen: Anyone can message (not recommended)
Channel-Specific Options
Telegram
| Option | Type | Description |
|---|---|---|
token |
string | Bot token from @BotFather |
Slack
| Option | Type | Description |
|---|---|---|
botToken |
string | Bot User OAuth Token (xoxb-...) |
appToken |
string | App-Level Token (xapp-...) for Socket Mode |
Discord
| Option | Type | Description |
|---|---|---|
token |
string | Bot token from Discord Developer Portal |
| Option | Type | Description |
|---|---|---|
selfChat |
boolean | Critical: true = only "Message Yourself" works |
Signal
| Option | Type | Description |
|---|---|---|
phone |
string | Phone number with + prefix |
selfChat |
boolean | true = only "Note to Self" works |
Features Configuration
Heartbeat
features:
heartbeat:
enabled: true
intervalMin: 60 # Check every 60 minutes
Heartbeats are background tasks where the agent can review pending work.
Cron Jobs
features:
cron: true
Enable scheduled tasks. See Cron Setup.
Polling Configuration
Background polling for integrations like Gmail. Runs independently of agent cron jobs.
polling:
enabled: true # Master switch (default: auto-detected from sub-configs)
intervalMs: 60000 # Check every 60 seconds (default: 60000)
gmail:
enabled: true
account: user@example.com # Gmail account to poll
| Option | Type | Default | Description |
|---|---|---|---|
polling.enabled |
boolean | auto | Master switch. Defaults to true if any sub-config is enabled |
polling.intervalMs |
number | 60000 |
Polling interval in milliseconds |
polling.gmail.enabled |
boolean | auto | Enable Gmail polling. Auto-detected from account |
polling.gmail.account |
string | - | Gmail account to poll for unread messages |
Legacy config path
For backward compatibility, Gmail polling can also be configured under integrations.google:
integrations:
google:
enabled: true
account: user@example.com
pollIntervalSec: 60
The top-level polling section takes priority if both are present.
Environment variable fallback
| Env Variable | Polling Config Equivalent |
|---|---|
GMAIL_ACCOUNT |
polling.gmail.account |
POLLING_INTERVAL_MS |
polling.intervalMs |
PORT |
api.port |
API_HOST |
api.host |
API_CORS_ORIGIN |
api.corsOrigin |
Transcription Configuration
Voice message transcription via OpenAI Whisper:
transcription:
provider: openai
apiKey: sk-... # Optional: uses OPENAI_API_KEY env var
model: whisper-1 # Default
Attachments Configuration
attachments:
maxMB: 20 # Max file size to download (default: 20)
maxAgeDays: 14 # Auto-delete after N days (default: 14)
Attachments are stored in /tmp/lettabot/attachments/.
API Server Configuration
The built-in API server provides health checks and CLI messaging endpoints.
api:
port: 9090 # Default: 8080
host: 0.0.0.0 # Default: 127.0.0.1 (localhost only)
corsOrigin: "*" # Default: same-origin only
| Option | Type | Default | Description |
|---|---|---|---|
api.port |
number | 8080 |
Port for the API/health server |
api.host |
string | 127.0.0.1 |
Bind address. Use 0.0.0.0 for Docker/Railway |
api.corsOrigin |
string | (none) | CORS origin header for cross-origin access |
Environment Variables
Environment variables override config file values:
| Env Variable | Config Equivalent |
|---|---|
LETTABOT_CONFIG |
Path to config file (overrides search order) |
LETTA_API_KEY |
server.apiKey |
LETTA_BASE_URL |
server.baseUrl |
LETTA_AGENT_ID |
agent.id |
LETTA_AGENT_NAME |
agent.name |
LETTA_MODEL |
agent.model |
TELEGRAM_BOT_TOKEN |
channels.telegram.token |
TELEGRAM_DM_POLICY |
channels.telegram.dmPolicy |
SLACK_BOT_TOKEN |
channels.slack.botToken |
SLACK_APP_TOKEN |
channels.slack.appToken |
DISCORD_BOT_TOKEN |
channels.discord.token |
WHATSAPP_ENABLED |
channels.whatsapp.enabled |
WHATSAPP_SELF_CHAT_MODE |
channels.whatsapp.selfChat |
SIGNAL_PHONE_NUMBER |
channels.signal.phone |
OPENAI_API_KEY |
transcription.apiKey |
GMAIL_ACCOUNT |
polling.gmail.account |
POLLING_INTERVAL_MS |
polling.intervalMs |
See SKILL.md for complete environment variable reference.