Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e690d61a12 | |||
| 6d5acb9121 | |||
| 28d223e43c | |||
| 471badd329 | |||
| 5b1636f94f | |||
| 18f6273f7c | |||
| cc774d5e69 | |||
| 8cbbe87c3e |
@@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [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
|
## [2.9.1] - 2026-03-05
|
||||||
|
|
||||||
### Highlights
|
### Highlights
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
# /last30days v2.9
|
# /last30days v2.9.1
|
||||||
|
|
||||||
**The AI world reinvents itself every month. This skill keeps you current.** /last30days researches your topic across Reddit, X, YouTube, TikTok, Instagram, Hacker News, Polymarket, and the web from the last 30 days, finds what the community is actually upvoting, sharing, betting on, and saying on camera, and writes you a grounded narrative with real citations. Whether it's Seedance 2.0 access, paper.design prompts, or the latest Nano Banana Pro techniques, you'll know what people who are paying attention already know.
|
**The AI world reinvents itself every month. This skill keeps you current.** /last30days researches your topic across Reddit, X, YouTube, TikTok, Instagram, Hacker News, Polymarket, and the web from the last 30 days, finds what the community is actually upvoting, sharing, betting on, and saying on camera, and writes you a grounded narrative with real citations. Whether it's Seedance 2.0 access, paper.design prompts, or the latest Nano Banana Pro techniques, you'll know what people who are paying attention already know.
|
||||||
|
|
||||||
|
**New in v2.9.1 — Auto-save to ~/Documents/Last30Days/:** Every run now saves the complete briefing as a topic-named `.md` file to your Documents folder. Build a personal research library automatically. Inspired by [@devin_explores](https://x.com/devin_explores).
|
||||||
|
|
||||||
**New in v2.9 — ScrapeCreators Reddit + Top Comments + Smart Discovery:**
|
**New in v2.9 — ScrapeCreators Reddit + Top Comments + Smart Discovery:**
|
||||||
|
|
||||||
Reddit now runs on [ScrapeCreators](https://scrapecreators.com) by default — one `SCRAPECREATORS_API_KEY` covers Reddit, TikTok, and Instagram (3 sources, 1 key). Smart subreddit discovery finds the right communities automatically, and top comments are elevated with a 10% scoring weight and `💬` display with upvote counts. [Details below.](#whats-new-in-v29)
|
Reddit now runs on [ScrapeCreators](https://scrapecreators.com) by default — one `SCRAPECREATORS_API_KEY` covers Reddit, TikTok, and Instagram (3 sources, 1 key). Smart subreddit discovery finds the right communities automatically, and top comments are elevated with a 10% scoring weight and `💬` display with upvote counts. [Details below.](#whats-new-in-v29)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: last30days
|
name: last30days
|
||||||
version: "2.9.1"
|
version: "2.9.2"
|
||||||
description: "Research a topic from the last 30 days. Also triggered by 'last30'. Sources: Reddit, X, YouTube, TikTok, Instagram, Hacker News, Polymarket, web. Become an expert and write copy-paste-ready prompts."
|
description: "Research a topic from the last 30 days. Also triggered by 'last30'. Sources: Reddit, X, YouTube, TikTok, Instagram, Hacker News, Polymarket, web. Become an expert and write copy-paste-ready prompts."
|
||||||
argument-hint: 'last30 AI video tools, last30 best project management tools'
|
argument-hint: 'last30 AI video tools, last30 best project management tools'
|
||||||
allowed-tools: Bash, Read, Write, AskUserQuestion, WebSearch
|
allowed-tools: Bash, Read, Write, AskUserQuestion, WebSearch
|
||||||
@@ -30,7 +30,7 @@ metadata:
|
|||||||
- prompts
|
- prompts
|
||||||
---
|
---
|
||||||
|
|
||||||
# last30days v2.9.1: Research Any Topic from the Last 30 Days
|
# last30days v2.9.4: Research Any Topic from the Last 30 Days
|
||||||
|
|
||||||
Research ANY topic across Reddit, X, YouTube, TikTok, Hacker News, Polymarket, and the web. Surface what people are actually discussing, recommending, betting on, and debating right now.
|
Research ANY topic across Reddit, X, YouTube, TikTok, Hacker News, Polymarket, and the web. Surface what people are actually discussing, recommending, betting on, and debating right now.
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ If `--agent` appears in ARGUMENTS (e.g., `/last30days plaud granola --agent`):
|
|||||||
5. **Skip** the follow-up invitation ("I'm now an expert on X...")
|
5. **Skip** the follow-up invitation ("I'm now an expert on X...")
|
||||||
6. **Output** the complete research report and stop - do not wait for further input
|
6. **Output** the complete research report and stop - do not wait for further input
|
||||||
|
|
||||||
Agent mode still saves the research briefing to `~/Documents/Last30Days/` using the same logic as interactive mode (see "Save Research to Documents" section).
|
Agent mode saves raw research data to `~/Documents/Last30Days/` automatically via `--save-dir` (handled by the script, no extra tool calls).
|
||||||
|
|
||||||
Agent mode report format:
|
Agent mode report format:
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ if [ -z "${SKILL_ROOT:-}" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
python3 "${SKILL_ROOT}/scripts/last30days.py" "$ARGUMENTS" --emit=compact --no-native-web # Add --x-handle=HANDLE if RESOLVED_HANDLE is set
|
python3 "${SKILL_ROOT}/scripts/last30days.py" "$ARGUMENTS" --emit=compact --no-native-web --save-dir=~/Documents/Last30Days # Add --x-handle=HANDLE if RESOLVED_HANDLE is set
|
||||||
```
|
```
|
||||||
|
|
||||||
Use a **timeout of 300000** (5 minutes) on the Bash call. The script typically takes 1-3 minutes.
|
Use a **timeout of 300000** (5 minutes) on the Bash call. The script typically takes 1-3 minutes.
|
||||||
@@ -498,54 +498,9 @@ For `/last30days war in Iran` (NEWS):
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Save Research to Documents
|
|
||||||
|
|
||||||
After displaying the invitation, save the complete research briefing to the user's Documents folder. This happens automatically on every run.
|
|
||||||
|
|
||||||
1. **Create the directory** (if it doesn't exist):
|
|
||||||
```bash
|
|
||||||
mkdir -p ~/Documents/Last30Days
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Generate the filename** from TOPIC:
|
|
||||||
- Lowercase the topic
|
|
||||||
- Replace spaces and special characters with hyphens
|
|
||||||
- Remove consecutive hyphens
|
|
||||||
- Trim to 60 characters max
|
|
||||||
- Example: "Claude Code Best Practices" -> `claude-code-best-practices`
|
|
||||||
|
|
||||||
3. **Check for duplicates**: If `~/Documents/Last30Days/{slug}.md` already exists, append today's date: `{slug}-YYYY-MM-DD.md`
|
|
||||||
|
|
||||||
4. **Use the Write tool** to save to `~/Documents/Last30Days/{slug}.md` with this exact structure:
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
# {TOPIC}
|
|
||||||
|
|
||||||
> Researched {date} | Query type: {QUERY_TYPE} | Target tool: {TARGET_TOOL or "general"}
|
|
||||||
|
|
||||||
## What I learned
|
|
||||||
|
|
||||||
{The full synthesis section you just displayed - all topics, patterns, and citations}
|
|
||||||
|
|
||||||
## Stats
|
|
||||||
|
|
||||||
{The full stats box with source counts and engagement - copy exactly as displayed}
|
|
||||||
|
|
||||||
## Follow-up suggestions
|
|
||||||
|
|
||||||
{The 2-3 specific suggestions from the invitation block}
|
|
||||||
|
|
||||||
---
|
|
||||||
*Generated by [last30days](https://github.com/mvanhorn/last30days-skill) v2.9.1*
|
|
||||||
```
|
|
||||||
|
|
||||||
5. **Confirm briefly** after saving: `Saved to ~/Documents/Last30Days/{slug}.md`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## WAIT FOR USER'S RESPONSE
|
## WAIT FOR USER'S RESPONSE
|
||||||
|
|
||||||
After showing the stats summary with your invitation, **STOP and wait** for the user to respond.
|
**STOP and wait** for the user to respond. Do NOT call any tools after displaying the invitation. The research script already saved raw data to `~/Documents/Last30Days/` via `--save-dir`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
---
|
||||||
|
title: "fix: Eliminate save-related output noise after research"
|
||||||
|
type: fix
|
||||||
|
status: active
|
||||||
|
date: 2026-03-06
|
||||||
|
---
|
||||||
|
|
||||||
|
# fix: Eliminate save-related output noise after research
|
||||||
|
|
||||||
|
## Problem Statement
|
||||||
|
|
||||||
|
After research completes, the auto-save feature adds 3-5 lines of unwanted output below the clean invitation block. Every approach tried so far has made things worse:
|
||||||
|
|
||||||
|
| Version | Approach | Lines added | Side effects |
|
||||||
|
|---------|----------|-------------|--------------|
|
||||||
|
| v2.9.1 | `Write` tool | ~5 | Shows "Wrote 43 lines to..." |
|
||||||
|
| v2.9.2 | `run_in_background: true` | ~5 | Background callback triggers 2-4 min cogitation, model hallucinates fake "Human:" messages and generates unsolicited multi-paragraph responses |
|
||||||
|
| v2.9.3 | Foreground `cat >` heredoc | ~3 | Shows `(No output)`, still triggers 2-4 min cogitation |
|
||||||
|
|
||||||
|
**Current v2.9.3 noise (3 lines):**
|
||||||
|
```
|
||||||
|
⏺ Bash(mkdir -p ~/Documents/Last30Days && cat > ...)
|
||||||
|
⎿ (No output)
|
||||||
|
✻ Churned for 2m 38s
|
||||||
|
```
|
||||||
|
|
||||||
|
The root cause is that ANY tool call after the invitation creates unavoidable Claude Code UI chrome, and the model cogitates for minutes regardless of foreground vs background.
|
||||||
|
|
||||||
|
## Proposed Solutions
|
||||||
|
|
||||||
|
### Option A: Remove auto-save entirely (Recommended)
|
||||||
|
|
||||||
|
Remove the entire "Save Research to Documents" section from SKILL.md. The research lives in the conversation. Zero extra tool calls, zero extra lines, zero cogitation.
|
||||||
|
|
||||||
|
**Changes to `SKILL.md`:**
|
||||||
|
- Delete the "Save Research to Documents" section (~45 lines)
|
||||||
|
- Update agent mode reference (line 126) - remove save mention
|
||||||
|
- Update security section (line 612) - change "Saves research briefings" to past tense or conditional
|
||||||
|
- Remove `📎` footer line from invitation format
|
||||||
|
- Simplify "WAIT FOR USER'S RESPONSE" section
|
||||||
|
|
||||||
|
**What users lose:** Auto-saved .md files in `~/Documents/Last30Days/`
|
||||||
|
**What users gain:** Clean output ending exactly at the invitation block
|
||||||
|
|
||||||
|
### Option B: Move save into Python script
|
||||||
|
|
||||||
|
Add `--save-dir` flag to `last30days.py`. The script saves its raw output during its existing Bash call (which already runs). Zero extra tool calls.
|
||||||
|
|
||||||
|
**Changes:**
|
||||||
|
- `scripts/last30days.py` - add `--save-dir` argument, write raw output to file at end of execution
|
||||||
|
- `SKILL.md` - add `--save-dir=~/Documents/Last30Days` to the script invocation, remove save section
|
||||||
|
|
||||||
|
**What users lose:** Saved file contains raw research data, not Claude's synthesis
|
||||||
|
**What users gain:** Zero extra lines, data is still preserved
|
||||||
|
|
||||||
|
### Option C: Opt-in save via follow-up command
|
||||||
|
|
||||||
|
Remove auto-save. Add a note to the invitation: "Say 'save' to save this research." When user says "save", run the Bash heredoc then.
|
||||||
|
|
||||||
|
**Changes to `SKILL.md`:**
|
||||||
|
- Delete auto-save section
|
||||||
|
- Add "save" as a recognized intent in "WHEN USER RESPONDS" section
|
||||||
|
- Save logic only runs when explicitly requested
|
||||||
|
|
||||||
|
**What users lose:** Nothing - save is still available on demand
|
||||||
|
**What users gain:** Clean output by default, save when they want it
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
- [ ] Research output ends at the invitation block with zero tool calls after it
|
||||||
|
- [ ] No `(No output)` line visible after invitation
|
||||||
|
- [ ] No multi-minute cogitation after invitation
|
||||||
|
- [ ] No hallucinated fake user messages
|
||||||
|
- [ ] Version bumped to v2.9.4
|
||||||
|
- [ ] CHANGELOG updated
|
||||||
|
- [ ] Synced to ~/.claude, ~/.agents, ~/.codex via sync.sh
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
- Source: `/Users/mvanhorn/last30days-skill-private/SKILL.md`
|
||||||
|
- Deployed to: `~/.claude/skills/last30days/SKILL.md`
|
||||||
|
- Sync command: `bash scripts/sync.sh`
|
||||||
|
- Current version: v2.9.3
|
||||||
@@ -1250,6 +1250,13 @@ def main():
|
|||||||
default=False,
|
default=False,
|
||||||
help="Skip native web search backends (Parallel/Brave/OpenRouter). Use when the assistant has its own WebSearch tool.",
|
help="Skip native web search backends (Parallel/Brave/OpenRouter). Use when the assistant has its own WebSearch tool.",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--save-dir",
|
||||||
|
type=str,
|
||||||
|
default=None,
|
||||||
|
metavar="DIR",
|
||||||
|
help="Auto-save raw research output to DIR/{topic-slug}.md",
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
args.topic = " ".join(args.topic) if args.topic else None
|
args.topic = " ".join(args.topic) if args.topic else None
|
||||||
@@ -1604,6 +1611,20 @@ def main():
|
|||||||
# Output result
|
# Output result
|
||||||
output_result(report, args.emit, web_needed, args.topic, from_date, to_date, missing_keys, args.days, source_info)
|
output_result(report, args.emit, web_needed, args.topic, from_date, to_date, missing_keys, args.days, source_info)
|
||||||
|
|
||||||
|
# Auto-save raw research to file if --save-dir is set
|
||||||
|
if args.save_dir:
|
||||||
|
import re
|
||||||
|
save_dir = Path(args.save_dir).expanduser()
|
||||||
|
save_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
slug = re.sub(r'[^a-z0-9]+', '-', args.topic.lower()).strip('-')[:60]
|
||||||
|
save_path = save_dir / f"{slug}-raw.md"
|
||||||
|
if save_path.exists():
|
||||||
|
save_path = save_dir / f"{slug}-raw-{datetime.now().strftime('%Y-%m-%d')}.md"
|
||||||
|
content = render.render_compact(report, missing_keys=missing_keys)
|
||||||
|
content += "\n" + render.render_source_status(report, source_info)
|
||||||
|
save_path.write_text(content, encoding="utf-8")
|
||||||
|
print(f"📎 {save_path}", file=sys.stderr)
|
||||||
|
|
||||||
# Persist findings to SQLite if requested
|
# Persist findings to SQLite if requested
|
||||||
if args.store:
|
if args.store:
|
||||||
import store as store_mod
|
import store as store_mod
|
||||||
|
|||||||
Reference in New Issue
Block a user