{"slug": "show-hn-unread-cli-that-turns-telegram-youtube-and-files-into-cited-reports", "title": "Show HN: Unread – CLI that turns Telegram, YouTube and files into cited reports", "summary": "A developer released Unread, a command-line tool that uses any LLM to turn Telegram chats, YouTube videos, web pages, and files into summarized reports with clickable citations. The tool aims to help users quickly digest large volumes of unread content by generating structured Markdown reports with source links.", "body_md": "*Read your Telegram unread. Without reading it.*\n\nA local CLI that turns Telegram chats, YouTube videos, web pages, and files into reports with citations — using whichever LLM you keep an API key for.\n\nYou have 47 unread Telegram groups. You will never read them. You will now.\n\n```\ncurl -LsSf https://astral.sh/uv/install.sh | sh\nuv tool install unread && unread init\nunread @somegroup --last-days 7\n```\n\nIt pulls the chat, runs it through whichever LLM you keep an API key\nfor, and hands you a report with clickable citations back to\nevery claim. Same shape for YouTube videos, web pages, voice messages,\nrecorded meetings, podcasts, PDFs, and stdin. Or run it as a\nself-hosted Telegram bot and forward anything weird at it — see\n[Self-hosted Telegram bot](#self-hosted-telegram-bot) below.\n\nSee [a real report](/maxbolgarin/unread/blob/main/.github/examples/summary.md) from `@thehackernews`\n\n— 99 messages over two weeks, four chunks, $0.016, every bullet linked back to its source.\n\nThree verbs. The same `<ref>`\n\nshape works on all of them.\n\n`unread <ref>`\n\n—**analyze**. Map-reduce the source into a Markdown report. Every claim links back to its message / paragraph / timestamp.`unread ask <ref> \"Q\"`\n\n—**ask**. One-shot Q&A with citations. Multi-turn follow-ups are one keystroke away.`unread dump <ref>`\n\n—**dump**. Save the original — chat history, transcript, article — verbatim. No LLM call.\n\n`<ref>`\n\nis any of:\n\n```\nunread @somegroup --last-days 7              # Telegram chat / channel / forum\nunread \"https://youtu.be/jmzoJCn8evU\"        # YouTube video (captions or Whisper)\nunread \"https://paulgraham.com/greatwork\"    # Web page / article\nunread ./meeting.mp3                         # Local file (PDF, DOCX, audio, video, image)\ncat notes.txt | unread                       # Stdin\n```\n\nThis is the bit you actually want.\n\nUse `unread tg`\n\nto analyze any yours chats with interactive picker.\n\nSource language and report language are independent. The chat can be in Russian, the report in English. Or English source → Spanish report. Or anything → anything — the LLM does the heavy lifting and the source hint is optional.\n\n```\n# Russian-language group, English summary\nunread @forklog --last-days 7 --report-language en\n\n# English channel, Russian summary\nunread @thehackernews --last-days 14 --report-language ru\n```\n\nOut of the box, hand-tuned preset *structures* ship for `en`\n\nand `ru`\n\nunder [ presets/<lang>/*.md](/maxbolgarin/unread/blob/main/presets) — section names, the forum\naddendum, the report skeleton. For any other report language the LLM\nwrites the structure on the fly using the English preset as a template.\nIt works. It's not as polished as the native trees.\n\nWhat you get back, for a Russian chat with `--report-language en`\n\n:\n\n```\n## Decisions\n- Migrate to indexed fund structures starting Q1 2026. [#1586](https://t.me/c/3865481227/584/1586)\n- Drop the legacy K8s 1.27 cluster by end of month — Bob owns the rollout. [#1604](...)\n\n## Open questions\n- Who pays the OpenAI bill across the joint team? [#1612](...)\n```\n\nEvery citation is a `t.me`\n\nlink. Click → Telegram opens that message.\n\n`unread`\n\nhandles forums (topics), channel comments, voice notes\n(transcribed), photos (described), forwarded media (deduped — Whisper\nruns once across N chats), and your folder structure (`--folder Work`\n\nbatches everything in that Telegram folder). The full source-shape\nmatrix is in [ docs/sources.md](/maxbolgarin/unread/blob/main/docs/sources.md).\n\n`unread <youtube-url>`\n\ndoes the obvious thing: tries captions first,\nfalls back to Whisper if the video has none. Every citation in the\nreport becomes a `t=SECONDS`\n\ndeep link, so clicking jumps you to that\nmoment of the video.\n\n```\nunread https://www.youtube.com/watch?v=Pmd6knanPKw\nunread https://www.youtube.com/watch?v=SBEtiXnLtpw --report-language de\n```\n\nfrom what timecode should i start watching if i want to know about RAG?\n\n```\nunread ask https://youtube.com/watch\\?v\\=k1njvbBmfsw \"from what timecode should i start watching if i want to know about RAG?\"\nunread dump https://www.youtube.com/watch?v=BDqvzFY72mg --mode=transcript\n```\n\nCached after the first run. Re-asking a question about the same video costs only the answer call — no yt-dlp, no Whisper, no re-spend.\n\nPlain web pages (`unread <url>`\n\n), PDFs, DOCX, Markdown, audio, video,\nand images all use the same `<ref>`\n\nsyntax. See\n[ docs/sources.md](/maxbolgarin/unread/blob/main/docs/sources.md) for the full list of supported\nextensions and the cache rules.\n\nThat 12-minute voice message someone sent you. The 45-minute meeting recording you'll never play back. The hour-long lecture you wanted to skim. Drop any of them in and get a Markdown summary:\n\n```\nunread ./meeting.mp3                 # audio → Whisper → summary\nunread ./standup.mp4                 # video → ffmpeg → Whisper → summary\nunread ./voice-note.ogg              # forwarded voice message saved to disk\nunread ./report.pdf                  # PDF\nunread ./screenshot.png              # image (vision)\n```\n\nInside a Telegram chat the same step runs invisibly: voice notes and\nvideo circles are transcribed, photos are described, the analysis\ntreats them as text. Forward a voice across five chats — Whisper runs\nonce, cached by Telegram's stable `document_id`\n\n.\n\nWhisper is roughly $0.006 per minute of audio. A 30-minute podcast costs under twenty cents. Re-running on the same file is free when it hits the cache.\n\nThe full kind matrix and cache rules are in\n[ docs/sources.md#media-enrichment](/maxbolgarin/unread/blob/main/docs/sources.md#media-enrichment).\n\nDrop in a key for any of these. Switch at any time with\n`unread settings`\n\n— caches and analyses persist across switches.\n\n| Provider | What you get |\n|---|---|\nOpenAI |\nChat models + Whisper (audio) + embeddings + vision. The full toolkit. |\nAnthropic (Claude) |\nChat models only. Pair with an OpenAI key if you also want voice / image enrichment. |\nGoogle (Gemini) |\nChat models only. Same pairing note. |\nOpenRouter |\nOne key, dozens of chat models — handy for trying Llama / DeepSeek / Mistral without separate signups. |\nLocal (Ollama / LM Studio / vLLM) |\nOpenAI-compatible HTTP. Zero cost, zero data leakage, your own model. |\n\nWhisper / vision / embeddings are OpenAI-only. If you pick Anthropic or\nGoogle as your chat provider and also want media enrichment, add an\nOpenAI key alongside — `unread init`\n\nwill offer it.\n\n```\n# 1. Install. uv handles the Python venv and binary.\ncurl -LsSf https://astral.sh/uv/install.sh | sh         # macOS / Linux\nuv tool install unread\n\n# 2. Interactive setup. Picks install folder, AI provider, Telegram (optional).\nunread init\n\n# 3. Run something.\nunread \"https://paulgraham.com/greatwork.html\"          # any web page\nunread ./meeting.mp3                                    # any local file\nunread @somegroup --last-days 7                         # last week of a chat\nunread doctor                                           # confirm everything works\nunread help                                           # show help\n```\n\nNo virtualenv to activate, no `pip`\n\nconflicts, no global Python\npollution. Upgrade later with `uv tool upgrade unread`\n\n.\n\nSkip the Telegram step if you only want YouTube / web / file analysis — those work with only an AI key.\n\nFull install matrix (Windows / ffmpeg / dev install / editable) is in\n[ docs/install.md](/maxbolgarin/unread/blob/main/docs/install.md).\n\nRun the same pipeline as a Telegram bot. Forward it a voice message\nyou don't feel like listening to, a PDF you don't feel like reading, a\nYouTube link, a `t.me/...`\n\npost from a channel you're not sure you\nwant to subscribe to, or that suspicious link a friend just sent —\nyou get a Markdown summary back as a document, with cost and timing\nin the caption.\n\nSingle-user by design: the bot only answers ONE Telegram ID. The\nallowlist is auto-derived from the user session you give it (mounted\nor sent via `/upload_session`\n\n); `UNREAD_BOT_OWNER_ID`\n\nis only a\nbootstrap fallback for the case where no session is installed yet.\nEveryone else is silently dropped.\n\nThree install paths — pick by environment:\n\n**1. Local laptop / dev** (`unread bot run`\n\nforeground):\n\n```\nuv tool install unread\nexport UNREAD_BOT_TOKEN=123:abc...   # from @BotFather\nunread bot run\n```\n\n**2. Fresh Linux VM** — one line, blank disk to running systemd service:\n\n```\nUNREAD_EXECUTABLE=\"install-unread-bot.sh\" && curl -fsSL https://raw.githubusercontent.com/maxbolgarin/unread/main/scripts/install-bot.sh > $UNREAD_EXECUTABLE && chmod +x $UNREAD_EXECUTABLE && ./$UNREAD_EXECUTABLE && rm ./$UNREAD_EXECUTABLE\n```\n\nInstalls uv + ffmpeg + libpango, runs `unread init`\n\n, asks for the\n`@BotFather`\n\ntoken, drops a `systemd --user`\n\nunit that auto-restarts\non crash and survives SSH disconnect.\n\n**3. Docker** — pull the generic `unread`\n\nimage from GHCR (same image\ncan also run one-off CLI commands; `command: [\"unread\",\"bot\",\"run\"]`\n\nin the compose file specifies the bot mode):\n\n```\ncp .env.bot.example .env.bot && $EDITOR .env.bot\ndocker compose -f docker-compose.bot.yml --env-file .env.bot up -d\n```\n\nReports default to PDF; set `UNREAD_BOT_REPORT_FORMAT=md`\n\nin `.env.bot`\n\nto skip PDF rendering (`.md`\n\nupload instead). The first time you\nmessage the bot with a `t.me/...`\n\nlink it'll ask for `/upload_session`\n\n— send your laptop's `~/.unread/storage/session.sqlite`\n\nas a Telegram\ndocument and it's ready.\n\nFull feature reference (slash commands, the confirm panel, what each\ninput kind does) is in [ docs/bot.md](/maxbolgarin/unread/blob/main/docs/bot.md). End-to-end VM\ndeployment guide covering all three paths is in\n\n[.](/maxbolgarin/unread/blob/main/docs/bot-vm-deploy.md)\n\n`docs/bot-vm-deploy.md`\n\nI have ~50 Telegram groups I genuinely want to follow and not enough hours to read them. The same is true for the videos I bookmark and the articles I save to \"read later.\" LLMs are now cheap enough that analyzing a week of group chat costs less than a coffee. My time is not. So I built the CLI I wanted to use — local-first, citation-backed, provider-agnostic — and now I open Telegram a lot less.\n\n**Local-first.** SQLite under`~/.unread/`\n\n. Your messages, embeddings, analyses, and secrets stay on your disk. The only network calls are to Telegram, your chosen AI provider, and any URLs you point at.**Security.** Your API keys, Telegram session, and other secrets can be encrypted at rest. You can use your OS keychain (default) or passphrase to unlock the CLI.**Citations on every claim.** Reports link back to the source message / paragraph / timestamp.`--cite-context N`\n\nexpands citations into`<details>`\n\nblocks with surrounding context, so the report is auditable without re-opening Telegram.**Two-layer cache.** Local analysis cache (re-running an unchanged chat is free) + the AI provider's prompt cache (server-side discount on repeated prefixes).`unread cache stats`\n\nshows the hit rate.**Cost guardrails.**`--max-cost 0.50`\n\naborts or confirms before you spend more than that.`--dry-run`\n\nestimates without calling the model.`unread stats`\n\nshows lifetime spend by chat / preset / day.**PII redaction.**`--redact`\n\nscrubs phones, emails, IBANs, and Luhn-valid card numbers from what gets sent to the LLM. Originals stay in the local DB.**Map-reduce, automatic.** Big histories get chunked, summarized in parallel, then merged. Each chunk is cached independently — adding one message to the tail re-costs only the last chunk.**Forums, channels with comments, folders.** Telegram's awkward shapes are first-class.`--all-per-topic`\n\n,`--with-comments`\n\n,`--folder Work`\n\n.\n\nEncryption modes (`keystore`\n\n, passphrase-derived `pass`\n\n), session\nhygiene, and the threat model are documented in\n[ docs/security.md](/maxbolgarin/unread/blob/main/docs/security.md).\n\n**Does this ship my Telegram history to OpenAI?**\nOnly the messages in the window you asked about, only after PII\nredaction if you set `--redact`\n\n, and only to the provider whose key you\nconfigured. Nothing else leaves the machine. The local cache is in\nyour install dir; you can wipe it any time with `unread cache ai purge`\n\n.\n\n**What if I don't use Telegram?**\nSkip `unread init`\n\n's Telegram step. `unread <url>`\n\nand `unread <file>`\n\nwork with only an AI key. Most of the codebase is source-agnostic.\n\n**What languages does it actually support?**\nSource content: anything Whisper auto-detects (audio) or your LLM can\nread (text) — pretty much everything human languages cover. Reports:\nanything your LLM can write. EN and RU get hand-tuned preset\nstructures; other report languages use the English preset as a\ntemplate that the LLM translates on the fly.\n\n**Will it cost me money?**\nYes — your AI provider charges. `unread`\n\nitself is free. Per-call USD\nis logged; `--max-cost N`\n\ncaps a single run. Re-running an unchanged\nchat is free (local cache hit). With cheap models (`gpt-5.4-mini`\n\n-class,\nGemini Flash, Claude Haiku) the bill is small enough that most users\nstop reading the cost reports after a week.\n\n**Is it actually fast?**\nFast enough that I stopped reading group chats. No benchmark table —\nspeed depends on chat size, model choice, and your network. Try it\nwith `unread @somegroup --last-days 1 --dry-run`\n\nto see the estimate\nbefore any LLM call.\n\n**Can I run it on a server / in cron?**\nYes. Non-TTY mode skips interactive prompts. `unread watch --interval 1h ...`\n\nloops in the foreground (run under tmux / systemd / nohup). API keys\ncan come from env vars or `~/.unread/.env`\n\n. The passphrase backend\nreads `UNREAD_PASSPHRASE`\n\nfor headless unlock.\n\n**Can I plug in my own preset / prompt?**\n`--preset custom --prompt-file my-prompt.md`\n\n. Same frontmatter format\nas the bundled ones in [ presets/](/maxbolgarin/unread/blob/main/presets). Bump\n\n`prompt_version`\n\nin the frontmatter when you edit, otherwise the cache won't notice.The full reference manual lives under `docs/`\n\n:\n\n| Topic | File |\n|---|---|\n| Install on macOS / Linux / Windows + first-run setup + where files live |\n`docs/install.md` |\n\n`docs/sources.md`\n\n`watch`\n\n, subscriptions`docs/reference.md`\n\n`config.toml`\n\n, maintenance, troubleshooting, architecture`docs/configuration.md`\n\n`docs/security.md`\n\nUseful inline help: `unread --help`\n\n, `unread <subcommand> --help`\n\n,\n`unread help`\n\n, `unread doctor`\n\n.\n\nPRs welcome. Read [ CLAUDE.md](/maxbolgarin/unread/blob/main/CLAUDE.md) first — it's the contributor\nmap (DB invariants, cache keys, preset version bumps, the three\nlanguage axes).\n\n[covers the bench (lint / format / tests).](/maxbolgarin/unread/blob/main/CONTRIBUTING.md)\n\n`CONTRIBUTING.md`\n\n[for vulnerability reports.](/maxbolgarin/unread/blob/main/SECURITY.md)\n\n`SECURITY.md`\n\n```\nuv sync --extra dev\nuv run pytest -q\nuv run ruff check . && uv run ruff format --check .\n```\n\nIssues and feature requests: [https://github.com/maxbolgarin/unread/issues](https://github.com/maxbolgarin/unread/issues).\n\nStanding on the shoulders of:\n[Telethon](https://github.com/LonamiWebs/Telethon) for the Telegram side,\n[OpenAI Whisper](https://platform.openai.com/docs/guides/speech-to-text) /\n[Anthropic](https://www.anthropic.com/) /\n[Google Gemini](https://ai.google.dev/) /\n[OpenRouter](https://openrouter.ai/) /\n[Ollama](https://ollama.com/) for the LLM side,\n[yt-dlp](https://github.com/yt-dlp/yt-dlp) for YouTube,\n[trafilatura](https://github.com/adbar/trafilatura) for article extraction,\n[tiktoken](https://github.com/openai/tiktoken) for token counting,\n[Typer](https://github.com/tiangolo/typer) /\n[Rich](https://github.com/Textualize/rich) /\n[structlog](https://www.structlog.org/) for the CLI shell,\nand [uv](https://github.com/astral-sh/uv) for keeping all of the above\nout of your system Python.\n\nApache 2.0 — see [LICENSE](/maxbolgarin/unread/blob/main/LICENSE).", "url": "https://wpnews.pro/news/show-hn-unread-cli-that-turns-telegram-youtube-and-files-into-cited-reports", "canonical_source": "https://github.com/maxbolgarin/unread", "published_at": "2026-06-25 12:54:59+00:00", "updated_at": "2026-06-25 13:15:32.019571+00:00", "lang": "en", "topics": ["artificial-intelligence", "large-language-models", "ai-tools", "developer-tools"], "entities": ["Telegram", "YouTube", "Whisper", "OpenAI"], "alternates": {"html": "https://wpnews.pro/news/show-hn-unread-cli-that-turns-telegram-youtube-and-files-into-cited-reports", "markdown": "https://wpnews.pro/news/show-hn-unread-cli-that-turns-telegram-youtube-and-files-into-cited-reports.md", "text": "https://wpnews.pro/news/show-hn-unread-cli-that-turns-telegram-youtube-and-files-into-cited-reports.txt", "jsonld": "https://wpnews.pro/news/show-hn-unread-cli-that-turns-telegram-youtube-and-files-into-cited-reports.jsonld"}}