{"id":51500135,"url":"https://github.com/darth-dodo/hn-herald","last_synced_at":"2026-07-07T17:30:52.210Z","repository":{"id":331619228,"uuid":"1127607226","full_name":"darth-dodo/hn-herald","owner":"darth-dodo","description":"📜 HackerNews summarizer using LangGraph and LangChain ecosystem","archived":false,"fork":false,"pushed_at":"2026-02-27T11:11:51.000Z","size":1054,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-27T16:25:36.385Z","etag":null,"topics":["fastapi","hackernews","langchain","langgraph","python"],"latest_commit_sha":null,"homepage":"https://hn-herald.onrender.com/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/darth-dodo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-04T08:26:26.000Z","updated_at":"2026-02-27T11:11:56.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/darth-dodo/hn-herald","commit_stats":null,"previous_names":["darth-dodo/hn-herald"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/darth-dodo/hn-herald","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darth-dodo%2Fhn-herald","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darth-dodo%2Fhn-herald/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darth-dodo%2Fhn-herald/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darth-dodo%2Fhn-herald/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/darth-dodo","download_url":"https://codeload.github.com/darth-dodo/hn-herald/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darth-dodo%2Fhn-herald/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35237753,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-07T02:00:07.222Z","response_time":90,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fastapi","hackernews","langchain","langgraph","python"],"created_at":"2026-07-07T17:30:49.044Z","updated_at":"2026-07-07T17:30:52.195Z","avatar_url":"https://github.com/darth-dodo.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# HN Herald\n\n**AI-Powered, Privacy-First HackerNews Digest**\n\n[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)\n[![FastAPI](https://img.shields.io/badge/FastAPI-0.115+-green.svg)](https://fastapi.tiangolo.com/)\n[![LangGraph](https://img.shields.io/badge/LangGraph-0.2+-purple.svg)](https://github.com/langchain-ai/langgraph)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n*Stop drowning in links. Get the stories that matter to you, summarized and scored for relevance.*\n\n[Features](#features) • [Demo](#demo) • [Quick Start](#quick-start) • [Architecture](#architecture) • [Documentation](#documentation)\n\n\u003c/div\u003e\n\n---\n\n![HN Herald - Configure your digest](docs/screenshots/01-configure-digest.png)\n\n## Features\n\n### Personalized Content Discovery\n- **Tag-Based Interests** — Select from curated categories (AI/ML, Web Dev, Security, etc.) or create custom tags\n- **Smart Scoring** — Hybrid algorithm: 70% relevance to your interests + 30% HN community signals\n- **Disinterest Filtering** — Actively exclude topics you don't want to see\n\n### AI-Powered Summaries\n- **Concise Summaries** — 2-3 sentence overview of each article\n- **Key Points** — 3-5 actionable takeaways extracted from content\n- **Auto-Tagging** — Technology tags identified from article content\n- **Batch Processing** — Efficient LLM calls (5 articles per request) for cost optimization\n\n### Privacy-First Design\n- **Zero Tracking** — No analytics, no cookies, no behavior logging\n- **Local Storage Only** — Your preferences never leave your browser\n- **No Account Required** — Start using immediately\n- **Ephemeral Processing** — Content processed in real-time, never stored\n\n### Real-Time Experience\n- **SSE Streaming** — Live pipeline progress updates as your digest generates\n- **Cancellable Requests** — Abort long-running operations anytime\n- **Fun Facts** — HN trivia while you wait\n- **Three Themes** — HN Orange, Ocean Blue, Dark Mode\n\n## Demo\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eScreenshots\u003c/b\u003e\u003c/summary\u003e\n\n### Real-Time Loading Progress\n![Loading state with pipeline stages](docs/screenshots/02-loading-state.png)\n\n### Mobile Experience\n![Mobile responsive design](docs/screenshots/04-mobile-digest.png)\n\n### Dark Theme\n![Dark theme on mobile](docs/screenshots/05-mobile-dark-theme.png)\n\n### Ocean Theme\n![Ocean theme](docs/screenshots/06-ocean-theme.png)\n\n\u003c/details\u003e\n\n## Quick Start\n\n### Prerequisites\n- Python 3.12+\n- [uv](https://github.com/astral-sh/uv) package manager\n- Anthropic API key\n\n### Installation\n\n```bash\n# Clone the repository\ngit clone https://github.com/darth-dodo/hn-herald.git\ncd hn-herald\n\n# Install dependencies\nmake install\n\n# Configure environment\ncp .env.example .env\n# Add your ANTHROPIC_API_KEY to .env\n\n# Start the server\nmake dev\n```\n\nOpen [http://localhost:8000](http://localhost:8000) and generate your first digest.\n\n## Architecture\n\n### System Overview\n\n```mermaid\ngraph TB\n    subgraph Browser[\"Browser\"]\n        UI[Vanilla JS + Tailwind]\n        LS[(localStorage)]\n    end\n\n    subgraph FastAPI[\"FastAPI Backend\"]\n        Routes[API Routes]\n        Pipeline[LangGraph Pipeline]\n    end\n\n    subgraph External[\"External Services\"]\n        HN[HN Firebase API]\n        Claude[Anthropic Claude]\n    end\n\n    UI \u003c--\u003e|SSE Stream| Routes\n    UI --\u003e LS\n    Routes --\u003e Pipeline\n    Pipeline --\u003e HN\n    Pipeline --\u003e Claude\n```\n\n### LangGraph Pipeline\n\nThe digest generation uses a 7-stage [LangGraph](https://github.com/langchain-ai/langgraph) pipeline with parallel execution:\n\n```mermaid\ngraph LR\n    A[fetch_hn] --\u003e B[fetch_article]\n    B --\u003e C[filter]\n    C --\u003e D[summarize]\n    D --\u003e E[score]\n    E --\u003e F[rank]\n    F --\u003e G[format]\n\n    style B fill:#e1f5fe\n```\n\n| Stage | Node | Description |\n|-------|------|-------------|\n| 1 | `fetch_hn` | Fetch stories from HN API (top/new/best/ask/show) |\n| 2 | `fetch_article` | **Parallel** content extraction via Send pattern |\n| 3 | `filter` | Remove articles without extractable content |\n| 4 | `summarize` | Claude 3.5 Haiku batch summarization |\n| 5 | `score` | Hybrid relevance + popularity scoring |\n| 6 | `rank` | Sort by final score, apply limits |\n| 7 | `format` | Assemble digest with statistics |\n\n### Tech Stack\n\n| Layer | Technology | Purpose |\n|-------|------------|---------|\n| **Backend** | FastAPI | Async REST API with SSE streaming |\n| **AI Orchestration** | LangGraph | Pipeline management with parallel execution |\n| **LLM** | Claude 3.5 Haiku | Cost-efficient summarization |\n| **Frontend** | Vanilla JS + Jinja2 | Lightweight, no build step |\n| **Styling** | Tailwind CSS | Utility-first responsive design |\n| **Observability** | LangSmith | Pipeline tracing and debugging |\n\n## Documentation\n\n| Document | Description |\n|----------|-------------|\n| [Architecture](docs/architecture.md) | System design, data models, API contracts |\n| [Product Requirements](docs/product.md) | Features, user stories, roadmap |\n| [Design Specs](docs/design/) | Implementation details for each component |\n| [ADRs](docs/adr/) | Architecture Decision Records |\n\n### Architecture Decision Records\n\n| ADR | Decision | Rationale |\n|-----|----------|-----------|\n| [001](docs/adr/001-langgraph-pipeline-architecture.md) | LangGraph for orchestration | Parallel execution, error handling, observability |\n| [002](docs/adr/002-sse-streaming-over-htmx.md) | SSE over HTMX | Real-time progress for 30-60s operations |\n| [003](docs/adr/003-privacy-first-architecture.md) | Privacy-first architecture | localStorage only, no server-side user data |\n| [004](docs/adr/004-tag-based-relevance-scoring.md) | Tag-based scoring | Simple, fast, explainable personalization |\n| [005](docs/adr/005-claude-haiku-for-summarization.md) | Claude Haiku | 10x cost savings with batch processing |\n\n## Development\n\n```bash\nmake install     # Install dependencies with uv\nmake dev         # Start dev server (hot reload)\nmake test        # Run test suite (469 tests)\nmake test-cov    # Run with coverage report\nmake lint        # Code style (ruff)\nmake typecheck   # Type checking (mypy)\nmake check       # All quality gates\n```\n\n### Project Structure\n\n```\nhn-herald/\n├── src/hn_herald/\n│   ├── api/              # FastAPI routes, rate limiting\n│   ├── graph/            # LangGraph pipeline (7 nodes)\n│   ├── models/           # Pydantic models\n│   ├── services/         # Business logic (HN client, loader, LLM, scoring)\n│   ├── templates/        # Jinja2 HTML templates\n│   └── static/           # CSS, JS assets\n├── tests/                # 469 tests (unit, integration, API)\n├── docs/                 # Architecture, design specs, ADRs\n└── Makefile              # Development commands\n```\n\n### Quality Metrics\n\n| Metric | Value |\n|--------|-------|\n| Test Count | 469 |\n| Coverage | 70%+ |\n| Type Coverage | Strict (mypy) |\n| Linting | ruff |\n\n## Contributing\n\nContributions welcome! Please:\n\n1. Read the [Architecture docs](docs/architecture.md)\n2. Check existing [ADRs](docs/adr/) for context\n3. Ensure `make check` passes\n4. Include tests for new functionality\n\n## License\n\nMIT License - see [LICENSE](LICENSE) for details.\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n**Built with [LangGraph](https://github.com/langchain-ai/langgraph) and [Claude](https://anthropic.com)**\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdarth-dodo%2Fhn-herald","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdarth-dodo%2Fhn-herald","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdarth-dodo%2Fhn-herald/lists"}