How the last30days Skill Works

An engineering walkthrough of github.com/mvanhorn/last30days-skill: an AI-agent research skill that searches Reddit, X, YouTube, TikTok, Hacker News, Polymarket, GitHub, arXiv and more, ranks results by real human engagement, and has the host LLM synthesize one cited brief.

v3.23.0 (Sep 1, 2026)61.1k GitHub stars1,203 commits~56,000 lines of Python2,307-line SKILL.mdMIT licenseAuthor: Matt Van Horn
TL;DR. /last30days <topic> is not a prompt and not a normal program. It is both: a 2,307-line instruction contract (SKILL.md) that scripts what the host LLM must do, plus a large deterministic Python engine (scripts/last30days.py + ~90 library modules) that the LLM runs via shell. The LLM resolves entities and writes a JSON query plan; the engine fans out to ~20 platforms in parallel, merges everything with weighted Reciprocal Rank Fusion, filters to the last 30 days, groups items into story clusters scored by upvotes, likes, views and prediction-market money; then the LLM reads the ranked evidence and writes the final brief under eight strict formatting "LAWs". The free tier needs zero API keys (Reddit, HN, Polymarket, GitHub); a setup wizard unlocks X, YouTube, TikTok and others using your own browser cookies and keys.

1. What it is

last30days is an Agent Skill: a folder containing a SKILL.md file (metadata plus instructions the agent follows) and a scripts/ directory with executable code. The format is an open standard originally developed by Anthropic and supported by 50+ agent runtimes ("harnesses"): Claude Code, OpenAI Codex, Cursor, Copilot, Gemini CLI, OpenClaw and others. Installation is either the Claude Code plugin marketplace (/plugin install last30days) or Vercel's skills CLI (npx skills add mvanhorn/last30days-skill -g), which symlinks the skill into whichever agents it detects on your machine.

The pitch, in the project's own words: "An AI agent-led search engine scored by upvotes, likes, and real money - not editors." Google indexes editorial pages; ChatGPT can search Reddit but not X; Gemini has YouTube but not Reddit. Each platform is a walled garden. last30days bridges them by letting an agent bring your own credentials and browser sessions to every platform at once, then ranking what it finds by what real people engaged with in the last 30 days.

Typical uses documented in the README: pre-meeting research on a person (recent PRs, X posts, podcast transcripts), tool comparisons with live GitHub star counts, breaking-news synthesis with Polymarket odds, trip planning from community threads, and --hiring-signals reports built from a company's live job pages.

2. The core design: a prose contract driving a Python engine

The repository's own CONCEPTS.md draws the line precisely:

The division of labor is the interesting part. Work that needs judgment (disambiguating "Kevin Rose", deciding what subqueries to search, writing the final narrative) is assigned to the host LLM. Work that needs reliability (hitting 20 APIs in parallel, date filtering, deduplication, engagement math) is assigned to Python. The contract between them is explicit: the LLM passes a JSON plan file in, the engine emits ranked evidence and a mandatory footer out, and the LLM is required to pass certain engine blocks through verbatim.

HOST LLM (follows SKILL.md) Parse intent + query-quality pre-flight topic vs comparison vs discovery; reframe keyword traps Resolve entities with WebSearch (Step 0.5/0.55) X handles, GitHub user/repos, subreddits, hashtags, creators Write JSON query plan (Step 0.75) 1-4 subqueries, weights, per-source routing, freshness mode 2-3 WebSearch supplements (Step 2) blogs, news, critic reactions the social engine misses Synthesize the brief under 8 LAWs version badge on line 1, "What I learned:" prose, KEY PATTERNS list, engine footer passed through verbatim, no Sources: block, no invented section headers PYTHON ENGINE (last30days.py) Parallel source fan-out (ThreadPoolExecutor) Reddit, X, YouTube, TikTok, IG, HN, Polymarket, GitHub, arXiv, Techmeme, Digg, LinkedIn, Bluesky, StockTwits... Enrich with real engagement numbers Reddit upvotes + top comments, X likes/reposts, YT transcripts Normalize → 30-day filter → entity grounding off-entity items get a decisive demotion; engagement cannot rescue off-topic virality Fuse + rank: weighted Reciprocal Rank Fusion score += subquery_weight x source_weight / (K + rank); URL-keyed dedupe, per-author caps, engagement keepers Cluster into stories → render compact output Ranked Evidence Clusters + Stats + Source Coverage + emoji-tree footer; raw Markdown saved to ~/Documents/Last30Days/ --plan evidence
Figure 1. Division of labor on a normal topic run: judgment on the left, deterministic retrieval and ranking on the right.

3. Anatomy of a run, step by step

When you type /last30days Peter Steinberger in a harness, SKILL.md walks the model through a fixed sequence:

  1. Stale-clone self-check (Step 0). The model verifies it did not load SKILL.md from Claude Code's auto-restored marketplaces/ git clone, which can lag the versioned plugin cache by a release. If it did, it re-reads the cached copy.
  2. First-run gate. A one-line grep for SETUP_COMPLETE=true in ~/.config/last30days/.env. On first run the model must run the setup wizard before any research: it installs yt-dlp (YouTube), the free Digg/arXiv/Techmeme CLIs, and extracts X cookies from your browser.
  3. Query-quality pre-flight (Step 0.45). Keyword-trap topics ("gift for 42 year old man", bare "sneakers") get reframed or trigger one clarifying question, because nobody titles a Reddit post that way and the engine would return noise.
  4. Entity resolution (Steps 0.5-0.55). Using the host's WebSearch tool, the model resolves the topic's X handle, GitHub username or repos, relevant subreddits, TikTok hashtags and Instagram creators. Person topics must produce at least --x-handle, --github-user and --subreddits. Collision-prone names get an anchor ("kevin rose digg founder", not "kevin rose").
  5. Query plan (Step 0.75). The model writes a JSON plan: an intent label (breaking_news, comparison, how_to, prediction...), a freshness mode, a cluster mode, and 1-4 weighted subqueries, each with a keyword-style search_query, a natural-language ranking_query, and a source list. The plan goes into a tmpfile passed as --plan; SKILL.md is emphatic that "YOU are the planner" so the engine's internal LLM planner is bypassed whenever a reasoning model is hosting.
  6. Engine run (Step 1). One foreground Bash call: python3 $SKILL_DIR/scripts/last30days.py "topic" --plan $FILE --x-handle=... --subreddits=... --emit=compact. The engine does everything in Section 4 below and prints ranked evidence bounded by <!-- EVIDENCE FOR SYNTHESIS --> markers, plus a footer bounded by <!-- PASS-THROUGH FOOTER --> markers.
  7. Web supplements (Step 2). The model runs exactly 2-3 host WebSearches for the long-form context social platforms lack (critic reviews, news explainers), then appends a ## WebSearch Supplemental Results section to the saved raw file so the research library records every source that informed the brief (Step 2.5).
  8. Synthesis. The model reads the evidence clusters and writes the brief: a version badge line, What I learned:, bold-lead-in narrative paragraphs with quotes and numbers, a KEY PATTERNS from the research: numbered list, the engine footer verbatim, and a closing invitation. The evidence clusters themselves are input, never output.

4. Inside the engine

4.1 Sources

SourceHow it is fetchedCost
RedditKeyless RSS + "shreddit" HTML scraping + arctic-shift for dedicated subreddits; per-thread JSON enrichment for real upvotes, ratios, and top comments. ScrapeCreators or an OpenAI web_search path as alternatives.Free
Hacker NewsPublic API; front/best listings in discovery mode.Free
PolymarketPublic API; real-money odds and volume, auto-included for prediction intents.Free
GitHubPublic API. Person mode: PR velocity, merge rate, top repos. Project mode: issues, discussions, releases, live star counts.Free
arXiv / Techmeme / DiggFree companion CLIs (arxiv-pp-cli, techmeme-pp-cli, digg-pp-cli) generated by the author's Printing Press project; auto-enabled when on PATH.Free
X / TwitterBundled "Bird" GraphQL client driven by your browser cookies (AUTH_TOKEN + CT0), with FROM and ABOUT search lanes; falls back to the paid xAI API (grok + x_search tool).Free with cookies
YouTubeyt-dlp search plus full transcript extraction; comments included; ScrapeCreators transcript backup.Free
TikTok / Instagram / LinkedIn / Threads / PinterestScrapeCreators API, including spoken-word transcripts for Reels and rank-diversified comments.API key
Bluesky / Truth Social / StockTwits / XiaohongshuAT Protocol app password, token, public API, or a local MCP bridge respectively; StockTwits auto-activates for tickers.Mostly free
Web / Perplexity / Amazon reviews / TrustpilotBrave, Exa, Serper or Parallel search keys, Perplexity API modes including Deep Research, Bright Data for Amazon buyer signals.API keys

All sources run concurrently under a ThreadPoolExecutor with per-source timeouts and a wall-clock budget; a paid-source budget object caps how many billable fetches a run may consume.

4.2 Ranking: engagement-weighted rank fusion

Each subquery in the plan queries each of its sources, producing many independently ranked "streams". The fusion stage (lib/fusion.py) merges them with weighted Reciprocal Rank Fusion: every item at rank r in a stream contributes subquery_weight × source_weight / (K + r) to the candidate keyed by its normalized URL, so items found by multiple subqueries or platforms accumulate score. Copies of the same item are merged keeping the richest version (for example the copy whose comments were fetched).

Three safeguards keep engagement from becoming a spam vector:

Candidates are then clustered into stories by entity overlap (lib/cluster.py), each cluster carrying a score, item count, source list, and honesty labels such as Uncertainty: single-source or thin-evidence. If every cluster fails the floor, the engine reports "Nothing solid this window" instead of padding, and the synthesis rules require relaying that honestly.

4.3 Output and persistence

With --emit=compact the engine prints the version badge, evidence clusters, stats, partial-coverage report (which sources timed out, rate-limited, or legitimately found nothing), and the emoji-tree footer beginning ✅ All agents reported back! with per-source counts. Every run is also saved as a slugified Markdown file (optionally JSON or a styled HTML page) under ~/Documents/Last30Days/, building a personal research library with offline SQLite full-text search (library search), a browsable HTML feed with Atom export (library feed), and a topic queue that tracks what discovery has surfaced and what you have marked "covered".

5. The output contract: a badge and eight LAWs

The most unusual part of the project is how aggressively SKILL.md constrains the LLM's final answer. The synthesis must open with a badge line (🌐 last30days v3.23.0 · synced 2026-09-02) and obey numbered LAWs, each annotated with the dated, named production failure it prevents:

LAWRuleFailure it fixed
1No trailing Sources: block; the engine footer is the only visible citation.WebSearch's own tool contract kept coercing models into appending source lists.
2No invented title; body starts What I learned: (comparison queries get one fixed title format).Runs that invented headlines like "Kanye West: the last 30 days".
3No em-dashes or en-dashes, ever ("the most reliable AI-slop tell").Generic LLM prose style.
4No ## section headers in the body except the fixed comparison template.Blog-post-shaped output with improvised sections.
5Engine footer passed through verbatim, never recomputed.Models paraphrasing or dropping the stats tree.
6Raw evidence clusters are input, never output; transform them into prose.Two runs that dumped the ranked cluster block at the user.
7The host model is the planner; --plan is mandatory on named-entity topics.Bare engine runs with keyword-only search and thin results.
8+Further rules govern honest partial-coverage language ("never write 'nothing on X' when X timed out") and the discovery relay.Overclaiming quiet sources.

This is prompt engineering run like a post-incident process: the file documents a "0/8 regression" day (eight consecutive public runs where the model improvised), names each disaster, and encodes the fix as a structural anchor. It even includes a worked example showing an evidence block and the exact prose a model should produce from it.

6. Beyond a single topic: the other modes

Discovery ("what's exploding in AI agents?")

Topic-less trending mode runs a three-leg, host-judged protocol with persisted checkpoints between legs:

  1. Nominate. --discover --nominate-only sweeps river listings (Reddit category feeds, HN front/best, Digg's AI 1000, X when authenticated), clusters items into candidate topics, and writes a nominations bundle.
  2. Judge (the LLM). The model reads the bundle and writes a judgments file: a short searchable name, a junk flag (help-me posts and promo cannot carry a story), and a 0-100 content-worthiness score per nomination.
  3. Research. --discover --judgments FILE runs a full research pipeline pass on every surviving topic in parallel against a wall-clock budget.
  4. Angles + finalize. The model writes podcast and X-article hooks per topic; --finalize --angles FILE renders 5-10 velocity-ranked trend cards, each with cross-source numbers, a momentum label, and a ready-to-run follow-up command.

Every topic must clear an absolute confidence floor (cross-source corroboration or a genuinely strong single-source spike); a run where nothing qualifies renders an honest "Nothing solid this window" with the nearest weak signal named. Surfaced topics persist in the topic queue so repeats get annotated and covered stories stay covered.

Comparison, hiring signals, watchlist, doctor

7. Setup, credentials, and the free tier

Zero-config: Reddit, HN, Polymarket and GitHub work with no keys at all (the "keyless path", where local lexical scoring replaces LLM reranking). The first-run wizard then unlocks more in about 30 seconds: it installs yt-dlp and the free source CLIs and extracts X session cookies from Chrome, Safari, Brave, Edge, Vivaldi, Opera or Arc. Credentials resolve through three tiers: .env files (~/.config/last30days/.env or project-scoped), macOS Keychain items prefixed last30days-, and Linux pass(1). Optional keys (ScrapeCreators, xAI, OpenAI, OpenRouter, Perplexity, Brave, Apify, Bluesky app passwords, and more) each unlock specific sources; a missing key just means that source is skipped and reported as unconfigured. On hosts without Python 3.12 the preflight provisions a uv-managed interpreter automatically.

8. Adoption and project health

9. Security and trust model

Read before installing. The capabilities that make last30days work are exactly the ones security scanners flag. Gen Agent Trust Hub rates the skill HIGH risk (verdict: Fail, May 2026), Snyk fails it, and Socket warns, citing four findings:

None of this is hidden; it is the documented bring-your-own-credentials design, the repo ships a Security & Permissions section, and the team has an active hardening record (stored-XSS fixes, locked-down cookie temp files, an RCE fix in a session hook, build provenance attestation). But installing it means letting an agent read your browser sessions and keychain and act on them. Review the source, scope the keys you provide, and skip cookie extraction if X search is not worth it to you.

10. Sources

Report generated 2026-09-02 by KISS Sorcar from the repository at v3.23.0 and ten independently visited web sources.