Openclaw-tools daily-digest
Daily digest pipeline — LinkedIn + Reddit keyword hunt, Reddit pulse, sports scores, LLM synthesis, and email/WhatsApp/Telegram delivery
install
source · Clone the upstream repo
git clone https://github.com/syphax/openclaw-tools
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/syphax/openclaw-tools "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/daily-digest" ~/.claude/skills/syphax-openclaw-tools-daily-digest && rm -rf "$T"
OpenClaw · Install into ~/.openclaw/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/syphax/openclaw-tools "$T" && mkdir -p ~/.openclaw/skills && cp -r "$T/skills/daily-digest" ~/.openclaw/skills/syphax-openclaw-tools-daily-digest && rm -rf "$T"
manifest:
skills/daily-digest/SKILL.mdsource content
Daily Digest Skill
Hunts for new social media posts across LinkedIn and Reddit based on configurable keywords, gathers Reddit pulse and sports scores, then synthesizes everything via LLM and delivers a digest via email, WhatsApp, and Telegram.
Pipeline
The full daily pipeline runs via
run-daily-digest.sh and executes in order:
- Keyword Hunt (
) — LinkedIn + Reddit keyword searchsocial-searcher.ts - Reddit Pulse (
) — Subreddit top/trending postsreddit-pulse.ts - Sports Pulse (
) — ESPN scoreboard for tracked teamssports-pulse.ts - Rex Engine (
) — LLM synthesis + email/WhatsApp/Telegram deliveryrex-engine.ts
Usage
# Full pipeline ./run-daily-digest.sh # Individual steps ./run-hunt.sh # Keyword hunt only (uses last check date) ./run-hunt.sh --days 7 # Override: search last 7 days ./run-pulse.sh # Reddit pulse only
Configuration
Keywords & subreddits:
cfg/social-search-config.json
{ "linkedin": { "keywords": ["agrivoltaics", "#agrivoltaics", "solar warehouse", "solar"], "last_successful_search": "2026-03-17T..." }, "reddit": { "monitors": [ { "sub": "agrivoltaics", "keywords": ["agrivoltaics"] } ], "last_successful_search": "2026-03-17T..." } }
Delivery targets:
cfg/addresses.json — email, phone, and Telegram chat IDs.
Sports teams:
cfg/sports-config.json — teams with ESPN sport/ID + extra leagues.
Output
Daily JSON files in
~/.openclaw/data/social-searcher/:
| File | Contents |
|---|---|
| LinkedIn + Reddit keyword hunt |
| Reddit pulse |
| Raw ESPN data |
| Merged data for Rex Engine |
| Delivery results per channel |
Implementation Details
LinkedIn Search
- Technology: Playwright with Chrome (non-headless, persistent profile)
- Browser profile:
~/.openclaw/browser-profiles/social-searcher - Container selector:
— LinkedIn uses obfuscated CSS classes that rotate on deploys, so we target ARIA roles which are stable (accessibility contract)div[role="listitem"] - Author extraction: Profile links (
,a[href*="/in/"]
) with timestamp/degree stripping;a[href*="/company/"]
fallbackspan[aria-hidden="true"] - Content extraction:
for post body text, with UI chrome cleanupspan[dir="ltr"] - URL extraction: Activity URN links →
links → profile link fallback/posts/ - Deduplication: URL-based dedup across keywords within a run
- Diagnostics: If extraction returns 0 posts but profile links exist on the page, logs a warning with count details and saves a debug screenshot — prevents silent failures when LinkedIn changes DOM structure
Reddit Search
- Technology: Direct HTTPS to Reddit JSON API (no auth required)
- Filtering:
, filtered bysort=new&t=week
since last runcreated_utc - Rate limiting: 500ms between requests
Rex Engine (LLM Synthesis)
- LLM: OpenRouter API (
)google/gemini-2.0-flash-001 - Delivery: Email (via
), WhatsApp and Telegram (viagog
)openclaw message - Credentials:
—~/.openclaw/credentials/.env
,OPENROUTER_API_KEYGOG_KEYRING_PASSWORD
Sports Pipeline
- Source: ESPN scoreboard API
- Sections: RESULTS (past 3 days), UPCOMING (today through today+2), QUIET STADIUM
- Config:
with team ESPN IDs + extra leaguescfg/sports-config.json
Logs
| Log | Purpose |
|---|---|
| Master pipeline log |
| Keyword hunt log |
| Reddit pulse log |
| Delivery status |
Troubleshooting
LinkedIn returns 0 posts
LinkedIn deliberately rotates CSS class names and DOM structure as an anti-scraping measure. If extraction breaks:
- Check logs for the diagnostic warning — it reports profile link counts and listitem div counts
- Look at the debug screenshot saved to
logs/debug-linkedin-*.png - The current extractor uses
— if that stops working, trace backwards from profile links (div[role="listitem"]
) to find their new container elementa[href*="/in/"] - The Voyager API route is currently not viable — search results are server-side rendered (React Server Components), and the
Python library's queryId hash is stalelinkedin-api
Browser profile locked
If you see "Failed to create ProcessSingleton":
# Kill orphaned Chrome processes ps aux | grep 'social-searcher' | grep -v grep | awk '{print $2}' | xargs kill rm ~/.openclaw/browser-profiles/social-searcher/SingletonLock
LinkedIn session expired
Delete the browser profile and re-authenticate:
rm -rf ~/.openclaw/browser-profiles/social-searcher # Run script manually, log in when browser opens ./run-hunt.sh --days 1
Runtime
- Uses
(NOTnpx tsx
)ts-node --esm - TypeScript config:
, imports usemodule: "NodeNext"
extensions.js
is installed as a devDependencytsx