Configuration¶
Most NBER-CLI runtime behavior uses built-in defaults. The local database also uses a small user config file to remember the database location selected by nber-cli db init or nber-cli db migrate.
For the full SQLite schema, cache tables, behavior logs, and backup guidance, see Persistence Layer.
Runtime Defaults¶
| Setting | Default | Description |
|---|---|---|
| Request timeout | 60 seconds |
Total timeout for network requests. |
| Retry count | 3 |
Failed eligible requests are retried before surfacing the error. |
| Request attempts | 4 |
Derived from retry count plus the first attempt. |
| Download connection limit | 100 |
Maximum concurrent download connections. |
| Per-host connection limit | 10 |
Maximum concurrent connections to one host. |
| Search page sizes | 20, 50, 100 |
Accepted values for --per-page. |
These values live in NBERCLIConfig and NBER_CLI_CONFIG. They are compile-time constants: they are not exposed in ~/.nber-cli/config.json, are not read from any environment variable, and are not settable through CLI flags. To change them you must edit the source code and reinstall the package.
If you need different transport behavior at runtime, call the Python API directly and pass a custom aiohttp.ClientSession with the timeout and connector limits you want. The package still wraps eligible requests with its own fixed-attempt retry helper; changing the retry count requires a source change.
What is configurable today¶
The following list is exhaustive — values not listed here are constants.
| Surface | Configurable? | Where |
|---|---|---|
info.cache_enabled |
Yes | ~/.nber-cli/config.json; toggle via nber-cli info cache --turn-on/--off |
info.cache_ttl_days |
Yes | ~/.nber-cli/config.json; set via nber-cli info cache --set-refresh <N> |
feed.db-path (database path or sqlite:///... URL) |
Yes | ~/.nber-cli/config.json; set via nber-cli db init --db-path ... or nber-cli db migrate ... |
download.restrict_dir |
Stored, not used as the CLI default | ~/.nber-cli/config.json; the current CLI still defaults --restrict to true on every invocation |
download.concurrency |
Yes | ~/.nber-cli/config.json; set via nber-cli config set download.concurrency <N> |
desktop.server_port |
Legacy / HTTP settings API only | Ignored by Desktop; nber-server binds from --port and does not read this field. |
desktop.feed_refresh_interval_minutes |
Yes | ~/.nber-cli/config.json or Desktop Settings; valid range 1–65535 |
desktop.detail_font_size |
Yes | Desktop Settings; accepted values are 14, 16, and 18 |
| Desktop preview width | Yes, device-local | WebView local storage; range 360–640 px, default 420 px |
| Request timeout | No | Code constant in NBERCLIConfig |
| Retry count / request attempts | No | Code constant in NBERCLIConfig |
| Download connection limits | No | Code constant in NBERCLIConfig |
| Per-host connection limit | No | Code constant in NBERCLIConfig |
| Search page sizes | No | Code constant in NBERCLIConfig |
| User-Agent string | No | Hard-coded Chrome-like value sent on every request |
| Other HTTP headers | No | Hard-coded browser-like headers sent on all requests |
User Config File¶
The user config file is:
Current schema:
{
"schema_version": 3,
"feed": {
"db-path": "/Users/name/.nber-cli/nber.db"
},
"info": {
"cache_enabled": true,
"cache_ttl_days": 30
},
"download": {
"restrict_dir": true,
"concurrency": 3
},
"desktop": {
"feed_refresh_interval_minutes": 60,
"detail_font_size": 16
}
}
feed.db-path points to the local database used by the Python info, search, download, and feed paths. It may be a normal filesystem path or a SQLite URL such as sqlite:///relative/nber.db or sqlite:////Users/name/data/nber.db. The historical feed key name is preserved for backward compatibility; the database itself is general-purpose. The optional HTTP server has a documented custom-path split, so pass the same path with nber-server --db-path.
download.restrict_dir is currently stored and schema-validated, but the CLI does not use it as the default for downloads. Each invocation defaults to restricted mode. Use --restrict false explicitly for an unrestricted invocation.
download.concurrency caps the number of concurrent downloads. It defaults to 3 and can be overridden per invocation with --concurrency <N>.
schema_version records the current database schema version. NBER-CLI updates it after db init or schema upgrades.
Desktop does not run a local server, so it ignores the legacy desktop.server_port value. The optional nber-server also does not read this field when binding; its actual port comes from --port. desktop.feed_refresh_interval_minutes controls automatic Feed refresh and must be between 1 and 65535. The timer runs only while Desktop is open, initialized, visible, and not already refreshing.
desktop.detail_font_size controls paper-detail reading text. Desktop accepts only 14, 16, or 18 and defaults invalid or missing values to 16. The preview-pane width is not written to this file; it is stored in WebView local storage for the current device.
info.cache_enabled controls the info_cache lookup globally. Set to false to force every info call (and the MCP get_paper_info tool) to go straight to NBER. Defaults to true.
info.cache_ttl_days sets the refresh interval in days. The TTL is sliding: every cache hit updates the row's last_fetched_at (via touch_info_cache) and increments fetch_count, so repeatedly consulted papers keep their cached copy for at least cache_ttl_days after the most recent hit. Cached entries whose last_fetched_at is older than the TTL threshold are treated as cache misses and re-fetched on the next info call. Must be a positive integer. Defaults to 30.
Both info keys are managed by nber-cli info cache --turn-on/--off/--set-refresh <N>. Missing or malformed fields fall back to defaults and never cause NBER-CLI to fail.
Local Database¶
Default database path:
Initialize the default database:
Initialize at a custom path:
Initialize with a SQLite URL:
Move an existing database and update the config:
If you upgraded from 0.3.0 and still have ~/.nber-cli/feed.db, NBER-CLI will keep using that legacy file when no nber.db is present. The schema is upgraded automatically on first invocation.
The database holds:
feed_itemsandfeed_fetches: RSS cache used byfeed fetchandfeed clean.info_cache: paper metadata cache used byinfoand the MCPget_paper_infotool. Cache reads are gated byinfo.cache_enabledand respect theinfo.cache_ttl_daysTTL.read_status: per-paper state used by Desktop and the optional HTTP API.desktop_raw_tags,desktop_user_tags,desktop_hidden_raw_tags, anddesktop_raw_tag_sync_state: Desktop-only tag source, user, hiding, and synchronization state.query_log,download_log,info_log: behavior logs for search keywords, download outcomes, and info lookups.
Storage, Safety, and Extensibility¶
The database is local-only. NBER-CLI does not send this cache or log database to project infrastructure, and no NBER-CLI server receives a copy. By default it lives under ~/.nber-cli/nber.db; when db init or db migrate is used on macOS or Linux, the selected file must stay inside the user's home directory. This keeps the default persistence model predictable and avoids accidental writes into system or shared locations.
The on-disk format is SQLite, so the database is a self-contained file plus standard SQLite sidecar files when WAL or journaling is active. Schema changes are versioned with SQLite's PRAGMA user_version; NBER-CLI refuses to write to a database created by a newer schema version, which protects data from accidental downgrade writes. Operations that update cache or log rows use transactions through the SQLModel/SQLAlchemy engine, and non-critical log/cache writes fail soft so a local database problem does not break search, download, or metadata lookup workflows.
The Python access layer is SQLModel on top of SQLAlchemy. Tables are declared as typed SQLModel models, while the public API still returns filesystem Path values for compatibility. This gives the current CLI a stable SQLite file today and leaves room for future database work, such as richer typed queries, stricter schema migrations, or additional SQLAlchemy-supported backends, without changing the user-facing commands first.
Database Operations¶
The database is created and upgraded automatically the first time any command that touches it runs. Running nber-cli db init is not required before using info, search, download, or feed; it exists for callers that want to pre-create the file or pin a non-default path. After db init (or after the first successful run), the schema version is recorded in ~/.nber-cli/config.json under schema_version.
Table Reference¶
| Table | Written by | Read by | Cleanup |
|---|---|---|---|
feed_items |
CLI / Desktop worker / HTTP API | CLI / Desktop / HTTP API | feed clean (with confirmation) |
feed_fetches |
CLI / Desktop worker / HTTP API | Desktop and HTTP status calculations | none |
read_status |
Desktop / HTTP API | Desktop / HTTP API | none |
info_cache |
CLI / MCP / Desktop worker / HTTP paper route | CLI / MCP / Desktop worker / HTTP paper route | info cache clear (with confirmation); HTTP uses configured/default Python DB, which may differ from server --db-path |
query_log |
search |
not read by any command | none |
download_log |
download (single and batch) |
not read by any command | none |
info_log |
info and get_paper_info |
not read by any command | none |
desktop_raw_tags |
Desktop | Desktop | none |
desktop_user_tags |
Desktop | Desktop | individual tag removal |
desktop_hidden_raw_tags |
Desktop | Desktop | none |
desktop_raw_tag_sync_state |
Desktop | Desktop | none |
CLI vs MCP Differences¶
- The CLI and the MCP
get_paper_infotool both write toinfo_logandinfo_cachewhen the cache is enabled. Neither surface emits a separate cache-hit hint. feed fetchbehaves identically in both surfaces; the MCP layer does not currently expose it.- The CLI is the only surface that writes
query_log(viasearch) anddownload_log(viadownload). The MCPsearch_papersanddownload_papertools do not write those tables in the current version.
Migrate and Reset¶
nber-cli db migrate <new_db_path> moves the database to a new path or SQLite URL, including any SQLite -wal, -shm, and -journal sidecar files, and updates feed.db-path in the user config. The destination must not already exist; the command refuses to overwrite an existing file.
There is no built-in command to reset the database to an empty state. The supported ways to start over are:
- Move the existing file aside with
nber-cli db migrate, or - Stop the CLI, delete
nber.db(and any sidecar files) directly, and runnber-cli db initagainst a new path.
Backups¶
The database is a single SQLite file plus its sidecar files. To back it up safely:
- Stop any running
nber-clior MCP server process that might hold a write transaction. - Copy
nber.dbtogether withnber.db-walandnber.db-shm(when present) into the backup location. - Use
sqlite3 nber.db ".backup '<backup_path>'"for a crash-consistent snapshot without stopping the CLI; this is the recommended approach for live systems.
Cleanup Coverage Today¶
feed cleanremoves rows fromfeed_itemsonly.feed_fetchesis a continuously growing audit log and is not cleared byfeed clean --all. To prune it, run a manualDELETE FROM feed_fetches WHERE ...against the database or usesqlite3directly.info cache clearremoves rows frominfo_cacheonly.info_logis not cleared.query_log,download_log, andinfo_loghave no CLI cleanup command. The only ways to remove them today arenber-cli db migrateto a new database, manualsqlite3operations, or deletingnber.db.
Output Paths¶
Single download default:
Creates:
Directory-based download:
Creates:
Explicit file download:
Creates exactly the requested path, including parent directories when possible.
Date Filtering¶
Search dates use YYYY-MM-DD.
If --start-date is provided without --end-date, NBER-CLI uses the current date as the end date.
Network Behavior¶
NBER-CLI sends a full set of browser-like request headers, including User-Agent, Accept, Accept-Language, and Sec-Fetch-* values, on every request to NBER. This matches the headers a real browser sends and is required because NBER's CDN now rejects requests that only carry a minimal User-Agent. NBER-CLI uses retries for transient failures and raises readable errors for common download failures.
- HTTP 403 can mean a newly released paper is still under NBER's first-week access restriction.
- HTTP 404 means the paper PDF was not found.
- Timeout and connection failures are reported as network errors.
Logging¶
NBER-CLI writes debug logs to ~/.nber-cli/debug.log. The file rotates at 1 MB and keeps up to three backups. By default only warnings and errors are written to the log file.
Use --verbose on any command to print debug messages to stderr and capture them in the log file.
You can also enable debug-level logging without printing to stderr by setting NBER_CLI_DEBUG=1. This is useful for headless or scripted runs where you want a persistent debug trail without noisy console output.
No Credentials Required¶
NBER-CLI does not require an API key. It works against public NBER web pages and NBER's public working paper search endpoint.