Stop drowning in tabs. Start understanding what matters.
Newsbuddy is an AI-powered knowledge companion that keeps you informed without the noise. It pulls in content from RSS feeds, podcasts, Hacker News, Reddit, Techmeme, X bookmarks, and any URL you throw at it — then summarizes everything with LLMs so you get focused, non-sensationalized reading on the things you actually care about.
Newsbuddy is a native iOS app built with SwiftUI. Coming soon to the App Store — or self-host it yourself with your own API keys.
|
Stay informed on the go with content that respects your attention. Newsbuddy delivers non-sensationalized, AI-summarized reading across the topics you care about — so you read what matters, when you want to. |
Chat with a council of AI experts grounded in your entire knowledge base. Dig deeper into any article, corroborate claims across sources, and explore new angles — all in one conversation. |
|
First-class support for RSS and Atom feeds, podcasts, and long-form articles. Subscribe to your favorite blogs, newsletters, and shows — Newsbuddy monitors them continuously and processes new content as it arrives. |
Curated, quick-hit summaries from Hacker News, Techmeme, Reddit, and more. Get the signal from the noisiest corners of the internet in seconds, not hours of scrolling. |
|
Newsbuddy surfaces related content and new sources based on what you've read and what's trending across the open web — expanding your knowledge graph without you having to hunt for it. |
Built-in support for X bookmarks, Hacker News, Techmeme, Reddit, Substack, YouTube, podcasts, and any RSS/Atom feed. Connect the sources you already follow and let Newsbuddy do the rest. |
|
A dedicated CLI lets you — or your AI agents — manage and curate your library from the terminal. Add feeds, submit articles, manage sources — the system classifies, processes, and enriches everything automatically. |
Export and sync your saved knowledge as Markdown files locally. Keep a searchable, offline archive of everything you've read for research, note-taking, or integration with your existing tools. |
The newsbuddy CLI is a Rust and Clap client for scripting content, source,
search, onboarding, and local Markdown-library operations. It uses the same
newsly-contracts request types as the Axum API while keeping its stable JSON
output envelope and forward-compatible response decoding.
Install it from this repository:
git clone https://github.com/willemave/newsbuddy.git
cd newsbuddy
cargo install --locked --path rust/crates/newsly-cliThe Homebrew formula lives in the independently released
willemave/newsbuddy tap. Verify that the current formula packages the Rust
newsbuddy binary before relying on it; the source install above always builds
the checked-out revision.
# Authenticate — scan the QR code in the app to approve, no password needed
newsbuddy auth login
# Subscribe to an RSS feed
newsbuddy sources add "https://simonwillison.net/atom/everything/" --feed-type atom --display-name "Simon Willison"
# Submit a one-off article and wait for processing
newsbuddy content submit "https://example.com/great-post" --wait
# Browse your unread content
newsbuddy content list --read-filter unread --limit 20
# Browse today's short-form news
newsbuddy news list --read-filter unread
# Convert a news item into a full article
newsbuddy news convert 4821
# Search across your sources
newsbuddy search "transformer architectures" --limit 10
# Sync your knowledge base to local Markdown
newsbuddy library sync --dir ~/newsbuddy-library --include-source
# List all your feed subscriptions
newsbuddy sources listFor full architecture details, see docs/architecture.md.
- Rust 1.94.1 and Cargo
- PostgreSQL 15+ (the setup helper uses Homebrew on macOS)
- uv only for the isolated Crawl4AI extractor and offline eval package
- Docker Compose only for a containerized development or production-style run
This is the default local-development path. For day-to-day local work, run the app and workers as normal host services against a local PostgreSQL instance.
# Clone
git clone https://github.com/willemave/newsbuddy.git
cd newsbuddy
# Install/start PostgreSQL, create the local app DB/user, and update .env
./scripts/setup_local_postgres.sh
# Start the full local stack
./scripts/start_services.sh all --env-file .env
# For bounded end-to-end testing on an explicit, unoccupied API port
./scripts/start_services.sh all --env-file .env --local-e2e --port 8010The setup script installs Homebrew PostgreSQL if needed, starts the service, creates the newsly database + role, and rewrites DATABASE_URL in .env to point at 127.0.0.1:5432.
Use this for staging or production-style container runs. Docker is not required for normal local development.
# Clone
git clone https://github.com/willemave/newsbuddy.git
cd newsbuddy
# Configure environment
cp .env.example .env
# Edit .env with your provider keys and development secrets
# Start PostgreSQL, SQLx migration, Rust API/workers/scheduler, the extractor,
# and the media worker's pinned PO-token provider
docker compose up --build -d
# View logs
docker compose logs -f api workers scheduler document-extractor bgutil-providerThe container exposes:
- API:
http://127.0.0.1:8000 - PostgreSQL:
127.0.0.1:5432
Production uses the separate blue-green topology in
docker-compose.production.yml. The root
Compose file is for local development only.
For native local development, use the unified launcher with .env:
# Run the local long-running stack
./scripts/start_services.sh all --env-file .env
# Run just the API server
./scripts/start_services.sh server --env-file .env --port 8000
# Run just the workers
./scripts/start_services.sh workers --env-file .env
# Run the Rust scheduler (scraper fan-out and queue recovery)
./scripts/start_services.sh scheduler --env-file .env
# Run only the isolated Crawl4AI service
./scripts/start_services.sh extractor --env-file .env
# Run migrations explicitly
./scripts/start_services.sh migrate --env-file .envThe --local-e2e profile constrains each process's PostgreSQL pool so the full
worker set can run against a normal local server. Pass the same API origin to
the iOS helper, for example
./scripts/codex_run_ios.sh --api-base-url http://127.0.0.1:8010.
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | Native PostgreSQL URL used by SQLx. Local host development uses 127.0.0.1:5432. |
PORT |
API port inside/outside the container (default 8000) |
|
JWT_SECRET_KEY |
Yes | Token-signing key |
ADMIN_PASSWORD |
Yes | Admin panel access |
DOCUMENT_EXTRACTOR_SHARED_SECRET |
Yes | Separate shared secret for the Rust-to-extractor boundary |
E2B_API_KEY |
Agent sandbox control and command streaming | |
ANTHROPIC_API_KEY |
Provider operations configured for Anthropic | |
OPENAI_API_KEY |
Provider operations configured for OpenAI | |
GOOGLE_API_KEY |
Provider operations configured for Google | |
EXA_API_KEY |
Web search in chat |
See .env.example for the full non-secret template.
open client/newsly/newsly.xcodeprojBuild and run on a simulator or device. The app connects to http://127.0.0.1:8000 by default. Features include:
- Apple Sign In authentication
- Share extension — save content from any app
- Integrated chat — converse with your knowledge base
- Markdown sync — export knowledge locally
# Rust backend checks
cd rust
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cd ..
# Public contract drift
scripts/check_public_contracts.sh
# Create a new reversible migration pair
# rust/crates/newsly-db/migrations/YYYYMMDDHHMMSS_describe_change.{up,down}.sql
# Apply migrations
scripts/run_sqlx_migrations.sh
# Validate the canonical E2B template definition without network access
scripts/build_agent_vm_template.sh --checkThe manual Publish E2B Template workflow validates a full current-main SHA,
runs the complete quality gate, and rebuilds the fixed newsly-agent alias with
the pinned official E2B CLI and SDK. It stores a receipt containing the E2B
template ID, source SHA, Dockerfile digest, tool versions, and image metadata.
rust/
└── crates/ # Axum API, domain, SQLx, queue, workers, providers, E2B
python/
├── document_extractor/ # Database-free Crawl4AI service
└── evals/ # Offline embedding and model pipelines
client/
└── newsly/ # SwiftUI iOS app + Share Extension
rust/crates/newsly-cli/ # Rust/Clap `newsbuddy` command-line client
contracts/ # Versioned OpenAPI and ownership policy artifacts
Newsly-owned Python is intentionally isolated from application state. The
production extractor may fetch and parse documents but cannot access
PostgreSQL, the queue, auth, or migrations. The eval package runs model and
embedding experiments offline and calls the Rust eval driver for production
algorithm behavior. The Rust application image also includes the pinned
third-party yt-dlp executable/runtime as a bounded media subprocess; it is not
an application authority.
uv sync --project python/document_extractor --frozen --group dev
uv run --project python/document_extractor pytest -q python/document_extractor/tests
uv sync --project python/evals --frozen --group dev
uv run --project python/evals mypy --config-file python/evals/pyproject.toml \
python/evals/src python/evals/scripts python/evals/tests
uv run --project python/evals pytest -q python/evals/testsProduction deploys are handled through .github/workflows/docker-racknerd-deploy.yml. The workflow gates the exact SHA, builds separate Rust application and Python extractor images, then rolls the blue-green topology in docker-compose.production.yml.
One Rust modular monolith owns auth, APIs, chat, discovery, migrations, and processing orchestration. User submissions and scheduled ingestion enqueue work onto a PostgreSQL-backed durable queue. Workers prepare immutable plans in short transactions, release their connections during provider calls, and finalize through fresh lease-fenced transactions.
flowchart LR
subgraph Clients
iOS["SwiftUI App"]
Share["Share Extension"]
CLI["Rust CLI"]
end
iOS -->|JWT / API key| API["Rust / Axum"]
Share --> API
CLI --> API
Sources["Sources<br/>HN · Reddit · RSS · Substack<br/>X · YouTube · podcasts"] --> Queue[("PostgreSQL<br/>task queue")]
API --> Queue
API --> DB[(PostgreSQL)]
Queue --> Workers["Async workers"]
Workers --> Extractor["Python Crawl4AI<br/>database-free"]
Workers --> Pipeline["Transcribe · Summarize<br/>Illustrate · Agent work"]
Pipeline --> Providers["OpenAI · Claude · Gemini<br/>Whisper · Exa"]
Workers --> DB
A few of the engineering decisions that make Newsbuddy interesting:
-
Postgres is the queue. The async task system is built directly on PostgreSQL — no Redis, Celery, or external broker. It claims jobs lock-free with
FOR UPDATE SKIP LOCKED, wakes workers instantly viaLISTEN/NOTIFY(with a polling fallback), dedupes with partial unique indexes, and renews time-based leases so long-running jobs survive. Scheduler-owned recovery re-routes stale or misrouted tasks, and rotating retry buckets keep old failures from starving fresh work. -
One contract authority, three clients. Utoipa types in the Rust API are the source of truth for public OpenAPI. A fail-closed generator emits the reviewed iOS app and Share Extension wire types, while the Rust CLI consumes
newsly-contractsdirectly. Contract checks byte-diff the checked-in schema and generated native-client artifacts. -
Content-aware model routing. Each piece of content picks its own model — cheap-and-fast for short news, stronger models for long-form articles and podcasts — across OpenAI, Anthropic, Google Gemini, OpenRouter, and DeepSeek. Provider errors and context-limit overflows fall back automatically, and users can bring their own (encrypted) API keys.
-
Structured outputs, never string-scraping. Newsly-owned Serde/Schemars contracts validate model and tool boundaries before typed domain values can be persisted. Rig and provider SDK objects remain transient adapter details.
-
A council of experts. Ask a hard question and the chat agent can fan it out to several AI personas at once; each runs in its own server-side session and the conversation fills in as each expert finishes. It's fully async — the client polls for completion instead of holding a socket open.
-
Cover art chosen by information theory. Editorial images come from Gemini + Runware, but the brief is picked by scoring each story's Shannon entropy, information density, surprise keywords, conceptual tension, and abstractness — so a dense, surprising story gets a bolder, more dramatic image than a routine update.
-
Self-healing extraction. Rust routes URL and media work through typed strategies; HTML is delegated over an authenticated, versioned boundary to the isolated Crawl4AI service. Podcasts, YouTube, and tweet videos flow through the native media workers.
-
One story, not fifty headlines. When the same event surfaces from Hacker News, Techmeme, Reddit, and a dozen blogs, Newsbuddy collapses it into a single card. Every incoming news item runs a cost-tiered cascade — exact-URL match → a cheap lexical pre-filter → multi-view sentence-embedding similarity (title, summary, and source scored separately) → a Qwen cross-encoder asked, yes-or-no, whether two headlines describe the same event (a fresh launch, lawsuit, or follow-up counts as different). Matches fold into one representative item that tracks how many sources covered it, and the feed only ever shows representatives. The whole thing runs incrementally on CPU inside a worker, narrowing thousands of items down to ~12 candidates before the heavy model ever loads.
-
Two read models, one product. Long-form articles and short-form "Fast Reads" are separate canonical models — each with its own read-state, visibility, and discussion rules — bridged by an explicit link, so each surface stays fast without denormalizing the other. Article bodies live in pluggable local-or-S3 storage rather than the database, and comment threads refresh on a leased, TTL-bounded schedule that stops parallel workers from stampeding the same discussion.
-
One application image, explicit services. The Rust image exposes API, worker, scheduler, migration, and
newsly-adminmodes, plus a pinned third-partyyt-dlpmedia subprocess. Production runs PostgreSQL and the database-free extractor separately, with blue-green API slots and singleton worker/scheduler services.
See docs/architecture.md for the full system reference.
| Layer | Technologies |
|---|---|
| Backend | Rust 1.94, Axum, Tokio, Tower, Serde, Utoipa |
| Database & queue | PostgreSQL, SQLx migrations/queries, SKIP LOCKED, LISTEN/NOTIFY, leases |
| AI / LLM | Rig, typed provider HTTP/SDK adapters, OpenAI, Anthropic, Google, OpenRouter, Exa |
| Ingestion & media | Rust workers, isolated Python Crawl4AI extractor, yt-dlp, ffmpeg, Runware |
| CLI | Rust, Clap, reqwest, shared newsly-contracts, newsbuddy binary |
| iOS | SwiftUI, Apple Sign In, Share Extension |
| Admin / Web | Axum server rendering, Tailwind CSS v4, newsly-admin |
| Observability | Structured JSONL logs and vendor usage records |
| Infrastructure | Docker Compose, GitHub Actions, Cargo, uv-isolated Python packages |
| Resource | Description |
|---|---|
| Architecture | System design, database schema, API reference, worker pipeline |
| CLAUDE.md | Development conventions, coding rules, project guidelines |
| docs/library/ | Operational, deployment, and integration guides |
- Fork the repository
- Create a feature branch (
git checkout -b feat/amazing-feature) - Make your changes and add tests
- Run the focused Cargo/client checks and the complete quality gate for cross-cutting changes
- Commit and push
- Open a Pull Request
Released under the MIT License.
Built with Rust, SwiftUI, and a council of LLMs
Made by @willemave