Separate history files per user with per-user subdirectories#169
Separate history files per user with per-user subdirectories#169
Conversation
Write conversation logs to DATA_DIR/history/<chat_id>/YYYY-MM-DD.jsonl instead of a shared flat file. Each user's messages are physically isolated on disk, so grep/jq searches are naturally scoped and one user's history can be managed independently. Legacy flat files (pre-migration) are included in reads transparently via the existing chat_id filter. They age out naturally as new writes go to per-user directories. No migration step needed. Inner Claude's injected history path is scoped to the user's subdirectory so searches target the right directory automatically. Fixes #157
Review by KaiPR Review:
|
Test used overlapping strings ('private' / 'also private') making the
assertion vacuously true. Use distinct strings ('from alice' / 'from
bob') for real isolation coverage.
Also fix falsy check to 'is not None' in claude.py history path
injection, consistent with the rest of the codebase.
Review by KaiPR Review:
|
Review by KaiPR Review:
|
Summary
Write conversation history to per-user subdirectories (
DATA_DIR/history/<chat_id>/) instead of shared flat files. This physically isolates each user's messages on disk, adding defense-in-depth to the existing read-sidechat_idfilter.Before
After
Changes
src/kai/history.pylog_message()writes to_LOG_DIR/<chat_id>/;get_recent_history()scans per-user dirs with legacy flat file fallbacksrc/kai/claude.pyDATA_DIR/history/<chat_id>/Migration
No migration step needed. Legacy flat files at
_LOG_DIR/*.jsonlare included in reads transparently via the existingchat_idfilter in the record-parsing loop. They age out naturally as new writes go to per-user directories.Test plan
test_creates_per_user_directory- log_message creates<chat_id>/subdirectorytest_different_users_get_separate_directories- users 111 and 222 get separate dirstest_no_flat_file_created- new writes don't go to the flat roottest_reads_only_target_user- get_recent_history(chat_id=111) returns only 111's messagestest_none_chat_id_returns_all- get_recent_history(chat_id=None) returns all userstest_legacy_flat_files_included- pre-migration flat files are included in readstest_new_user_empty_history- user with no directory gets empty stringmake checkcleanFixes #157