Files
last30days-skill/CHANGELOG.md
T
Trevin Chow daca71f89e
Release / build-and-release (push) Has been cancelled
chore(release): v3.3.0
~75 PRs merged since v3.2.0 plus 7 community fixes salvaged via PR triage.

Highlights:
- Install everywhere: npx skills add is canonical for Claude Code, Codex,
  Cursor, Gemini CLI, Copilot, Windsurf, and 50+ Agent Skills hosts.
- New emit mode: --emit=html for shareable HTML briefs.
- New source: Digg (auto-enabled when digg-pp-cli on PATH).
- New env vars: EXCLUDE_SOURCES, LAST30DAYS_YOUTUBE_SSH_HOST.
- New credential source: macOS Keychain.
- Reliability sweep: Reddit (4xx + URL prefix + multi-key auth), xAI
  error surfacing, Windows compatibility, YouTube/HN unblock,
  HTTP retries, planner gating, render fixes.
- Multi-harness reframe: AGENTS.md becomes canonical, CLAUDE.md points
  at it. SKILL_ROOT → SKILL_DIR substitution.

Breaking:
- .codex-plugin/plugin.json removed. Codex installs via npx skills add.
2026-05-17 09:25:46 -07:00

46 KiB
Raw Permalink Blame History

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[Unreleased]

[3.3.0] - 2026-05-17

A week-long shipping cycle: ~75 PRs merged plus 7 community fixes salvaged through PR triage. Big themes: install story modernized for the multi-harness world (Claude Code, Codex, Cursor, Gemini CLI, Copilot, Windsurf, and 50+ Agent Skills hosts), new emit and source modes, and a substantial reliability sweep across Reddit, X, Windows, YouTube, and the planner.

Added

Emit modes and sources

  • --emit=html for shareable, print-friendly HTML research briefs (#332).
  • Digg AI 1000 source, auto-enabled when digg-pp-cli is on PATH (#370). Surfaces curated story clusters from the AI 1000 leaderboard and pulls attributable X-post quotes into the brief.

Configuration knobs

  • EXCLUDE_SOURCES env var — the inverse of INCLUDE_SOURCES, honored in source count and pipeline filter (#399).
  • LAST30DAYS_YOUTUBE_SSH_HOST — opt-in SSH routing for yt-dlp through a residential-IP host, for users on datacenter VPS hit by YouTube's bot-wall (#376). Host validated against ^[a-zA-Z0-9._-]+$ to reject SSH option-injection. Transcript path unchanged (uses HTTP fallback).
  • macOS Keychain as a credential source — reads from the system keychain when env vars and config files aren't set (#407).
  • Configuration enablement: env-var defaults and source-resilience patterns across the config layer (#344).

Pipeline and storage

  • Reddit URL auto-enrichment from web search via the public JSON API (#366).
  • Per-run finding sightings recorded in the SQLite store (#373).
  • Brave browser support for X/Twitter cookie extraction (#320).

Tests and CI

  • Full pytest suite restored to CI; 13 rotted tests repaired (#416).
  • greptile.json added with triggerOnUpdates + statusCheck (#418).
  • Advisory security workflow (#368).
  • Parallel grounding backend test coverage (#355).

Docs

  • New CONFIGURATION.md with README pointers (#339).
  • docs/solutions/ learning capture for release-time consistency-test cascades (#413) and the eval-not-in-CI design decision (#417).

Changed

Install story modernized

  • npx skills add is now the canonical install path for every harness (#405). README and SKILL.md flipped to recommend npx skills add . -g -y over per-harness manual instructions. Surfaces Gemini CLI, Copilot, Windsurf, and 50+ other Agent Skills hosts that the install pattern reaches.
  • README dropped the Gemini CLI native-extension install path (now covered by npx skills add).
  • hooks.json made polyglot for Gemini CLI + Claude Code compatibility (#318).

Skill semantics and multi-harness reframe

  • AGENTS.md is now canonical; CLAUDE.md points at it (#410). Reframes the project as a multi-harness Agent Skills package rather than a Claude-Code-specific tool.
  • SKILL.md path resolution rewritten: STEP 0 narrows to a Claude-Code-marketplaces-only stale-clone guard; Step 1 walks a single SKILL_DIR substitution pattern (#400, #409). Removes ~80 lines of bash and fixes a real spec-vs-engine divergence where the previous resolver could pick a different install than the SKILL.md the model loaded from.
  • SKILL.md version regex consolidated into lib/skill_meta.py (#412).
  • --plan / --competitors-plan invocation templates switched from inline single-quoted JSON to heredoc-written tmpfiles (#404, fixes #403). Apostrophes in resolved context strings ("McDonald's", "people's choice") no longer break shell parsing.
  • POSTS_PER_CLUSTER raised 3→5 and render-side display limit 2→3 to match the per-source enrichment caps used by Reddit, HN, YouTube, TikTok, and GitHub. The previous caps routinely truncated cluster context.
  • Digg AI 1000 renamed to "Digg" in user-facing output (#372) — footer line, source label, inline-quote suffix, why_relevant, container attribution. Internal references retain the upstream product name.
  • GitHub repo resolution canonicalized for ambiguous product comparisons (#302).

Dependencies and tooling

  • Dropped requests runtime dependency. All providers route through stdlib urllib via the lib/http wrapper (#393).
  • Migrated to gemini-3.1-flash-lite GA model (#378).
  • Aligned Codex/Claude plugin manifests + added Codex AGENTS.md (#321).
  • pytest dev dep bumped 9.0.2 → 9.0.3 (#414).

Removed

  • BREAKING for Codex native-plugin users: .codex-plugin/plugin.json and the matching SKILL_ROOT resolver branch in SKILL.md Step 1 (#400). Codex users should install via npx skills add mvanhorn/last30days-skill or copy the skill to ~/.codex/skills/last30days/.
  • skills/last30days/scripts/sync.sh — maintainer dev-deploy script (#405). Replaced by npx skills add . -g -y (live-symlink into every detected harness's skill dir — better than sync.sh's copy model since edits propagate live). Hermes uses hermes skills install mvanhorn/last30days-skill --force; OpenClaw uses clawhub install last30days-official.
  • Orphaned SPEC.md and TASKS.md (#419).

Fixed

Reddit

  • lstrip("r/") mangled subreddits starting with r (r/roboticsobotics, r/rubyuby); replaced with removeprefix("r/") at 4 sites (Alex Key, salvaged from #288).
  • Browser-like User-Agent + Accept-Language/Accept-Encoding/Connection headers + gzip decompression to fix urllib 403s on Reddit's public JSON endpoint (Franco Carballar, salvaged from #199).
  • HTTP 402 re-raised across all three ScrapeCreators paths (_global_search, _subreddit_search, fetch_post_comments) so the OpenAI/public-JSON fallback chain triggers when credits are exhausted (Jonathan Oppenheim, salvaged from #170).

Authentication and credentials

  • Restored multi-key rotation for SCRAPECREATORS_API_KEY accidentally dropped in v3.0.6 (Eric Oberhofer, salvaged from #287). Comma-separated keys round-robin via random.choice per run.

Windows compatibility

  • os.killpg in _cleanup_children() guarded with hasattr(os, "killpg"), falls back to os.kill(SIGTERM) (gujishh, salvaged from #226).
  • POSIX-style secret-permission warning skipped on Windows (#357).
  • Render uses forward slashes in save-path footer for Windows (#338).

xAI / X / xurl

  • parse_x_response now raises http.HTTPError on empty output, missing JSON, or decode failure — surfaces in errors_by_source instead of silently returning an empty result list (Kaustav Mishra, salvaged from #155).
  • xurl treats PermissionError from PATH lookup as unavailable (#322).

YouTube

  • SC YouTube + multi-token HN searches unblocked (#388).
  • Transcript-fetch ratio surfaced + degraded-run nudge for stale yt-dlp (#340).

bird_x / HTTP

  • Subprocess retry on non-JSON stdout to handle X anti-bot HTML interstitials (#383).
  • HTTP retry budget expanded + exponential backoff on DNS resolution failure (#382).
  • Parallel AI search aligned with current API schema (#341).
  • Parallel web backend routed through grounding (#354).

Planner and sources

  • xquik registered in SOURCE_CAPABILITIES (#336, fixes #319).
  • Honor explicit optional source requests (#356).
  • ScrapeCreators source-gating aligned between code and docs (#415).
  • OpenClaw works without ScrapeCreators key (#392, by @thinkun).

Render, version display, hosting paths

  • Hardcoded v3.0.0 in render replaced with dynamic _skill_version() (#365).
  • Comparison HTML artifacts saved correctly (#389).
  • OPENROUTER_DEFAULT model ID corrected (#323).
  • OpenClaw poll-timing initialized once (#358).
  • Prefer sandboxed Safari cookie path (#343).
  • Preserve clean mode for last-run state (#334).
  • Replaced hardcoded /Users/mvanhorn/... paths in test-v1-vs-v2.sh with portable env-var overrides (Dave Morin, salvaged from #297).

Hooks

  • check-config.sh path-quoting fix for paths with spaces (#337).
  • Replaced unsafe eval with declare in check-config.sh (#364).

Sync and version metadata

  • sync.sh pointed at this repo's plugin cache, not the private repo's (#402).
  • Sync cache target bumped to 3.2.1 to match SKILL.md (#397).
  • ScrapeCreators free-tier credit count corrected to 100 in docs (#369, fixes #367).
  • Gemini extension version synced (#349).
  • Various stale path/link fixes (#345, #346, #347, #348, #351).

Contributors

First-time contributors whose fixes shipped in this release (most via PR triage salvage — fix re-applied directly to main with co-author credit when path migration made the original branch un-rebaseable):

  • Dave Morin — portable test-harness paths
  • Alex Key — removeprefix("r/") for subreddit names
  • Eric Oberhofer — multi-key rotation restored
  • gujishh — Windows process cleanup
  • Franco Carballar — Reddit browser-like headers
  • Jonathan Oppenheim — Reddit 402 fallback chain
  • Kaustav Mishra — xAI error surfacing
  • @thinkun (#363) — OpenClaw ScrapeCreators-key-optional fix

Full PR list at github.com/mvanhorn/last30days-skill/releases/tag/v3.3.0.

[3.2.0] - 2026-05-09

Added

  • Add --emit=html for shareable, print-friendly HTML research briefs.
  • Digg AI 1000 source (auto-enabled when digg-pp-cli is on PATH). Surfaces curated story clusters from the AI 1000 leaderboard and pulls attributable X-post quotes into the brief as [@handle](xUrl) via Digg AI 1000: ... lines. Footer line: ⛏️ Digg AI 1000: N clusters │ K posts │ M authors. No X auth required for the inline quotes since they flow through Digg's read-only endpoints.

[3.1.1] - 2026-04-24

Fixed

  • Codex plugin layout. Move the canonical runtime payload under skills/last30days/ and update Codex/Claude plugin metadata and tests for the relocated engine path.
  • Claude Code cache resolution. Resolve Claude plugin installs to skills/last30days/scripts/last30days.py after the plugin-layout restructure.

[3.1.0] - 2026-04-22

Consolidates the 3.0.10 to 3.0.14 dev cycle (commenter handles, --competitors, per-entity Step 0.55, vs-mode N passes, comparison title attribution) and republishes the OpenClaw bundle, which had been frozen on ClawHub at 3.0.0-open since April 8.

Added

  • OpenClaw republish. clawhub install last30days-official now resolves to 3.1.0-open, matching current main. Closes #307, #195, #236. The ClawHub bundle had shipped a broken env.py get_config() and stale SKILL.md path references since April; both are fixed at source on main and the republish carries the fixes to installers.

Fixed

  • Claude Code plugin manifest path-escape. The .claude-plugin/plugin.json skills key was removed in commit 93fbed2 but never shipped in a tagged release. Installing via /plugin install last30days-skill could hit /doctor's Path escapes plugin directory: ./ (skills) error. This release ships the fix. Closes #306.
  • Broken README link. The README's "source of truth" link pointed at root SKILL.md, which is no longer maintained after the plugin-layout restructure. Fixed to point at skills/last30days/SKILL.md.

Dev cycle journal (3.0.10 - 3.0.14, not separately tagged)

Individual changelog entries for 3.0.10 through 3.0.14 below document the incremental work consolidated into this release.

[3.0.14] - 2026-04-22

Changed

  • Comparison-mode title attribution. The synthesis title for vs-mode and --competitors outputs changes from What the Community Says (Last 30 Days) to What the Community Says (/Last30Days). Surfaces the slash-command identity instead of restating the date range. Three SKILL.md occurrences updated; pure documentation change.

[3.0.13] - 2026-04-22

Changed

  • vs mode runs N full passes in parallel, one per entity. Architectural revert of the 3-pass → 1-pass latency optimization from an earlier version. /last30days "OpenAI vs Anthropic vs xAI" now runs three full pipeline.run() calls in parallel via the same fanout --competitors uses, producing three *-raw.md save files plus a merged comparison output. Each entity gets its own Step 0.55-grade targeting, own primary X handle weight, own subreddit scoping — apples-to-apples depth instead of the one-pool merged retrieval the single-pass path produced. Parallel execution keeps wall clock ≈ single pass.
  • --competitors is now a SKILL.md-level shortcut for vs-mode with auto-discovery. The hosting reasoning model (Claude Code, Codex, Hermes, Gemini, any agent with WebSearch) performs discovery and Step 0.55 per entity via its own WebSearch tool, then invokes the engine with a vs-topic and --competitors-plan JSON. The engine flag remains for headless/cron use with BRAVE/EXA/SERPER/PARALLEL/OPENROUTER keys (engine-internal auto_resolve stays as fallback).
  • LAW 7-style stderr for --competitors with no backend now leads with the hosting-model path (WebSearch + Step 0.55 + --competitors-plan) instead of BRAVE_API_KEY. API-key framing moved to a secondary "headless" section.

Added

  • --competitors-plan JSON flag for per-entity Step 0.55 targeting. Schema: {entity_name: {x_handle?, x_related?, subreddits?, github_user?, github_repos?, context?}}. Accepts inline JSON or a file path (matches --plan). When present for an entity, skips engine-internal auto_resolve and uses the provided values; missing fields fall back to auto_resolve (if backend) or planner defaults. Case-insensitive entity matching. The subrun_kwargs_for helper is the single source of truth for per-entity kwargs — no closure-default fallthrough from main scope.
  • Per-entity save files when --save-dir is set on a vs-mode or --competitors run. Each entity's sub-run produces its own {slug}-raw.md with a single-row Resolved Entities block — matches historical vs-mode behavior (N passes → N save files).
  • --polymarket-keywords "kw1,kw2" to filter Polymarket matches for ambiguous single-token topics (e.g., "Warriors" → nba,gsw,golden-state kills Glasgow Warriors rugby and Honor of Kings Rogue Warriors noise).

Fixed

  • BRAVE/SERPER footer nudge suppressed when --plan or --competitors-plan is present. The nudge told Claude Code users to set an API key when they already have WebSearch via the hosting model. Nudge still fires for true headless runs (no --plan, no backend) where the advice is correct.
  • Override-leak regression testing. 3.0.12 already fixed the main-topic --subreddits / --x-handle / --github-* from leaking into peer sub-runs via explicit per-entity kwargs scrubbing. This release adds a 4-test regression suite (test_competitor_subrun_isolation.py) locking in the invariant.

[3.0.12] - 2026-04-22

Fixed

  • Per-entity Step 0.55 resolution for competitor sub-runs. In 3.0.11, only the main topic got X handle / subreddit / GitHub resolution; competitor sub-runs ran with planner defaults and produced visibly thinner evidence (Reddit 403 fallbacks, single-word queries). Each competitor sub-run now calls resolve.auto_resolve() inside fanout.run_competitor_fanout when a web backend is available, mirroring the main topic's pre-flight resolution. Per-entity X handle, subreddit list, GitHub user/repos, and news context are threaded into each sub-run's pipeline.run() call. Deep-copied config per sub-run prevents _auto_resolve_context cross-leak. Surfaces in a new ## Resolved Entities output block so the resolution coverage is visible without reading stderr.
  • LAW 7 false-positive on internal fan-out sub-runs. Each competitor sub-run was emitting the [Planner] No --plan passed... YOU ARE the planner stderr warning. LAW 7 targets the hosting-reasoning-model path, not engine-internal fan-out. New internal_subrun=True keyword on planner.plan_query and pipeline.run suppresses the warning for sub-runs only; the default path is unchanged.
  • Marketplace-stale SKILL.md trap. Added a STEP 0 canonical-path self-check at the top of SKILL.md. Two of three 2026-04-22 test runs loaded SKILL.md from plugins/marketplaces/last30days-skill/ (Claude-Code-managed git clone pinned to origin/main, lagging the versioned cache), then ran --help against the same stale path, did not see --competitors, and fell back to a manual comparison plan. The STEP 0 block forces any reader to verify they loaded from plugins/cache/last30days-skill/last30days/{VERSION}/SKILL.md and re-read from the versioned cache if not.

Changed

  • Default --competitors count is now 2 (3-way total: original + 2 peers). Previously 3. --competitors=N still customizes (range 1..6). Matches the feature description's canonical example (Kanye vs Drake vs Kendrick).

Added

  • ## Resolved Entities block in render_comparison_multi output. Shows per-entity X handle, subreddits, GitHub user/repos, and truncated context for every entity in the comparison. Block is omitted entirely when no entity has a resolved payload (mock mode, no backend).

[3.0.11] - 2026-04-22

Added

  • --competitors flag for auto-discovered comparison fan-out. Pass --competitors on a single-entity topic and the engine discovers 2-6 peer entities via web search, then runs the full pipeline on each in parallel and emits one N-way comparison. last30days Kanye West --competitors resolves Drake, Kendrick Lamar, and one more peer. last30days OpenAI --competitors resolves Anthropic, xAI, Google Gemini. --competitors=N controls count, --competitors-list="A,B,C" skips discovery and uses the explicit list. Discovery mirrors the auto_resolve pattern (Brave / Exa / Serper / Parallel) with deterministic text extraction - no internal LLM call. Sub-runs inherit the main --quick/--deep/--days, run in a ThreadPoolExecutor, and degrade gracefully when at least 2 entities survive. Output reuses the existing 9-axis ## Head-to-Head scaffold.

[3.0.10] - 2026-04-21

Added

  • Commenter handles on evidence lines. Top-comment rendering now includes the commenter's handle - u/author for Reddit, @handle for TikTok/YouTube/Instagram/Bluesky/X/Threads. The enrichment adapters already captured author; the render layer just was not using it. Evidence lines change from - Comment (6822 upvotes): Finally, John Apple to - u/Cyrisaurus (6822 upvotes): Finally, John Apple. Person-level citations make synthesis-side inline markdown links per LAW 8 much more natural. Both the compact and full render paths are covered.

Fixed

  • TikTok author preference. _fetch_post_comments in scripts/lib/tiktok.py preferred user.nickname over user.unique_id, so the engine captured display names ("Moosa Noormahomed") instead of @handles ("moosanoormahomed"). Flipped to prefer unique_id. Nickname still wins as a fallback when unique_id is missing. Display names can contain emoji, spaces, and non-Latin characters that do not round-trip to a profile URL; the @handle is the stable identifier.
  • Single plugin payload layout. The canonical runtime moved to skills/last30days/ for both Claude Code and Codex plugin loading. Root-level SKILL.md, scripts/, agents/, and assets/ are no longer maintained as duplicate copies.

Behavior fallback

  • When an author is empty, [deleted], or [removed], the render falls back to the legacy Comment (...) shape - no u/ or @ prefix with an empty handle is ever emitted.

3.0.9 - 2026-04-18 - The Self-Debug Release

Highlights

v3.0.9 adds the engine-side Class 1 keyword-trap refuse-gate ("birthday gift for 40 year old" now gets a clarifying question, not 5 minutes of junk), promotes TikTok and YouTube top comments to the same first-class rendering Reddit's got, lands Hermes AI Agent as a first-class deploy target, and moves the SKILL.md formatting contract from line 1094 to the top of the file.

"The Self-Debug Release" refers to how the fixes in 3.0.6-3.0.9 were written: 5 separate Opus 4.7 instances each debugged their own failed outputs. Three converged on "SKILL.md is too big and the LAWs are too deep." Two converged on "the engine should refuse demographic-shopping queries." I shipped exactly what they said. Validation: 5/5 canonical compliance.

Added

  • Engine Class 1 keyword-trap refuse-gate (scripts/lib/preflight.py, new). Pattern-matches demographic-shopping queries at main() front-door. Exit code 2 with structured REFUSE message. Escape hatch: LAST30DAYS_SKIP_PREFLIGHT=1. 29 tests in tests/test_preflight.py.
  • TikTok + YouTube top comments rendered with same 💬 Top comment prominence as Reddit's. Shipped in #260; enrichment fixed in #265.
  • Hermes AI Agent as a deploy target - thanks @stephenmcconnachie (#228). scripts/sync.sh detects ~/.hermes/skills/research and deploys automatically.
  • Multi-key SCRAPECREATORS_API_KEY rotation - thanks @zaydiscold (#268). Set SCRAPECREATORS_API_KEY_1, _2, etc. Engine rotates on rate-limit.
  • Offline quality evaluation fixture - thanks @j-sperling (#233). eval_topics.json lets contributors run quality regressions without burning live API credits.
  • END-OF-CANONICAL-OUTPUT boundary in render_compact(). Engine now emits an explicit pass-through instruction so re-synthesis requires actively ignoring a visible boundary.
  • LAW 1 verbatim-pattern override. LAW 1 now quotes the exact WebSearch tool-result reminder ("CRITICAL REQUIREMENT: MUST include Sources: section") and declares it OVERRIDDEN inside last30days output.

Changed

  • SKILL.md restructure. VOICE CONTRACT LAWs and BADGE MANDATORY block moved from line 1094 to lines 75-150. Grounded in 3 separate Opus 4.7 self-debugs.
  • Engine emits the badge as stdout. 🌐 last30days v3.0.9 · synced YYYY-MM-DD is the first line of every compact emit. Pass-through is now the default-correct behavior.
  • Reddit client HTTP consolidation - thanks @iliaal (#207). Migrated to http.get(params=...) helper.
  • ScrapeCreators header consolidation - thanks @iliaal (#209). _sc_headers refactored into http.scrapecreators_headers.
  • Simpler Hermes sync. scripts/sync.sh Hermes branch now always uses main SKILL.md (previously had a .hermes-plugin/SKILL.md fallback that created a wrong-file-capture hazard).

Fixed

  • Peter Steinberger trailing Sources leak. 2026-04-18 validation failure where the model appended a TechCrunch / TED / Fortune / Wikipedia Sources list after the invitation. Now structurally prevented at three layers: engine emits the canonical body, LAW 1 quotes the exact WebSearch reminder, closing boundary names the anti-pattern.
  • Wrong-file SKILL.md capture. Deleted .agents/skills/last30days/SKILL.md (1382 lines, April 13 snapshot) and .hermes-plugin/SKILL.md (269 lines). One SKILL.md per plugin now, at the plugin root.
  • GitHub date parsing garbage - thanks @iliaal (#208). _parse_date now rejects invalid input cleanly.
  • Windows Bird X stability - thanks @Chelebii (#227).
  • Linux check_perms false-warn - thanks @george231224 (#216). Uses GNU stat first.
  • UTF-8 saved output - thanks @Gujiassh (#225).
  • Version metadata alignment - thanks @Gujiassh (#217) and @shalomma (#229).
  • --days alias backcompat - thanks @BryanTegomoh (#230).
  • INCLUDE_SOURCES env default - thanks @hnshah (#223).
  • Bird X all-None engagement - thanks @j-sperling (#234).

Contributors

@j-sperling, @stephenmcconnachie, @zaydiscold, @iliaal, @Chelebii, @Gujiassh, @hnshah, @george231224, @shalomma, @BryanTegomoh for PRs since v3.0.0. @uppinote20, @zerone0x, @thinkun, @thomasmktong, @fanispoulinakisai-boop, @pejmanjohn, @zl190, @Jah-yee, @dannyshmueli, @Cody-Coyote for issues and PRs that shaped the v3 roadmap.

Recovery

/plugin update last30days
/reload-plugins

Verify: cat ~/.claude/plugins/cache/last30days-skill/last30days/*/.claude-plugin/plugin.json | grep version returns "version": "3.0.9".

Smoke test: /last30days birthday gift for 40 year old should ask a clarifying question before running.

[3.0.5] - 2026-04-15

Added

  • /last30days slash command for plugin users. New commands/last30days.md registers a Claude Code slash command. Users type /last30days <topic> and Claude Code's autocomplete prefix-matches it to the canonical /last30days:last30days form (the same way /ce:plan resolves to /compound-engineering:ce-plan). The command delegates to the existing last30days skill body — no skill behavior changes.

Removed

  • skills/last30days-nux/ — byte-identical duplicate of root SKILL.md that created confusing /last30days:last30days-nux autocomplete entries via Claude Code's plugin namespacing. The root SKILL.md remains the canonical skill source.

Recovery

/plugin update last30days
/reload-plugins

Then type /last30days <topic> to invoke the skill via slash command. Natural-language invocation ("search the last 30 days for X") continues to work unchanged.

[3.0.4] - 2026-04-15

Fixed

  • Cleared /doctor path-escape error on Claude Code v2.1.109+. .claude-plugin/plugin.json previously declared "skills": ["./"]. That value shipped unchanged from v2.1.0 through v3.0.3 and worked on older Claude Code, but current versions reject ./ with Path escapes plugin directory: ./ (skills). The "skills" key is now omitted entirely, matching the pattern used by every other plugin in the Claude Code marketplace ecosystem. Claude Code auto-discovers skills/*/SKILL.md when the key is absent.

Recovery

If /doctor reports a path-escape error for last30days, run /plugin update last30days then /reload-plugins. If errors persist, uninstall and reinstall the plugin.

[3.0.3] - 2026-04-15

Fixed

  • Restored skills/ and .claude-plugin/ to the plugin install tarball. v3.0.1 added .gitattributes rules that excluded both directories from git archive output to shrink the claude.ai .skill bundle. Claude Code's /plugin install fetches the same archive, so users installing v3.0.1 or v3.0.2 received a tarball with no plugin manifest and no skill files. git archive v3.0.0 contained 8 files under those paths; v3.0.1 and v3.0.2 contained 0. This release reverts those .gitattributes lines.
  • Reverted plugin.json "skills" field to ["./"]. v3.0.2 changed this to ["skills"] based on a misdiagnosis — the manifest change had no effect because the manifest wasn't in the tarball at all. The historical ["./"] value shipped in every release from v2.1.0 through v3.0.0 without issues and is restored here.

Recovery

Users on v3.0.1 or v3.0.2: run /plugin update last30days then /reload-plugins. If autoUpdate is enabled, the next session start will pull v3.0.3 automatically. Users on cached v3.0.0 or earlier installs were unaffected.

Notes

  • The claude.ai .skill bundle built by scripts/build-skill.sh still works — the archive grew from 89 to 97 files, well under the 200-file cap.
  • claude.ai-specific exclusions (avoiding duplicate SKILL.md files in the bundle) should move into scripts/build-skill.sh rather than .gitattributes in a future release, since .gitattributes cannot distinguish between the two distribution channels.

[3.0.2] - 2026-04-15

Fixed

  • /last30days slash command now registers on Claude Code v2.1.105+. .claude-plugin/plugin.json declared "skills": ["./"], which newer Claude Code rejects with Path escapes plugin directory: ./ (skills). The skill silently failed to register, so /last30days <query> returned "Unknown command" even though /plugin list showed the plugin as installed. Fix: "skills": ["skills"] so the loader scans the real skill subdirectory.
  • Version drift between manifests. .claude-plugin/marketplace.json was pinned to 3.0.0 while .claude-plugin/plugin.json advertised 3.0.1. The /plugin resolver used the marketplace version and could install stale cached metadata alongside the correct build. Both manifests now agree on 3.0.2.

Recovery

If /last30days stopped working for you, run /plugin update last30days then /reload-plugins. If /doctor still reports errors, uninstall and reinstall the plugin from the marketplace.

[3.0.1] - 2026-04-14

Fixed

  • Skill upload packaging - scripts/build-skill.sh produces a claude.ai-upload-ready .skill file that fits under the 200-file cap. Previously, zipping the repo hit 406 files and the "Upload skill" UI rejected it outright.
  • SKILL.md description length - trimmed from 228 to 167 chars (Anthropic caps descriptions at 200).

Removed

  • Unused root vendor/ directory (215 files from an accidental commit in PR #48 - the real vendored X client lives at scripts/lib/vendor/bird-search/).
  • Legacy top-level plans/ directory (superseded by docs/plans/; both plans described work that was already shipped in v3).

Added

  • .gitattributes with export-ignore entries so git archive drops tests, docs, fixtures, assets, historical manifests, and internal skill subdirs. Mirrors Anthropic's canonical package_skill.py exclusions.
  • scripts/build-skill.sh - one-command path to produce dist/last30days.skill with a single top-level last30days/ folder, defensive =200 file check, and dirty-tree refusal.
  • README.md section documenting the claude.ai skill upload workflow.

[3.0.0] - 2026-04-11

Highlights

Intelligent search, fun judge, cross-source cluster merging, single-pass comparisons, and OpenClaw as a first-class citizen. The v3 engine doesn't just search for your topic -- it figures out where to search before the search begins. Engine architecture by @j-sperling.

Added

  • Intelligent pre-research -- Resolves X handles, subreddits, TikTok hashtags, and YouTube channels via a new Python brain before any API calls fire. Bidirectional: person to company, product to founder.
  • Fun judge / Best Takes -- Second parallel LLM judge scores humor, cleverness, and virality. Surfaces the best reactions in a dedicated output section.
  • Cross-source cluster merging -- Entity-based overlap detection merges the same story across Reddit, X, YouTube into one cluster instead of three separate items.
  • Single-pass comparisons -- "X vs Y" runs one pass with entity-aware subqueries instead of three serial passes. 3 minutes instead of 12+.
  • GitHub as a source -- Stars, reactions, and comments from repos and issues.
  • OpenClaw first-class citizen -- Auto-resolve for engine-side pre-research. Device auth for frictionless ScrapeCreators signup.
  • Per-author cap -- Max 3 items per author prevents single-voice dominance.
  • Entity disambiguation -- Synthesis trusts resolved handles over keyword matches.
  • Perplexity Sonar Pro as additive source -- AI-synthesized research with citations via OpenRouter. Opt-in via INCLUDE_SOURCES=perplexity. Returns structured narratives that complement social data.
  • Perplexity Deep Research -- --deep-research flag for exhaustive 50+ citation reports (~$0.90/query). Premium opt-in for serious investigation.
  • OpenRouter as reasoning provider -- One OPENROUTER_API_KEY powers planning, reranking, and Perplexity search. Auto-detected after Gemini/OpenAI/xAI.
  • Parallel AI grounding backend -- --web-backend parallel or auto-detected via PARALLEL_API_KEY.
  • Grounding in planner -- Grounding source properly registered in SOURCE_CAPABILITIES instead of force-injected.

Changed

  • YouTube transcript candidate pool widened 3x past music videos to reach talk/review content with captions
  • Reddit comment enrichment sorted by total engagement (upvotes + comments), not just upvotes
  • Polymarket display shows % odds only; dollar volumes removed
  • 852 tests passing

Fixed

  • Marketplace validation: duplicate name: last30days collision in skills/last30days/SKILL.md caused strict validators to reject the plugin. Resolved by renaming the internal v3 architecture spec to last30days-v3-spec with user-invocable: false. Fixed in #214 (reported by @Cody-Coyote in #204).
  • Stale README link to the deleted skills/last30days-v3/ path from the v3 directory rename. Fixed in #214.
  • OpenAI Codex CLI discoverability: added .agents/skills/last30days/SKILL.md as a real file (Codex's loader skips symlinked files) plus .codex-plugin/plugin.json as the namespace marker. The skill now registers as last30days:last30days when Codex runs in a checkout of the repo. Fixed in #219 (inspired by @Jah-yee in #153 and @dannyshmueli on X).

Contributors

  • @j-sperling -- v3 engine architecture, Python pre-research brain
  • @hnshah -- Watchlist features
  • @Cody-Coyote -- Marketplace validation bug report (#204)
  • @Jah-yee -- Codex CLI integration inspiration (#153)

[2.9.4] - 2026-03-06

Changed

  • Move save into Python script via --save-dir flag - raw research data saved during the existing script Bash call, zero extra tool calls after invitation
  • Remove entire "Save Research to Documents" section from SKILL.md (~45 lines removed)
  • No more 📎 footer, no Bash heredoc, no (No output), no multi-minute cogitation after research

[2.9.3] - 2026-03-06

Fixed

  • Critical: Switch save from run_in_background to foreground Bash - background callbacks caused model to re-engage, hallucinate fake user messages, and generate unsolicited multi-paragraph responses
  • Save uses foreground cat > heredoc (executes sub-second, no callback, no delayed notification)

[2.9.2] - 2026-03-06

Fixed

  • Save research silently using background Bash heredoc instead of Write tool (eliminates "Wrote N lines..." clutter)
  • Suppress follow-up text after background save completes (no more "Research briefing saved..." noise)
  • Add 📎 footer line for save path instead of verbose confirmation

2.9.1 - 2026-03-05

Highlights

Auto-save research briefings to the default memory directory as topic-named .md files. Every run now builds a personal research library automatically - no more manual copy-paste.

Added

  • Auto-save complete research briefings (synthesis, stats, follow-up suggestions) to the default memory directory after every run
  • Kebab-case filename generation from topic (e.g., "Claude Code skills" -> claude-code-skills.md)
  • Duplicate topic handling: appends date suffix instead of overwriting (e.g., claude-code-skills-2026-03-05.md)
  • Agent mode (--agent) also saves research files
  • Brief confirmation after save with the saved file path

Credits

  • @devin_explores -- Inspired this feature by sharing their workflow of saving every last30days run into organized .md files (PR #51)

2.9.0 - 2026-03-05

Highlights

ScrapeCreators Reddit as the default backend (one SCRAPECREATORS_API_KEY covers Reddit + TikTok + Instagram), smart subreddit discovery with relevance-weighted scoring, and top comments elevated with 10% scoring weight and prominent display.

Added

  • ScrapeCreators Reddit backend (scripts/lib/reddit.py) — keyword search, subreddit discovery, comment enrichment, all via api.scrapecreators.com
  • Smart subreddit discovery with relevance-weighted scoring: frequency × recency × topic-word match, replacing pure frequency count
  • UTILITY_SUBS blocklist to filter noise subreddits (r/tipofmytongue, r/whatisthisthing, etc.) from discovery results
  • Top comment scoring: 10% weight in engagement formula via log1p(top_comment_score)
  • Top comment rendering: 💬 Top comment lines with upvote counts in compact and full report output
  • Comment excerpt length increased from 300 → 400 chars; comment_insights limit raised from 7 → 10

Changed

  • primaryEnv switched from OPENAI_API_KEY to SCRAPECREATORS_API_KEY — one key now powers Reddit, TikTok, and Instagram
  • Reddit engagement scoring formula: 0.55/0.40/0.05 (score/comments/ratio) → 0.50/0.35/0.05/0.10 (score/comments/ratio/top-comment)
  • SKILL.md synthesis instructions updated to emphasize quoting top comments

Fixed

  • Utility subreddit noise in discovery (e.g., r/tipofmytongue appearing for unrelated topics)
  • Reddit search no longer requires OPENAI_API_KEY — ScrapeCreators API handles search directly

2.8.0 - 2026-03-04

Highlights

Instagram Reels as the 8th signal source, TikTok migrated from Apify to ScrapeCreators API, and SKILL.md quality improvements. One API key (SCRAPECREATORS_API_KEY) now covers both TikTok and Instagram.

Added

  • Instagram Reels as 8th research source via ScrapeCreators API — keyword search, engagement metrics (views, likes, comments), spoken-word transcript extraction (scripts/lib/instagram.py)
  • InstagramItem dataclass, normalization, scoring (45% relevance / 25% recency / 30% engagement), deduplication, cross-source linking, and rendering
  • Instagram in SKILL.md: stats template (📸 Instagram:), citation priority, item format description, output footer
  • URL-to-name extraction examples in SKILL.md for cleaner web source display
  • --search=instagram flag support

Changed

  • TikTok backend migrated from Apify to ScrapeCreators API (api.scrapecreators.com)
  • APIFY_API_TOKEN replaced by SCRAPECREATORS_API_KEY in config
  • SKILL.md version bumped to v2.8
  • WebSearch citation instruction strengthened to prevent trailing Sources: blocks
  • Security section updated: Apify → ScrapeCreators references

Fixed

  • Web stats line showing full URLs instead of plain domain names
  • Trailing "Sources:" block appearing after skill invitation (WebSearch tool mandate conflict)
  • Instagram/TikTok not running in web-only mode when --search=instagram used without Reddit/X
  • $ARGUMENTS quoting in SKILL.md for correct flag forwarding

2.1.0 - 2026-02-15

Highlights

Three headline features: watchlists for always-on bots, YouTube transcripts as a 4th source, and Codex CLI compatibility. Plus bundled X search with no external CLI needed.

Added

  • Open-class skill with watchlists, briefings, and history modes (SQLite-backed, FTS5 full-text search, WAL mode) (feat(open))
  • YouTube as a 4th research source via yt-dlp -- search, view counts, and auto-generated transcript extraction (feat: Add YouTube)
  • OpenAI Codex CLI compatibility -- install to ~/.agents/skills/last30days, invoke with $last30days (feat: Add Codex CLI)
  • Bundled X search -- vendored subset of Bird's Twitter GraphQL client (MIT, originally by @steipete), no external CLI needed (v2.1: Bundle Bird X search)
  • Native web search backends: Parallel AI, Brave Search, OpenRouter/Perplexity Sonar Pro (feat(engine))
  • --diagnose flag for checking available sources and authentication status
  • --store flag for SQLite accumulation (open variant)
  • Conversational first-run experience (NUX) with dynamic source status (feat(nux))

Changed

  • Smarter query construction -- strips noise words, auto-retries with shorter queries when X returns 0 results
  • Two-phase search architecture -- Phase 1 discovers entities (@handles, r/subreddits), Phase 2 drills into them
  • Reddit JSON enrichment -- real upvotes, comments, and upvote ratio from reddit.com/.json endpoint
  • Engagement-weighted scoring: relevance 45%, recency 25%, engagement 30% (log1p dampening)
  • Model auto-selection with 7-day cache and fallback chain (gpt-4.1 -> gpt-4o -> gpt-4o-mini)
  • --days=N configurable lookback flag (thanks @jonthebeef, #18)
  • Model fallback for unverified orgs (thanks @levineam, #16)
  • Marketplace plugin support via .claude-plugin/plugin.json (inspired by @galligan, #1)

Fixed

  • YouTube timeout increased to 90s, Reddit 429 rate limit fail-fast
  • YouTube soft date filter -- keeps evergreen content instead of filtering to 0 results
  • Eager import crash in __init__.py that broke Codex environments
  • Reddit future timeout (same pattern as YouTube timeout bug)
  • Process cleanup on timeout/kill -- tracks child PIDs for clean shutdown
  • Windows Unicode fix for cp1252 emoji crash (thanks @JosephOIbrahim, #17)
  • X search returning 0 results on popular topics due to over-specific queries

New Contributors

  • @JosephOIbrahim -- Windows Unicode fix (#17)
  • @levineam -- Model fallback for unverified orgs (#16)
  • @jonthebeef -- --days=N configurable lookback (#18)

Credits

  • @galligan -- Marketplace plugin inspiration
  • @hutchins -- Pushed for YouTube feature

1.0.0 - 2026-01-15

Initial public release. Reddit + X search via OpenAI Responses API and xAI API.