From 63de326df04aaf3f1e726ea11ed5113368dfd234 Mon Sep 17 00:00:00 2001 From: Matt Van Horn Date: Fri, 6 Feb 2026 09:38:32 -0800 Subject: [PATCH] Fix skill not executing: remove agent:Explore, front-load run command 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 --- SKILL.md | 95 +---- ...6-feat-last30days-bird-cli-release-plan.md | 391 ++++++++++++++++++ 2 files changed, 401 insertions(+), 85 deletions(-) create mode 100644 docs/plans/2026-02-06-feat-last30days-bird-cli-release-plan.md diff --git a/SKILL.md b/SKILL.md index 3b55d6f..af9aa33 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,31 +1,22 @@ --- name: last30days -description: Research a topic from the last 30 days on Reddit + X + Web with Bird CLI support. +description: last30days: Research Any Topic from the Last 30 Days (user) argument-hint: '"[topic] for [tool]" or "[topic]"' context: fork -agent: Explore -disable-model-invocation: true allowed-tools: Bash, Read, Write, AskUserQuestion, WebSearch --- -# last30days: Research the Last 30 Days +# STEP 1: RUN THE RESEARCH SCRIPT IMMEDIATELY -Research ANY topic across Reddit, X, and the web. Surface what people are actually discussing, recommending, and debating right now. +Do NOT describe this skill. Do NOT summarize workflows. Do NOT explain what you will do. EXECUTE. -**Features:** -- Bird CLI support for free X/Twitter search (no API key needed) -- Auto-detects Bird if installed (no prompts) -- Falls back to xAI API or WebSearch if Bird not available +The user's arguments are in $ARGUMENTS. Run this command NOW: -Use cases: -- **Prompting**: "photorealistic people in Nano Banana Pro", "Midjourney prompts", "ChatGPT image generation" → learn techniques, get copy-paste prompts -- **Recommendations**: "best Claude Code skills", "top AI tools" → get a LIST of specific things people mention -- **News**: "what's happening with OpenAI", "latest AI announcements" → current events and updates -- **General**: any topic you're curious about → understand what the community is saying +```bash +python3 ~/.claude/skills/last30days/scripts/last30days.py "$ARGUMENTS" --emit=compact 2>&1 +``` -## CRITICAL: Parse User Intent - -Before doing anything, parse the user's input for: +While that runs, parse the user's input for: 1. **TOPIC**: What they want to learn about (e.g., "web app mockups", "Claude Code skills", "image generation") 2. **TARGET TOOL** (if specified): Where they'll use the prompts (e.g., "Nano Banana Pro", "ChatGPT", "Midjourney") @@ -53,75 +44,9 @@ Common patterns: --- -## Setup Check +## STEP 2: DO WEBSEARCH WHILE SCRIPT RUNS -The skill works in multiple modes based on available sources: - -1. **Bird Mode** (free): X via Bird CLI + Reddit via OpenAI + WebSearch -2. **Full Mode** (both API keys): Reddit + X via xAI + WebSearch -3. **Partial Mode** (one key): Reddit-only or X-only + WebSearch -4. **Web-Only Mode** (no keys): WebSearch only - -**Bird CLI is the preferred X source** - free, uses your browser session. - -### First-Time Setup - -**Option 1: Install Bird CLI (Recommended - Free X search)** - -```bash -npm install -g @steipete/bird -``` - -Then log into X (twitter.com) in your browser. Bird uses your browser session. -The script auto-detects Bird if installed. - -**Option 2: API Keys (Optional)** - -If you want API-based access: -```bash -mkdir -p ~/.config/last30days -cat > ~/.config/last30days/.env << 'ENVEOF' -# last30days API Configuration -# All keys are optional - Bird CLI or WebSearch fallback available - -# For Reddit research (uses OpenAI's web_search tool) -OPENAI_API_KEY= - -# For X/Twitter research (uses xAI's x_search tool - fallback if no Bird) -XAI_API_KEY= -ENVEOF - -chmod 600 ~/.config/last30days/.env -``` - -**DO NOT stop if no keys are configured.** Proceed with available sources. - ---- - -## Research Execution - -**IMPORTANT: The script handles source detection automatically.** Run it and check the output. - -**Step 1: Run the research script** -```bash -python3 ~/.claude/skills/last30days/scripts/last30days.py "$ARGUMENTS" --emit=compact 2>&1 -``` - -The script will automatically: -- Check for Bird CLI (free X search) -- Offer to install Bird if not found and npm available -- Detect API keys -- Run Reddit/X searches with best available source -- Signal if WebSearch is needed - -**Step 2: Check the output mode** - -The script output will indicate the mode: -- **"Mode: both"** - Has both Reddit and X sources -- **"Mode: reddit-only"** or **"Mode: x-only"** - Has one source -- **"Mode: web-only"** - No API keys or Bird, Claude must do ALL research via WebSearch - -**Step 3: Do WebSearch** +The script auto-detects sources (Bird CLI, API keys, etc). While waiting for it, do WebSearch. For **ALL modes**, do WebSearch to supplement (or provide all data in web-only mode). diff --git a/docs/plans/2026-02-06-feat-last30days-bird-cli-release-plan.md b/docs/plans/2026-02-06-feat-last30days-bird-cli-release-plan.md new file mode 100644 index 0000000..4eae631 --- /dev/null +++ b/docs/plans/2026-02-06-feat-last30days-bird-cli-release-plan.md @@ -0,0 +1,391 @@ +--- +title: "feat: Release last30days v2 with Bird CLI to GitHub" +type: feat +date: 2026-02-06 +--- + +# Release last30days v2 (Bird CLI) to GitHub + +## Overview + +Replace the current public `last30days-skill` on GitHub with the new Bird CLI-enhanced version from `last30days-skill-private`. The new version adds free X/Twitter search via Bird CLI while maintaining backward compatibility with xAI API keys. + +**Goal:** Ship with confidence. No rollbacks. + +## Current State + +| | Old (Public) | New (Private) | +|---|---|---| +| **Repo** | `mvanhorn/last30days-skill` | `mvanhorn/last30days-skill-private` | +| **Local path** | `~/.claude/skills/last30days/` | `~/.claude/skills/last30daystest/` (symlink) | +| **Remote** | `origin` → public repo | `origin` → private, `upstream` → public | +| **Key addition** | -- | Bird CLI (`@steipete/bird`) for free X search | +| **X source chain** | xAI API only | Bird (free) → xAI (paid) → WebSearch | +| **Uses** | 136 | 18 | +| **Latest commit** | `cc892d7` | `4230fa2` | + +**Why both show as `/last30days`:** Both `SKILL.md` files declare `name: last30days` in frontmatter. Claude Code discovers both from `~/.claude/skills/` and lists them separately. + +--- + +## Phase 0: Clean Swap (Day 1) + +Remove the old skill so only the new one is active. This eliminates ambiguity during testing. + +### Steps + +1. **Back up the old skill** (safety net): + ```bash + mv ~/.claude/skills/last30days ~/.claude/skills/last30days.backup-v1 + ``` + +2. **Promote the new skill to primary**: + ```bash + # Remove the test symlink + rm ~/.claude/skills/last30daystest + + # Create new symlink with the primary name + ln -s /Users/mvanhorn/last30days-skill-private ~/.claude/skills/last30days + ``` + +3. **Verify only one `/last30days` appears**: + - Open a new Claude Code session + - Type `/last` and confirm only ONE `/last30days` shows in autocomplete + - Confirm description mentions Bird CLI + +4. **Rollback procedure** (if something goes wrong): + ```bash + rm ~/.claude/skills/last30days + mv ~/.claude/skills/last30days.backup-v1 ~/.claude/skills/last30days + ``` + +### Acceptance Criteria +- [ ] Only one `/last30days` appears in Claude Code autocomplete +- [ ] Old skill preserved at `~/.claude/skills/last30days.backup-v1` +- [ ] New skill responds to `/last30days` invocation + +--- + +## Phase 1: Claude's Test Plan (Automated) + +These are tests Claude can run autonomously to validate the new skill before the user touches it. + +### 1.1 Script-Level Smoke Tests + +Run the Python scripts directly to verify core functionality without invoking the full skill. + +#### Bird CLI Detection +```bash +# Test: Bird is installed and authenticated +python3 -c " +import sys; sys.path.insert(0, '/Users/mvanhorn/last30days-skill-private/scripts/lib') +import bird_x +print('installed:', bird_x.is_bird_installed()) +print('authenticated:', bird_x.is_bird_authenticated()) +print('status:', bird_x.get_bird_status()) +" +``` +- [ ] `is_bird_installed()` returns True (or False with clear message) +- [ ] `is_bird_authenticated()` returns True if logged into X in browser +- [ ] `get_bird_status()` returns a dict with `installed`, `authenticated`, `available` keys + +#### Environment & Source Detection +```bash +python3 -c " +import sys; sys.path.insert(0, '/Users/mvanhorn/last30days-skill-private/scripts/lib') +import env +config = env.load_config() +print('x_source:', env.get_x_source(config)) +print('has_openai:', bool(config.get('OPENAI_API_KEY'))) +" +``` +- [ ] `get_x_source()` returns `'bird'` if Bird available, `'xai'` if API key set, `None` otherwise +- [ ] Config loads from `~/.config/last30days/.env` + +#### Bird Search (Direct) +```bash +python3 -c " +import sys, json; sys.path.insert(0, '/Users/mvanhorn/last30days-skill-private/scripts/lib') +import bird_x +result = bird_x.search_x('Claude Code tips', '2026-01-07', '2026-02-06', 'quick') +print(json.dumps(result, indent=2, default=str)[:2000]) +" +``` +- [ ] Returns search results (list of dicts with `url`, `text`, `author_handle`) +- [ ] No Python tracebacks +- [ ] Results are from the expected date range + +#### Full Research Pipeline (Compact Output) +```bash +cd /Users/mvanhorn/last30days-skill-private +python3 scripts/last30days.py "Claude Code tips" --emit=compact --quick 2>&1 | head -100 +``` +- [ ] Completes without error +- [ ] Output includes X results (via Bird or xAI) +- [ ] Output includes Reddit results (via OpenAI) if key configured +- [ ] Stats summary shows source counts + +### 1.2 Source Fallback Tests + +Verify graceful degradation when sources are unavailable. + +#### Bird unavailable, xAI available +```bash +# Temporarily hide Bird +PATH_BACKUP="$PATH" +export PATH=$(echo "$PATH" | tr ':' '\n' | grep -v "$(dirname $(which bird 2>/dev/null))" | tr '\n' ':') + +python3 -c " +import sys; sys.path.insert(0, '/Users/mvanhorn/last30days-skill-private/scripts/lib') +import env +config = env.load_config() +print('x_source (no bird):', env.get_x_source(config)) +" + +export PATH="$PATH_BACKUP" +``` +- [ ] Falls back to `'xai'` when Bird not in PATH +- [ ] No crash or unhandled exception + +#### No X source at all +```bash +python3 -c " +import sys; sys.path.insert(0, '/Users/mvanhorn/last30days-skill-private/scripts/lib') +import env +config = {} # empty config, no keys +print('x_source (nothing):', env.get_x_source(config)) +" +``` +- [ ] Returns `None` +- [ ] No crash + +### 1.3 Response Parsing Tests + +Validate that Bird responses are correctly normalized to the canonical schema. + +```bash +python3 -c " +import sys; sys.path.insert(0, '/Users/mvanhorn/last30days-skill-private/scripts/lib') +import bird_x + +# Test with sample Bird response format +sample = { + 'tweets': [{ + 'permanentUrl': 'https://x.com/user/status/123', + 'text': 'Test tweet about Claude Code', + 'username': 'testuser', + 'likeCount': 42, + 'retweetCount': 10, + 'replyCount': 5, + 'timeParsed': '2026-02-01T12:00:00.000Z' + }] +} +parsed = bird_x.parse_bird_response(sample) +print('Parsed count:', len(parsed)) +print('First item keys:', sorted(parsed[0].keys()) if parsed else 'EMPTY') +print('URL:', parsed[0].get('url')) +print('Author:', parsed[0].get('author_handle')) +" +``` +- [ ] Parses correctly with expected keys +- [ ] Handles both camelCase and snake_case fields +- [ ] URL, text, author, engagement metrics all present + +### 1.4 SKILL.md Validation + +```bash +# Verify YAML frontmatter parses correctly +python3 -c " +import yaml +with open('/Users/mvanhorn/last30days-skill-private/SKILL.md') as f: + content = f.read() + # Extract YAML between --- markers + parts = content.split('---', 2) + meta = yaml.safe_load(parts[1]) + print('name:', meta.get('name')) + print('context:', meta.get('context')) + print('agent:', meta.get('agent')) + print('allowed-tools:', meta.get('allowed-tools')) +" +``` +- [ ] `name` is `last30days` (not `last30daystest`) +- [ ] `context` is `fork` +- [ ] `agent` is `Explore` +- [ ] `allowed-tools` includes `Bash`, `WebSearch` + +### 1.5 Diff Audit (Old vs New) + +```bash +# Verify the only meaningful addition is bird_x.py +diff -rq ~/.claude/skills/last30days.backup-v1/scripts/lib/ \ + /Users/mvanhorn/last30days-skill-private/scripts/lib/ 2>/dev/null +``` +- [ ] Only new file is `bird_x.py` +- [ ] Modified files: `env.py` (source detection), `__init__.py` (exports) +- [ ] No unexpected deletions or renames + +--- + +## Phase 2: User's Test Plan (Manual) + +These require human judgment - evaluating quality, UX, and real-world behavior. + +### 2.1 Basic Invocation (5 min) + +Open a fresh Claude Code session after Phase 0 is complete. + +| # | Test | Command | Pass Criteria | +|---|------|---------|---------------| +| 1 | Simple topic | `/last30days AI music generation` | Returns results, shows source stats | +| 2 | Topic + tool | `/last30days Suno prompts for music production` | Returns results + generates a prompt | +| 3 | Quick mode | `/last30days --quick TypeScript tips` | Faster, fewer results, still valid | +| 4 | Empty input | `/last30days` | Prompts for topic (doesn't crash) | + +### 2.2 Bird CLI Verification (5 min) + +| # | Test | What to Check | +|---|------|---------------| +| 1 | Source indicator | Output shows Bird as X source (not xAI) | +| 2 | X results quality | X/Twitter results are real, recent, have engagement metrics | +| 3 | Bird promo | If Bird NOT installed, shows non-blocking info banner | +| 4 | Mixed sources | Both Reddit (OpenAI) and X (Bird) results appear | + +### 2.3 Fallback Behavior (5 min) + +| # | Test | Setup | Expected | +|---|------|-------|----------| +| 1 | No Bird | `npm uninstall -g @steipete/bird` temporarily | Falls back to xAI or WebSearch | +| 2 | No API keys | Rename `~/.config/last30days/.env` temporarily | WebSearch-only mode works | +| 3 | Restore | Reinstall bird + restore .env | Full mode returns | + +### 2.4 Output Quality (10 min) + +Run 3 real research queries you care about. For each, evaluate: + +- [ ] Results are actually from the last 30 days (not stale) +- [ ] Engagement metrics (likes, upvotes) are present and reasonable +- [ ] No duplicate results +- [ ] Sources are properly cited with URLs +- [ ] Synthesis is grounded in actual results (not hallucinated) +- [ ] Generated prompts (if requested) are usable + +### 2.5 Comparison Test (10 min) + +Before removing the backup, run the SAME query on both versions: + +```bash +# New version (active) +/last30days [your topic] + +# Old version (temporarily restore) +rm ~/.claude/skills/last30days +mv ~/.claude/skills/last30days.backup-v1 ~/.claude/skills/last30days +# New Claude Code session +/last30days [same topic] +# Then swap back +``` + +- [ ] New version produces equal or better results +- [ ] No features regressed +- [ ] Bird results add value over xAI-only + +--- + +## Phase 3: Release Plan (30-Day Timeline) + +**Target release date:** March 1, 2026 (conservative buffer before March 8 deadline) + +### Week 1: Feb 6-12 - Clean & Test + +| Day | Task | Owner | +|-----|------|-------| +| Feb 6 | Phase 0: Clean swap (remove old, activate new) | User | +| Feb 6 | Phase 1: Claude runs automated tests | Claude | +| Feb 7-8 | Phase 2: User runs manual tests (2.1-2.4) | User | +| Feb 9 | Phase 2.5: Comparison test | User | +| Feb 10-12 | Fix any issues found during testing | Claude + User | + +### Week 2: Feb 13-19 - Harden + +| Day | Task | Owner | +|-----|------|-------| +| Feb 13 | Run edge cases: unicode topics, very long topics, special chars | Claude | +| Feb 14 | Test with Bird logged out (auth expiry scenario) | User | +| Feb 15 | Review all error messages for clarity | Claude | +| Feb 16-17 | Update README.md with Bird CLI setup instructions | Claude | +| Feb 18-19 | Buffer for fixes | Claude + User | + +### Week 3: Feb 20-26 - Pre-Release + +| Day | Task | Owner | +|-----|------|-------| +| Feb 20 | Final diff audit: private repo vs public repo | Claude | +| Feb 21 | Strip any private/test artifacts (test symlinks, debug prints) | Claude | +| Feb 22 | Update SKILL.md description if needed | Claude | +| Feb 23 | Dry-run: push to a branch on public repo (not main) | User | +| Feb 24 | Test installation from the branch (fresh `~/.claude/skills/`) | User | +| Feb 25-26 | Buffer for fixes | Claude + User | + +### Week 4: Feb 27 - Mar 1 - Ship + +| Day | Task | Owner | +|-----|------|-------| +| Feb 27 | Merge branch to main on public repo | User | +| Feb 28 | Create GitHub release with changelog | Claude + User | +| Mar 1 | Delete backup: `rm -rf ~/.claude/skills/last30days.backup-v1` | User | +| Mar 1 | Archive private repo (optional) | User | + +### Release Checklist (Final Gate) + +Before merging to `main` on the public repo: + +- [ ] All Phase 1 automated tests pass +- [ ] All Phase 2 manual tests pass +- [ ] Comparison test shows new >= old quality +- [ ] SKILL.md frontmatter is correct (`name: last30days`, not `last30daystest`) +- [ ] README.md documents Bird CLI setup +- [ ] No debug/test artifacts in codebase +- [ ] No hardcoded paths (e.g., `/Users/mvanhorn/...`) +- [ ] `.env` files are gitignored +- [ ] Git history is clean (no "test" or "WIP" commits on main) +- [ ] Bird CLI failure doesn't break the skill (graceful fallback verified) + +### Rollback Plan (Emergency) + +If something goes wrong after release: + +```bash +# Option 1: Revert to backup (if still exists) +rm ~/.claude/skills/last30days +mv ~/.claude/skills/last30days.backup-v1 ~/.claude/skills/last30days + +# Option 2: Git revert on public repo +cd ~/.claude/skills/last30days +git log --oneline -5 # find the last good commit +git revert HEAD # revert the merge commit +git push origin main + +# Option 3: Pin to old version +cd ~/.claude/skills/last30days +git checkout cc892d7 # last known good commit from old version +``` + +--- + +## Risk Analysis + +| Risk | Likelihood | Impact | Mitigation | +|------|-----------|--------|------------| +| Bird CLI breaks after X API changes | Medium | Low | Fallback to xAI/WebSearch still works | +| Bird auth expires silently | Medium | Low | `is_bird_authenticated()` check + user message | +| Old xAI workflows regress | Low | High | Comparison test in Phase 2.5 | +| Hardcoded paths in codebase | Low | Medium | Grep for `/Users/mvanhorn` before release | +| SKILL.md name still says `last30daystest` | Low | High | Already fixed in commit `4e972d0` | + +## References + +- Private repo: `https://github.com/mvanhorn/last30days-skill-private.git` +- Public repo: `https://github.com/mvanhorn/last30days-skill.git` +- Bird CLI: `https://github.com/steipete/bird` +- Bird implementation plan: `docs/plans/2026-02-03-bird-cli-implementation.md` +- Bird integration design: `docs/plans/2026-02-03-bird-cli-integration-design.md`