mcpbeat

Last30flames

firecrawl/last30flames

Research what's genuinely new about a topic in a recent time window. Use when the user asks what's new, recent, or trending on a subject and wants a source-grounded brief rather than a quick lookup.

18k tokens
context cost
the whole folder, loaded on every use
21
files
ships runnable scripts
0
copies elsewhere
how many repositories repackaged it
29
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/firecrawl/last30flames --skill last30flames

What comes with it

60 175 bytes besides the instruction
.env.example
bun.lock
package.json
scripts/bluesky.ts
scripts/config.ts
scripts/derive-sides.test.ts
scripts/derive-sides.ts
scripts/firecrawl.ts
scripts/format.test.ts
scripts/format.ts
scripts/github.ts
scripts/hackernews.ts
scripts/htmlify.ts
scripts/index.ts
scripts/lobsters.ts
scripts/resolve.ts
scripts/run.sh
scripts/types.ts
scripts/url.ts
tsconfig.json

What it tells the agent to use

found in the instruction text
Bash runs shell commands — read the instruction before connecting
Read reads your files

The instruction itself

8 sections, as written by the author

last30flames

Research a topic across the recent web and write a short, source-grounded brief.

This skill is a thin engine plus your synthesis. The engine gathers sources and

prints a clean, numbered research context; you (the model running this skill)

read that context and write the brief.

No keys are required. The engine never calls an LLM (you do the synthesis),

and it reaches Firecrawl through the Firecrawl CLI, which runs on a keyless free

tier when no key is set. If FIRECRAWL_API_KEY *is* in the environment the CLI

uses it automatically for higher limits and concurrency - so a key is a speed

upgrade, never a requirement. A user who starts keyless and later sets

FIRECRAWL_API_KEY (or runs firecrawl login) is authenticated on the very next

run, with nothing to reinstall.

How it works

Five sources run in parallel:

  • Firecrawl Search - web results scraped into full-page markdown, not snippets.
  • Hacker News (public Algolia API) - points + comment counts.
  • Lobste.rs (public JSON feeds) - points + comment counts.
  • Bluesky (public AT Protocol API) - likes + reposts + replies.
  • GitHub (official API) - stars + recent push activity.

Engagement numbers come only from APIs that publish them openly. The skill never

touches Reddit, X, TikTok, Instagram, or anything behind a login or cookie.

Run the engine

This works in any agent harness that supports skills. You already know the

absolute path of this SKILL.md because you just read it; call scripts/run.sh

next to it. It self-locates, installs deps on first run,

and takes the topic plus an optional --days N window (any number - 7, 30, 365;

default 30):

bash <SKILL_DIR>/scripts/run.sh "<TOPIC>" --days 30

Replace <SKILL_DIR> with the directory this file is in. Do not rely on

$CLAUDE_PLUGIN_ROOT or the current working directory - the launcher handles

both. The only requirement is the bun binary; no API key is needed (set

FIRECRAWL_API_KEY only if you want higher Firecrawl limits).

Progress prints to stderr; the numbered research context prints to stdout. Read

the stdout - that is your evidence.

If the topic could point at more than one thing - a person's name, a product

that shares a name with something common ("Apple", "Cursor"), a bare handle -

run a cheap resolution pass before the main gather:

bash <SKILL_DIR>/scripts/run.sh --resolve "<TOPIC>"

It prints candidate identities (web titles + descriptions, GitHub repo and user

candidates) without scraping any pages. Read them and decide:

  • 2-4 refined subqueries that pin down the intended entity (e.g. for

"Cursor" the AI editor: "Cursor AI editor", "Cursor IDE agent").

Each subquery multiplies the Firecrawl search/scrape work, so runtime scales

with query count - use the fewest that pin down the entity, usually 2.

  • If the topic is a person or project, the matching GitHub login and/or

owner/name repo.

Then run the main gather with those, passing --query once per subquery:

bash <SKILL_DIR>/scripts/run.sh "<TOPIC>" --days 30 \
  --query "<subquery 1>" --query "<subquery 2>" \
  --github-user <login> --github-repo <owner/name>

The engine searches the web, Hacker News, Lobste.rs, and Bluesky with each

subquery (up to 4, deduplicating overlapping results), and scopes GitHub to the

given login/repo. All flags are optional - a clear, specific topic can skip

resolution entirely and run one-shot as before. The resolution pass never

decides anything itself; you do.

Comparison topics ("X vs Y")

When the topic pits two or three things against each other ("cursor vs zed",

"bun versus deno"), the engine runs a full gather per side in one pass and

groups the research context per side, with continuous citation numbering.

A topic containing "vs"/"versus" in any capitalization auto-splits, so the simple form just works.

The one carve-out is all-caps "VS", so topics like "best VS Code extensions" stay a single side; use --compare to compare things whose names contain "VS":

bash <SKILL_DIR>/scripts/run.sh "cursor vs zed" --days 30

The web-scrape budget (--limit) is shared across sides, so each side of a

comparison scrapes fewer pages than a dedicated run would; pass a higher

--limit (e.g. --limit 10 for two sides) when you want full per-side depth.

For sharper sides, pass --compare once per side; any --query,

--github-user, or --github-repo flags that follow a --compare scope to

that side (run --resolve per side first if a name is ambiguous):

bash <SKILL_DIR>/scripts/run.sh "cursor vs zed" \
  --compare "Cursor" --query "Cursor AI editor" --github-repo getcursor/cursor \
  --compare "Zed" --query "Zed editor" --github-repo zed-industries/zed

Synthesize a side-by-side brief from the grouped context: what moved for each side in the window, then a direct comparison (traction via the engagement numbers, notable shipping activity, best-for).

Cite both sides inline as usual; the numbering never collides because it is continuous across sides.

Save & reuse the context (optional)

By default, do not write any files - just synthesize the brief. Only save when

the user asks (e.g. "save the context", "I'll want this again later").

Saved contexts live under ~/.last30flames/, grouped into thread folders so a

run of related calls can be reloaded as one set. A thread is just a named

subdirectory; each call saves its own file, which keeps every call's [1], [2]

citation numbering intact (never concatenate two contexts into one file - the

numbering would collide):

~/.last30flames/<thread>/
  <slug>-<YYYY-MM-DD>.md      # one file per engine call

On save: redirect the engine's stdout so the *raw numbered research context* is

preserved (that is the reusable evidence - not the brief). Pick the thread folder

first:

  • If the user names a thread ("save this to my ai-agents research"), slugify it as

<thread>.

  • Otherwise reuse the thread from earlier saves in this same conversation, so

related calls land together.

  • If neither applies, derive <thread> from the topic and tell the user the name

you chose so they can reference it later.

Derive <slug> by slugifying the topic (lowercase, spaces to hyphens, drop

punctuation) so the filename tells you what the call was about. Then create the

folder and write the file, and report the exact path afterward:

mkdir -p ~/.last30flames/<thread>
bash <SKILL_DIR>/scripts/run.sh "<TOPIC>" --days 30 > ~/.last30flames/<thread>/<slug>-<YYYY-MM-DD>.md

Because the redirect sends the research context to the file instead of stdout,

the Bash output shows only stderr progress. If the user also wants the brief this

session, Read the saved file first to get the context, then synthesize as usual.

If the user explicitly names a different path, honor it instead.

On reuse (a later session): the user need not recall exact names. If they

reference saved research even loosely ("load my ai-agents research"), list the

thread folders under ~/.last30flames/ and match on the thread name; then Read

every .md file in that folder and synthesize across all of them, keeping

citations namespaced by source file so numbers from different calls don't clash.

To reload a single call rather than the whole thread, match one file by its

<slug>-<date> name. If nothing matches, ask where they saved it.

Because each filename is <slug>-<YYYY-MM-DD>.md, both topic and save date are

recoverable from the name alone - no external memory needed. Before synthesizing,

check each file's date against the --days window: if today is more than that many

days past the saved date, the recency claim no longer holds - warn the user that

context is stale and offer to re-run fresh.

Reuse-shaped prompts to handle this way (do not re-run the engine):

last30flames load my ai-agents research
last30flames using my saved ai-agents research, what did I find on local inference?

Write the brief

From the numbered sources, write a few tight paragraphs that:

  • Lead with what is genuinely new or moving in the window. Not background.
  • Ground every claim in the sources and cite inline like [1], [3].
  • Use the engagement numbers (HN points/comments, GitHub stars) as a signal

of what people actually care about - weight high-engagement items.

  • Say plainly where evidence is thin rather than inventing detail. If HN or

GitHub returned little, that honesty is part of the answer.

After the brief, end with a compact Sources list so every inline citation is

clickable. One line per source you actually cited, keeping the same numbers used

inline, as markdown links:

Sources:
[1] [Title of the page](https://example.com/article) - example.com
[3] [Show HN: Something](https://news.ycombinator.com/item?id=123) - news.ycombinator.com

List only cited sources - this is a reference list for the reader, not a dump of

the research context. Never paste the raw research context back.

Shareable HTML brief (optional)

When the user asks for a shareable version of the brief ("make this shareable", "give me an HTML file", "something I can drop in Slack/email/Notion"), emit the synthesis as a self-contained dark-mode HTML file alongside the normal chat response.

The file has inline CSS, no JavaScript, and no external assets, so it works offline and renders the same everywhere.

First write the brief you synthesized - including its Sources: list with the same numbering - as markdown into the thread folder, picking <thread> and <slug> exactly as in the save flow above:

mkdir -p ~/.last30flames/<thread>
# Write the brief markdown to ~/.last30flames/<thread>/<slug>-<YYYY-MM-DD>-brief.md
bun <SKILL_DIR>/scripts/htmlify.ts ~/.last30flames/<thread>/<slug>-<YYYY-MM-DD>-brief.md

The converter turns headings, paragraphs, lists, links, and inline [N] citations into HTML - each citation becomes a clickable jump to its entry in the Sources list - writes <slug>-<YYYY-MM-DD>-brief.html next to the markdown, and prints the output path.

Report that path to the user.

If the user names a different output location, pass it with -o <path>.

This converts your synthesized brief, not the raw research context - never htmlify the engine's stdout.

How to use it

Copy the folder

Take firecrawl/last30flames from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.