type: operations title: Configuration and data files description: How src/config.rs loads config.toml, the supported keys and defaults (including ai_retries and web_port), the template file, where the data directory and databases live, and operational and security caveats. tags: [configuration, toml, data-directory, sqlite, security] sources:
ea70eb6c04
resource: repo://.gitignore0d5b861992
resource: repo://config.toml.global.template1b05507d70
resource: repo://src/ai.rs2a737474d8
resource: repo://src/config.rs
generated: { by: "claude-code", at: "2026-10-20T20:27:06.515Z" }
verified:All runtime settings come from one TOML file loaded by Config::load
(src/config.rs:259-263). No environment variable is ever read
(src/config.rs:1-25).
The data directory is fixed: <platform config dir>/wh, resolved with
dirs::config_dir() (src/config.rs:166-170). On Windows this is
%APPDATA%\wh. It cannot be changed from the config file. At startup
ensure_data_dir creates it if missing (src/config.rs:293-296).
| File | Purpose | Defined by |
|---|---|---|
config.toml |
Optional settings | CONFIG_FILE, src/config.rs:56 |
session.db |
WhatsApp session store used by whatsapp-rust (WhatsApp client) |
session_db_path, src/config.rs:302-304 |
history.db |
Local messages, chats, contacts, per-chat autoreply flags and the global autoreply setting (History store) | history_db_path, src/config.rs:310-312 |
ai_requests.log |
Optional AI request log, written only when ai_log = true (AI client) |
ai_log_path, src/config.rs:318-320 |
The two databases are separate by design: session.db belongs to the
WhatsApp library (linked-device session and keys, schema owned by
whatsapp-rust), while history.db belongs to the app (chats, messages,
contacts, autoreply flags).
| Key | Purpose | Default when missing or blank |
|---|---|---|
openai_api_key |
Bearer token for the AI endpoint (trimmed) | none — the AI client cannot be built |
openai_base_url |
Base URL of the OpenAI-compatible endpoint (trimmed, trailing / removed) |
https://ollama.com/v1 |
openai_model |
Model for text replies (trimmed) | deepseek-v4.1-flash |
openai_vision_model |
Model for image replies (trimmed) | none — image understanding disabled |
system_prompt |
Persona/instructions for autoreplies, kept as written (not trimmed, multiline allowed) | none — AI not configured |
ai_log |
Boolean; when true every request sent to the AI model is appended to ai_requests.log |
false |
cooldown_seconds |
Minimum seconds between autoreplies in a private chat or to a group message addressed to the user; 0 disables it |
30 |
group_cooldown_seconds |
Same, for group messages not addressed to the user; 0 disables it |
300 |
catch_up_seconds |
After a restart, the last unanswered message of each private chat is answered once if it is at most this old; 0 disables the catch-up |
7200 |
ai_retries |
How many times a failed AI request is retried, waiting 2 s, 4 s, …; HTTP 4xx other than 429 is never retried; 0 disables retrying |
2 |
web_port |
TCP port of the web control panel on 0.0.0.0, no authentication; valid range 1–65535 |
unset — panel disabled |
Mapping and defaults: Config::from_file (src/config.rs:269-287) and the
constants at src/config.rs:34-45. The timing keys and ai_retries are
unsigned integers in the file (Option<u32>, src/config.rs:121-128), so a
negative value is rejected as an invalid value type; the timing keys are
stored as i64 in Config. web_port is Option<u16>
(src/config.rs:129-131), so negatives and values above 65535 fail TOML
parsing, and resolve_web_port (src/config.rs:243-252) additionally
rejects 0. Their use is described in
AI autoreply, AI client
and Web control panel.
The binary embeds no prompt text: without system_prompt the AI is not
configured and the status line says so (see
Application state). Unknown keys are ignored.
config.toml.global.template in the repository root lists every key with
its default and a comment (with web_port commented out); copy it to the
data directory as config.toml and fill in openai_api_key and
system_prompt.
read_config_file, src/config.rs:202-212).cannot read config file <path>.invalid config file <path> with the
cause invalid TOML syntax or value type at line L, column C; the error
never echoes file content (parse_config_file, src/config.rs:187-196).
This also covers negative or non-integer timing keys and ai_retries, a
non-boolean ai_log and an out-of-range web_port.openai_base_url consisting only of slashes is rejected with
openai_base_url in config.toml must not be empty or only slashes
(src/config.rs:234-241).web_port = 0 is rejected with
web_port in config.toml must be between 1 and 65535.Startup aborts with cannot load configuration on any of these errors
(Runtime).
Config's Debug shows *** or <unset>
(src/config.rs:134-160), and the raw FileConfig has no Debug impl at
all (src/config.rs:105-132). The AI client redacts it too.ai_requests.log never contains the API key and replaces image data
with a size placeholder, but it does store the full request (system
prompt and chat context) and the reply in clear text, one record per
attempt including retries, and it is only appended to, never rotated.
Enable ai_log only for diagnosis and delete the file afterwards.web_port exposes an unauthenticated HTTP panel on every network
interface: anyone who can reach the port can see chat names, toggle
autoreplies and quit the bot. Set it only on a trusted network or
firewall the port. A port already in use aborts startup with
cannot start web server on port <port>.config.toml in the data directory, outside the repository.
.gitignore ignores a root-level /config.toml and .env
(.gitignore:4-6), as well as SQLite journal/WAL/SHM files; note that the
*.db pattern is commented out (.gitignore:7), so databases copied into
the repo would not be ignored.session.db holds the linked-device credentials: deleting it forces a new
QR pairing. history.db can be deleted to reset local history and the
per-chat and global autoreply flags; it is recreated on start.src/config.rs:323+ covers defaults, full files, blank values, multiline
prompts, trimming, base URL normalisation and errors, Debug masking,
vision model, DB and AI log paths, ai_log, cooldown, catch-up and
ai_retries defaults, custom values (including 0) and rejection of
negatives, web_port (unset, valid, 0 and out-of-range rejected), unknown
keys, BOM/CRLF, non-leaking parse errors, missing, existing, invalid and
unreadable files. See Unit tests.