fredq brings FRED (Federal
Reserve Economic Data) to Python two ways: a typed library for programs
(fredq.Series("DGS10").observations() returns a polars frame; .info()
returns a validated, typed record) and an LLM-friendly command line
(fredq series observations DGS10) that prints the raw JSON FRED returns,
byte-for-byte, for scripts, agents, and quick terminal work.
fredq is a Python 3.10+ package:
pip install fredq
# or, as a standalone CLI tool
uv tool install fredqAdd the pandas extra for to_pandas() / to_arrow() frame conversions:
pip install "fredq[pandas]"A free FRED API key is required — see Auth.
fredq ships an Agent Skills–standard skill (a SKILL.md package readable
by Claude Code, Codex CLI, Cursor, Gemini CLI, Copilot, Pi, and other
agents) that teaches coding agents both the library and the CLI: idiomatic
patterns, endpoint routing, and corpus-dated sharp edges. Install it into
an agent's skill directory by name:
fredq skills install --agent claudeNamed targets: claude, codex, copilot, cursor, gemini, pi
(comma-separable). Add --project to install into the current repository's
agent directories instead of your user-level ones, or --to PATH for any
other skills root. Installs are plain copies — re-run fredq skills install after upgrading fredq. fredq skills list shows every named
location with its installed version, and fredq skills uninstall removes
installs (it never touches a directory it does not own). See
fredq skills --help.
import fredq
# Observations come back as a typed, polars-backed frame.
obs = fredq.Series("DGS10").observations(observation_start="2024-01-01")
df = obs.to_polars() # or .to_pandas() / .to_arrow() (needs [pandas]) / .to_dicts()
print(obs.meta.units, obs.meta.count) # the response envelope, corpus-typed
# Metadata calls return validated pydantic models with real fields.
info = fredq.Series("DGS10").info()
print(info.title, info.frequency, info.observation_start)
# Free-text search, releases, sources — all typed.
hits = fredq.search_series("10-year treasury", limit=10)
for s in hits.seriess:
print(s.id, s.title)
release = fredq.Release(53).info() # 53 = GDP
print(release.name, release.link)Errors are raised as typed exceptions instead of surfacing raw HTTP details:
from fredq import FredApiError
try:
fredq.Series("NOT-A-REAL-SERIES").info()
except FredApiError as exc:
print(exc.error_code, exc.error_message)Configure the shared client once, before the first call (API key, timeout):
fredq.configure(api_key="...", timeout=None)Anything without a first-class method is reachable through the escape hatch, which validates parameters exactly like the typed calls and returns the parsed payload as a plain dict:
payload = fredq.raw("series", series_id="DGS10")Every entity class binds one ID and exposes endpoint methods as
keyword-only calls (wire parameter names, unchanged from FRED's own
spelling). Every call is one HTTP request and returns a typed pydantic
model, except Series.observations(), which returns an Observations
frame.
| Entity | Methods |
|---|---|
Series(series_id) |
info, observations, vintage_dates, categories, tags, release |
Category(category_id) |
info, children, related, series, tags, related_tags |
Release(release_id) |
info, dates, series, sources, tags, related_tags, tables |
Source(source_id) |
info, releases |
Module-level functions cover the endpoints with no natural entity owner:
| Function | FRED data |
|---|---|
search_series(search_text, ...) |
Search FRED series by keyword. |
search_series_tags(series_search_text, ...) |
Tags for a series full-text search. |
search_series_related_tags(series_search_text, tag_names, ...) |
Tags related to a search and existing tag filter. |
series_updates(...) |
Recently updated FRED series. |
releases(...) |
All FRED economic data releases. |
release_calendar(...) |
Release dates across all FRED releases. |
sources(...) |
All FRED data sources. |
tags(...) |
All FRED tags. |
tag_series(tag_names, ...) |
Series matching a set of FRED tags. |
related_tags(tag_names, ...) |
Tags related to an existing tag filter. |
raw(command, **params) |
Escape hatch — any command by name. |
configure(*, api_key=None, timeout=None) |
Set shared-client options before the first call. |
Date-like parameters (observation_start, realtime_start, ...) accept a
str, datetime.date, or datetime.datetime. Errors are raised as
fredq.FredApiError (FRED's structured error response) or
fredq.FredClientUsageError (invalid arguments caught before any request is
sent); both subclass fredq.FredqError.
Every typed return value is a frozen pydantic model under fredq.models,
built directly from a corpus of real FRED responses: fields are marked
required only when they are present in 100% of the corpus's captures for
that endpoint, and optional otherwise — no guessing from documentation.
Unrecognized fields land on model_extra rather than raising, so a new FRED
field surfaces as data, not a crash. fredq ships PEP 561
type information (py.typed), so type checkers see the real return types
without stubs.
examples/fred_explorer.py is an interactive
marimo notebook built entirely on the library: a series
explorer with units transforms and frequency aggregation, multi-series
comparison, catalog search, ALFRED vintage-revision analysis, and a
mortgage-vs-Treasury spread dashboard. Run it without adding dependencies:
uv run --with marimo --with altair marimo edit examples/fred_explorer.pyThe CLI is a separate, from-scratch layer: it prints the FRED response body to stdout exactly as returned, with no reshaping or interpretation — the library's typed models are not involved. It is built for scripts, agents, and terminal use that want raw JSON.
fredq --helpShow metadata for a series:
fredq series show GNPCAFetch a series' observations:
fredq series observations CPIAUCSLApply a unit transformation and frequency aggregation:
fredq series observations CPIAUCSL --units pch --frequency mSearch for a series by keyword:
fredq series search "10-year treasury" --limit 10Browse the FRED category tree from the root:
fredq category children 0List recent economic releases:
fredq release list --limit 10List recent release publication dates across all releases:
fredq release calendar --limit 20Show metadata for a specific release (53 = GDP):
fredq release show 53Find all series tagged with a set of FRED tags:
fredq tag series "usa;monthly;cpi" --limit 25ALFRED point-in-time: see what GDP looked like on a past date:
fredq series vintage-dates GNPCA
fredq series observations GNPCA --realtime-start 2024-09-25series observations can write a typed Parquet table instead of raw JSON.
Parquet output is included in a plain install — no extra required. Pass
--format parquet --out PATH:
fredq series observations CPIAUCSL --units pch --frequency m \
--format parquet --out cpi_yoy.parquetOn success a single JSON descriptor line goes to stdout (the file format, out
path, row count, byte size). The Parquet schema is date (date32), value
(float64), realtime_start (date32), realtime_end (date32). FRED's
missing-value sentinel . is written as NaN. The full response envelope
(count, offset, limit, observation range, units, sort order) and the request
context (units, frequency, realtime range) are stored as schema key-value
metadata so the table is self-describing.
Parquet writes are scoped to series observations only; every other command
stays JSON-only, and rejects --format parquet with a usage error. Parquet
output assumes FRED's default observation layout (one row per observation);
fredq does not expose FRED's alternative output_type modes.
Most commands take an ID as a positional argument. If you don't know one yet, start with the commands that need no ID, then chain:
# Find a series ID by keyword
fredq series search "unemployment rate" --limit 10
# List the catalogs
fredq release list --limit 1000 # release IDs
fredq source list # source IDs
fredq tag list --limit 50 # tag names
# Walk the category tree from the root (0 = root)
fredq category children 0Then use the ID with the matching command:
fredq series observations DGS10
fredq category series 106
fredq release series 10Use root help to see the command list:
fredq --helpCurrent commands, grouped by how often they're reached for:
Daily-driver fetches
| Command | FRED data |
|---|---|
series show |
Show metadata for one FRED series (title, units, frequency, observation range). |
series observations |
Fetch the observation values for one FRED series. |
Series discovery
| Command | FRED data |
|---|---|
series search |
Search FRED series by keyword. |
series search-tags |
List tags for a series full-text search. |
series search-related-tags |
List tags related to a search and existing tag filter. |
tag series |
List series matching a set of FRED tags. |
tag list |
List all FRED tags. |
tag related |
List tags related to an existing tag filter. |
Series-bound analysis
| Command | FRED data |
|---|---|
series vintage-dates |
List vintage dates (revision dates) for one FRED series. |
series categories |
List categories that contain a given series. |
series tags |
List tags assigned to a FRED series. |
series release |
Show the release that a FRED series belongs to. |
series updates |
List recently updated FRED series. |
Category browse
| Command | FRED data |
|---|---|
category show |
Show metadata for one FRED category. |
category children |
List child categories of a FRED category. |
category related |
List categories related to a given FRED category. |
category series |
List series belonging to one FRED category. |
category tags |
List tags for series in one FRED category. |
category related-tags |
List tags related to a category and existing tag filter. |
Releases and calendar
| Command | FRED data |
|---|---|
release list |
List all FRED economic data releases. |
release calendar |
List release dates across all FRED releases. |
release show |
Show metadata for one FRED release. |
release dates |
List publication dates for one FRED release. |
release series |
List series belonging to one FRED release. |
release sources |
List sources for one FRED release. |
release tags |
List tags for one FRED release. |
release related-tags |
List tags related to a release and existing tag filter. |
release tables |
Fetch the hierarchical data table for one FRED release. |
Sources
| Command | FRED data |
|---|---|
source list |
List all FRED data sources. |
source show |
Show metadata for one FRED source. |
source releases |
List releases published by one FRED source. |
A bare group prints its list of subcommands; each leaf command has its own adaptive help:
fredq series --help # group: lists the series subcommands
fredq series observations --help # leaf: full endpoint help
fredq series search --help
fredq release calendar --helpLeaf-command help is the primary documentation surface. It shows the FRED target endpoint, accepted parameters, allowed value sets, defaults, and examples.
Date parameters accept:
YYYY-MM-DDcalendar dates.- ISO 8601 datetimes (the time component is dropped; UTC assumed for naive values).
- Unix timestamps in seconds (≥10 digits).
Boolean parameters accept common true and false forms such as true, false,
1, 0, yes, and no.
Tag lists (--tag-names, --exclude-tag-names) use semicolons as
separators, matching FRED's wire format:
fredq tag series "usa;annual"Most endpoints accept --realtime-start and --realtime-end to view data
as of a historical date (the ALFRED
archival API). Combined with series vintage-dates, this lets you replay
what an analyst would have seen on a specific past date — useful for
backtests and for distinguishing data revisions from real-time signals.
# When were GNP revisions published?
fredq series vintage-dates GNPCA
# What did GNP look like on 2024-09-25?
fredq series observations GNPCA \
--realtime-start 2024-09-25 --realtime-end 2024-09-25fredq writes the FRED response body to stdout exactly as returned. This makes it easy to pipe into tools that expect JSON:
fredq series show GNPCA | jq .
fredq release list --limit 25 | jq '.releases[].name'Diagnostics, warnings, and errors are written to stderr. The exit code is
0 on success, 1 on a FRED request failure, and 2 on a usage or
configuration error.
The FRED API requires a free API key. Request one at https://fred.stlouisfed.org/docs/api/api_key.html.
Both the library and the CLI read the key from, in order:
- The
FRED_API_KEYenvironment variable. - The first non-empty line of
~/.fredq/api_key. - CLI only: the
--api-keyflag (visible in process listings; prefer the env var). Library callers passapi_key=tofredq.configure()instead.
On POSIX systems, restrict the key file so only your user can read it:
chmod 600 ~/.fredq/api_keyfredq emits a warning if the file is readable by group or world. To disable
the file fallback entirely (for hermetic runs), set FREDQ_DISABLE_KEY_FILE=1
or pass --no-key-file (CLI), or call fredq.configure(api_key=...) with an
explicit key (library).
fredq never prints, logs, or echoes the API key. The key is also redacted
from URLs in error messages and from any httpx2 debug logs emitted under
--verbose.
See AGENTS.md for architecture, conventions, and the CLI-layer/library-layer split. In short:
uv sync --all-groups
uv run pytest
uv run tox # full gate: formatting, lint, type check, tests across supported Python versions, spellingfredq is released under the MIT License. See LICENSE.