Configuration reference
Bestie stores non-secret settings in .bestie/config.json during local development. Secrets live in .bestie/.env and must never be printed or logged.
Installed builds may use user-level paths such as ~/.config/bestie-agent/config.json, ~/.local/share/bestie-agent/, and ~/.local/state/bestie-agent/logs/.
Minimal config
Section titled “Minimal config”{ "version": 1, "agent": { "name": "Bestie", "ownerName": "Owner", "language": "vi", "toneIntensity": 7, "emojiLevel": "light" }, "llm": { "provider": "openai-compatible", "baseUrl": "https://api.openai.com/v1", "model": "provider-model-name", "apiKeyEnv": "BESTIE_LLM_API_KEY", "timeoutMs": 60000, "maxRetries": 1, "retryDelayMs": 500 }, "memory": { "provider": "sqlite", "writePolicy": "ask" }}Environment file
Section titled “Environment file”.bestie/.env contains secrets:
BESTIE_LLM_API_KEY=BESTIE_TELEGRAM_BOT_TOKEN=BESTIE_TRANSCRIPTION_API_KEY=COMPOSIO_CONSUMER_API_KEY=ZEP_API_KEY=Only add secrets for features you enable. Basic setup only requires the LLM API key.
llm config selects the OpenAI-compatible provider:
{ "llm": { "provider": "openai-compatible", "baseUrl": "https://api.openai.com/v1", "model": "provider-model-name", "apiKeyEnv": "BESTIE_LLM_API_KEY", "timeoutMs": 60000, "maxRetries": 1, "retryDelayMs": 500 }}apiKeyEnv is the environment variable name, not the secret value.
Memory
Section titled “Memory”{ "memory": { "provider": "sqlite", "writePolicy": "ask", "sqlitePath": "~/.local/share/bestie-agent/memory.sqlite", "zepEnabled": false, "zepApiKeyEnv": "ZEP_API_KEY" }}memory.writePolicy controls model-requested writes through internal.remember_memory:
| Policy | Behavior |
|---|---|
allow |
Store allowed non-secret memories directly. |
ask |
Queue allowed non-secret memories for approval. This is the default. |
deny |
Reject memory writes. |
Memory commands include status, pause, resume, list, search, add, inspect, edit, forget, export, clear, pending inspection, approve, reject, and reject-all flows.
Workspace
Section titled “Workspace”{ "workspace": { "defaultPath": ".bestie/workspace", "externalPaths": [] }}workspace.defaultPath controls where relative write, edit, and exec paths land. workspace.externalPaths is an explicit allowlist for absolute paths outside the project root and agent workspace.
Internal tools
Section titled “Internal tools”{ "internalTools": { "policies": { "internal.write_file": "ask", "internal.edit_file": "ask", "internal.apply_patch": "ask", "internal.exec": "ask", "internal.list_processes": "allow", "internal.read_url": "ask" }, "exec": { "timeoutMs": 120000 } }}Policies use allow, ask, or deny.
Telegram
Section titled “Telegram”Telegram config stays non-secret in .bestie/config.json:
{ "channels": { "telegram": { "enabled": true, "botTokenEnv": "BESTIE_TELEGRAM_BOT_TOKEN", "ownerUserId": "123456789", "attachments": { "downloadPolicy": "allow", "maxBytes": 20971520, "previewMaxBytes": 16384, "parseMaxBytes": 5242880, "visionPolicy": "deny", "visionMaxBytes": 4194304, "transcriptionPolicy": "deny", "transcriptionMaxBytes": 10485760, "deleteAfterProcessingKinds": [], "allowedMimeTypes": ["text/*", "application/json"] } } }}Run setup with:
bestie telegram setupRun the bot locally:
bestie telegrambestie telegram --onceSupported Telegram commands include /start, /help, /status, /doctor, /memory, /memory pending, /memory pause, /memory resume, /approvals, /approve <id>, and /deny <id>.
Transcription
Section titled “Transcription”OpenAI-compatible transcription:
{ "transcription": { "provider": "openai-compatible", "baseUrl": "https://api.openai.com/v1", "model": "whisper-1", "apiKeyEnv": "BESTIE_TRANSCRIPTION_API_KEY", "timeoutMs": 60000 }}Local whisper transcription:
{ "transcription": { "provider": "local-whisper", "command": ".bestie/tools/local-whisper-transcribe.sh", "args": ["{modelPath}", "{audioPath}", "-l", "vi"], "modelPath": ".bestie/models/ggml-small.bin", "timeoutMs": 120000 }}The local command runs without a shell. {audioPath} and {modelPath} are replaced by Bestie.
Speech replies
Section titled “Speech replies”Voice replies are opt-in for Telegram voice/audio inputs:
{ "speech": { "provider": "elevenlabs", "apiKeyEnv": "ELEVENLABS_API_KEY", "voiceId": "NOpBlnGInO9m6vDvFkFC", "modelId": "eleven_v3", "languageCode": "en", "outputFormat": "mp3_44100_128", "timeoutMs": 60000 }, "channels": { "telegram": { "voiceReplyPolicy": "voice-input-only" } }}Bestie sends the text reply first, then converts generated speech to Telegram Ogg/Opus voice-note format.
{ "mcp": { "servers": [ { "name": "local-files", "enabled": false, "transport": "stdio", "command": "node", "args": ["server.js"], "tools": [ { "name": "read_file", "category": "read" } ] } ] }}A top-level mcpServers object is also accepted and normalized to mcp.servers for compatibility with common MCP snippets.