Newer
Older
navi-1 / docs / store.md

Session KV Store

PostgreSQL-backed key-value storage for session-scoped data that must survive server restarts.

Purpose

Provides a simple API for tools to persist per-session state without inventing ad-hoc storage mechanisms.

Current consumers:

  • todo — task plans (scope='todo')
  • scratchpad — working notes (scope='scratchpad')

Future consumers: recall context, wizard state, user preferences per session.

Schema

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.

API (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.

Wiring

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.