What's new in AI today? Ranked AI news with a short daily digest, in English and Vietnamese.
▶ Watch the introduction video (30 seconds)
| Channel | Link |
|---|---|
| Website | aidr.today |
| Chrome new tab | Chrome Web Store |
| Telegram (Vietnamese) | @aihomnay |
| Telegram (English) | @aidr_today |
| Email digest | aidr.today/subscribe |
| RSS | feed.xml |
Cloudflare Worker (aidr), TanStack Start frontend, D1 as the primary store.
| Path | Role |
|---|---|
apps/web |
Site, API, ingest workflow (@aidr/web) |
apps/extension |
Chrome MV3 new-tab (@aidr/extension) |
packages/* |
Shared libs / UI |
videos |
Video sources, built with HyperFrames (videos/README.md) |
.agents/skills |
Agent skills for this repo |
The scheduler starts a NewsIngestWorkflow every 30 minutes, with a 25-minute coalesce (INGEST_MIN_INTERVAL_MS). The contract is apps/web/ALGORITHM.md.
- Consume — enabled sources (
worker/sources/) are fetched, deduped, and enriched intoitems. - Rank — score, translate, then a pure
rank_score(worker/ranking.ts). The top of the last 24h becomes today's TL;DR snapshot:bullets_enandbullets_vi(worker/tldr.ts). - Publish — one edition per language (
worker/digest/edition.ts). Email uses the subscriber's timezone from 07:00 and their digest size. Telegram VI, Telegram EN, and the English Facebook Page (facebook-en) each post once from 08:00Asia/Ho_Chi_Minh, on the same trending bar. A missing language column is skipped and retried; it is not filled from the other language.
pnpm install
cp .env.example .env.local # fill values (gitignored)
pnpm --filter @aidr/web dev # http://localhost:3014Extension (unpacked):
chrome://extensions→ Developer mode- Load unpacked →
apps/extension
pnpm run deploy # build + wrangler deploy (see CLAUDE.md: cf cannot carry Workflows yet)
pnpm run cf:deploy:prod # production env + smokeCI: .github/workflows/deploy-web.yml on push to main/master when apps/web, apps/extension, packages, or lockfile change.
GitHub secrets: CLOUDFLARE_API_TOKEN, VITE_CLERK_PUBLISHABLE_KEY. Account ID comes from apps/web/wrangler.toml (and the workflow env). D1 queries and secret sync use cf, not Wrangler.
Smoke: curl https://aidr.today/api/public
One command syncs local env → GitHub Actions + Cloudflare Worker:
cp .env.example .env.local # fill values
pnpm sync-env # both targets
pnpm sync-env --dry-run
pnpm sync-env --workers # Worker only
pnpm sync-env --github # GitHub only (repo + production env)Alias: pnpm config. Non-secret config stays in wrangler.toml [vars]. Key list: .env.example.
Zip: https://aidr.today/aidr.zip (built into the Worker).
- Unzip → load unpacked → select the
aidr/folder inside
Versioning: release-please opens separate release PRs from separate
manifests (.github/.release-please-web.json and
.github/.release-please-extension.json). Leave those PRs for a human to merge.
- Website (
apps/web) →chore(web): release X.Y.Z, tagsweb-v* - Chrome extension (
apps/extension) →chore(extension): release X.Y.Z, tagsaidr-v*
Commits that touch each package path (and scopes like feat(web): /
feat(extension):) feed that package’s changelog. Merge the PR to cut
the GitHub Release.
Primary: Durable Object alarm (NewsIngestScheduler).
Watchdog: .github/workflows/ingest.yml POSTs /api/admin/ingest with NEWS_ADMIN_TOKEN. Manual: Actions workflow_dispatch, or admin POST with ?force=1.
No Worker [triggers] crons (Free plan limit) and no Workflow schedules (paid).
pnpm run lint
pnpm run test
pnpm run check-types
pnpm --filter @aidr/web smoke
