Config file
Every key in ~/.tomo/config.yaml: the model and providers, agent knobs, policy, channels, heartbeat, voice, MCP servers, workers, and the data dir.
tomo reads one YAML file, ~/.tomo/config.yaml by default, or the path you pass with --config.
Run tomo onboard to write a starter file with every section present and annotated.
A missing config is an error that names the fix.
This page lists every key tomo reads. Anything not here is ignored.
Environment variable expansion
Any value may reference an environment variable with ${VAR}, and tomo expands it when it loads the file.
An unset variable expands to the empty string.
This keeps secrets like API keys and bot tokens out of the file itself:
providers:
anthropic:
api_key: ${ANTHROPIC_API_KEY}
default_model
default_model: anthropic/claude-fable-5
The provider/model spec used when a command gives no --model.
The form is provider/model, where provider names an entry under providers and model is whatever that backend calls the model.
The model part may itself contain slashes, which some gateways use.
There is no built-in default: with no default_model and no --model, a command that needs a model errors.
providers
providers:
<name>:
type: anthropic
api_key: ${ANTHROPIC_API_KEY}
base_url: ""
A map from a provider name to a backend.
The name on the left is what default_model and --model reference before the slash.
| Key | Meaning |
|---|---|
type |
The backend dialect: anthropic or openai. Anything speaking the OpenAI chat completions dialect uses openai. |
api_key |
The provider key. Usually a ${VAR} reference. |
base_url |
Override the endpoint. Point it at a local server or a gateway; leave it empty for the provider's own API. |
You can define as many providers as you like and switch between them per command with --model.
agent
agent:
max_tokens: 8192
max_turns: 24
The loop knobs shared by every front end.
| Key | Default | Meaning |
|---|---|---|
max_tokens |
8192 |
Maximum tokens the model may generate per turn. |
max_turns |
24 |
Maximum tool-use rounds in a single turn before tomo stops looping. |
Either key set to zero falls back to its default.
policy
policy:
read: allow
net: allow
write: ask
exec: ask
rules:
shell: deny
write_file: allow
The gate every tool call passes before it runs.
The four class keys set the baseline decision for each capability class; rules overrides individual tools by name.
See the policy and safety guide for the full trust model, including the taint escalation and how external tools are handled.
| Key | Default | Meaning |
|---|---|---|
read |
allow |
Baseline for tools that read local state. |
net |
allow |
Baseline for tools that talk to the network. |
write |
ask |
Baseline for tools that mutate local state. |
exec |
ask |
Baseline for tools that run arbitrary code. |
rules |
Map of tool name to decision (allow, ask, or deny), winning over the class default. |
Each decision is one of allow, ask, or deny.
A class you leave unset stays at the safe default shown above, and a value tomo does not recognize falls back to ask rather than opening up.
channels
channels:
telegram: {}
discord: {}
slack: {}
imessage: {}
The front doors tomo serve opens.
The web chat is always on and has no entry here; the rest start only when configured.
Each names the conversations it will serve, so a leaked token or a stray invite does not hand anyone an agent.
See the channels guide.
telegram
channels:
telegram:
token: ${TELEGRAM_BOT_TOKEN}
allow_chats: [123456789]
| Key | Meaning |
|---|---|
token |
The bot token. The channel starts only when this is set. |
allow_chats |
List of numeric chat ids allowed to reach the bot. |
discord
channels:
discord:
token: ${DISCORD_BOT_TOKEN}
allow_channels: ["000000000000000000"]
| Key | Meaning |
|---|---|
token |
The bot token. The channel starts only when this is set. |
allow_channels |
List of channel ids (as strings) allowed to reach the bot. |
slack
channels:
slack:
app_token: ${SLACK_APP_TOKEN}
bot_token: ${SLACK_BOT_TOKEN}
allow_channels: ["C0000000000"]
| Key | Meaning |
|---|---|
app_token |
The app-level token that opens the socket. The channel starts only when this is set. |
bot_token |
The bot token used to post messages. |
allow_channels |
List of channel ids (as strings) allowed to reach the bot. |
imessage
channels:
imessage:
enabled: true
allow_handles: ["+15555550123"]
db_path: ""
macOS only, and needs Full Disk Access since it reaches a real Messages account.
| Key | Meaning |
|---|---|
enabled |
Off unless set true. |
allow_handles |
List of phone numbers or emails permitted to drive the agent. |
db_path |
Path to the Messages database. Leave empty for the default location. |
heartbeat
heartbeat:
enabled: true
every: "@every 30m"
file: ~/.tomo/HEARTBEAT.md
channel: telegram
chat: "123456789"
Runs tomo on a cadence against a checklist file, so it can pick up standing work without being spoken to. It stays quiet when there is nothing worth saying. Background runs cannot get approval, so anything gated to ask is declined while unattended. See the scheduling guide.
| Key | Default | Meaning |
|---|---|---|
enabled |
false |
Off unless set true. The defaults below apply only when it is on. |
every |
@every 30m |
The schedule, in the same forms tomo cron add accepts. |
file |
HEARTBEAT.md in the data dir |
The checklist read each beat. |
channel |
web |
Where to deliver anything worth saying. The web chat has nowhere to push, so point this at a poster like telegram to have results delivered. |
chat |
Chat id within that channel. |
voice
voice:
model: ~/.tomo/models/ggml-base.en.bin
bin: whisper-cli
ffmpeg: ffmpeg
tts_model: ~/.tomo/models/en_US-amy-medium.onnx
tts_bin: piper
Speech both ways, handled locally, so no audio leaves the machine.
Setting model turns on transcription of inbound voice notes with whisper.cpp.
Setting tts_model turns on spoken replies with piper, sent back as a voice note wherever you spoke first.
| Key | Default | Meaning |
|---|---|---|
model |
Path to a ggml whisper model. Setting it enables voice-in. | |
bin |
whisper-cli |
The whisper.cpp CLI on PATH. |
ffmpeg |
ffmpeg |
ffmpeg on PATH, used to decode inbound clips and encode the spoken reply to opus. |
tts_model |
Path to a piper voice model. Setting it enables voice-out. | |
tts_bin |
piper |
The piper CLI on PATH. |
mcp
mcp:
servers:
<name>:
command: ""
args: []
env: {}
url: ""
headers: {}
Model Context Protocol servers to attach on startup.
Each server's tools join the toolset, namespaced by the server key: a filesystem tool named read under a server keyed files becomes files_read.
These tools are not tomo's own code, so they default to ask even when their class would run; add a policy.rules entry to allow one you trust.
See the MCP guide.
A server sets either command (a local subprocess over stdio) or url (a remote server over HTTP).
| Key | Meaning |
|---|---|
command |
Executable to launch for a stdio server. |
args |
Its arguments. |
env |
Extra environment for the subprocess. |
url |
Endpoint of an HTTP server. |
headers |
Sent on every HTTP request, for auth. |
workers
workers:
<name>:
persona: You dig up sources and summarize. Cite what you find.
model: anthropic/claude-fable-5
policy:
write: deny
channels: ["slack:C0RESEARCH"]
Named specialists that handle some conversations in their own right.
The default worker is tomo itself and needs no entry here.
Each worker gets its own memory, so nothing one learns leaks into another's prompt.
Reach a worker by starting a message with @name, or bind a channel:chat to it so its messages always route there; an explicit @name wins over a binding.
See the workers guide.
| Key | Meaning |
|---|---|
persona |
Extra system-prompt lines that set its role. |
model |
Provider/model override. Empty means the default. |
policy |
Its own gate, in the same shape as the top-level policy, merged over the top-level one. |
channels |
List of channel:chat keys whose messages route to it. |
data_dir
data_dir: ~/.tomo
Where tomo keeps everything: the config, the tomo.db ledger, the audit.log, and the memory, skills, and skill-drafts dirs.
Defaults to ~/.tomo.
Complete example
A full config with every section filled in. Commented lines mark the optional pieces you can leave out.
# tomo config. Values may reference environment variables with ${VAR}.
default_model: anthropic/claude-fable-5
providers:
anthropic:
type: anthropic
api_key: ${ANTHROPIC_API_KEY}
local:
type: openai
base_url: http://gamingpc:8000/v1
api_key: ${LOCAL_API_KEY}
agent:
max_tokens: 8192
max_turns: 24
# Reads and network run; writes and code execution ask first.
# A per-tool rule wins over the class default.
policy:
read: allow
net: allow
write: ask
exec: ask
rules:
shell: deny # never run shell, whatever the class says
write_file: allow # trust file writes without a prompt
# The web chat is always on; these start only when configured.
channels:
telegram:
token: ${TELEGRAM_BOT_TOKEN}
allow_chats: [123456789]
discord:
token: ${DISCORD_BOT_TOKEN}
allow_channels: ["000000000000000000"]
slack:
app_token: ${SLACK_APP_TOKEN}
bot_token: ${SLACK_BOT_TOKEN}
allow_channels: ["C0000000000"]
imessage: # macOS only, needs Full Disk Access
enabled: true
allow_handles: ["+15555550123"]
# Runs on a cadence against a checklist and stays quiet when there is nothing to say.
heartbeat:
enabled: true
every: "@every 30m"
file: ~/.tomo/HEARTBEAT.md
channel: telegram
chat: "123456789"
# Speech both ways, all local. model enables voice-in, tts_model enables voice-out.
voice:
model: ~/.tomo/models/ggml-base.en.bin
bin: whisper-cli
ffmpeg: ffmpeg
tts_model: ~/.tomo/models/en_US-amy-medium.onnx
tts_bin: piper
# MCP servers attached on startup; their tools default to ask.
mcp:
servers:
files:
command: mcp-server-filesystem
args: [/Users/me/work]
github:
command: npx
args: [-y, "@modelcontextprotocol/server-github"]
env:
GITHUB_TOKEN: ${GITHUB_TOKEN}
remote:
url: https://mcp.example.com/mcp
headers:
Authorization: Bearer ${MCP_TOKEN}
# Named specialists with their own persona, model, policy, and memory.
workers:
research:
persona: You dig up sources and summarize. Cite what you find.
model: anthropic/claude-fable-5
policy:
write: deny # this one only reads and reports
channels: ["slack:C0RESEARCH"]
data_dir: ~/.tomo