Research
Turn one question into a sourced research brief
Ask the web, pull the pages behind the answer as Markdown, add what X is saying, then keep the evidence in a LiveDoc you can query again later.
Copy the prompt
Replace the bracketed fields, then paste it into Claude Code, Codex, or any AI with terminal access. It installs the Felo skill, asks before spending credits, and runs the workflow.
Build a sourced research brief for [question or decision]. Scope: [market, region, language]. Time window: [last 30 days / last 12 months]. Audience: [who will read it]. Depth: [one-page scan / full brief]. Produce a Markdown brief with: 1. A short answer in three bullets. 2. An evidence table: claim, source title, URL, publication date. 3. What the sources disagree on. 4. What is still unknown. 5. A full source list. Rules: - Every factual claim needs a source link. Separate facts, opinions, and your inference. - Never invent quotes, metrics, dates, or sources. Missing data is "Not available", never zero. - Prefer primary sources. Use X for practitioner signal, not as proof. - Resolve the time window to explicit start and end dates; state the timezone. - Before spending credits, show the API calls you plan to make and wait for my approval. - Do not create a recurring task, send messages, or publish anything. - Write the result to ./research-brief.md and summarize it in chat.
The copy also includes the install steps and safety rules.
What you get
Example output from a run. Not a live generation.
Will small models replace large ones for support bots?
Short answer
- Small models are already good enough for classification and first-line answers.
- The bottleneck is retrieval quality, not model size.
- Teams that switched report lower cost per ticket, not higher resolution rates.
| Claim | Source | Date |
|---|---|---|
| Retrieval quality dominates answer quality | https://example.com/rag-eval | 2026-10-12 |
| Cost per resolved ticket fell 38% | https://example.com/support-case | 2026-09-28 |
What the sources disagree on
Vendor benchmarks show near-parity; independent tests still find a gap on multi-step refunds.
Still unknown
Whether the gap closes with better tool use or requires a larger model.
The exact calls
For developers: the same workflow as copy-paste code, in the order it runs.
Show the exact API calls
Ask the web a question
Chat searches the web, ranks the sources, writes the answer, and returns the resources it used. Keep the top three: every later step follows one of those links. The helper below sends the key once and throws on a non-2xx response.
research.ts const BASE = "https://openapi.felo.ai"; const headers = { Authorization: `Bearer ${process.env.FELO_API_KEY}`, "Content-Type": "application/json", }; async function felo<T>(path: string, body?: unknown): Promise<T> { const res = await fetch(`${BASE}${path}`, { method: body ? "POST" : "GET", headers, body: body ? JSON.stringify(body) : undefined, }); if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`); return res.json() as Promise<T>; } type ChatData = { data: { answer: string; resources: { link: string; title: string }[] }; }; export async function answer(question: string) { const chat = await felo<ChatData>("/v2/chat", { query: question }); return { answer: chat.data.answer, sources: chat.data.resources.slice(0, 3) }; }Example output
{ "answer": "Recent developments include …", "sources": [ { "link": "https://example.com/article", "title": "…" } ] }Pull the pages behind the answer
A snippet is not enough for a brief. Fetch the pages in Markdown with readability enabled, so quotes and headings survive without the navigation clutter. Requesting the same URL again can hit the extractor cache.
research.ts type ExtractData = { data: { content: string } }; const pages = await Promise.all( sources.map((source) => felo<ExtractData>("/v2/web/extract", { url: source.link, output_format: "markdown", with_readability: true, with_cache: true, }).then((page) => ({ ...source, content: page.data.content })), ), );Example output
// pages[0].content "# Example Article\n\nExtracted article content…"
Add what X is saying
News covers announcements; X covers what people hit in practice. Search the last seven days, then keep the author and timestamp so the brief can attribute every claim. Raise
limitfor a wider net; each page of results carries a cursor.research.ts type XData = { data: { tweets: { content: string; author: { username: string }; created_at: string; }[]; }; }; const since = Math.floor((Date.now() - 7 * 24 * 60 * 60 * 1000) / 1000); const social = await felo<XData>("/v2/x/tweet/search", { query: question, limit: 10, since_time: since, });Example output
{ "data": { "tweets": [ { "content": "…", "author": { "username": "…" }, "created_at": "…" } ] } }File the evidence in a LiveDoc
Create a LiveDoc and add the sources as URL resources. The API deduplicates what it has already seen and returns a resource id per URL, so the same evidence can be retrieved by any later question instead of being fetched again.
research.ts type LiveDocData = { data: { short_id: string } }; const doc = await felo<LiveDocData>("/v2/livedocs", { name: `Research: ${question.slice(0, 60)}`, description: "Sources collected while answering the question", }); await felo(`/v2/livedocs/${doc.data.short_id}/resources/urls`, { urls: sources.map((source) => ({ url: source.link, title: source.title })), }); console.log(doc.data.short_id); // keep this for later queriesAsk the evidence again later
This is the payoff: the next question runs semantic retrieval over the LiveDoc instead of the open web. Pass
resource_idsonly when you want to search a known subset.research.ts type Retrieved = { data: { title: string; content: string; score: number }[]; }; async function ask(livedoc: string, query: string) { const hits = await felo<Retrieved>( `/v2/livedocs/${livedoc}/resources/retrieve`, { query }, ); return hits.data.filter((hit) => hit.score >= 0.7); }Example output
[ { "title": "…", "content": "…", "score": 0.92 } ]
What's included
- A sourced answer from Chat API, with the pages behind it
- Full-page Markdown extraction for the strongest sources
- X posts with author and timestamp for practitioner signal
- A LiveDoc that keeps the evidence queryable for later questions
What it doesn't do
- Public sources only; paywalled or login-only pages may fail
- X coverage is a signal, not a representative survey
- No interviews, private data, or paid databases
- It says when the evidence is thin instead of filling gaps
- One run per prompt; scheduling belongs to your agent or cron
Questions
Where do the sources come from?
Chat API returns the pages it used, Web Fetch turns the strongest ones into Markdown, and X Search adds dated practitioner posts. Every item keeps its URL.
Can I research a market outside tech?
Yes. Replace the scope placeholder with your market. Niche markets may have fewer public sources; the brief marks those gaps instead of guessing.
Does it keep the evidence after the run?
Yes, when the LiveDoc step runs. The returned short_id lets later questions retrieve the same pages instead of fetching them again.
How much does a brief cost?
Billing is usage-based credits; current rates are on the pricing page. The prompt asks for approval before it spends anything.
Can I run it every week?
Yes, but this prompt runs once. Set the schedule in an agent or cron job that can execute the same workflow.
What if a source is paywalled?
It is skipped and labeled unavailable. The brief never fills a paywalled gap with an invented fact or quote.
Related workflows
Ship a daily AI news digest your team actually reads
Get a sourced roundup, add what practitioners are posting on X, pull one video transcript, then compose the issue in Markdown and archive it in a LiveDoc.
Open workflowOfficeTurn a research page into a slide deck
Extract the page, file it as LiveDoc context, then let the PPT Task API build the deck while you poll for the finished link.
Open workflowSupportAnswer support questions from your own documentation
Create a LiveDoc, load your help center and internal runbook, retrieve the passages that answer the ticket, and let a model answer only from that evidence.
Open workflowMake it yours
The same recipe, adapted to the way you actually ship.
Write the brief to a file
Compose the answer, the page excerpts, and the X quotes into Markdown, then hand that string to your report tool or commit it to your docs repo. Keep the source links beside the claims — the brief is only as useful as its citations.
Run it on a schedule
Wrap `answer()` in a cron job and write each brief to a dated file. The same LiveDoc keeps accumulating sources, so week four answers from the evidence collected in weeks one to three.
Skip the LiveDoc
If you already have a database, store the chat answer and the extracted pages there. The LiveDoc step is for retrieval, not storage by default.
Keep going
The reference pages behind this recipe, and where to go next.