pub struct Config {Show 14 fields
pub addr: String,
pub token: String,
pub db_path: String,
pub git_commit: String,
pub backup_dir: String,
pub backup_interval: Duration,
pub backup_keep: usize,
pub rate_limit_window: Duration,
pub rate_limit_max: u32,
pub trusted_ip_header: String,
pub merge_enabled: bool,
pub merge_timeout: Duration,
pub claude_bin: String,
pub claude_status_interval: Duration,
}Expand description
What recall serve needs.
Every field has a default that is safe to run with, except token,
which has none — see ConfigError::MissingToken.
| Field | Variable | Default |
|---|---|---|
addr | RECALL_HOST, RECALL_PORT | 0.0.0.0:8787 |
token | RECALL_TOKEN | required |
db_path | RECALL_DB_PATH | data/recall.db |
git_commit | RECALL_GIT_COMMIT | unknown |
backup_dir | RECALL_BACKUP_DIR | off |
backup_interval | RECALL_BACKUP_INTERVAL_MS | 24h |
backup_keep | RECALL_BACKUP_KEEP | 7 |
rate_limit_window | RECALL_RATE_LIMIT_WINDOW_MS | 60s |
rate_limit_max | RECALL_RATE_LIMIT_MAX | 60 |
trusted_ip_header | RECALL_TRUSTED_IP_HEADER | cf-connecting-ip |
merge_enabled | RECALL_MERGE_ENABLED | on |
merge_timeout | RECALL_MERGE_TIMEOUT_MS | 45s |
claude_bin | RECALL_CLAUDE_BIN | claude |
claude_status_interval | RECALL_CLAUDE_STATUS_INTERVAL_MS | 30m |
Fields§
§addr: StringThe socket to bind, assembled from host and port.
token: StringThe single bearer token. There is no second one, by design.
db_path: StringThe SQLite file. Opened, never created from a schema migration — it is the same file the Node server wrote.
git_commit: StringReported by GET /health so a deploy can be confirmed from outside.
backup_dir: StringWhere periodic database snapshots go. Empty disables backups.
backup_interval: DurationHow often to take one.
backup_keep: usizeHow many to keep before deleting the oldest.
rate_limit_window: DurationThe window rate limiting counts requests over.
rate_limit_max: u32How many requests one client may make in that window.
trusted_ip_header: StringThe one request header whose value is taken as the client’s address, or empty to trust none and use the socket’s peer address.
Rate limiting keys off this, and rate limiting runs before auth precisely so a flood of invalid tokens is limited too — so a client that can choose its own value here can rotate it and get unlimited attempts at guessing the token.
That makes this a statement about the deployment, not a preference: it names the header the ingress sets, and it is only safe when nothing can reach this server except through that ingress. Exactly one header is read, so a value the client supplies under any other name is ignored.
| Ingress | Set this to |
|---|---|
| Cloudflare Tunnel | cf-connecting-ip (the default) |
| Traefik, nginx, Caddy | x-real-ip |
| None — reached directly | empty |
Deliberately not x-forwarded-for: a proxy appends to it, so the
first entry is whatever the client sent. Reading it as one value is
the classic way to make this setting useless.
merge_enabled: boolWhether to attempt semantic merge at all. Off means last-write-wins.
merge_timeout: DurationHow long a merge may take before it is abandoned — and, like every other merge failure, degraded to last-write-wins.
claude_bin: StringThe claude binary to shell out to. Never the Anthropic API.
claude_status_interval: DurationHow often to re-check that the binary is present and logged in.
Implementations§
Source§impl Config
impl Config
Sourcepub fn from_env() -> Result<Self, ConfigError>
pub fn from_env() -> Result<Self, ConfigError>
Reads configuration from the real process environment.
Sourcepub fn from_lookup<F>(lookup: F) -> Result<Self, ConfigError>
pub fn from_lookup<F>(lookup: F) -> Result<Self, ConfigError>
Reads configuration through a caller-supplied lookup, applying the same defaults the Node implementation used.
The lookup is injected rather than read from std::env inside so the
clamping below is testable: set_var is process-global, and Rust runs
tests in parallel threads, so an env-reading test races every other
test in the binary.
An unparseable value falls back rather than failing the boot, matching the Node and Go implementations — a typo in one tunable should not be the reason a server won’t start.