Configuration
All Zubo configuration lives in a single file: ~/.zubo/config.json. You can edit this file directly with any text editor, or use the zubo config CLI commands for quick changes without opening a file. Changes to the configuration file are picked up on the next restart, while CLI changes via zubo config set take effect immediately if Zubo is running.
Copy-Paste Task Cards
Secure API Access
Enable API auth and create a key before exposing ports beyond localhost.
zubo config set auth.enabled true
zubo auth create-key my-app
Set Local Model Fallback
Keep responses available during provider outages or API quota issues.
zubo config set failover '["openai","ollama"]'
zubo config set providers.ollama.model llama3.3
Common Errors
If auth.enabled is true, all /api/* calls require Authorization: Bearer <key>. Create a new key if needed.
curl -H "Authorization: Bearer YOUR_KEY" http://localhost:3000/api/dashboard/status
Use failover and switch temporarily to a responsive provider or smaller model. Check logs for repeated timeout patterns.
zubo model openai/gpt-4o-mini
zubo logs --follow
If local providers fail, ensure the runtime is running and a model is installed.
ollama serve
ollama pull llama3.3
Safe Config Workflow
- Inspect current values first:
zubo config get. - Apply one change at a time with
zubo config set <key> <value>. - Confirm behavior in the dashboard and with
zubo status. - Run
zubo evalafter important changes to validate reliability + safety paths.
For production usage, set auth.enabled, rateLimit.chatPerMinute, and budget limits before exposing any external channel.
Quick Config via CLI
The zubo config command provides a convenient way to read and write configuration values from the terminal:
# Set values
zubo config set activeProvider ollama
zubo config set model llama3.3
zubo config set heartbeatMinutes 60
zubo config set auth.enabled true
zubo config set rateLimit.chatPerMinute 30
zubo config set channels.webchat.port 8080
zubo config set providers.anthropic.model claude-sonnet-4-5-20250929
# Get values
zubo config get # Show entire configuration (pretty-printed)
zubo config get activeProvider # Show a single value
zubo config get channels.telegram # Show a nested object
zubo config get rateLimit # Show all rate limit settings
Notes on the CLI:
- Supports dotted keys for nested values.
zubo config set channels.webchat.port 8080writes to{"channels": {"webchat": {"port": 8080}}}. - Types are auto-detected:
trueandfalsebecome booleans, strings of digits become numbers, everything else stays a string. - To explicitly set a string that looks like a number, wrap it in quotes:
zubo config set someField '"12345"'. - The
setcommand writes directly to~/.zubo/config.json. Avoid editing the file concurrently from multiple processes.
LLM Providers
Zubo supports a multi-provider architecture. You configure one or more LLM providers under the providers object, set one as activeProvider, and optionally define a failover chain. If the active provider fails (network error, rate limit, authentication error), Zubo automatically tries each failover provider in order until one succeeds.
Supported Providers
| Provider Key | Default Base URL | Notes |
|---|---|---|
anthropic |
(uses Anthropic SDK directly) | Claude models. Supports up to 200k token context. Native streaming. Recommended primary provider. |
openai |
https://api.openai.com/v1 |
GPT-4o, GPT-4-turbo, and other OpenAI models. Streaming supported. |
ollama |
http://localhost:11434/v1 |
Run models locally. No API key required. Great as a failover for offline operation. |
groq |
https://api.groq.com/openai/v1 |
Extremely fast inference. Supports Llama, Mixtral, and other open models. |
together |
https://api.together.xyz/v1 |
Wide selection of open-source models. Competitive pricing. |
openrouter |
https://openrouter.ai/api/v1 |
Multi-model gateway. Access Claude, GPT-4, Llama, and more through a single API key. |
lmstudio |
http://localhost:1234/v1 |
Local model GUI. Download and run models with a graphical interface. No API key required. |
custom |
set explicitly | Any OpenAI-compatible provider endpoint. Configure baseUrl, apiKey, and model. |
deepseek |
https://api.deepseek.com/v1 |
DeepSeek models. OpenAI-compatible API with strong reasoning capabilities at competitive pricing. |
xai |
https://api.x.ai/v1 |
xAI Grok models. OpenAI-compatible API with real-time knowledge. |
fireworks |
https://api.fireworks.ai/inference/v1 |
Fireworks AI. Fast inference for open-source models with optimized serving. |
Provider Configuration Fields
Each provider object under providers accepts the following fields:
| Field | Type | Required | Description |
|---|---|---|---|
apiKey |
string | Yes* | API key for the provider. Not required for local providers (Ollama, LM Studio). |
baseUrl |
string | No | Override the default base URL. Useful for proxies or self-hosted endpoints. |
model |
string | Yes | Model name to use. Defaults vary by provider (e.g., claude-sonnet-4-5-20250929 for Anthropic). |
streaming |
boolean | No | Enable or disable streaming responses. Defaults to true. |
contextWindow |
number | No | Maximum context window size in tokens. Zubo uses this for context compaction decisions. Defaults to the provider's known maximum. |
Local Models (Ollama & LM Studio)
Local models run entirely on your machine — no API keys, no usage fees, and your data never leaves your computer. They're ideal as a primary provider for privacy-focused setups, or as a failover when your internet is down.
Ollama
Ollama is a lightweight runtime for running open-source models locally. It provides an OpenAI-compatible API out of the box.
Installation:
# macOS (Homebrew)
brew install ollama
# Linux
curl -fsSL https://ollama.com/install.sh | sh
# Windows — download from https://ollama.com/download
Getting started:
# Start the Ollama server (runs on port 11434)
ollama serve
# Pull a model
ollama pull llama3.3 # Meta Llama 3.3 (good general-purpose)
ollama pull mistral # Mistral 7B (fast, lightweight)
ollama pull qwen2.5 # Qwen 2.5 (strong multilingual)
ollama pull deepseek-r1 # DeepSeek R1 (strong reasoning)
ollama pull gemma2 # Google Gemma 2
# List downloaded models
ollama list
Zubo configuration:
"ollama": {
"baseUrl": "http://localhost:11434/v1",
"model": "llama3.3",
"apiKey": "ollama"
}
The apiKey field is required by the OpenAI-compatible client but Ollama ignores it — any value works.
LM Studio
LM Studio provides a graphical interface for downloading, managing, and running local models. It includes a built-in server that exposes an OpenAI-compatible API.
Installation:
- Download LM Studio from lmstudio.ai (macOS, Windows, Linux)
- Open LM Studio and browse the model library to download a model
- Go to the Local Server tab in the left sidebar
- Select your model and click Start Server — it runs on port 1234 by default
Zubo configuration:
"lmstudio": {
"baseUrl": "http://localhost:1234/v1",
"model": "your-model-name",
"apiKey": "lm-studio"
}
Tip: Local models work great as a failover. Set a cloud provider as primary and Ollama/LM Studio as the fallback — if your API key runs out or the network drops, Zubo seamlessly falls back to your local model:
"activeProvider": "anthropic",
"failover": ["ollama"]
CLI Providers (Claude Code & OpenAI Codex)
These providers use locally installed CLI tools that handle their own authentication — no API key configuration needed in Zubo.
| Provider | CLI Tool | Install | Auth |
|---|---|---|---|
claude-code |
claude |
npm install -g @anthropic-ai/claude-code |
Run claude once to authenticate via browser |
codex |
codex |
npm install -g @openai/codex |
Run codex login to authenticate |
"claude-code": { "model": "claude-sonnet-4-5-20250929" }
"codex": { "model": "o4-mini" }
Multi-Provider Example with Failover
{
"providers": {
"anthropic": {
"apiKey": "sk-ant-api03-...",
"model": "claude-sonnet-4-5-20250929",
"streaming": true,
"contextWindow": 200000
},
"openai": {
"apiKey": "sk-proj-...",
"model": "gpt-4o",
"streaming": true
},
"ollama": {
"baseUrl": "http://localhost:11434/v1",
"model": "llama3.3",
"streaming": true
}
},
"activeProvider": "anthropic",
"failover": ["openai", "ollama"]
}
In this configuration, Zubo uses Claude as the primary model. If Anthropic returns an error (rate limit, network issue, etc.), it automatically tries OpenAI next, and finally Ollama as a local fallback. The failover is transparent to the user — they receive a response regardless of which provider handled it.
Smart Routing
Smart routing automatically selects the best provider for each query based on complexity. Simple questions (greetings, quick lookups, short follow-ups) are routed to fast, inexpensive models, while complex queries (multi-step reasoning, code generation, long-form writing) go to your most capable provider. This can significantly reduce costs without noticeable quality loss.
| Field | Type | Default | Description |
|---|---|---|---|
smartRouting.enabled |
boolean | false |
Enable automatic query routing between providers. |
smartRouting.fastProvider |
string | — | Provider key to use for simple queries (e.g., "groq", "deepseek"). |
smartRouting.fastModel |
string | — | Model to use for the fast provider. Falls back to the provider's default model. |
"smartRouting": {
"enabled": true,
"fastProvider": "groq",
"fastModel": "llama-3.3-70b-versatile"
}
When smart routing is enabled, Zubo classifies each incoming message and routes it accordingly. You can always override the routing for a specific message by prefixing it with the provider name (e.g., @anthropic explain quantum computing).
Memory Retrieval Tuning
These settings control how much memory context is injected into each conversation turn.
| Field | Type | Default | Description |
|---|---|---|---|
memoryRetrieval.contextTopK |
number | 3 |
Number of memory chunks considered for prompt context injection (1-10). |
memoryRetrieval.minConfidence |
number | 0 |
Minimum confidence threshold for memory chunks to be injected (0-1). |
"memoryRetrieval": {
"contextTopK": 4,
"minConfidence": 0.25
}
Tool Scope Safety
Use tool scopes to enforce least-privilege behavior and safer default execution for risky tools.
| Field | Type | Default | Description |
|---|---|---|---|
toolScopes.allowed |
string[] | [] (allow all) |
If non-empty, blocks any tool whose scopes are not in this allowlist. |
toolScopes.dryRunByDefault |
boolean | false |
When true, confirm-gated risky tools return a dry-run preview unless explicitly executed with _dryRun: false. |
"toolScopes": {
"allowed": ["memory", "network_read", "filesystem_read"],
"dryRunByDefault": true
}
Tool Permission Overrides
You can override per-tool permission levels without changing code.
"toolPermissions": {
"shell": "deny",
"file_write": "confirm",
"memory_search": "auto"
}
Valid values are auto, confirm, and deny. These overrides are used by both the dashboard and slash commands such as /permissions set <tool> <level>.
Channel Configuration
Channels define how users interact with Zubo. Each channel is independently configured under the channels object. All enabled channels share the same memory, personality, tools, and conversation history — a fact learned via Telegram is immediately available in Discord or the web dashboard.
Web Chat
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | true |
Enable the built-in web chat dashboard. |
port |
number | 0 (auto) |
HTTP port for the web dashboard and API. Set to 0 for automatic port assignment (default). |
"webchat": {
"enabled": true,
"port": 3000
}
Telegram
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | false |
Enable the Telegram channel. |
botToken |
string | — | Bot token from @BotFather. |
allowedUsers |
number[] | [] |
Array of numeric Telegram user IDs allowed to interact. Empty array means no restriction. |
"telegram": {
"enabled": true,
"botToken": "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11",
"allowedUsers": [12345678, 87654321]
}
Discord
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | false |
Enable the Discord channel. |
botToken |
string | — | Bot token from the Discord Developer Portal. |
allowedUsers |
string[] | [] |
Array of Discord user ID strings allowed to interact. Empty array means no restriction. |
"discord": {
"enabled": true,
"botToken": "MTk4NjIyNDgzNDcxOTI1...",
"allowedUsers": ["198622483471925248"]
}
Slack
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | false |
Enable the Slack channel. |
botToken |
string | — | Bot User OAuth Token (starts with xoxb-). |
appToken |
string | — | App-Level Token (starts with xapp-). Required for Socket Mode. |
allowedUsers |
string[] | [] |
Array of Slack member ID strings allowed to interact. Empty array means no restriction. |
"slack": {
"enabled": true,
"botToken": "xoxb-1234567890-abcdefghij",
"appToken": "xapp-1-A0123456789-1234567890123-abcdef",
"allowedUsers": ["U01ABCDEF"]
}
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | false |
Enable the WhatsApp channel. |
authDir |
string | ~/.zubo/whatsapp-auth |
Directory to store WhatsApp Web authentication data. On first run, a QR code is displayed for pairing. |
allowedNumbers |
string[] | [] |
Array of phone numbers (with country code, e.g., "14155551234") allowed to interact. Empty array means no restriction. |
"whatsapp": {
"enabled": true,
"authDir": "/Users/you/.zubo/whatsapp-auth",
"allowedNumbers": ["14155551234", "447700900000"]
}
Signal
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | false |
Enable the Signal channel. |
phoneNumber |
string | — | The phone number registered with Signal for the bot (with country code, e.g., "+14155551234"). |
signalCliPath |
string | signal-cli |
Path to the signal-cli binary. Defaults to looking on the system PATH. |
allowedNumbers |
string[] | [] |
Array of phone numbers allowed to interact. Empty array means no restriction. |
"signal": {
"enabled": true,
"phoneNumber": "+14155551234",
"signalCliPath": "/usr/local/bin/signal-cli",
"allowedNumbers": ["+447700900000"]
}
| Field | Type | Required | Description |
|---|---|---|---|
enabled |
boolean | No | Enable the Email channel. Defaults to true when the email object is present. |
imap.host |
string | Yes | Hostname of the IMAP server (e.g., "imap.gmail.com"). |
imap.port |
number | No | IMAP server port. Defaults to 993. |
imap.user |
string | Yes | IMAP login username (typically your email address). |
imap.password |
string | Yes | IMAP login password or app-specific password. |
imap.tls |
boolean | No | Enable TLS for the IMAP connection. Defaults to true. |
smtp.host |
string | Yes | Hostname of the SMTP server (e.g., "smtp.gmail.com"). |
smtp.port |
number | No | SMTP server port. Defaults to 587. |
smtp.user |
string | Yes | SMTP login username (typically your email address). |
smtp.password |
string | Yes | SMTP login password or app-specific password. |
smtp.tls |
boolean | No | Enable TLS for the SMTP connection. Defaults to true. |
pollIntervalSeconds |
number | No | How often (in seconds) to check for new emails. Minimum 10, defaults to 60. |
allowedSenders |
string[] | No | Array of email addresses allowed to interact. If omitted, all senders are accepted. |
fromName |
string | No | Display name used in the “From” header of outgoing replies. |
"email": {
"enabled": true,
"imap": {
"host": "imap.gmail.com",
"port": 993,
"user": "you@gmail.com",
"password": "app-specific-password",
"tls": true
},
"smtp": {
"host": "smtp.gmail.com",
"port": 587,
"user": "you@gmail.com",
"password": "app-specific-password",
"tls": true
},
"pollIntervalSeconds": 60,
"allowedSenders": ["friend@example.com", "boss@example.com"],
"fromName": "Zubo"
}
Voice Configuration
Zubo supports speech-to-text (STT) for transcribing voice messages received on any channel, and text-to-speech (TTS) for generating spoken audio responses. Voice is configured under the voice object.
Speech-to-Text (STT)
| Field | Type | Default | Description |
|---|---|---|---|
provider |
string | "whisper" |
STT provider. Currently supported: whisper (OpenAI Whisper API). |
apiKey |
string | — | API key for the STT provider. For Whisper, this is your OpenAI API key. |
model |
string | "whisper-1" |
Model to use for transcription. |
Text-to-Speech (TTS)
| Field | Type | Default | Description |
|---|---|---|---|
provider |
string | "openai" |
TTS provider. Supported: openai, elevenlabs. |
apiKey |
string | — | API key for the TTS provider. |
voice |
string | "nova" |
Voice to use for speech generation. OpenAI voices: alloy, echo, fable, onyx, nova, shimmer. ElevenLabs voices depend on your account. |
"voice": {
"stt": {
"provider": "whisper",
"apiKey": "sk-proj-...",
"model": "whisper-1"
},
"tts": {
"provider": "openai",
"apiKey": "sk-proj-...",
"voice": "nova"
}
}
Agent Settings
These top-level settings control the core agent behavior.
| Field | Type | Default | Description |
|---|---|---|---|
agentName |
string | "Zubo" |
The name of your agent. Used in the system prompt and memory file. Set during setup or change via config_update. |
maxTurns |
number | 50 |
Maximum number of tool-call rounds per conversation turn. When the agent reaches this limit, it stops calling tools and produces a text response with whatever information it has gathered. This prevents runaway tool loops. Reasonable values range from 10 (tightly constrained) to 100 (complex multi-step tasks). |
heartbeatMinutes |
number | 30 |
Interval in minutes (1–1440) between heartbeat cycles. During each heartbeat, Zubo wakes up, checks for pending cron jobs, processes scheduled tasks, evaluates proactive memory triggers, and optionally sends notifications. Set to a low value (1–5) for near-real-time scheduling, or a high value (60–1440) to conserve resources. |
{
"agentName": "Zubo",
"maxTurns": 50,
"heartbeatMinutes": 30
}
Rate Limiting
Zubo includes built-in per-IP rate limiting to protect against abuse. Rate limits use a sliding window algorithm — each IP address gets an independent counter that resets on a rolling 60-second basis.
| Field | Type | Default | Description |
|---|---|---|---|
rateLimit.chatPerMinute |
number | 60 |
Maximum chat messages per minute per IP address. Applies to the /api/chat endpoint and WebSocket messages. When exceeded, the client receives a 429 Too Many Requests response. |
rateLimit.uploadPerMinute |
number | 10 |
Maximum file uploads per minute per IP address. Applies to the /api/upload endpoint. Uploads are more resource-intensive (document parsing, chunking, embedding), so the default is lower. |
"rateLimit": {
"chatPerMinute": 60,
"uploadPerMinute": 10
}
For personal use on localhost, the defaults are generous. If you are exposing Zubo on a public network or sharing it with others, consider lowering these values (e.g., chatPerMinute: 30, uploadPerMinute: 5).
Budget Controls
Zubo tracks token usage and estimated costs for every LLM request. You can set spending limits to prevent surprise bills and view per-model cost breakdowns in the dashboard.
| Field | Type | Default | Description |
|---|---|---|---|
budget.dailyLimitUsd |
number | 0 |
Maximum daily spend in USD. Set to 0 for no limit. When the limit is reached, Zubo pauses LLM requests and notifies you. |
budget.monthlyLimitUsd |
number | 0 |
Maximum monthly spend in USD. Set to 0 for no limit. |
budget.alertThreshold |
number | 0.8 |
Percentage (0–1) of the budget at which Zubo sends a warning notification. Default is 80%. |
"budget": {
"dailyLimitUsd": 5,
"monthlyLimitUsd": 50,
"alertThreshold": 0.8
}
Cost tracking is always active even without spending limits. View your usage breakdown in the dashboard under Analytics → Costs, or ask Zubo directly: “How much have I spent today?”
Email Digest
Zubo can send periodic email digests summarizing conversation activity, usage statistics, and key interactions. Digests are delivered via the configured email channel (IMAP/SMTP), so the email channel must be configured for this feature to work.
| Field | Type | Default | Description |
|---|---|---|---|
emailDigest.enabled |
boolean | false |
Enable automated email digest delivery. |
emailDigest.schedule |
string | "0 8 * * 1-5" |
Cron expression for when to send digests. The default sends weekdays at 8:00 AM. |
emailDigest.recipients |
string[] | [] |
Array of email addresses to receive digests. If empty, the digest is sent to the email channel's SMTP user address. |
emailDigest.includeStats |
boolean | true |
Include usage statistics (messages, tokens, cost) in the digest. |
emailDigest.includeTopConversations |
boolean | true |
Include summaries of the most active conversations since the last digest. |
emailDigest.maxConversations |
number | 10 |
Maximum number of top conversations to include in the digest. |
"emailDigest": {
"enabled": true,
"schedule": "0 8 * * 1-5",
"recipients": ["you@example.com", "team@example.com"],
"includeStats": true,
"includeTopConversations": true,
"maxConversations": 10
}
Digests are delivered using the same SMTP credentials configured in the email channel. The email's “From” name uses the email.fromName field (or defaults to the agent name). You can send a digest from the dashboard or via POST /api/dashboard/digests/send. See the Email Digest API endpoints for programmatic management.
Authentication
When auth.enabled is true, all HTTP API endpoints and WebSocket connections require a valid API key. This is strongly recommended if you are exposing Zubo's port beyond localhost.
| Field | Type | Default | Description |
|---|---|---|---|
auth.enabled |
boolean | false |
Enable API key authentication for all HTTP and WebSocket endpoints. |
Managing API Keys
API keys can be created and managed via the CLI or the web dashboard:
# Create a new API key
zubo auth create-key my-app
# Output: API key created (id: N, label: my-app): ...
# List all API keys
zubo auth list-keys
# Delete an API key by numeric id
zubo auth delete-key 3
Using API Keys
Include the API key in the Authorization header as a Bearer token:
curl -X POST http://localhost:3000/api/chat \
-H "Authorization: Bearer zb_k1_a1b2c3d4e5f6..." \
-H "Content-Type: application/json" \
-d '{"message": "Hello, Zubo!"}'
For WebSocket connections, pass the key as a query parameter:
ws://localhost:3000/ws?token=zb_k1_a1b2c3d4e5f6...
API keys are stored as hashed values in the SQLite database. The plain-text key is only shown once at creation time and cannot be retrieved later. If you lose a key, revoke it and create a new one.
Sandbox
The sandbox controls how user-installed skills (from ~/.zubo/workspace/skills/) are executed. Built-in tools always run in the main process, but user skills run in isolated subprocesses for safety.
| Field | Type | Default | Description |
|---|---|---|---|
sandbox.enabled |
boolean | true |
Enable subprocess sandboxing for user-installed skills. When enabled, each skill invocation runs in a separate Bun subprocess with restricted access. Disabling this is not recommended but may be necessary for skills that require direct main-process access. |
sandbox.timeoutMs |
number | 30000 |
Maximum execution time in milliseconds for a single skill invocation. If a skill exceeds this timeout, its subprocess is terminated and an error is returned to the agent. Set higher for skills that perform long-running operations (e.g., large file processing, slow API calls). |
"sandbox": {
"enabled": true,
"timeoutMs": 30000
}
Full Example
Here is a complete ~/.zubo/config.json showing all configuration sections together. This represents a fully configured instance with Anthropic as the primary provider, Groq for smart routing, Ollama as a local failover, three channels enabled, voice support, budget controls, and production-ready security settings:
{
"providers": {
"anthropic": {
"apiKey": "sk-ant-api03-...",
"model": "claude-sonnet-4-5-20250929",
"streaming": true,
"contextWindow": 200000
},
"groq": {
"apiKey": "gsk_...",
"model": "llama-3.3-70b-versatile",
"streaming": true
},
"ollama": {
"baseUrl": "http://localhost:11434/v1",
"model": "llama3.3",
"streaming": true
}
},
"activeProvider": "anthropic",
"failover": ["groq", "ollama"],
"smartRouting": {
"enabled": true,
"fastProvider": "groq",
"fastModel": "llama-3.3-70b-versatile"
},
"channels": {
"webchat": {
"enabled": true,
"port": 3000
},
"telegram": {
"enabled": true,
"botToken": "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11",
"allowedUsers": [12345678]
},
"discord": {
"enabled": true,
"botToken": "MTk4NjIyNDgzNDcxOTI1...",
"allowedUsers": []
},
"slack": {
"enabled": false,
"botToken": "",
"appToken": "",
"allowedUsers": []
},
"whatsapp": {
"enabled": false,
"authDir": "",
"allowedNumbers": []
},
"signal": {
"enabled": false,
"phoneNumber": "",
"signalCliPath": "signal-cli",
"allowedNumbers": []
},
"email": {
"enabled": false,
"imap": {
"host": "imap.gmail.com",
"port": 993,
"user": "",
"password": "",
"tls": true
},
"smtp": {
"host": "smtp.gmail.com",
"port": 587,
"user": "",
"password": "",
"tls": true
},
"pollIntervalSeconds": 60,
"allowedSenders": [],
"fromName": "Zubo"
}
},
"voice": {
"stt": {
"provider": "whisper",
"apiKey": "sk-proj-...",
"model": "whisper-1"
},
"tts": {
"provider": "openai",
"apiKey": "sk-proj-...",
"voice": "nova"
}
},
"agentName": "Zubo",
"maxTurns": 50,
"heartbeatMinutes": 30,
"rateLimit": {
"chatPerMinute": 60,
"uploadPerMinute": 10
},
"budget": {
"dailyLimitUsd": 5,
"monthlyLimitUsd": 50,
"alertThreshold": 0.8
},
"emailDigest": {
"enabled": false,
"schedule": "0 8 * * 1-5",
"recipients": [],
"includeStats": true,
"includeTopConversations": true,
"maxConversations": 10
},
"auth": {
"enabled": false
},
"sandbox": {
"enabled": true,
"timeoutMs": 30000
}
}
Tip: You do not need to include every field. Zubo applies sensible defaults for any omitted values. A minimal config only needs activeProvider and the corresponding provider entry with an API key.
Environment
By default, Zubo stores all data and configuration under ~/.zubo. You can override this by setting the ZUBO_HOME environment variable to an absolute path:
# Use a custom home directory
export ZUBO_HOME=/opt/zubo-data
zubo start
# Or inline for a single invocation
ZUBO_HOME=/opt/zubo-data zubo start --daemon
When ZUBO_HOME is set, all paths — config file, database, logs, sessions, models, and workspace — are resolved relative to that directory instead of ~/.zubo. This is useful for running multiple isolated Zubo instances on the same machine, or for placing the data directory on a specific volume or mount point.
Other environment variables recognized by Zubo:
| Variable | Description |
|---|---|
ZUBO_HOME |
Override the default ~/.zubo data directory. |
ZUBO_LOG_LEVEL |
Set the log level: debug, info, warn, error. Defaults to info. |
ZUBO_PORT |
Override the web dashboard port (takes precedence over config file). |
NODE_ENV |
When set to production, Zubo disables verbose logging and enables additional security hardening. |