| name | hf-morning-news-digest |
| description | Every morning (08:00 KST, launchd) scrape HuggingNews (huggingnews.com) for the latest day's top AI news, Korean-localize it, dedup across mornings, and post to Slack #deep-research-trending as a ranked main message + one thread reply per story (핵심 + ThakiCloud 관점, Notion-style). Use when "허깅페이스 아침 뉴스", "HuggingNews 다이제스트", "deep-research-trending 뉴스 자동", HF morning news to Slack. Do NOT use for HF trending papers/models radar (use hf-trending-intelligence), Gmail-sourced Bespin news (use bespin-news-digest), or Twitter timeline (use twitter-timeline-to-slack). |
hf-morning-news-digest
HuggingNews (Hugging Face CEO's AI-curated news wire) → Korean morning digest in
Slack #deep-research-trending (C0AN34G4QHK). Format is code-owned
([[sonnet-format-determinism]]); the model writes only Korean content.
Pipeline (4 stages, model touches only stage 2)
1. hf_morning_fetch.py scrape huggingnews.com latest day → top-N ranked →
(deterministic) cross-run dedup (seen.json) → per-story og:description →
manifest.json [exit 3 = nothing new → skip, no empty post]
2. claude -p (SONNET) read manifest → write records/story-<rank>.json =
(content only) title_ko / key_facts / thaki_perspective (contract below)
3. hf_morning_render.py deterministic mrkdwn + quality gate (fail → no post)
(deterministic) main.txt (ranked KO headlines) + thread-NN.txt (per story)
4. hf_morning_post.py main + threaded replies via slack_post_message.py →
(deterministic) mark slugs seen ONLY after posting
Content contract: references/subagent-quality-contract.md.
Source facts (why this shape)
- No RSS/API/MCP for huggingnews (all 404, per 2026-07-13 probe). We scrape the
SSR homepage with a browser UA (curl HTTP 200) — day-grouped, rank-ordered
story rows. The URL slug is the dedup key. Article bodies are JS-rendered and
NOT fetched; each story page's
og:description (in SSR HTML) is the factual summary.
- Freshness = latest day section on the homepage (site groups by its own day).
Cross-run
seen.json guarantees no repeats across consecutive mornings
([[news-freshness-and-sourcing]] dedup intent; window is "latest day + never-repeat").
- Top 10 by the site's own rank (HuggingNews frames itself as ~10/morning).
Run
bash scripts/skills/run_hf_morning_news.sh
DRY_RUN=1 bash scripts/skills/run_hf_morning_news.sh
.venv/bin/python scripts/skills/hf_morning_fetch.py --top 10 --json
.venv/bin/python scripts/skills/hf_morning_render.py outputs/hf-morning-news/<date> --print
.venv/bin/python scripts/skills/hf_morning_post.py outputs/hf-morning-news/<date> [--dry-run]
Interactive: run fetch, then YOU are the content worker (write records per the
contract), then render (--print to eyeball) and post.
Schedule (daily 08:00 KST)
cp scripts/launchd/com.thaki.hf-morning-news.plist ~/Library/LaunchAgents/
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.thaki.hf-morning-news.plist
launchctl print gui/$(id -u)/com.thaki.hf-morning-news
Model: policy-driven (scripts/skills/skill_model_policy.json, sonnet, unpinned →
auto-escalates on repeated failure via skill_retro.py). Format determinism holds
quality, not model tier ([[scheduled-skill-model-escalation]] / [[loop-monitor-cost-guard]] §3).
Guardrails
- Finite daily fire, NOT a polling loop ([[loop-monitor-cost-guard]]).
- Slack mrkdwn only ([[slack-post-formatting]]):
*bold*, •, <url|label>, no #, no pipe tables.
- Headless auth via subscription OAuth (
headless.env), unset ANTHROPIC_API_KEY
([[scheduled-skill-model-escalation]] auth premise).
- 날조 금지: worker uses only title + og:description; only cites the story's own URL.
Files
scripts/skills/hf_morning_{fetch,render,post}.py
scripts/skills/run_hf_morning_news.sh
scripts/launchd/com.thaki.hf-morning-news.plist
outputs/hf-morning-news/{seen.json, <date>/manifest.json, <date>/records/, <date>/*.txt, log.md}