PostgreSQL-backed key-value storage for session-scoped data that must survive server restarts.
Provides a simple API for tools to persist per-session state without inventing ad-hoc storage mechanisms.
Current consumers:
scope='todo')scope='scratchpad')Future consumers: recall context, wizard state, user preferences per session.
CREATE TABLE session_store (
id SERIAL PRIMARY KEY,
user_id TEXT NOT NULL DEFAULT '',
session_id TEXT NOT NULL,
scope TEXT NOT NULL,
key TEXT NOT NULL,
value TEXT NOT NULL DEFAULT '',
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (user_id, session_id, scope, key)
);
Note on user_id: NULL is normalized to an empty string before every operation. This prevents duplicate rows for anonymous sessions because PostgreSQL treats NULL as distinct in unique constraints.
navi.store.KvStore)from navi.store import KvStore
store = KvStore("postgresql://...")
await store.get(user_id, session_id, scope, key) # str | None
await store.set(user_id, session_id, scope, key, value) # None
await store.get_all(user_id, session_id, scope) # dict[str, str]
await store.delete(user_id, session_id, scope, key) # None
await store.clear_scope(user_id, session_id, scope) # None
user_id — nullable for legacy single-user mode.session_id — the chat session UUID.scope — namespace: todo, scratchpad, or any custom string.key — arbitrary string identifier within the scope.KvStore is created as a singleton in navi/api/deps.py (get_kv_store()) and injected into build_default_registries(), which passes it to TodoTool and ScratchpadTool on startup.