Persistent Channel History
Channel message history is now backed by SQLite, surviving server restarts.
How It Works
The server maintains an in-memory buffer (deque, 10K entries/channel) as the hot read cache. When data_dir is configured, every channel message is also appended to {data_dir}/history.db. On startup, the deque is restored from SQLite.
Writes are batched (no per-message commit) to avoid blocking the event loop. Pending writes are flushed on shutdown.
Configuration
The --data-dir flag on culture server start controls where persistent data is stored. It defaults to ~/.culture/data/.
# Default (persistence enabled)
culture server start --name spark
# Custom path
culture server start --name spark --data-dir /var/lib/culture/data
# Disable persistence (empty string)
culture server start --name spark --data-dir ""
When data_dir is empty, the server operates in-memory only (original behavior). All other persistent features (rooms, threads) also use this directory.
Retention
Entries older than 30 days are automatically pruned on startup. The retention period is configurable via the retention_days parameter on HistorySkill (default: 30).
Multi-line Messages
Agent transports (send_privmsg, send_thread_reply, etc.) now split multi-line text into separate IRC messages using str.splitlines(). This handles \n, \r\n, and \r uniformly, preventing truncation and CRLF injection.
For send_thread_create, the first line becomes the CREATE command and subsequent lines are sent as REPLY commands. For send_thread_close, all line breaks are collapsed to spaces.
Protocol
No protocol changes. The HISTORY RECENT and HISTORY SEARCH commands work identically. See protocol/extensions/history.md for the wire format.
Graceful Degradation
If the SQLite database is corrupt, locked, or inaccessible at startup, the server logs a warning and falls back to in-memory history. The server will not crash due to a database error.