Six small additive changes that make the skill correctly understand its
configured sources, plus tests + docs.
User-visible benefits
- LAST30DAYS_STORE=1 in .env turns persistence default-on without
remembering --store on every invocation. Mirrors LAST30DAYS_DEBUG /
LAST30DAYS_SKIP_PREFLIGHT convention.
- SCRAPE_CREATORS_API_KEY (with underscore) accepted as alias for the
canonical name. Matches the spelling used in the vendor's own example
code (Adrian Horning's repo); saves the next user the same diagnostic
rabbit hole.
- Bluesky search now hits api.bsky.app (canonical AppView) instead of
public.api.bsky.app (BunnyCDN-blocked public mirror as of 2026-05-04).
BSKY_SEARCH_HOST env var lets users self-rescue future host migrations
without a code release. Pre-fix: silent 0 Bluesky posts on every run.
- App-password format validator emits a one-shot stderr warning when
BSKY_APP_PASSWORD doesn't match xxxx-xxxx-xxxx-xxxx form. Detect-don't-
gate: createSession still accepts main passwords; the warning helps
users identify a hygiene issue without breaking existing setups.
- Instagram retry on multi-token 500. SC's v2 reels endpoint wraps
Google Search and 500's frequently on multi-word queries; a hashtag-
form retry runs once before bubbling up. Documented vendor instability.
- LAST30DAYS_TRANSCRIPT_TIMEOUT env var (default 30s, was hardcoded 15s).
SC's transcript endpoint regularly takes >15s; the old default was
clipping legitimate responses.
- Silent-failure visibility: new bonus_errored field in the quality
nudge fires when SC is configured but Instagram returned 0 items.
Users see "Bonus source silent: Instagram" instead of unexplained
absence.
- YouTube degraded-ratio false-positive fixed. Captions-disabled videos
can never produce a transcript regardless of yt-dlp version; they're
now subtracted from the denominator so a single uploader-disabled
video doesn't false-trigger the "stale yt-dlp" nudge.
- urllib retry path: status_code attribute typo fix. The Instagram
500-retry was dead code on the urllib branch (getattr(e, 'status', ...)
while http.HTTPError exposes status_code).
Docs
- README.md: added /plugin install last30days step after marketplace add
in three places (the install was previously omitted in the docs).
- CONFIGURATION.md: documented LAST30DAYS_STORE env var, added
BSKY_SEARCH_HOST + app-password format section, mentioned
LAST30DAYS_TRANSCRIPT_TIMEOUT in the Instagram source row.
Test plan
- 43 new unit tests across test_bluesky.py, test_instagram_sc.py,
test_quality_nudge.py, test_youtube_yt.py
- 141 total tests passing in target suite
- Verified end-to-end: /last30days "Toronto resale condo market" with
all 11+ sources active stored 35 new + 5 updated findings, all builder-
PR-style accounts absent (organic agent voice in Instagram + TikTok
results)
Backward compatibility
All changes are strictly additive. Optional kwargs default to None.
New env vars are opt-in. Existing CLI flags untouched. Existing callers
of public functions unaffected.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When Cloudflare blocks requests to bsky.social or public.api.bsky.app
with a 403, the error was swallowed by a generic except clause and
reported as "Bluesky auth failed" - misleading users into thinking
their credentials were wrong.
Now _create_session() preserves the specific error in _session_error,
and search_bluesky() surfaces it. Cloudflare 403s get a clear message
about network-level blocks. Actual 401s say "Invalid credentials".
Closes#69
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
searchPosts endpoint now returns 403 for unauthenticated requests.
Add session auth via createSession, gate on BSKY_HANDLE + BSKY_APP_PASSWORD
env vars. When unconfigured, Bluesky is completely invisible (no error).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Free, no-auth-required search via public.api.bsky.app.
Always-on like HN and Polymarket (no API key needed).
- New scripts/lib/bluesky.py: search + parse via AT Protocol
- BlueskyItem schema, normalization, scoring, deduplication
- Wired into orchestrator ThreadPoolExecutor with timeout config
- Rendering in compact, full, and JSON output modes
- 14 unit tests covering parsing, dates, relevance, edge cases
- --search=bluesky / --search=bsky for bluesky-only mode
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>