A command-line tool for exploring, retrieving, and analyzing economic data from the Federal Reserve Bank of St. Louis FRED® API.
FRED® is a registered trademark of the Federal Reserve Bank of St. Louis.
Data sourced from FRED®, Federal Reserve Bank of St. Louis; https://fred.stlouisfed.org/
This project is not affiliated with or endorsed by the Federal Reserve Bank of St. Louis.
- Why reserve?
- Install
- Release Integrity
- Quick Start
- Design Philosophy
- The Command Model
- Command Reference
- series — discover and inspect data series
- obs — retrieve observations
- category — browse the data hierarchy
- release — data releases
- source — data source institutions
- tag — search by tag
- search — global full-text search
- meta — batch metadata retrieval
- fetch — accumulate data locally
- transform — pipeline operators
- window — rolling statistics
- analyze — statistical analysis
- cache — manage local database
- config — configuration management
- version — binary version and build info
- onboard — machine-readable onboarding context
- Pipeline Usage
- Output Formats
- Global Flags
- Configuration
- Changelog
- License
The FRED® API is one of the richest free economic data sources in the world — 800,000+ series, updated continuously. But most tools that wrap it are platform-locked, dependency-heavy, or require a running database server just to get started.
reserve takes a different approach:
-
Cross-platform, zero-dependency binary. Written in Go,
reservecompiles to a single static executable with no runtime, no interpreter, and no external libraries to install. Run the same binary on Linux x86-64, Windows, ARM servers, and Apple Silicon — natively, without emulation. -
Command-object model. Every subcommand is a first-class object with a defined input schema, validation, and a uniform
Resultenvelope. Commands compose cleanly, behave predictably, and are trivial to extend. No monolithic scripts, no implicit globals. -
Embedded database — no server required. Observation data is persisted in a single embedded database file that is created on the fly. The actual embedded database is bbolt, a proven embedded key-value store used in production systems. It can scale to hold tens of millions of datapoints with ease. No Postgres, no SQL Server, no running process. If your use cases require data to be centralized in a server or cloud data platform such as Snowflake, comma-separated value outputs are supported throughout reserve.
-
Pipeline-ready for large data environments.
reservespeaks JSONL on stdin/stdout — the lingua franca of Unix data pipelines. Chain transforms and analyses with|, redirect to files, or feed downstream tools. Every operator is NaN-aware and handles FRED's missing-value conventions correctly at scale. CSV formatting is also supported for importing data into other data stores or spreadsheets. -
LLM and agentic workflow ready. JSONL is the native input format for modern AI pipelines. Pipe
reserveoutput directly into LLM tool-call chains, vector embedding workflows, or agentic analysis frameworks — economic time series, transformed and structured, exactly where your model expects it. -
Built-in rate limiting and retry logic. The API client enforces a configurable token-bucket rate limiter and exponential backoff on transient failures — the right defaults for shared financial data environments where API quotas matter.
-
Idiomatic Go semantics throughout. Structured logging via
slog, context cancellation on every HTTP call, bounded concurrency withsync.WaitGroupand semaphores, deterministic output ordering, and clean separation between packages. The codebase is readable, testable, and auditable. -
Small, fast, and self-contained. The compiled binary is under 15 MB. Cold start is measured in milliseconds. Analysis on years of monthly data runs in memory without paging. The right tool for automated pipelines, cron jobs, and production data workflows — not just interactive exploration.
curl -fsSL https://download.reservecli.dev/install.sh | shPinned version:
curl -fsSL https://download.reservecli.dev/install.sh | sh -s v1.1.0Windows PowerShell:
irm https://download.reservecli.dev/install.ps1 | iexThese installers download from your configured download.reservecli.dev distribution endpoint. Publishing to that endpoint is a manual release step. The release payload now includes a root-level release.json manifest that powers reserve update check.
From source:
git clone https://github.com/derickschaefer/reserve
cd reserve
go build -o reserve .Requires Go 1.25.7+ for source builds.
Release artifacts are signed with keyless Sigstore/cosign signatures from GitHub Actions OIDC.
- Workflow:
.github/workflows/release-keyless.yml - Verification guide:
docs/release-security.md
Quick verification (after downloading release assets from your distribution endpoint):
sha256sum -c SHA256SUMS
cosign verify-blob \
--certificate SHA256SUMS.pem \
--signature SHA256SUMS.sig \
--certificate-identity-regexp '^https://github.com/derickschaefer/reserve/\.github/workflows/release-keyless\.yml@refs/tags/v[0-9].*$' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
SHA256SUMS1. Get a free API key
Register at https://fred.stlouisfed.org/docs/api/api_key.html
2. Configure
reserve config init
reserve config set api_key YOUR_KEY_HEREOr set via environment variable:
export FRED_API_KEY=YOUR_KEY_HERE3. Explore live data
reserve series search "unemployment rate" --limit 5
reserve series get UNRATE
reserve obs get UNRATE --start 2020-01-01
reserve obs latest GDP UNRATE CPIAUCSL4. Accumulate data locally for analysis
reserve fetch series GDP CPIAUCSL UNRATE FEDFUNDS --start 2010-01-01 --store
reserve obs get GDP --from cache5. Run the analysis pipeline
# Quarter-over-quarter GDP growth with summary statistics
reserve obs get GDP --from cache --format jsonl | reserve transform pct-change | reserve analyze summary
# Long-run unemployment trend
reserve obs get UNRATE --from cache --format jsonl | reserve analyze trend
# Annual CPI averages
reserve obs get CPIAUCSL --from cache --format jsonl | reserve transform resample --freq annual --method meanreserve operates in two distinct modes:
Live mode — Discovery and retrieval commands (series, obs, category, search, etc.) hit the FRED API directly by default. obs get uses --from live implicitly when no source is specified.
Analysis mode — You explicitly accumulate data into a local bbolt database using fetch --store, then read it back with obs get --from cache. That makes analysis fast, reproducible, and offline-capable.
The pipeline is Unix-native. Commands that produce observations write JSONL to stdout; transform and analyze commands read JSONL from stdin. Chain them with |. When stdout is a terminal, output defaults to a formatted table. When piped, it defaults to JSONL.
reserve uses a pragmatic command model that is worth understanding before you explore the full command reference.
Most commands follow a noun-verb pattern: the top-level command names a resource, and its subcommands are operations on that resource. This maps naturally onto the structure of the FRED API and the local data model.
reserve series get UNRATE # noun: series / verb: get
reserve category tree root # noun: category / verb: tree
reserve release list # noun: release / verb: list
reserve obs get CPIAUCSL --from cache # noun: obs / verb: get
reserve config set api_key XYZ # noun: config / verb: set
obs is still a normal FRED wrapper noun. It is slightly unusual only because the name is abbreviated; conceptually it belongs alongside series, category, release, source, tag, and meta.
onboard is different: it is a support/meta command that emits machine-readable documentation for agents, LLMs, and advanced users.
reserve obs get UNRATE --start 2020-01-01 # noun: obs (observations)
reserve onboard --topic pipeline # onboarding context for agents and advanced users
Pipeline operators — transform, window, analyze, and chart — are pure verbs. They have no resource noun because they do not target a named entity. They operate on whatever JSONL stream arrives on stdin. The data source is implicit, so there is nothing meaningful to name.
... | reserve transform pct-change --period 12
... | reserve window roll --stat mean --window 6
... | reserve analyze trend
... | reserve chart plot
Finally, fetch and search are action-oriented commands rather than resource nouns. fetch performs batch acquisition across supported entity types, while search performs full-text query across supported global entities such as series and tags.
reserve fetch series GDP UNRATE CPIAUCSL --store
reserve search "yield curve"
In summary:
| Class | Pattern | Examples |
|---|---|---|
| FRED API wrappers | noun verb | obs, series, category, release, source, tag, meta |
| Local state operations | noun verb | cache, config |
| Support / meta commands | noun verb | onboard |
| Pipeline operators | verb only | transform, window, analyze, chart |
| Batch acquisition | verb noun | fetch |
| Standalone query | verb only | search |
| Utility | standalone | version, completion, help |
The noun-verb commands follow consistent flag conventions and produce the same Result envelope. The pipeline operators follow consistent stdin/stdout JSONL semantics. Within each class, behavior is uniform and predictable.
Discover and inspect FRED data series. Use series get for immediate metadata lookup on known IDs; use fetch when you want batch acquisition workflows.
reserve series get <SERIES_ID...> # metadata for one or more series
reserve series search "<query>" [--limit N] # full-text search
reserve series tags <SERIES_ID> # tags applied to a series
reserve series categories <SERIES_ID> # categories a series belongs toExamples:
reserve series get CPIAUCSL
reserve series get GDP UNRATE CPIAUCSL --format json
reserve series search "consumer price index" --limit 10
reserve series tags UNRATE
reserve series categories GDPFetch time series observations from a selected source. The default source is live FRED API access. Use obs get for immediate retrieval on stdout; use fetch series --store when you want to build or refresh a reusable local dataset first.
reserve obs get <SERIES_ID...> [flags]
reserve obs latest <SERIES_ID...>Flags for obs get:
--start YYYY-MM-DD start date
--end YYYY-MM-DD end date
--freq daily|weekly|monthly|quarterly|annual
--units lin|chg|ch1|pch|pc1|pca|cch|cca|log
--agg avg|sum|eop
--from live|cache data origin (default: live)
--limit N max observations (0 = all)
Units reference: lin = levels, pch = % change, pc1 = % change from year ago, log = natural log.
Examples:
reserve obs get UNRATE --start 2020-01-01 --end 2024-12-31
reserve obs get GDP --from cache
reserve obs get GDP --from cache --format jsonl
reserve obs get CPIAUCSL --freq monthly --units pc1 # year-over-year % change
reserve obs get GDP CPIAUCSL --format csv --out data.csv
reserve obs latest GDP UNRATE CPIAUCSL FEDFUNDSBrowse the FRED category hierarchy.
reserve category get <CATEGORY_ID>
reserve category list <CATEGORY_ID|root>
reserve category tree <CATEGORY_ID|root> [--depth N]
reserve category series <CATEGORY_ID> [--limit N]Examples:
reserve category list root # top-level categories
reserve category tree 32991 --depth 2 # subtree with depth limit
reserve category series 32991 # series within a categoryExplore scheduled FRED data releases.
reserve release list
reserve release get <RELEASE_ID>
reserve release dates <RELEASE_ID>
reserve release series <RELEASE_ID> [--limit N]Explore the institutions that provide data to FRED.
reserve source list
reserve source get <SOURCE_ID>
reserve source releases <SOURCE_ID>Search and explore FRED tags.
reserve tag search "<query>" [--limit N]
reserve tag series <TAG...> [--limit N]
reserve tag related <TAG> [--limit N]Global full-text search across supported global entity types.
reserve search "<query>" [--type series|tag|all] [--limit N]Examples:
reserve search "consumer price index" --type series --limit 10
reserve search "employment" --type allBatch metadata retrieval for any entity type.
reserve meta series <SERIES_ID...>
reserve meta category <CATEGORY_ID...>
reserve meta release <RELEASE_ID...>
reserve meta tag <TAG...>
reserve meta source <SOURCE_ID...>Fetch metadata or observations from the FRED API in batch. Use series get or obs get when you want data immediately on stdout; use fetch, especially fetch series --store, when you want to acquire and persist a reusable local working set.
reserve fetch series <SERIES_ID...> [--start YYYY-MM-DD] [--end YYYY-MM-DD] [--store]
reserve fetch category <CATEGORY_ID|root>
reserve fetch query "<query>" [--limit N]For fetch series:
--store fetch observations and persist them to the local database; also stores series metadata
--start YYYY-MM-DD start date for fetched observations
--end YYYY-MM-DD end date for fetched observations
Examples:
# Build a local dataset with four core macro series from 2010 onward
reserve fetch series GDP CPIAUCSL UNRATE FEDFUNDS --start 2010-01-01 --store
# Refresh one cached series from a known start date
reserve fetch series GDP --start 2010-01-01 --storeStored data is written to ~/.reserve/reserve.db by default (override with db_path in config.json or the RESERVE_DB_PATH environment variable). There is no automatic expiry on stored observations.
Pipeline operators. Each reads JSONL from stdin, applies a transformation, and writes JSONL to stdout.
reserve transform pct-change [--period N]
reserve transform diff [--order 1|2]
reserve transform log
reserve transform index --base 100 --at YYYY-MM-DD
reserve transform normalize [--method zscore|minmax]
reserve transform resample --freq monthly|quarterly|annual --method mean|last|sum
reserve transform filter [--after YYYY-MM-DD] [--before YYYY-MM-DD] \
[--min N] [--max N] [--drop-missing]| Operator | Description |
|---|---|
pct-change |
`(v[t] − v[t-N]) / |
diff |
First difference v[t] − v[t-1], or second difference with --order 2. |
log |
Natural log of each value. Non-positive inputs produce NaN with a warning. |
index |
Re-scales the series so the value at --at equals --base (default 100). |
normalize |
Z-score standardization (zscore) or min-max scaling to 0–1 (minmax). |
resample |
Downsample to a lower frequency. mean averages the period, last takes the final value, sum accumulates. |
filter |
Retain observations within a date range or value bounds. --drop-missing removes NaN rows. |
Examples:
# Quarter-over-quarter GDP growth rate
reserve obs get GDP --from cache --format jsonl | reserve transform pct-change
# Year-over-year CPI inflation (monthly data)
reserve obs get CPIAUCSL --from cache --format jsonl | reserve transform pct-change --period 12
# Index GDP to 100 at the start of 2010
reserve obs get GDP --from cache --format jsonl | reserve transform index --base 100 --at 2010-01-01
# Annual average CPI
reserve obs get CPIAUCSL --from cache --format jsonl | reserve transform resample --freq annual --method mean
# Post-2020 observations only
reserve obs get UNRATE --from cache --format jsonl | reserve transform filter --after 2020-01-01Rolling window statistics over a JSONL stream.
reserve window roll --stat mean|std|min|max|sum --window N [--min-periods M]NaN values are excluded from window computations. If fewer than --min-periods valid values exist in a window, the output for that period is NaN.
Examples:
# 12-month rolling average unemployment rate
reserve obs get UNRATE --from cache --format jsonl | reserve window roll --stat mean --window 12
# 4-quarter rolling standard deviation of GDP growth
reserve obs get GDP --from cache --format jsonl | reserve transform pct-change \
| reserve window roll --stat std --window 4Statistical analysis on a JSONL stream. Results print to the terminal (table or JSON).
reserve analyze summary # descriptive statistics
reserve analyze trend [--method linear|theil-sen]analyze summary produces:
| Field | Description |
|---|---|
| count | total observations |
| missing | NaN count and percentage |
| mean, std | mean and standard deviation |
| min, p25, median, p75, max | five-number summary |
| skew | Fisher-Pearson skewness coefficient |
| first, last | boundary non-NaN values |
| change, change_pct | absolute and percentage change over the full series |
analyze trend produces:
| Field | Description |
|---|---|
| direction | up, down, or flat |
| slope_per_year | trend slope in original units per year |
| slope_per_day | slope in original units per day |
| intercept | regression intercept |
| r2 | coefficient of determination (0–1) |
| method | linear (OLS) or theil-sen (robust) |
Examples:
reserve obs get UNRATE --from cache --format jsonl | reserve analyze summary
reserve obs get GDP --from cache --format jsonl | reserve transform pct-change | reserve analyze summary
reserve obs get UNRATE --from cache --format jsonl | reserve analyze trend
reserve obs get UNRATE --from cache --format jsonl | reserve analyze trend --method theil-senManage the local bbolt database.
reserve cache stats # bucket row counts and DB size
reserve cache clear --all # wipe all data
reserve cache clear --bucket obs # wipe observations only
reserve cache clear --bucket series_meta # wipe metadata only
reserve cache compact # reclaim disk space after clearingcache clear removes entries from one bucket or all buckets. bbolt does not shrink the database file automatically — freed pages are returned to an internal freelist and reused on future writes. The file footprint does not decrease until you run compact.
cache compact rewrites the database to a new file, recovering all space freed by prior clears. The operation is safe: live data is copied to a temporary file first, then the original is atomically replaced.
# Typical maintenance workflow after a large clear:
reserve cache clear --all
reserve cache compactManage config.json in the user config directory, with optional local ./config.json overrides.
reserve config init # create a template config.json in your user config directory
reserve config get [--show-secrets] # print resolved configuration (key redacted by default)
reserve config set <key> <value> # update a single valueValid keys: api_key, default_format, timeout, concurrency, rate, base_url, db_path.
Print the reserve version string and build metadata.
reserve version # plain text — grep/awk friendly
reserve version --format json # structured output
reserve version --format jsonl # single line for audit streamsPlain text output:
reserve v1.0.9
go go1.25.7
os linux/amd64
built 2026-02-28T18:42:00ZCheck a lightweight remote release manifest for newer versions and short release notes.
reserve update check # human-readable update status
reserve update check --format json # structured output for scripts
reserve update check --format jsonl # single-line audit/event outputWhen a new release is available, reserve prints the current version, latest version, a short summary, release highlights, and static update instructions from the remote manifest.
Emit a machine-readable onboarding document for agents, LLMs, and advanced users. It is designed to be pasted directly into Claude, ChatGPT, or another agent session so the model gets authoritative reserve semantics without guessing at commands or flags.
reserve onboard # full-program onboarding
reserve onboard obs # command-specific onboarding
reserve onboard --topic pipeline # single topic
reserve onboard --topic pipeline,gotchas # comma-separated topics
reserve onboard --topic all # full document (large context windows)
reserve onboard --topic all | pbcopy # copy to clipboard
reserve onboard export ./onboard # write program.json + per-command docsTopics:
| Topic | Contents |
|---|---|
toc |
Topic index and interaction guide (default) |
commands |
Full command reference: nouns, verbs, flags, formats |
pipeline |
stdin/stdout semantics, JSONL format, operator chaining |
data-model |
Core types, NaN handling, Result envelope |
examples |
Verified end-to-end examples with confirmed output values |
gotchas |
Sharp edges, missing data, known limitations |
version |
Build metadata for provenance |
all |
Everything — for large context windows |
Workflow:
# Step 1 — handshake: let the AI tell you what it needs
reserve onboard --topic toc
# paste into your LLM session
# Step 2 — surgical context: paste only what the AI requested
reserve onboard --topic pipeline,data-model,gotchas
# paste → LLM confirms ready
# Step 3 — ask your questionProject export:
reserve onboard export ./onboard
# writes program.json plus command docs like obs.json, series.json, and config.jsonSuggested prompt:
I am about to explore macro-economic data from the FRED API.
Use this as your reference for a CLI called reserve.
It contains the authoritative command reference, pipeline
semantics, verified examples, and known gotchas.
Tell me when you are ready.
Output is always JSON with HTML escaping disabled — < and > render
literally, not as \u003c / \u003e.
Any command that produces observations can be piped into a transform or analyze command:
# Full macro pipeline: fetch → cache read → transform → analyze
reserve obs get GDP --from cache --format jsonl \
| reserve transform pct-change \
| reserve analyze summary
# Post-COVID unemployment: filter → rolling average
reserve obs get UNRATE --from cache --format jsonl \
| reserve transform filter --after 2020-01-01 \
| reserve window roll --stat mean --window 12
# Inflation signal: resample monthly CPI to annual → trend
reserve obs get CPIAUCSL --from cache --format jsonl \
| reserve transform resample --freq annual --method mean \
| reserve analyze trend
# Year-over-year unemployment change → CSV file
reserve obs get UNRATE --from cache --format jsonl \
| reserve transform pct-change --period 12 \
| reserve transform filter --drop-missing \
> unrate_yoy.csvNaN handling: FRED missing values (reported as ".") become NaN internally. Transforms skip NaN inputs in calculations and propagate NaN to outputs where appropriate. analyze summary counts and reports missing values explicitly.
Format auto-detection: Pipeline commands default to jsonl when piped, table when output is a terminal. Override with --format on any command.
All commands accept --format:
| Format | Description |
|---|---|
table |
Human-readable aligned table (default for terminal output) |
json |
Full result envelope as pretty-printed JSON |
jsonl |
One JSON object per line (default for piped output) |
csv |
Comma-separated with header row |
tsv |
Tab-separated with header row |
md |
Markdown table |
Write to a file with --out:
reserve obs get GDP --format csv --out gdp.csv
reserve obs get CPIAUCSL --from cache --format jsonl --out cpi.jsonlThese flags are available on every command:
--format table|json|jsonl|csv|tsv|md output format
--out <path> write command output to file (renderer-backed commands)
--api-key <key> override API key for this invocation only
--timeout <duration> HTTP request timeout (default: 30s)
--concurrency <n> parallel requests for batch operations (default: 8)
--rate <n> API requests/sec client-side limit (default: 5.0)
--verbose show timing and cache stats after output
--debug log HTTP requests (API key redacted)
--quiet suppress all non-error output
--no-cache bypass local database reads
--refresh force re-fetch and overwrite cached entries
reserve config init creates config.json in your user config directory:
- Linux:
~/.config/reserve/config.json - macOS:
~/Library/Application Support/reserve/config.json - Windows:
%AppData%\reserve\config.json
If a local ./config.json exists in the current working directory, it overrides the user config file for that shell location.
This makes ad hoc project overrides easy in a very Unix-style way: keep your personal API key and defaults in the user config file, then drop a local ./config.json into a test or project directory when you want to override only selected settings such as default_format or db_path.
Example local override:
{
"default_format": "json",
"db_path": "/tmp/reserve-local.db"
}In that directory, reserve will still inherit any missing values such as api_key from your user config, while honoring the local overrides for the fields you set.
Example file contents:
{
"api_key": "YOUR_KEY_HERE",
"default_format": "table",
"timeout": "30s",
"concurrency": 8,
"rate": 5.0,
"db_path": ""
}API key resolution order (first non-empty wins):
--api-keyCLI flagFRED_API_KEYenvironment variableapi_keyin local./config.jsonapi_keyin userconfig.json
Database path resolution order:
RESERVE_DB_PATHenvironment variabledb_pathin local./config.jsondb_pathin userconfig.json- Default:
~/.reserve/reserve.db
See CHANGELOG.md for the full version history.
MIT — see LICENSE.
FRED® is a registered trademark of the Federal Reserve Bank of St. Louis.
This project is not affiliated with or endorsed by the Federal Reserve Bank of St. Louis.