Configuration Reference¶
This page is the file-by-file reference for everything Timberbot reads and writes on disk. For the step-by-step setup walkthrough, see Getting Started; this page is the lookup table behind it.
Timberbot has two configuration sides:
- the mod (the C# server running inside Timberborn) owns server-side runtime and security settings — its files live next to the mod under
Documents/Timberborn/Mods/Timberbot/. - the client (the
tbotCLI and thetimberbotPython package) owns the connection target, per-backend defaults, andtbot servesettings — its files live under your OS user-config and user-data directories.
The mod's settings.json is not consulted for client endpoint resolution, and the client never reads settings.json. The two sides communicate only over HTTP/WebSocket.
Files at a glance¶
| File | Owner | Format | Lives in | You edit it? |
|---|---|---|---|---|
config.toml |
client (tbot) |
TOML | config dir | Yes — primary client config |
settings.json |
mod (C# server) | JSON | mod dir | Yes — but the in-game Settings modal is the primary surface |
state.json |
mod (C# server) | JSON | mod dir | Rarely — the widget writes it via POST /api/agent/config |
brain.toon |
client (tbot) |
TOON | data dir | Rarely — managed by tbot brain and location/task commands |
agent_prompts/*.md |
client (tbot) |
Markdown | config dir | Yes — editable copies materialized by tbot init |
config.toml and settings.json are the two you configure by hand. state.json and brain.toon are machine-managed state — documented here so you know what they are, not because you normally edit them.
File locations¶
All three roots follow OS conventions and each has an environment-variable override.
Client config directory¶
Holds config.toml and the materialized agent_prompts/. Resolved by timberbot.config.config_dir():
| Platform | Location |
|---|---|
| Linux | $XDG_CONFIG_HOME/timberbot, falling back to ~/.config/timberbot |
| macOS | ~/Library/Application Support/timberbot |
| Windows | %APPDATA%\timberbot, falling back to ~/AppData/Roaming/timberbot |
Override the whole directory with the TBOT_CONFIG_DIR environment variable (useful for tests or unusual setups).
Client data directory¶
Holds per-settlement memory/<settlement>/brain.toon. Resolved by timberbot.config.data_dir():
| Platform | Location |
|---|---|
| Linux | $XDG_DATA_HOME/timberbot, falling back to ~/.local/share/timberbot |
| macOS | ~/Library/Application Support/timberbot (no separate data convention) |
| Windows | %LOCALAPPDATA%\timberbot, falling back to ~/AppData/Local/timberbot |
Override with the TBOT_DATA_DIR environment variable.
Mod directory¶
Holds settings.json and state.json, alongside the mod's Timberbot.dll and manifest.json:
| Platform | Location |
|---|---|
| Windows | C:\Users\<you>\Documents\Timberborn\Mods\Timberbot\ |
| macOS, native Linux | ~/Documents/Timberborn/Mods/Timberbot/ |
| Linux + Proton | ~/.steam/steam/steamapps/compatdata/1062090/pfx/drive_c/users/steamuser/Documents/Timberborn/Mods/Timberbot/ |
The build-time scripts/deploy.sh honors TBOT_DOCUMENTS_DIR when autodiscovering this folder on Proton/Wine setups with a non-steamuser username.
config.toml (client)¶
The tbot CLI looks for a TOML file at <config dir>/config.toml. A missing or unparseable file is non-fatal — the loader returns an empty mapping, the rest of the resolution chain fills in defaults, and at most one UserWarning is emitted per process per error.
Full annotated example with every recognized section:
# <config dir>/config.toml
# Linux/macOS: ~/.config/timberbot/config.toml
# Windows: %APPDATA%\timberbot\config.toml
[client]
host = "127.0.0.1" # default target host for the CLI / Python client
port = 8085 # default target port (mod HTTP API)
ws_port = 8086 # default target port (mod WebSocket)
auth_token = "" # bearer token; required when the mod sets authToken
[backends.claude] # used by `tbot watch` and `tbot agent run`
model = "claude-opus-4-7"
effort = "high"
[backends.opencode]
model = "glm-4.6"
attach_url = "http://127.0.0.1:4096" # attach to a long-running `opencode serve`
[backends.custom]
command = "aider --system-prompt-file {skill} {prompt}" # argv template
[serve] # used by `tbot serve` only
backend = "claude" # or "opencode"
model = "claude-opus-4-7"
acp_binary = "claude-agent-acp" # ACP agent CLI
mcp_host = "127.0.0.1"
mcp_port = 8091
allowed_tools = ["game.*"]
[serve.telegram]
token = "7912345678:AAH..." # also: TBOT_TELEGRAM_TOKEN env, --telegram-token flag
allowed_users = [12345678] # Telegram user IDs allowed to talk to the bot
[client]¶
The connection target shared by every tbot command and TimberbotClient.
| Key | Type | Default | Meaning |
|---|---|---|---|
host |
string | 127.0.0.1 |
Target host for the mod's HTTP API. |
port |
int | 8085 |
Target port for the mod's HTTP API. |
ws_port |
int | 8086 |
Target port for the mod's WebSocket (tbot watch / listen / serve). |
auth_token |
string | (none) | Bearer token sent as Authorization: Bearer <token>. Required when the mod sets a non-empty authToken (mandatory for a non-localhost listenAddress). |
[backends.<name>]¶
Per-backend defaults fed into tbot agent run / tbot watch. <name> is one of claude, codex, opencode, or custom. Explicit CLI flags always win over these defaults.
| Key | Type | Meaning |
|---|---|---|
model |
string | Model identifier passed to the backend. |
effort |
string | Reasoning effort passed to the backend. |
binary |
string | Override the backend's CLI binary path. |
command |
string | argv template (required for custom); placeholders: {skill}, {instructions_file}, {prompt}, {prompt_file}, {model}, {effort}. |
terminal_prefix |
string | Command prefix wrapping the agent invocation; supports {cwd} (e.g. "wt -d {cwd} --"). |
attach_url |
string | URL of a long-running backend server to attach to (opencode only). Set attach_url = "" and pass --attach-url "" to clear it. |
[serve]¶
Read only by tbot serve. It intentionally does not fall back to [backends.*], so the interactive and one-shot stacks can pick models and binaries independently. The full flag/env/config matrix is in Getting Started → tbot serve flags.
| Key | Type | Default | Meaning |
|---|---|---|---|
backend |
string | claude |
ACP runtime to spawn (claude or opencode). |
model |
string | claude-opus-4-7 |
Model identifier passed to the agent CLI. |
acp_binary |
string | claude-agent-acp (claude) / opencode (opencode) |
Path or name of the ACP agent CLI. |
mcp_host |
string | 127.0.0.1 |
Bind address for the game MCP HTTP/SSE server. |
mcp_port |
int | 8091 |
Port for the game MCP HTTP/SSE server. |
allowed_tools |
list[string] | ["game.*"] |
Glob list of MCP tool names the connector auto-approves; everything else is auto-rejected. |
[serve.telegram]¶
| Key | Type | Default | Meaning |
|---|---|---|---|
token |
string | (required) | Bot token from @BotFather. Also settable via TBOT_TELEGRAM_TOKEN or --telegram-token. |
allowed_users |
list[int] | [] |
Telegram user IDs allowed to talk to the bot. Empty/unset means any user who finds the bot can drive it — tbot serve logs a warning at startup. Must be a list of integers or the server refuses to start. |
Environment variables¶
Environment variables sit between CLI flags and config.toml in the precedence chain.
| Variable | Affects | config.toml / flag equivalent |
|---|---|---|
TBOT_HOST |
Client target host | [client].host / --host |
TBOT_PORT |
Client target HTTP port | [client].port / --port |
TBOT_WS_PORT |
Client target WebSocket port | [client].ws_port / --ws-port |
TBOT_AUTH_TOKEN |
Bearer token | [client].auth_token / --auth-token |
TBOT_TELEGRAM_TOKEN |
tbot serve bot token |
[serve.telegram].token / --telegram-token |
TBOT_CONFIG_DIR |
Overrides the config directory location | — |
TBOT_DATA_DIR |
Overrides the data directory location | — |
TBOT_DEBUG |
When set to 1, true, True, or yes, raises logging to DEBUG |
-vv / --debug |
TBOT_PORT / TBOT_WS_PORT are parsed as integers; a malformed value emits a UserWarning and is ignored (the chain falls through). TBOT_DOCUMENTS_DIR and TBOT_MOD_DIR are build-time variables for scripts/deploy.sh only (overriding the Timberborn Documents directory and the mod folder respectively when deploying a source build), not client settings.
settings.json (mod)¶
The mod reads settings.json from its mod directory at startup. The in-game Settings modal is the primary way to change these — TimberbotService keeps the values in memory and debounces writes back to disk. Editing the file directly is supported as the advanced/manual path.
The file shipped with the mod sets only the common keys:
{
"debugEndpointEnabled": false,
"httpPort": 8085,
"wsPort": 8086,
"wsEnabled": true,
"listenAddress": "127.0.0.1",
"authToken": "",
"maxBodyBytes": 1048576
}
Every recognized key:
| Key | Type | Default | Meaning |
|---|---|---|---|
httpPort |
int | 8085 |
HTTP /api/* listener port. Values <= 0 fall back to the default. |
wsPort |
int | 8086 |
WebSocket /api/ws listener port. Values <= 0 fall back to the default. |
wsEnabled |
bool | true |
When false, the WS listener isn't opened; clients fall back to HTTP polling of /api/agent/state. |
listenAddress |
string | 127.0.0.1 |
Bind address for both listeners. + / 0.0.0.0 binds all interfaces and requires a non-empty authToken. |
authToken |
string | "" |
Bearer secret. When set, every /api/* route except /api/ping (and every WS upgrade) requires Authorization: Bearer <token>. Mandatory when listenAddress is non-loopback — the mod refuses to start otherwise. |
maxBodyBytes |
int | 1048576 |
Max POST body size in bytes. Negative values fall back to the default. |
debugEndpointEnabled |
bool | false |
Enables debug-only endpoints such as POST /api/benchmark. |
writeBudgetMs |
double | 1.0 |
Per-frame main-thread budget (ms) for draining queued writes. Values <= 0 fall back to 1.0. |
corsOrigin |
string | "" |
Value echoed in Access-Control-Allow-Origin. Empty disables CORS headers. |
actionLoggingEnabled |
bool | true |
Toggles the in-widget action log. |
widgetLeft, widgetTop |
string | — | Widget on-screen position; written by the widget as you drag it, stored as JSON strings (e.g. "widgetLeft": "100"). |
Some runtime settings are applied on load, so changing them may require reloading the save (or the mod) to fully take effect.
127.0.0.1 vs localhost
Under Mono's HttpListener the prefix matches the Host: header exactly — a server bound to 127.0.0.1 rejects Host: localhost with HTTP 400. Either use http://127.0.0.1:... everywhere or set listenAddress to localhost.
Deprecated keys
These keys are read by older mod versions but are now ignored, logging a one-line deprecation notice on load: terminal, pythonCommand, agentModel, agentEffort, agentCommandTemplate, agentAllowlistEnabled, agentAllowedBinaries, webhooksEnabled, webhookBatchMs, webhookCircuitBreaker, webhookMaxPendingEvents, webhookValidateUrls.
Backend choice and per-backend model/effort/command defaults now live in config.toml — the connector runs tbot, not the mod. Any other unrecognized key (including legacy agentBinary, agentGoal, tbotCommand) is simply ignored without a warning.
state.json (mod)¶
Agent-shaped state, written next to settings.json in the mod directory. The widget mutates it through POST /api/agent/config; you rarely touch it by hand.
Only three fields are persisted:
| Field | Type | Meaning |
|---|---|---|
mode |
string | "request" (one dispatch per Launch) or "autonomous" (keep dispatching until Stop). |
goal |
string | Persistent objective for autonomous mode / the last request prompt. |
lastError |
string | null | Last agent error surfaced to the widget. |
Ephemeral fields — ready, pendingRequest, agentStatus, and the request-id counters — are in-memory only and reset to startup defaults on every save load. They appear in the GET /api/agent/state response but are never written to disk.
brain.toon (per-settlement memory)¶
Persistent colony knowledge, one file per settlement, stored in TOON format at <data dir>/memory/<settlement>/brain.toon. Managed by tbot brain (and the in-game agent during startup); you rarely edit it directly. The settlement name is sanitized for the filesystem. Live summary data is never persisted here — only the goal, tasks, and locations survive between sessions.
tbot brain # live summary + saved goal/tasks/locations
tbot brain --goal="reach 50 beavers with 77 wellbeing" # set a persistent goal
Logical shape of the stored data (on disk it is serialized via the toons library):
timestamp : "2026-05-25T12:04:18.123456" # ISO timestamp of the last refresh
goal : "reach 50 beavers with 77 wellbeing"
tasks :
- id: 1, status: "pending", action: "build a plank chain" # status: pending | done | failed
locations :
dc : { x: 120, y: 140, z: 2 }
forest : { x: 95, y: 130, z: 0, species: [Pine, Birch] }
berries : { x: 110, y: 150, z: 0, note: "near the dam" }
On first run, locations is auto-seeded from live data (district center, up to three tree clusters, up to three food clusters).
Legacy location
Pre-#43 brain.toon files lived under the game's Documents/Timberborn/Mods/Timberbot/memory/ tree and are migrated to the data directory on first run. If you skipped that upgrade window, copy them across manually: cp -r <old-mods>/Timberbot/memory/ <data-dir>/memory/.
Resolution and precedence¶
For client settings (host, port, auth_token, …), the first match wins:
| Tier | Where | Owns |
|---|---|---|
| 1. CLI flags | tbot --host=X --port=Y --auth-token=T |
per-invocation overrides |
| 2. Environment | TBOT_* variables |
per-shell overrides |
| 3. User config | config.toml |
per-user defaults |
| 4. Built-in | hard-coded | 127.0.0.1:8085, etc. |
Run any command with -v to see a (host=… port=… auth=…) tag reporting which tier each setting came from (cli / env / config / default / none) — handy for debugging "why is the client hitting the wrong server" or "why is no auth being sent".
Agent prompts (tbot init)¶
tbot init materializes editable copies of the packaged system prompts into <config dir>/agent_prompts/. It is idempotent: without --force it leaves your edits alone and only fills in missing files; --force overwrites all of them. List the packaged and user-override prompts with tbot agent prompts.
Packaged prompts: auditor, connector-mode, scout, timberbot, wirer. The timberbot prompt is the default loaded by tbot agent run; the full operating guide behind it is the Timberbot Guide.
- Getting Started — install and first-run walkthrough
- API Reference — every endpoint, including auth behavior
- Events — WebSocket event stream consumed by
tbot watch/listen - Developing — build from source and the mod's settings model