Skip to content

feat: --readonly mode — guaranteed non-mutating DB access for agents and the dashboard (borrowed from mnemon) #233

Description

@edheltzel

Context

From the 2026-07-13 mnemon competitive review, red-team validated (breadcrumb #3984, learning #668). This was the red team's highest-value addition to the original steal list — not in the review's first ranking. STEAL LATER tier: queue behind the STEAL NOW pair #231/#232.

mnemon reference: OpenReadOnly opens SQLite with mode=ro + journal_mode=OFF (internal/store/db.go:205), plus a --readonly CLI flag — safe for read-only mounts and guaranteed non-mutating queries.

Why Recall wants it

A memory tool daily-driven across three hosts benefits from a mode that cannot mutate data:

  • Safe to point exploratory/spawned agents at (recall --readonly search ..., or RECALL_READONLY=1)
  • Safe foundation for the planned web dashboard (create a website and web ui dashboard #221) — the UI process never holds a write handle
  • Fits the pre-1.0 'reduce the ways the tool can break or mutate data' posture

Sketch

  • Connection-level enforcement, not convention: open with SQLite mode=ro (bun:sqlite readonly: true), so writes fail at the driver, not by code discipline
  • Surface: global --readonly flag + RECALL_READONLY env (env matters for MCP server registration and spawned agents)
  • WAL note: read-only connections to a WAL DB need the -wal/-shm files readable; verify behavior when the main process has the DB open concurrently
  • Mutating commands exit early with a clear error naming the mode

Acceptance criteria

  • With readonly active, every mutating path (add/dump/age/consolidate/prune/import/migrations) fails fast with a clear message; search/recall/stats/export work
  • Enforced at the connection level (driver rejects writes), not just per-command guards
  • Works for both CLI and MCP server (env-based)
  • bun tests: write rejection, read paths OK, concurrent read-only + writer session

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-triageMaintainer needs to evaluate this issuerisk:lowwork that is non-ambiguous, no human judgement as `agent:ready`type:featureNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions