last30days Skill

repository·main·Indexed 10 days ago

https://github.com/mvanhorn/last30days-skill

An AI agent-led search engine and research skill (v3.18.4) that synthesizes activity from the last 30 days. It prioritizes human engagement metrics—such as upvotes, likes, and prediction market odds—over editorial curation. Compatible with Claude Code, Claude Desktop (via last30days-pp-mcp), Cursor, Copilot, Gemini CLI, and Grok. Supports a wide array of sources including Reddit, X, Hacker News, Polymarket, and GitHub.

Tokens
82.1K
Snippets
202
Records
347
Agent score
94%

What's inside last30days

  1. Overview of the last30days skill

    main

    The last30days skill is a research tool designed to analyze what people are saying about specific topics over the last 30 days. It aggregates posts and engagement data from a wide variety of sources including Reddit, X (Twitter), YouTube, TikTok, Hacker News, Polymarket, GitHub, and general web searches.

    Key Features:

    • Multi-source analysis: Pulls from social media, news, and specialized platforms.
    • Health Check: Includes a "doctor" command to diagnose broken or missing data sources.
    • Deep Research: Designed for high-fidelity research rather than generic search queries.
  2. Overview of supported data sources

    main

    /last30days aggregates data from a wide variety of sources, often without requiring individual API keys for many of them:

    • Academic & Tech News: arXiv (research papers), Techmeme (editorial tech news), and Digg (AI-1000 story clusters).
    • Social & Community: Reddit (via RSS and scraping), X (requires authentication), YouTube (comments and transcripts), and Instagram.
    • Professional & Financial: LinkedIn (via ScrapeCreators), StockTwits (automatic activation for tickers/crypto), and Polymarket (prediction markets).
    • Developer Tools: GitHub (live star counts and person-mode).
  3. Cite sources correctly based on the host environment

    main

    The method for citing sources depends on whether the host environment supports hidden links (like Claude Code) or visible URLs (like Codex, Cursor, or Gemini CLI).

    1. Hidden-link hosts (e.g., Claude Code)

    • Detection: CLAUDECODE environment variable is set.
    • Format: Use inline Markdown links for every citation: [name](url).
    • Example: per [Rolling Stone](https://www.rollingstone.com/...) or [r/hiphopheads](https://reddit.com/r/hiphopheads).

    2. Visible-URL hosts (e.g., Codex, Cursor, Gemini CLI, raw CLI)

    • Detection: CLAUDECODE environment variable is unset.
    • Format: Use plain text labels without Markdown links to avoid "URL soup."
    • Example: per Rolling Stone or per r/hiphopheads.

    General Citation Rules:

    • Never use raw URL strings (e.g., per https://...).
    • Never use empty links (e.g., [Name]()).
    • If a URL is missing for a specific source, fall back to a plain label.
  4. Use a remote API for research

    main

    To run research through a configured remote API instead of local sources, set both LAST30DAYS_API_KEY and LAST30DAYS_API_BASE (the endpoint URL).

    Important considerations:

    • Privacy Exception: If --corpus or LAST30DAYS_CORPUS_DIRS is configured, the engine bypasses the hosted backend and runs locally to ensure file-derived input is not forwarded.
    • Output Format: Remote endpoints do not return the local Report object. To get the server's response, use the flags --emit=json --json-profile=raw.
    • Error Handling:
      • Exit Code 3: The API has asked a clarifying question. The question and options will be printed to stderr. You must present these to the user and re-run the command with the chosen angle included in the topic.
      • HTTP 402 (Insufficient Credits): The engine will print the account balance, the amount needed, and a billing link. Relay these details to the user verbatim; do not fall back to WebSearch-only synthesis.
    export LAST30DAYS_API_KEY="your_key"
    export LAST30DAYS_API_BASE="https://api.example.com"
    python3 scripts/last30days.py --emit=json --json-profile=raw <topic>
  5. CI Policy: Search-quality evaluation vs. deterministic gates

    main

    The project maintains a strict distinction between two types of CI checks:

    1. Standard PR CI Gates: These are deterministic, offline-safe, and contract-shaped. They include pytest (offline-safe), plugin-contract checks, version-consistency contracts, and linting (e.g., ruff). These run automatically on every PR.
    2. Search-Quality Evaluation: This is non-deterministic and requires live API access. It is not included in the default validate.yml workflow to avoid high costs, latency, and flaky signals.

    Best Practices for Contributors/Maintainers:

    • Do not wire evaluate_search_quality.py into the default validate.yml workflow.
    • Do use workflow_dispatch (manually-dispatched workflows) or label-gated runs to trigger evaluations.
    • Do run the evaluation locally before submitting a PR to get signal on quality changes.
    • Do request a manual evaluation during code review if a PR affects the retrieval or ranking logic.
  6. How Reddit search works in last30days

    main

    Reddit search is performed using the OpenAI Responses API with the web_search tool, specifically filtered to the reddit.com domain. The process involves:

    1. Subject Extraction: The model strips noise words to find the core topic.
    2. Patterned Searching: It searches using three patterns: "{topic} site:reddit.com", "reddit {topic}", and "{topic} reddit".
    3. JSON Extraction: The model returns title, url, subreddit, date, and relevance.
    4. Validation: URLs must contain both /r/ and /comments/ to ensure they are real threads.

    Model Fallback Chain: If an access error occurs (HTTP 400/403), the system automatically falls back through this chain: gpt-5.2gpt-5.1gpt-5gpt-4.1gpt-4ogpt-4o-mini.

    {
      "model": "gpt-5.2",
      "tools": [{
        "type": "web_search",
        "filters": { "allowed_domains": ["reddit.com"] }
      }],
      "input": "Search Reddit for threads about {topic}..."
    }
  7. How the nominations bundle handles data (Engine vs. Host)

    main

    The nominations bundle serves two distinct audiences with different data requirements:

    1. Engine (Lossless Resume State): Contains the full judge pool with complete seed items serialized losslessly. This ensures that math for floor, velocity, and entity scoring remains identical between a single-shot run and a resumed protocol leg.
    2. Host (Capped Fenced Digest): A truncated version used for LLM context.
      • Capping: Titles, snippets, and comments are capped by _DIGEST_TITLE_MAX_CHARS, _DIGEST_SNIPPET_MAX_CHARS, and _DIGEST_COMMENT_MAX_CHARS respectively.
      • Fencing: Evidence lines are wrapped in an untrusted-content fence (e.g., using rerank._fenced_untrusted_content) to separate scraped content from structural metadata like IDs and sources.
  8. Understand the Checkpointed Discovery Protocol for Host-side LLM Judgment

    main

    The Checkpointed Discovery Protocol is an architecture pattern used when the primary consumer of a tool is a frontier reasoning model (an Agent) rather than a programmatic client. Instead of the tool performing its own LLM-based judgment (which can lead to silent failures or degraded heuristic fallbacks), the tool pauses at specific stages and persists state into versioned checkpoint files. The hosting model (the Agent) is then responsible for performing the semantic judgment (naming, classification, scoring) between tool invocations.

    This protocol is mandated by LAW 11: "YOU ARE THE JUDGE" in the project's SKILL.md.

    The Three-Leg Pipeline Workflow

    1. Leg 1: Nomination

      • Command: --discover --nominate-only
      • Action: Sweeps sources and writes a nominations bundle.
      • Host Task: The host model reads the bundle and writes a judgments file.
    2. Leg 2: Enrichment

      • Command: --discover --judgments <file>
      • Action: Resumes using the provided judgments file, performs deep enrichment, and writes a pending report.
      • Host Task: The host model reads the report and writes an angles file.
    3. Leg 3: Finalization

      • Command: --discover --finalize [--angles <file>]
      • Action: Renders the final report offline.

    When to use this pattern

    • When the tool's consumer is an Agent (e.g., Claude Code, Codex, Gemini).
    • When a pipeline stage requires semantic judgment that only an LLM can provide.
    • When you want to avoid silent heuristic fallbacks for keyless users.
    • When you need to persist state across multiple CLI invocations while a host model performs reasoning in between.
    # Leg 1: Generate nominations
    last30days --discover --nominate-only
    
    # Leg 2: Resume with host-provided judgments
    last30days --discover --judgments <path_to_judgments_file>
    
    # Leg 3: Finalize report
    last30days --discover --finalize [--angles <path_to_angles_file>]
  9. How fuzzy matching works in the Discovery Topic Queue

    main

    The system uses fuzzy matching to identify topics even when LLM-generated names drift between runs.

    Key Behaviors:

    • Annotate-only: A fuzzy match only adds context to the rendered output (e.g., Pipeline: surfaced Nth time, marked covered). It never merges or rewrites existing rows in the database. This prevents a false-positive match from causing unrecoverable data loss by collapsing two distinct stories into one.
    • Threshold: Matching is performed using entity_key token overlap or anchor-token overlap. The default threshold is 0.6.
    • Two-Phase Matching: To prevent a topic from matching a sibling row created in the same run (which would falsely report it as a repeat), the system performs a two-phase operation:
      1. Phase 1: Match all topics in the current report against the database to compute priors.
      2. Phase 2: Record the surfacings for the current run.

    This ensures that if a single report contains two similar topics, neither is incorrectly flagged as a 'repeat' of the other.

    # Threshold constant in skills/last30days/scripts/store.py
    DISCOVERY_QUEUE_OVERLAP_THRESHOLD = 0.6
  10. Understand the Discovery Checkpoint Protocol lifecycle

    main

    The discovery protocol is designed to pause the pipeline at judgment points, allowing a host LLM to perform reasoning between invocations. This prevents the need for an internal engine-side LLM call and ensures the host (the user's reasoning model) has full control over the evidence.

    Key Constraints:

    • Identity-bound: Every host file must echo the bundle_id minted by Leg 1.
    • Time-bound: Nominations bundles have a validity window defined by DISCOVERY_HANDOFF_TTL_SECONDS (default 3600.0). This is independent of the LAST30DAYS_REPORT_CACHE_TTL_SECONDS environment variable.
    • Store Scoping: The --save-dir flag is the sole handoff store. If provided, the system will not fall back to the config directory, preventing accidental cross-contamination of runs.
  11. HTML brief content structure

    main

    When the last30days engine renders an HTML brief using --emit=html, it constructs a self-contained document with the following components:

    • Badge: 🌐 last30days vX.Y.Z · synced YYYY-MM-DD at the top.
    • Metadata: A single inline line showing {date range} · {active sources}.
    • Synthesis: The provided synthesis text, where prose labels are promoted to <h2> tags and bold lead-ins are preserved.
    • Citations: All [name](url) patterns are converted into standard <a> tags.
    • Engine Footer: The ✅ All agents reported back! tree is rendered in monospace.
    • Colophon: Includes the topic and a re-run hint.

    Note on Comparison Mode: If the topic is a comparison (e.g., X vs Y), the engine uses render_for_html_comparison to handle specific sections like ## Quick Verdict, ## {Entity}, and ## Head-to-Head tables.

  12. Understand the Skill, Engine, and Harness architecture

    main

    The last30days-skill project is built on three core abstractions that define how an agent interacts with the research capabilities:

    • Skill: The unit of distribution. It is a self-contained package following the Agent Skills format, consisting of a SKILL.md (the agent-facing prose contract) and a scripts/ directory (the executable code).
    • Engine: The implementation layer. Specifically, the Python script scripts/last30days.py that performs the actual research. The SKILL.md instructs the agent on which flags to pass to the Engine (e.g., --plan, --subreddits, --emit=compact), and the Engine returns a specific output shape that the agent must pass through.
    • Harness: The agent runtime (e.g., Claude Code, Cursor, GitHub Copilot, Gemini CLI) that loads the Skill and executes it on the user's behalf.

    To ensure a Skill is "multi-harness," avoid hardcoding paths specific to one runtime and ensure all Engine flags are properly integrated into the SKILL.md instructions.