DemandReport whose every quote is exact-matched to a real comment.
The simplest call
Let the planner shape the brief
.research(question) builds a minimal brief. For a richer brief — refined
question, success criteria, must-address sub-questions, suggested subreddits —
walk the planner:
ResearchBrief by hand for full control over every field (see
Core concepts).
Scope the corpus
time_window_months— how far back to pull (default 12; the bundleddemo()corpus is a single month).per_sub_limit— cap submissions pulled per subreddit.max_findings— cap web findings.
HF_TOKEN for windows beyond a few months. To run without
Arctic Shift at all, bring your own corpus.
Provenance, by construction
The report can’t contain fabricated evidence:- Quotes are exact-matched against stored comments; a quote that doesn’t
match a real comment is dropped (
no-quote-no-theme). - Web findings carry their
source_urlfrom the grounding tool’s citation metadata — zero citations means the finding is dropped; URLs are never synthesized. - Counts (distinct authors, mentions, must-address resolution) are computed from membership, never asserted by a model.
Compose the stages yourself
run_research is one assembly of public stages. To build a custom flow — your
own triage thresholds, a different corpus, an extra synthesis pass — call them
directly:
Web grounding
When your chat model supports native grounding (Geminigoogle_search, Anthropic
web_search), the web stream uses it and maps findings to citations by character
span. Otherwise it falls back to an external SearchProvider (Exa, Tavily) — set
EXA_API_KEY or TAVILY_API_KEY and metalworks picks it up. With neither, the
report notes the web stream degraded and continues.