cd /news/ai-products/show-hn-newsroom-self-hosted-ai-rank… · home topics ai-products article
[ARTICLE · art-84505] src=github.com ↗ pub= topic=ai-products verified=true sentiment=· neutral

Show HN: Newsroom Self-hosted, AI-ranked meta-aggregator for HN Subreddits etc.

Newsroom, a self-hosted, AI-ranked meta-aggregator for Hacker News, Substack, podcasts, Bluesky, Reddit, and other feeds, was released on GitHub. The Node.js-based tool combines keyword and optional AI ranking to create a personalized feed with Save/Dismiss, topic filters, and an Advisor for refining interests. It supports multi-user data models and APIs, with a web UI and an upcoming Expo mobile feed.

read6 min views1 publishedAug 3, 2026
Show HN: Newsroom Self-hosted, AI-ranked meta-aggregator for HN Subreddits etc.
Image: source

Focused news aggregator — an aggregator of aggregators. It sits on top of Hacker News, Substack, podcasts, Bluesky, Reddit, and other personal feeds you subscribe to, then ranks stories to the topics you care about.

Instead of browsing each source separately, Newsroom pulls recent items into one hybrid-ranked feed (keywords + optional AI), with Save / Dismiss, topic filters, and an in-app Advisor for refining interests.

Personal-first; multi-user-ready data model and APIs. Web UI today; Expo mobile feed next.

  • Node.js 20+ pnpm9 (corepack enable

recommended)- Docker (Postgres + Ollama via Compose — docker compose up -d

; seedocs/ops-local.md) - Optional: host Ollamaonly if you want easierGPU access —docs/ops-local.md

cp .env.example .env
cp apps/web/.env.example apps/web/.env.local

pnpm install
docker compose up -d          # Postgres + Ollama
pnpm db:migrate
pnpm db:seed                  # demo user + HN + Platformer Substack + example topic
pnpm --filter @newsroom/web dev

Open http://localhost:3000 — sign up / sign in. Default seed login after pnpm db:seed

: ** demo@example.com** /

newsroom-demo. Authenticated home is the ranked

Feed; use

Topics,

Advisor,

Sources, and

Settings in the masthead.

Scores are per user: after seed + ingest + rank, sign in as the seeded demo user (or run SEED_USER_ID=<your-user-id> pnpm db:seed

then pnpm worker:rank

, or use Rank latest on the Feed) to see story rows.

Check health:

curl -sS http://localhost:3000/api/health | jq

One-shot ingest then rank (requires migrate + seed or your own subscriptions/topics):

pnpm worker:ingest            # upserts articles; marks affected users dirty; enqueues per-user rank jobs
pnpm worker:rank              # drains rank jobs for dirty ∩ active users (feed activity in last 30m)
pnpm worker:rank -- --all-dirty  # enqueue/drain all dirty users (ignore activity gate)
pnpm worker:prune-scores      # prune stale scores + articles older than ARTICLE_TTL_DAYS (keeps saved; also runs after Rank latest)

After ingest + rank, refresh the Feed on http://localhost:3000 — story rows appear with Save / Dismiss; filter by topic, source, search, or Saved. Topic/source changes mark you dirty and clear unscored feed rows; opening the Feed records activity and enqueues catch-up rank when dirty. Rank latest always ranks the signed-in user. Wipe rankings clears new

/seen

scores (Saved/Dismissed stay) and does not auto re-rank.

Long-running worker (claims ingest

and rank

jobs; ingest cadence ~12 minutes):

pnpm --filter @newsroom/worker start
Path Role
apps/web
Next.js — auth, editorial feed / topics / sources / settings UI, APIs
apps/mobile
Expo Router shell (health via api-client)
apps/worker
Postgres job poller + one-shot ingest/rank CLI
packages/db
Drizzle schema + migrations (auth, ingest, topics, scores)
packages/ai
AiProvider + createAiProvider (Ollama / OpenAI / Google) + keyword/rankArticleBatch helpers
packages/sources
Source adapters: HN, Substack/RSS, podcasts, Bluesky, Reddit
packages/api-client
Typed client (health, sources, topics, topic-tree, feed)

make help

lists the same shortcuts. Prefer Make for day-to-day; pnpm

/ docker compose

remain the underlying commands.

Target Description
make setup
Copy .env + apps/web/.env.local if missing, then pnpm install
make install
Install workspace deps
make up
Start Postgres; Compose Ollama only if :11434 is free (else use host Ollama)
make up-postgres
Postgres only (skip Ollama)
make up-gpu
Compose with NVIDIA GPU passthrough for Ollama
make down
Stop Compose services
make logs
Tail Compose logs
make migrate
Apply Drizzle migrations
make generate
Generate Drizzle migrations from schema
make seed
Demo user + HN + Platformer Substack + example topic
make studio
Drizzle Studio
make web
Next.js dev server (:3000)
make worker
Long-running ingest + rank job poller
make ingest
One-shot ingest then exit
make rank
One-shot rank (RANK_ARGS=-- --all-dirty optional)
make prune
One-shot prune stale scores + old articles
make test
AI + sources unit tests (offline-safe)
make test-ai / test-web / test-worker / test-sources
Package test suites
make typecheck / make build
Turbo typecheck / build
make ollama-pull
Pull model into Compose Ollama (OLLAMA_MODEL=llama3.2 default)
make verify
Local acceptance script (web must be up)
Command Description
pnpm install
Install workspace deps
docker compose up -d
Start Postgres + Ollama
docker compose up -d postgres
Postgres only (skip Ollama)
docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d
Start with NVIDIA GPU passthrough for Ollama (needs NVIDIA Container Toolkit on host, see

docker exec -it newsroom-ollama ollama pull llama3.2

docker exec -it newsroom-ollama ollama pull llama3.1:8b

/ qwen2.5:7b

reason

quality, slower (see docs/ops-local.md#model-options)pnpm db:generate

pnpm db:migrate

DATABASE_URL

pnpm db:seed

AI & infra

topicpnpm db:studio

pnpm --filter @newsroom/web dev

/ pnpm web:dev

pnpm --filter @newsroom/web build

/ start

pnpm --filter @newsroom/worker start

/ pnpm worker:start

pnpm worker:ingest

/ pnpm --filter @newsroom/worker ingest

pnpm worker:rank

/ pnpm --filter @newsroom/worker rank

pnpm worker:prune-scores

pnpm --filter @newsroom/mobile start

/ pnpm mobile:start

pnpm sources:test

pnpm worker:test

pnpm web:test

pnpm --filter @newsroom/ai test

/ pnpm ai:test

pnpm --filter @newsroom/ai smoke

/ pnpm ai:smoke

AI_PROVIDER

(skips if unreachable; AI_SMOKE=1

/ OLLAMA_SMOKE=1

to require it)pnpm build

/ pnpm typecheck

./scripts/verify-scaffold.sh

Env vars: see docs/ops-local.md#environment-files for which file loads what. Templates: root .env.example (worker/CLI) and

apps/web/.env.example

apps/web/.env.local

(Next / Rank latest). Shared: DATABASE_URL

, BETTER_AUTH_*

, OLLAMA_*

, RANK_*

, AI_TOKEN_*

, TTLs. Web-only optional: LANGSEARCH_API_KEY

(Sources feed search). Root-only: GITHUB_*

, SEED_USER_ID

, NEWSROOM_WORKER_ONCE

. Mobile: EXPO_PUBLIC_API_URL

. Ranking tiers: docs/ops-local.md#ranking-model-tiers.

Method Path Notes
GET/PATCH
/api/settings/rank-model
Get / set ranking model tier: none fast standard
GET/PUT/DELETE
/api/settings/ai-credentials
Optional BYOK OpenAI/Google key (encrypted; requires AI_CREDENTIALS_KEY )
Method Path Notes
GET/POST
/api/sources
List / create (caller’s sources only)
PATCH/DELETE
/api/sources/:id
Update / delete own source
GET
/api/feed-catalog
Curated suggested feeds
POST
/api/feed-search
Discover RSS/Atom URLs via LangSearch (LANGSEARCH_API_KEY ); { query }{ results }
Method Path Notes
GET
/api/topic-tree
Curated catalog { version, nodes[] } (selectable leaves for topic names)
GET/POST
/api/topics
List / create (caller’s topics only; name = catalog leaf label)
PATCH/DELETE
/api/topics/:id
Update / delete own topic
GET
/api/feed?cursor=&topic=&excludeTopic=&source=&status=&limit=
Ranked scores; default is new /seen only; topic= includes (OR), excludeTopic= excludes; status=saved (etc.) filters to that status; returns rankedCount / evaluatedCount / articlesCount pipeline counters
POST
`/api/feed/:articleId/seen saved dismissed`
Update status; 404 if no score row

Ranking formulas and job behavior: docs/decisions/002-hybrid-ranking.md. Health, seed, Compose: docs/ops-local.md.

Doc Purpose

docs/ops-local.mddocs/decisions/001-ingest-url-and-hn.mddocs/decisions/002-hybrid-ranking.mddocs/decisions/004-ai-confirmed-topic-membership.mddocs/feature-backlog.mddocs/feature-completed.mddocs/github-workflow.mddocs/contributing.mdCore loop is shipped: auth, multi-source ingest (HN, Substack/RSS, podcasts, Bluesky, Reddit), hybrid rank + Advisor (Ollama / OpenAI / Google, optional BYOK), editorial web UI. Expo feed UI is next per the backlog.

MIT © 2026 SpektrNO

── more in #ai-products 4 stories · sorted by recency
── more on @newsroom 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/show-hn-newsroom-sel…] indexed:0 read:6min 2026-08-03 ·