@pipeworx/us-econ-calendar
Connect: https://pipeworx.io/mcp — every tool in the catalog, including @pipeworx/us-econ-calendar’s. Install: one-click buttons
Connect to just the @pipeworx/us-econ-calendar pack
https://gateway.pipeworx.io/us-econ-calendar/mcp — only @pipeworx/us-econ-calendar’s own tools, nothing else in the catalog.
No MCP client? Skip the connection: POST https://gateway.pipeworx.io/v1/tools/search_packs {"query":"..."} to find a tool below, GET /v1/tools/<name> for its schema, POST the same URL with arguments for the data — see For AI agents.
Tools: 3
US macro-economic release SCHEDULE — when CPI, PPI, the Employment Situation
(jobs report), JOLTS, FOMC meetings, weekly DOL jobless-claims reports and
Treasury auctions happen, in Eastern Time. This pack answers when, never
what the number was — for the released values, use bls or fred.
Tools
econ_calendar_upcoming({hours?, days?, types?})— every tracked release falling in the next N hours/days, sorted by datetime.econ_calendar_next({release, from?})— the next occurrence of one release type (cpi,ppi,employment_situation,jolts,fomc,claims,treasury_auction).econ_calendar_recent({days?})— releases in the last N days (“what came out this week”).
Auth
Keyless. No platform key, no BYO key.
Data sources
- https://www.bls.gov/schedule/news_release/cpi.htm,
ppi.htm,empsit.htm,jolts.htm— BLS’s own annual release calendars, published roughly 12-13 months ahead. - https://www.federalreserve.gov/monetarypolicy/fomccalendars.htm — the
FOMC meeting calendar, via the already-live
fed-commspack’sfomc_calendartool (compound call — this pack does not re-scrape it). - DOL weekly Unemployment Insurance claims: fixed Thursday 08:30 ET cadence (https://oui.doleta.gov/unemploy/claims.asp, https://www.dol.gov/), computed rather than fetched, with a hardcoded override for the one known 2026 holiday shift (Thanksgiving week: Thu 2026-11-26 → Wed 2026-11-25).
- https://www.treasurydirect.gov/TA_WS/securities/upcoming — Treasury’s own live, keyless JSON auction calendar. Fetched live on every call.
Important gotcha: bls.gov refuses the clients we SERVE from — but not Node
www.bls.gov sits behind Akamai bot-management. What it refuses is the client
FINGERPRINT, not our address and not our user-agent. Measured 2026-09-13 from
one laptop on one residential IP, within the same minute:
| Client | Result |
|---|---|
curl, plain UA | 403 Access Denied (AkamaiGHost) |
curl, full Chrome header set (UA, sec-ch-ua-*, all four Sec-Fetch-*) | 403 |
curl https://www.bls.gov/robots.txt | 403 |
a deployed Cloudflare Worker fetch() (measured in #1914) | 403 |
node fetch() (undici) with the same Chrome headers | 200, 55,572 bytes, the real schedule table |
Headers and IP were held constant across the curl and Node rows, so the difference is the TLS/HTTP stack. Two consequences, and they point opposite ways:
- At runtime the pack still cannot fetch bls.gov. The Worker is one of the
refused clients, so the CPI / PPI / Employment-Situation / JOLTS tables in
src/index.tsremain a checked-in copy with a coverage horizon. Nothing about the sections below changes. - At refresh time we can.
scripts/refresh-econ-calendar.mjsruns on a dev machine, reads all four schedule pages with Node’sfetch, and rewrites the tables. The annual refresh is a command, not a browser-and-retype chore.
Re-measure rather than trust this table; bot rules move. node scripts/refresh-econ-calendar.mjs --check is the probe — it exits non-zero on
drift and prints the HTTP status when bls.gov refuses it.
(Separately: data.bls.gov’s general pages are blocked too, while its
/timeseries/<series> data-table path is not — but that path carries series
data, never schedule information.)
Coverage is reported on every response — and it expires
The BLS legs are DATA WITH AN EXPIRY DATE, so every response carries a
schedule_coverage array saying, per release, how far this pack reaches and on
what basis:
cpi/ppi/employment_situation/jolts—basis: "published calendar": BLS issues these dates about a year ahead, so they have a horizon. Carriescovered_through(the last date this pack answers for) andsource_vintage(when the dates were last brought current).fomc/treasury_auction—basis: "live upstream". No expiry.claims—basis: "computed cadence". Answers for any future date; only the federal-holiday overrides are hardcoded, and they currently cover 2026.
When a query reaches past covered_through:
econ_calendar_upcoming/_recentadd acoverage_warningarray naming the release, the cutoff and the fact that our data ran out — so an emptyeventslist is never read as “nothing is scheduled”.econ_calendar_nextreturnsfound: falsewithreason: "schedule_coverage_exhausted",covered_through, and a hint that says in words that BLS has very likely published past that date and we have not refreshed.
pnpm check:econ-calendar-coverage is the other half: a CI gate (and pre-push
gate) that warns from 120 days of coverage out and fails the build at 60, so
the refresh below gets done while there is still slack. Under 60 days it passes
(with a warning on every run) only while SCHEDULE_VINTAGE is under 14 days
old — i.e. somebody ran the refresh against bls.gov in the last two weeks and
bls.gov genuinely had nothing newer. Under 14 days of coverage it fails
whatever the vintage says. Do not silence it — run the refresh.
Refreshing the BLS schedule (automated weekly — you probably have nothing to do)
.github/workflows/econ-calendar-refresh.yml does this every Monday and
commits what it finds, including the SCHEDULE_VINTAGE stamp. Nobody has to
remember it, and you do not need to run anything before pushing.
That workflow exists because the thing this section used to insist on was false.
“bls.gov only answers a laptop” was inferred from a deployed Cloudflare Worker
getting 403 and curl getting 403, and it turned the refresh into a fortnightly
human errand. Measured 2026-10-14 from a GitHub Actions ubuntu-latest runner
(workflow run 38497568684): all four schedule pages answered HTTP 200 with the
real release-list table, from Node’s fetch(). The refusal tracks the client
stack, not the IP class — a Worker and curl are refused from anywhere, Node’s
fetch() is served from a laptop, a mini and an Azure runner alike. So it is
ordinary CI work (fleet #2680).
By hand, if you are debugging the pipeline or want it stamped now:
node scripts/refresh-econ-calendar.mjs --write # merge any new rows, stamp the vintage + horizon
node scripts/check-econ-calendar-coverage.mjs # confirm the gate is green
# then commit mcps/us-econ-calendar/src/index.ts (tables, vintage and horizon together)
--write stamps SCHEDULE_VINTAGE to today even when every table already
matches bls.gov — the vintage means “compared against bls.gov on this date”,
not “rows last changed on this date”.
What the gate asks now, and why it stopped asking the other thing
The old hard floor is gone (fleet #2680). It failed at 14 days of remaining
coverage “whatever the vintage says”, and when BLS has published nothing
further, nothing a pusher does makes that green. It was due to block every
lane’s push from 2026-11-18 over JOLTS, whose 2027 dates do not exist on
bls.gov, in BLS’s .ics, in FRED release 192 or in OMB’s PFEI schedule. The
same shape had already cost two days on 2026-10-03
(docs/checks-that-cannot-fail.md).
What replaced it: the pack records SCHEDULE_UPSTREAM_HORIZON — how far
bls.gov itself had published, per release, as of the vintage — so the gate can
ask the question that has an action behind it.
| Gate verdict | Means | Who can fix it |
|---|---|---|
behind-upstream FAIL | the last shipped row is earlier than bls.gov’s own | you — refresh --write adds the rows |
stale-vintage FAIL | nobody compared us to bls.gov in >60 days | you, and it means the weekly workflow has stopped |
forged-vintage FAIL | the stamp is dated in the future | whoever hand-edited it; only --write may write it |
unparseable FAIL | a table, the vintage or the horizon cannot be read | you — fix the parser in the same commit |
at-upstream-horizon pass, loudly | short on coverage, but level with bls.gov | nobody — upstream has not published |
ok | reaches past 60 days | — |
Short coverage at parity is still reported on every run, with the date the pack
stops answering for that release, and the pack says it to callers too
(schedule_coverage.at_upstream_horizon / coverage_warning). It is just not a
red push gate, because a red gate nobody can clear blocks everyone and teaches
--no-verify. node scripts/check-econ-calendar-coverage.mjs --selftest runs
all six verdicts against fixtures and asserts each one, red paths included.
--write merges, it does not replace, in BOTH directions. bls.gov wins for
every reference month it lists; every row for a month it does not list is
kept. Both directions is the fix from #2680 — the merge used to keep only rows
past upstream’s horizon, and bls.gov’s page is a ~14-month rolling window,
so elapsed months drop off it. Measured 2026-10-14 against the shipped pack, one
--write would have deleted 11 CPI, 11 PPI, 11 Employment Situation and 12
JOLTS elapsed rows — taking JOLTS from 13 rows to 1 — and econ_calendar_recent
would have gone quietly empty while every coverage check stayed green, because
they all read the LAST date.
Row-level provenance. A row bls.gov did not list when it was written carries
src: 'omb-pfei' and reports OMB’s PFEI schedule as its source, not BLS. Before
#2680 the source string was a per-table constant, so 36 OMB-sourced 2027 rows
told callers they came from bls.gov. bls.gov has since published those rows
itself and agrees row-for-row, so none is OMB-only today and the markers are
cleared — tests/econ-calendar-row-provenance.test.ts keeps the mechanism
honest for next autumn.
1. Preferred: scripts/refresh-econ-calendar.mjs. It fetches all four
schedule pages from bls.gov with Node’s fetch (which Akamai lets through —
see the table above), parses the Reference Month / Release Date / Release Time
rows, and diffs them against the tables in src/index.ts:
node scripts/refresh-econ-calendar.mjs # dry run: fetch + diff, exit 1 on drift, writes nothing
node scripts/refresh-econ-calendar.mjs --write # merge drifted tables + stamp SCHEDULE_VINTAGE
node scripts/check-econ-calendar-coverage.mjs # confirm the gate is green
Commit the pack change and the stamped vintage together. Verified 2026-09-13:
--check returned 52 rows across the four releases and matched the checked-in
tables exactly, which is also an independent re-verification that what we ship
is what BLS published.
It refuses rather than returns empty — a block page, renamed table headers, or
a table that parses to zero rows all throw. --selftest proves those three
directions plus a real parse, with no network.
2. Fallback: FRED’s release-date API. If Akamai’s rules move and Node stops
clearing them, the St. Louis Fed mirrors each BLS release’s scheduled future
dates, keyless-to-us through our own fred pack:
scripts/pwcall.sh call fred_release_dates '{"release_id":10,"limit":24,"include_release_dates_with_no_data":true}'
Release ids: CPI 10 · PPI 46 · Employment Situation 50 · JOLTS 192. Verified 2026-09-13 — all four returned exactly the dates in our tables, through the same mid-December cutoff, which is BLS’s own published horizon. FRED does NOT give you two things the tables need: the release time (stable: 08:30 ET for CPI, PPI and the Employment Situation, 10:00 ET for JOLTS) and the reference period (CPI/PPI/empsit describe the prior month; JOLTS lags two).
3. When bls.gov AND FRED both stop at the same date, that’s not drift — BLS
genuinely hasn’t published next year’s calendar yet. Hit 2026-10-03: the
60-day gate went red (jolts had 59 days left), but refresh-econ-calendar.mjs
reported zero drift — bls.gov’s own per-release pages, the FRED release-dates
endpoint, and BLS’s own master .ics calendar
(https://www.bls.gov/schedule/news_release/bls.ics) all independently
stopped at the exact same row. That’s expected: under OMB Statistical Policy
Directive No. 3, agencies submit next year’s schedule to OIRA and it is not
required to post until December, so a gap where “the pack’s refresh has zero
drift against three independent BLS-adjacent sources, and the gate is still
red” is real, not a parser bug — don’t spend time re-probing bls.gov harder.
The escape hatch that saved it this time: OMB’s PFEI schedule, a different
official annual calendar that can land earlier than BLS’s own page. OMB
publishes a consolidated “Schedule of Release Dates for Principal Federal
Economic Indicators” (PFEI) covering CPI, PPI, Employment Situation (and
Real Earnings, ECI, Productivity & Costs, import/export prices — but
not JOLTS, which OMB’s directive does not track) at
https://www.whitehouse.gov/omb/information-resources/guidance/us-principal-federal-economic-indicators/.
Its next-year PDF (FY<year+1>-PFEI.pdf) posted 2026-10-01, two days before
bls.gov’s own per-release pages had moved — each release’s table gives the
release day-of-month for every month of the next calendar year; cross the day
with “data are for previous month” (true for CPI/PPI/Employment Situation) to
get the reference month, same shape as the existing ScheduleRow entries.
Because it isn’t JOLTS-covered, that leg has no early-release lever: when only
jolts is the gate’s failing leg and this PDF doesn’t help, that is a real,
unresolvable-today external gap, not a refresh you haven’t tried hard enough.
Run refresh --write anyway: the stamped vintage is exactly what lets the gate
pass on that gap (above), and the gate re-arms after 14 days. Do NOT guess a
JOLTS date from its recent cadence, which has been irregular since the 2025
government-shutdown lapse and is not safe to extrapolate. Only if the table
falls under 14 days of coverage with still nothing published anywhere is it a
real outage of that leg — then escalate it rather than editing the gate.
Does the egress relay clear bls.gov? The question is moot — do not wire it.
The relay (supabase/functions/egress-proxy, the non-CF hop this pack already
uses for its TreasuryDirect leg) exists for upstreams that block Cloudflare
egress addresses. bls.gov is not that class: the block follows the client
fingerprint, not the IP, which is why curl is refused from a residential
address and Node is served from the same one. It was never probed through the
relay and now does not need to be — the refresh runs on a dev machine where
plain Node already works, and allow-listing a host to route a build-time chore
through a production relay buys nothing. If someone ever wants the pack to
fetch bls.gov at runtime, that is a different question and the relay is an
untested guess at it; the honest starting point is that Deno’s stack has not
been measured against Akamai here.
Who does it: whoever the 60-day gate stops. It fails on push with the
release name, the cutoff and this procedure, so the person holding a commit is
the person who fixes it. --write stamps SCHEDULE_VINTAGE for you. Never
hand-edit it: the gate trusts a fresh stamp to mean bls.gov was really checked,
so a hand-bumped vintage is a forged verification.
Treasury and the Fed calendar have no such problem — both are fetched live
(Treasury directly; FOMC via fed-comms) and need no manual refresh.
Tools
- econ_calendar_upcoming — Upcoming US macro release SCHEDULE — which of CPI, PPI, the Employment Situation (jobs report), JOLTS, an FOMC meeting/rate decision, the weekly DOL jobless-claims report, and Treasury auctions fall i
- econ_calendar_next — When the NEXT occurrence of a specific US macro release is — next CPI, next PPI, next jobs report, next JOLTS, next FOMC meeting, next weekly jobless-claims report, or next Treasury auction — with its
- econ_calendar_recent — What US macro releases happened in the last N days — ‘what was released this week’, ‘has CPI come out yet this month’. Lists CPI/PPI/Employment Situation/JOLTS/FOMC/claims/Treasury-auction events whos
Tools
econ_calendar_next— When the NEXT occurrence of a specific US macro release is — next CPI, next PPI, next jobs report, next JOLTS, next FOMC meeting, next weekly jobless-claims report, or next Treasury auction — with itsecon_calendar_recent— What US macro releases happened in the last N days — 'what was released this week', 'has CPI come out yet this month'. Lists CPI/PPI/Employment Situation/JOLTS/FOMC/claims/Treasury-auction events whosecon_calendar_upcoming— Upcoming US macro release SCHEDULE — which of CPI, PPI, the Employment Situation (jobs report), JOLTS, an FOMC meeting/rate decision, the weekly DOL jobless-claims report, and Treasury auctions fall i