Three bugs in _extract_core_subject():
1. Multi-word noise phrases ("what are", "how to") never matched
because code compared individual words against multi-word strings.
"what are people saying about DeepSeek R1" became "what are people
saying" — losing the entire topic.
2. Missing meta words — "prompt", "techniques", "tips" weren't
filtered (only "prompting" was). "vibe motion best prompt
techniques" kept 4 keywords instead of 2.
3. No retry on 0 results — Reddit retries with simplified queries
but X accepted 0 and moved on.
Fix: Two-phase extraction (strip multi-word prefixes/suffixes first,
then individual noise words), expanded noise set, max 3 words (was 4),
and automatic retry with first 2 words when Bird returns 0 results.
Before → After:
- "vibe motion best prompt techniques" → "vibe motion" (was 4 words, 0 results)
- "what are people saying about DeepSeek R1" → "deepseek r1" (was "what are people saying")
- "nano banana pro prompts for gemini" → "nano banana pro" (was 4 words)
Tested: vibe motion (12 X posts, was 0), DeepSeek R1 (12 posts),
kanye west (12 posts, no regression).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add V2 to title
- Document Bird CLI installation (free X search)
- Add --days=N to options table
- Update Requirements to show Bird CLI as recommended free option
- Replace How It Works with two-phase search architecture
- Add What's New in V2 section with all new features
- Credit community contributors (@JosephOIbrahim, @levineam, @jonthebeef)
- Bump http.py USER_AGENT from 1.0 to 2.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Every invitation now includes 2-3 specific examples based on what the
research actually found. PROMPTING mode explicitly offers to write prompts
with creative examples. NEWS suggests follow-up questions about the
biggest stories. GENERAL suggests specific deep-dives and applications.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GENERAL mode said "write a prompt for it" which sounds weird for people/topics
("write a prompt for Kanye West"). Changed to "describe what you're working on
and I'll help." Added "I'm now an expert on {TOPIC}" prefix to all 4 modes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After the initial broad search (Phase 1), extract key entities from results
and run targeted secondary searches to surface content the broad pass missed:
- New entity_extract.py: parses @handles, #hashtags, subreddits from results
- bird_x.py: search_handles() does targeted from:handle searches via Bird CLI
- openai_reddit.py: search_subreddits() uses Reddit's free .json search endpoint
- last30days.py: Phase 2 orchestration runs after enrichment, merges + dedupes
Tested with "kanye west" (+9 Reddit, +1 X) and "claude code skills" (+6 Reddit, +1 X).
Phase 2 is skipped on --quick mode. Default caps at 3 handles/subs, deep at 5.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Invitation adapts to QUERY_TYPE: NEWS gets "ask me anything",
PROMPTING gets "share your vision", RECOMMENDATIONS gets "compare options"
- Follow-up handler reads intent: questions get answers, not forced prompts
- Restored V1's "if they ask a question, answer it" context memory line
- URL formatting rule: "per Rolling Stone" not raw URLs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add citation priority rule: @handles > r/subreddits > web sources
- Fix examples: "per @honest30bgfan_" instead of "per Rolling Stone"
- Add "lead with people, not publications" instruction
- Stats box: web now shows "(supplementary)" instead of domain list
- No changes to actual research — same quality, better attribution framing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add .claude-plugin/marketplace.json and plugin.json manifests
- Use ${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/skills/last30days} for script path
- Plugin install: uses CLAUDE_PLUGIN_ROOT when set
- Manual install: falls back to ~/.claude/skills/last30days (no breakage)
- SKILL.md stays at root, plugin.json points skills to "./"
Users can now install via:
claude plugin marketplace add mvanhorn/last30days-skill
claude plugin install last30days@last30days
Inspired by PR #1 (galligan) — lighter approach without repo restructure.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
User preferred V1's "I'll research X across Reddit, X, and the web..."
with explicit Parsed intent block over V2's emoji format.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Feature audit found 11 things v2 dropped from v1. Restored the 7 that affect
output quality: quality checklist for prompts, anti-pattern examples, self-check
instruction, "don't re-search" context memory, prompt format anti-pattern,
multi-prompt guidance, and emoji footer with engagement counts.
Also adds visible query parsing display (🔍 **{TOPIC}** · {QUERY_TYPE}) and
the full v1-vs-v2 comparison test plan with all 17 test queries from README.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The old v1 skill worked because context: fork was SILENTLY IGNORED
due to Claude Code bug #17283. The skill ran inline in the main
conversation. Claude Code 2.1+ fixed the bug and now properly
honors fork mode, creating an isolated subagent that ignores all
instruction ordering (text output, bash-first, etc.).
Fix: remove context: fork so the skill runs inline again, matching
the behavior the user knows works. Also restored v1-style
instruction flow: parse intent first, then run script, then WebSearch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The agent in fork mode ignores text output instructions and jumps
straight to WebSearch. Reverted to the original "YOUR FIRST ACTION:
Run this command. EXECUTE." pattern that actually worked. Embedded
progress display as echo statements inside the bash command so they
can't be skipped. The agent was not running the Python script at all
when the first instruction was about text output.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The agent was skipping the progress text because it was buried after
parsing logic at line 41. Restructured so the FIRST section is
"YOUR FIRST OUTPUT" with the progress block, BEFORE any tool call
instructions. Added explicit "DO NOT skip this" enforcement.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The ui.py spinner/color output goes to stderr which Claude Code
buffers invisibly. Instead, have the agent output a visible progress
block with emoji showing Reddit/X/Web agents deploying.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add back the brief topic acknowledgment ("Researching X — searching
Reddit for upvotes...") and descriptive intro that the v1 skill had.
The v2 version was jumping straight into script execution with no
user-facing feedback about what was being researched.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Stats: replace BAD/GOOD examples with strict fill-in-the-blank template
- Reddit: add subreddit-targeted fallback search, soften scoring penalties
(engagement -10→-3, date confidence -10→-5), add minimum result guarantee
- Citations: limit to 1 per insight, short format, no engagement metrics
- Summary: add bold topic headers template for structured paragraphs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Reverted description to original public repo copy
- Restored H1 heading, moved imperative instruction to bold paragraph
- Added BAD/GOOD examples enforcing emoji tree stats format
- Required @handle and r/subreddit citation in ALL summary types
- Removed agent:Explore and disable-model-invocation from frontmatter
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Explore agent was treating SKILL.md as documentation to summarize
instead of instructions to follow. Removed agent:Explore from frontmatter
and restructured opening to immediately command script execution.
Also adds release plan for Bird CLI v2.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wrap value in single quotes to properly escape nested double quotes.
This fixes skills CLI installation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update skill name and description (remove TEST markers)
- Update script path to ~/.claude/skills/last30days/
- Clean up header, keep Bird CLI features prominent
Ready for local testing as the main skill.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove over-prescriptive format requirements
- Let Claude choose table vs stacked naturally based on content
- Keep critical requirement: Sources line with @handles
- Claude Code's renderer handles the responsive wrapping
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace ASCII table with stacked card format
- Each card: Tool/Mentions/Use Case/Sources on separate lines
- Cards separated by horizontal rule (────)
- Doesn't break when terminal window is narrow
- Still includes @handles in Sources line
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Changed from numbered list to ASCII box-drawing table format
- Added "Key Sources" column that MUST include @handles from X posts
- Added explicit instructions to parse and display highest-engagement handles
- Matches the output quality of the original xAI version
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Claude was summarizing qualitatively ('mostly casual conversation')
instead of summing actual engagement numbers from the output.
Added CRITICAL note to:
- Parse [Xlikes, Yrt] from each X post
- Sum totals for the stats display
- Show top voices with engagement (e.g., @handle (15K likes))
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1. Add _extract_core_subject() to strip noise words before X search
- X search is literal keyword matching, not semantic
- "best open claw usecases" → "open claw" (27 results vs 0)
2. Fix ISO date detection bug
- Was: if "T" in created_at (matched "Tue" in "Tue Feb 03...")
- Now: if created_at[10] == "T" (proper ISO separator check)
- Dates now parse correctly: (2026-02-03) instead of (date unknown)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1. last30days.py: Check isinstance(dict) before .get() - Bird returns
list on success, dict on error
2. bird_x.py: Update field mappings for Bird's actual response format:
- author.username not user.screen_name
- createdAt not created_at (camelCase)
- likeCount, retweetCount, etc. (camelCase)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Now reads from ~/.config/last30days/.env like the regular skill.
Bird CLI + API keys both work together.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Bird CLI doesn't support --since as a CLI flag.
Use X's search syntax: 'topic since:YYYY-MM-DD'
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove interactive "Install Bird CLI?" prompt
- Add Bird as FREE option in promo messages
- Auto-detect Bird silently (use if authenticated)
- Keep original flow: show promo → continue with available sources
Bird now appears in the promo alongside API keys:
🔵 X (Twitter)
└─ FREE: npm install -g @steipete/bird (uses browser session)
└─ Or: Add XAI_API_KEY (paid API)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move Bird CLI check to run before topic validation so users see
the install prompt even when running without a topic argument.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add LAST30DAYS_CONFIG_DIR env var to override config location
- Set LAST30DAYS_CONFIG_DIR="" in test skill for clean mode
- Test skill now ignores existing API keys to show Bird install prompt
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Creates SKILL-TEST.md with name "last30daystest" so the Bird CLI
integration can be tested without affecting the original /last30days
skill installed from the public repo.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move progress display initialization early to support Bird prompts
- Check Bird availability and offer install if no X source available
- Override available sources when Bird is ready
- Pass x_source parameter to run_research function
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add bird_x import and setup_bird_if_needed function to main script.
The function checks Bird status and offers installation if needed,
returning 'bird' if ready, 'declined' if user declined, or None if
unavailable.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- is_bird_installed() checks if bird command is in PATH
- is_bird_authenticated() runs bird whoami to verify auth
- check_npm_available() checks if npm can install bird
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
12-task implementation plan for integrating Bird CLI as free X/Twitter
search alternative. Includes detection, interactive install, search
dispatch, and main flow integration.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>