type: operations title: Configuration and data files description: How src/config.rs loads config.toml, the supported keys and defaults, where the data directory and databases live, and operational and security caveats. tags: [configuration, toml, data-directory, sqlite, security] sources:
ea70eb6c04
resource: repo://.gitignore1b05507d70
resource: repo://src/ai.rs2a737474d8
resource: repo://src/config.rs
generated: { by: "claude-code", at: "2026-10-19T19:53:56.480Z" }
verified:All runtime settings come from one TOML file loaded by Config::load
(src/config.rs:226-230). No environment variable is ever read
(src/config.rs:1-20).
The data directory is fixed: <platform config dir>/wh, resolved with
dirs::config_dir() (src/config.rs:144-148). 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:258-261).
| File | Purpose | Defined by |
|---|---|---|
config.toml |
Optional settings | CONFIG_FILE, src/config.rs:49 |
session.db |
WhatsApp session store used by whatsapp-rust (WhatsApp client) |
session_db_path, src/config.rs:267-269 |
history.db |
Local messages, chats, contacts and autoreply flags (History store) | history_db_path, src/config.rs:275-277 |
ai_requests.log |
Optional AI request log, written only when ai_log = true (AI client) |
ai_log_path, src/config.rs:283-285 |
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 |
Mapping and defaults: src/config.rs:236-252, src/config.rs:29-38.
The three timing keys are unsigned integers in the file (Option<u32>,
src/config.rs:104-111), so a negative value is rejected as an invalid
value type; they are stored as i64 in Config. Their use is described
in AI autoreply.
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.
src/config.rs:180-190).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 (src/config.rs:165-174). This also covers
negative or non-integer timing keys and a non-boolean ai_log.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:212-219).Startup aborts with cannot load configuration on any of these errors
(Runtime).
Config's Debug shows *** or <unset>
(src/config.rs:114-138), and the raw FileConfig has no Debug impl at
all (src/config.rs:90-112). 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, and it is only
appended to, never rotated. Enable ai_log only for diagnosis and delete
the file afterwards.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
autoreply flags; it is recreated on start.src/config.rs:288+ 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 and catch-up defaults,
custom values (including 0) and rejection of negatives, unknown keys, BOM/CRLF, non-leaking parse errors,
missing, existing, invalid and unreadable files. See
Unit tests.