Persistence Layer¶
NBER-CLI uses a local SQLite database plus a JSON config file. The database stores caches and operational logs; the config file stores user-selected runtime settings such as the database path, info cache behavior, and download defaults.
Files¶
| File | Default path | Purpose |
|---|---|---|
| Config | ~/.nber-cli/config.json |
Stores schema_version, database path, cache, download, and Desktop settings. |
| Database | ~/.nber-cli/nber.db |
Stores Feed, paper metadata, read state, Desktop tags, and behavior logs. |
| Legacy database | ~/.nber-cli/feed.db |
Used only as a fallback when upgrading from older releases and no nber.db exists. |
| Debug log | ~/.nber-cli/debug.log |
Rotating log file for warnings, errors, and debug output when enabled. |
| Desktop diagnostics directory | ~/.nber-cli/logs/ |
Reserved for local diagnostics; Desktop creates no long-running Python sidecar log. |
| WebView local storage | Platform-managed | Stores the Desktop paper-detail pane width on the current device. |
Database Tables¶
| Table | Primary use | Written by | Cleaned by |
|---|---|---|---|
feed_items |
Cached RSS paper entries keyed by paper ID. | CLI / Desktop worker / HTTP API | feed clean |
feed_fetches |
Audit trail for RSS fetch attempts and counts. | CLI / Desktop worker / HTTP API | No CLI cleanup command. |
read_status |
Per-paper read/unread state shared by Desktop and the optional HTTP API. | Desktop / HTTP API | No CLI cleanup command. |
info_cache |
Cached paper metadata used by info workflows and Desktop details. | CLI / MCP / Desktop worker / HTTP paper route | info cache clear |
query_log |
CLI search query history and result counts. | CLI search |
No CLI cleanup command. |
download_log |
CLI download successes and failures. | CLI download |
No CLI cleanup command. |
info_log |
Paper info lookup history. | CLI info, MCP get_paper_info |
No CLI cleanup command. |
desktop_raw_tags |
NBER Topics and Programs copied from cached metadata. | Desktop | No UI/CLI cleanup command. |
desktop_user_tags |
User-created or edited paper tags. | Desktop | Individual Desktop tag removal only. |
desktop_hidden_raw_tags |
NBER-derived tags hidden on this device. | Desktop | No UI/CLI bulk cleanup command. |
desktop_raw_tag_sync_state |
Per-paper source-tag synchronization marker. | Desktop | No UI/CLI cleanup command. |
The shared schema version is stored in SQLite PRAGMA user_version. Version 3 is current. Existing v1 and v2 databases upgrade automatically on the next database-backed CLI operation, Desktop start, or optional HTTP-server start. The v2-to-v3 migration adds read_status without removing existing Feed, cache, or log rows. NBER-CLI refuses to write to a database created by a newer schema version.
The four desktop_* tag tables are Desktop extensions created with CREATE TABLE IF NOT EXISTS. They do not change PRAGMA user_version, so the same database remains compatible with CLI schema v3. Source tags, user tags, and hidden-source choices are intentionally separate.
The optional HTTP server has a custom-path caveat in 0.10.0. Feed and read-state routes use the server's --db-path; the paper-details metadata-cache call uses the Python-configured feed.db-path or its default. Keep those paths identical to prevent info_cache from being written to a different database. See Local HTTP API.
Info Cache Behavior¶
The info cache is controlled by:
When the cache is enabled, info and MCP get_paper_info first check info_cache. A fresh cache hit returns local data and then updates last_fetched_at plus fetch_count. This makes the TTL sliding: frequently used paper metadata remains fresh relative to the most recent local hit.
Use --refresh on the CLI to bypass the cache for one info call:
The MCP tool does not expose a per-call refresh flag. To force a live MCP lookup, disable the cache temporarily or wait for the TTL to expire.
Feed Cache Behavior¶
feed fetch stores every fetched RSS item, then returns either only newly discovered items or all fetched items:
feed_items is keyed by paper ID. Existing rows are updated with the latest title, abstract, URL, source URL, GUID, authors, and last_seen_at. New rows keep their original first_seen_at.
feed_fetches is an append-only audit table. feed clean does not remove it. Desktop refresh calls the same Python Feed implementation. When info.cache_enabled is true, the worker also prefetches paper details into info_cache; when false, it skips that step. Rust then synchronizes Topics and Programs that are available in cached metadata into the Desktop raw-tag tables.
Logs and Soft Failures¶
Search, download, and info operations try to append behavior logs. These writes are intentionally non-critical: a database error can emit a warning, but it should not prevent the main search, download, or metadata lookup from completing.
Cache reads also fail soft where possible. If a cache read cannot be completed safely, the command falls back to the network path or returns an empty cache count depending on the helper.
Migration and Path Rules¶
Initialize or move the database:
nber-cli db init
nber-cli db init --db-path ~/data/nber.db
nber-cli db init --db-path sqlite:////Users/name/data/nber.db
nber-cli db migrate ~/data/nber.db
On macOS and Linux, the database path must stay inside the user's home directory. This limit avoids accidental writes into system or shared locations. The destination for db migrate must not already exist, and sidecar files such as -wal, -shm, and -journal move with the database.
Cleanup Coverage¶
nber-cli feed clean --days 30
nber-cli feed clean --all
nber-cli info cache clear --days 30
nber-cli info cache clear --all
Both cleanup commands show a preview and require confirmation before deleting rows. feed clean deletes only feed_items. info cache clear deletes only info_cache. Logs, feed_fetches, read_status, and all desktop_* tables require individual Desktop actions where available, manual SQLite maintenance, or a fresh database.
Removing a paper from feed_items does not automatically remove related read state or Desktop tag rows. Treat manual SQL cleanup as an advanced operation and back up the database first.
Backup¶
For a safe backup, close Desktop and stop any running CLI, MCP, or local HTTP server process. Copy nber.db together with any nber.db-wal and nber.db-shm sidecar files. For a database that must remain online, use SQLite's backup command: