Metadata-Version: 2.4
Name: unread
Version: 0.2.0
Summary: Local CLI for pulling Telegram chats and channels, transcribing voice/video via OpenAI, and analyzing with Chat Completions.
Project-URL: Homepage, https://github.com/maxbolgarin/unread
Project-URL: Repository, https://github.com/maxbolgarin/unread
Project-URL: Issues, https://github.com/maxbolgarin/unread/issues
Project-URL: Changelog, https://github.com/maxbolgarin/unread/blob/main/CHANGELOG.md
Author-email: Max Bolgarin <mxbolgarin@gmail.com>
License:                                  Apache License
                                   Version 2.0, January 2004
                                http://www.apache.org/licenses/
        
           TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
        
           1. Definitions.
        
              "License" shall mean the terms and conditions for use, reproduction,
              and distribution as defined by Sections 1 through 9 of this document.
        
              "Licensor" shall mean the copyright owner or entity authorized by
              the copyright owner that is granting the License.
        
              "Legal Entity" shall mean the union of the acting entity and all
              other entities that control, are controlled by, or are under common
              control with that entity. For the purposes of this definition,
              "control" means (i) the power, direct or indirect, to cause the
              direction or management of such entity, whether by contract or
              otherwise, or (ii) ownership of fifty percent (50%) or more of the
              outstanding shares, or (iii) beneficial ownership of such entity.
        
              "You" (or "Your") shall mean an individual or Legal Entity
              exercising permissions granted by this License.
        
              "Source" form shall mean the preferred form for making modifications,
              including but not limited to software source code, documentation
              source, and configuration files.
        
              "Object" form shall mean any form resulting from mechanical
              transformation or translation of a Source form, including but
              not limited to compiled object code, generated documentation,
              and conversions to other media types.
        
              "Work" shall mean the work of authorship, whether in Source or
              Object form, made available under the License, as indicated by a
              copyright notice that is included in or attached to the work
              (an example is provided in the Appendix below).
        
              "Derivative Works" shall mean any work, whether in Source or Object
              form, that is based on (or derived from) the Work and for which the
              editorial revisions, annotations, elaborations, or other modifications
              represent, as a whole, an original work of authorship. For the purposes
              of this License, Derivative Works shall not include works that remain
              separable from, or merely link (or bind by name) to the interfaces of,
              the Work and Derivative Works thereof.
        
              "Contribution" shall mean any work of authorship, including
              the original version of the Work and any modifications or additions
              to that Work or Derivative Works thereof, that is intentionally
              submitted to Licensor for inclusion in the Work by the copyright owner
              or by an individual or Legal Entity authorized to submit on behalf of
              the copyright owner. For the purposes of this definition, "submitted"
              means any form of electronic, verbal, or written communication sent
              to the Licensor or its representatives, including but not limited to
              communication on electronic mailing lists, source code control systems,
              and issue tracking systems that are managed by, or on behalf of, the
              Licensor for the purpose of discussing and improving the Work, but
              excluding communication that is conspicuously marked or otherwise
              designated in writing by the copyright owner as "Not a Contribution."
        
              "Contributor" shall mean Licensor and any individual or Legal Entity
              on behalf of whom a Contribution has been received by Licensor and
              subsequently incorporated within the Work.
        
           2. Grant of Copyright License. Subject to the terms and conditions of
              this License, each Contributor hereby grants to You a perpetual,
              worldwide, non-exclusive, no-charge, royalty-free, irrevocable
              copyright license to reproduce, prepare Derivative Works of,
              publicly display, publicly perform, sublicense, and distribute the
              Work and such Derivative Works in Source or Object form.
        
           3. Grant of Patent License. Subject to the terms and conditions of
              this License, each Contributor hereby grants to You a perpetual,
              worldwide, non-exclusive, no-charge, royalty-free, irrevocable
              (except as stated in this section) patent license to make, have made,
              use, offer to sell, sell, import, and otherwise transfer the Work,
              where such license applies only to those patent claims licensable
              by such Contributor that are necessarily infringed by their
              Contribution(s) alone or by combination of their Contribution(s)
              with the Work to which such Contribution(s) was submitted. If You
              institute patent litigation against any entity (including a
              cross-claim or counterclaim in a lawsuit) alleging that the Work
              or a Contribution incorporated within the Work constitutes direct
              or contributory patent infringement, then any patent licenses
              granted to You under this License for that Work shall terminate
              as of the date such litigation is filed.
        
           4. Redistribution. You may reproduce and distribute copies of the
              Work or Derivative Works thereof in any medium, with or without
              modifications, and in Source or Object form, provided that You
              meet the following conditions:
        
              (a) You must give any other recipients of the Work or
                  Derivative Works a copy of this License; and
        
              (b) You must cause any modified files to carry prominent notices
                  stating that You changed the files; and
        
              (c) You must retain, in the Source form of any Derivative Works
                  that You distribute, all copyright, patent, trademark, and
                  attribution notices from the Source form of the Work,
                  excluding those notices that do not pertain to any part of
                  the Derivative Works; and
        
              (d) If the Work includes a "NOTICE" text file as part of its
                  distribution, then any Derivative Works that You distribute must
                  include a readable copy of the attribution notices contained
                  within such NOTICE file, excluding those notices that do not
                  pertain to any part of the Derivative Works, in at least one
                  of the following places: within a NOTICE text file distributed
                  as part of the Derivative Works; within the Source form or
                  documentation, if provided along with the Derivative Works; or,
                  within a display generated by the Derivative Works, if and
                  wherever such third-party notices normally appear. The contents
                  of the NOTICE file are for informational purposes only and
                  do not modify the License. You may add Your own attribution
                  notices within Derivative Works that You distribute, alongside
                  or as an addendum to the NOTICE text from the Work, provided
                  that such additional attribution notices cannot be construed
                  as modifying the License.
        
              You may add Your own copyright statement to Your modifications and
              may provide additional or different license terms and conditions
              for use, reproduction, or distribution of Your modifications, or
              for any such Derivative Works as a whole, provided Your use,
              reproduction, and distribution of the Work otherwise complies with
              the conditions stated in this License.
        
           5. Submission of Contributions. Unless You explicitly state otherwise,
              any Contribution intentionally submitted for inclusion in the Work
              by You to the Licensor shall be under the terms and conditions of
              this License, without any additional terms or conditions.
              Notwithstanding the above, nothing herein shall supersede or modify
              the terms of any separate license agreement you may have executed
              with Licensor regarding such Contributions.
        
           6. Trademarks. This License does not grant permission to use the trade
              names, trademarks, service marks, or product names of the Licensor,
              except as required for describing the origin of the Work and
              reproducing the content of the NOTICE file.
        
           7. Disclaimer of Warranty. Unless required by applicable law or
              agreed to in writing, Licensor provides the Work (and each
              Contributor provides its Contributions) on an "AS IS" BASIS,
              WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
              implied, including, without limitation, any warranties or conditions
              of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
              PARTICULAR PURPOSE. You are solely responsible for determining the
              appropriateness of using or redistributing the Work and assume any
              risks associated with Your exercise of permissions under this License.
        
           8. Limitation of Liability. In no event and under no legal theory,
              whether in tort (including negligence), contract, or otherwise,
              unless required by applicable law (such as deliberate and grossly
              negligent acts) or agreed to in writing, shall any Contributor be
              liable to You for damages, including any direct, indirect, special,
              incidental, or consequential damages of any character arising as a
              result of this License or out of the use or inability to use the
              Work (including but not limited to damages for loss of goodwill,
              work stoppage, computer failure or malfunction, or any and all
              other commercial damages or losses), even if such Contributor
              has been advised of the possibility of such damages.
        
           9. Accepting Warranty or Additional Liability. While redistributing
              the Work or Derivative Works thereof, You may choose to offer,
              and charge a fee for, acceptance of support, warranty, indemnity,
              or other liability obligations and/or rights consistent with this
              License. However, in accepting such obligations, You may act only
              on Your own behalf and on Your sole responsibility, not on behalf
              of any other Contributor, and only if You agree to indemnify,
              defend, and hold each Contributor harmless for any liability
              incurred by, or claims asserted against, such Contributor by reason
              of your accepting any such warranty or additional liability.
        
           END OF TERMS AND CONDITIONS
        
           APPENDIX: How to apply the Apache License to your work.
        
              To apply the Apache License to your work, attach the following
              boilerplate notice, with the fields enclosed by brackets "[]"
              replaced with your own identifying information. (Don't include
              the brackets!)  The text should be enclosed in the appropriate
              comment syntax for the file format. We also recommend that a
              file or class name and description of purpose be included on the
              same "printed page" as the copyright notice for easier
              identification within third-party archives.
        
           Copyright 2026 Maksim Bolgarin
        
           Licensed under the Apache License, Version 2.0 (the "License");
           you may not use this file except in compliance with the License.
           You may obtain a copy of the License at
        
               http://www.apache.org/licenses/LICENSE-2.0
        
           Unless required by applicable law or agreed to in writing, software
           distributed under the License is distributed on an "AS IS" BASIS,
           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
           See the License for the specific language governing permissions and
           limitations under the License.
License-File: LICENSE
Keywords: ai,anthropic,cli,digest,google,openai,rag,summarize,telegram,transcription,whisper,youtube
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications :: Chat
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
Classifier: Topic :: Text Processing :: Linguistic
Classifier: Topic :: Utilities
Requires-Python: >=3.11
Requires-Dist: aiosqlite>=0.20
Requires-Dist: anthropic>=0.40
Requires-Dist: beautifulsoup4>=4.12
Requires-Dist: click<9
Requires-Dist: cryptography>=42
Requires-Dist: google-genai>=0.5
Requires-Dist: httpx>=0.27
Requires-Dist: keyring>=24
Requires-Dist: markdown-it-py>=3.0
Requires-Dist: openai>=1.50
Requires-Dist: packaging>=24
Requires-Dist: pydantic-settings>=2.3
Requires-Dist: pydantic>=2.7
Requires-Dist: pypdf>=4.0
Requires-Dist: python-dateutil>=2.9
Requires-Dist: python-docx>=1.1
Requires-Dist: questionary>=2.0
Requires-Dist: rapidfuzz>=3.9
Requires-Dist: rich>=13.7
Requires-Dist: structlog>=24.1
Requires-Dist: telethon>=1.36
Requires-Dist: tenacity>=8.5
Requires-Dist: tiktoken>=0.7
Requires-Dist: trafilatura>=1.12
Requires-Dist: typer>=0.12
Requires-Dist: weasyprint>=62
Requires-Dist: yt-dlp>=2024.7
Provides-Extra: bot
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.3; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Description-Content-Type: text/markdown

<p align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="assets/wordmark/wordmark-ondark.png">
    <img alt="unread" src="assets/wordmark/wordmark-onlight.png" width="320">
  </picture>
</p>
<p align="center"><em>Read your unread. Without reading it.</em></p>

<p align="center">
  <a href="https://pypi.org/project/unread/"><img src="https://img.shields.io/pypi/v/unread.svg" alt="PyPI"></a>
  <a href="https://github.com/maxbolgarin/unread/actions/workflows/ci.yml"><img src="https://github.com/maxbolgarin/unread/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
  <a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.11%2B-blue" alt="Python"></a>
  <a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff"></a>
  <a href="LICENSE"><img src="https://img.shields.io/badge/License-Apache_2.0-blue.svg" alt="License: Apache 2.0"></a>
</p>

<p align="center">
  <strong><a href="https://maxbolgarin.github.io/unread/">Website</a></strong> ·
  <strong><a href="https://maxbolgarin.github.io/unread/docs/">Docs</a></strong> ·
  <strong><a href="https://pypi.org/project/unread/">PyPI</a></strong>
</p>

> A local CLI that turns Telegram chats, YouTube videos, web pages,
> and files into Markdown reports with citations — using whichever LLM
> you keep an API key for.

---

You have 47 unread Telegram groups. You will never read them.
You will now.

```bash
uv tool install unread && unread init
```
```bash
unread @somegroup --last-days 7
```

It pulls the chat, runs it through whichever LLM you keep an API key
for, and hands you a Markdown report with clickable citations back to
every claim. Same shape for YouTube videos, web pages, voice messages,
recorded meetings, podcasts, PDFs, and stdin. Or run it as a
self-hosted Telegram bot and forward anything weird at it — see
[Self-hosted Telegram bot](#self-hosted-telegram-bot) below.

![unread analyzing a Telegram channel into a Markdown report](.github/examples/analyze-example.gif)

## What it does

Three verbs. The same `<ref>` shape works on all of them.

- `unread <ref>` — **analyze**. Map-reduce the source into a Markdown report. Every claim links back to its message / paragraph / timestamp.
- `unread ask <ref> "Q"` — **ask**. One-shot Q&A with citations. Multi-turn follow-ups are one keystroke away.
- `unread dump <ref>` — **dump**. Save the original — chat history, transcript, article — verbatim. No LLM call.
- `unread tg` — **telegram**. Interactive picker for Telegram chats.

`<ref>` is any of:

```bash
unread @somegroup --last-days 7              # Telegram chat / channel / forum
unread "https://youtu.be/jmzoJCn8evU"        # YouTube video (captions or Whisper)
unread "https://paulgraham.com/greatwork"    # Web page / article
unread ./meeting.mp3                         # Local file (PDF, DOCX, audio, video, image)
cat notes.txt | unread                       # Stdin
```

## Telegram in any language

This is the bit you actually want.

Source 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.

```bash
# Russian-language group, English summary
unread @forklog --last-days 7 --report-language en

# English channel, Russian summary
unread @thehackernews --last-days 14 --report-language ru
```

Out of the box, hand-tuned preset *structures* ship for `en` and `ru`
under [`presets/<lang>/*.md`](presets/) — section names, the forum
addendum, the report skeleton. For any other report language the LLM
writes the structure on the fly using the English preset as a template.
It works. It's not as polished as the native trees.

What you get back, for a Russian chat with `--report-language en`:

```markdown
## Decisions
- Migrate to indexed fund structures starting Q1 2026. [#1586](https://t.me/c/3865481227/584/1586)
- Drop the legacy K8s 1.27 cluster by end of month — Bob owns the rollout. [#1604](...)

## Open questions
- Who pays the OpenAI bill across the joint team? [#1612](...)
```

Every citation is a `t.me` link. Click → Telegram opens that message.

See [a real report](.github/examples/summary.md) from `@thehackernews` — 99 messages over two weeks, four chunks, $0.016, every bullet linked back to its source.

`unread` handles forums (topics), channel comments, voice notes
(transcribed), photos (described), forwarded media (deduped — Whisper
runs once across N chats), and your folder structure (`--folder Work`
batches everything in that Telegram folder). The full source-shape
matrix is in [`docs/sources.md`](docs/sources.md).

## YouTube — the bonus that pays for itself

`unread <youtube-url>` does the obvious thing: tries captions first,
falls back to Whisper if the video has none. Every citation in the
report becomes a `t=SECONDS` deep link, so clicking jumps you to that
moment of the video.

#### Analyze 30 mins of podcast:

```bash
unread https://www.youtube.com/watch?v=Pmd6knanPKw 
```

#### Analyze a random old russian lecture with german report:

```bash
unread https://www.youtube.com/watch?v=SBEtiXnLtpw --report-language de
```

#### Ask a question about the video:

> from what timecode should i start watching if i want to know about RAG?

```bash
unread ask https://youtube.com/watch\?v\=k1njvbBmfsw "from what timecode should i start watching if i want to know about RAG?"
```

#### Save the transcript only:

```bash
unread dump https://www.youtube.com/watch?v=BDqvzFY72mg --mode=transcript
```


Cached 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.

Plain web pages (`unread <url>`), PDFs, DOCX, Markdown, audio, video,
and images all use the same `<ref>` syntax. See
[`docs/sources.md`](docs/sources.md) for the full list of supported
extensions and the cache rules.

## Voice, video, and any file — talk-to-text in one command

That 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:

```bash
unread ./meeting.mp3                 # audio → Whisper → summary
unread ./standup.mp4                 # video → ffmpeg → Whisper → summary
unread ./voice-note.ogg              # forwarded voice message saved to disk
unread ./report.pdf                  # PDF
unread ./screenshot.png              # image (vision)
```

Inside a Telegram chat the same step runs invisibly: voice notes and
video circles are transcribed, photos are described, the analysis
treats them as text. Forward a voice across five chats — Whisper runs
once, cached by Telegram's stable `document_id`.

Whisper is roughly **$0.006 per minute of audio**. A 30-minute podcast
costs less than two cents. Re-running on the same file is free (cache
hit). The full kind matrix and cache rules are in
[`docs/sources.md#media-enrichment`](docs/sources.md#media-enrichment).

## Bring your own model

Drop in a key for any of these. Switch at any time with
`unread settings` — caches and analyses persist across switches.

| Provider | What you get |
|---|---|
| **OpenAI** | Chat models + Whisper (audio) + embeddings + vision. The full toolkit. |
| **Anthropic** (Claude) | Chat models only. Pair with an OpenAI key if you also want voice / image enrichment. |
| **Google** (Gemini) | Chat models only. Same pairing note. |
| **OpenRouter** | One key, dozens of chat models — handy for trying Llama / DeepSeek / Mistral without separate signups. |
| **Local** (Ollama / LM Studio / vLLM) | OpenAI-compatible HTTP. Zero cost, zero data leakage, your own model. |

Whisper / vision / embeddings are OpenAI-only. If you pick Anthropic or
Google as your chat provider and also want media enrichment, add an
OpenAI key alongside — `unread init` will offer it.

## Quickstart (90 seconds)

```bash
# 1. Install. uv handles the Python venv and binary.
curl -LsSf https://astral.sh/uv/install.sh | sh         # macOS / Linux
uv tool install unread

# 2. Interactive setup. Picks install folder, AI provider, Telegram (optional).
unread init

# 3. Run something.
unread "https://paulgraham.com/greatwork.html"          # any web page
unread ./meeting.mp3                                    # any local file
unread @somegroup --last-days 7                         # last week of a chat
unread doctor                                           # confirm everything works
unread help                                           # show help
```

No virtualenv to activate, no `pip` conflicts, no global Python
pollution. Upgrade later with `uv tool upgrade unread`.

Skip the Telegram step if you only want YouTube / web / file analysis —
those work with only an AI key.

Full install matrix (Windows / ffmpeg / dev install / editable) is in
[`docs/install.md`](docs/install.md).

## Self-hosted Telegram bot

Run the same pipeline as a Telegram bot. Forward it a voice message
you don't feel like listening to, a PDF you don't feel like reading, a
YouTube link, a `t.me/...` post from a channel you're not sure you
want to subscribe to, or that suspicious link a friend just sent —
you get a Markdown summary back as a document, with cost and timing
in the caption.

<p align="center">
  <img src=".github/examples/bot.jpg" alt="Bot replying with a voice-message summary, attaching the PDF report" width="320">
</p>

Single-user by design: the bot only answers ONE Telegram ID. The
allowlist is auto-derived from the user session you give it (mounted
or sent via `/upload_session`); `UNREAD_BOT_OWNER_ID` is only a
bootstrap fallback for the case where no session is installed yet.
Everyone else is silently dropped.

Three install paths — pick by environment:

**1. Local laptop / dev** (`unread bot run` foreground):
```bash
uv tool install unread
export UNREAD_BOT_TOKEN=123:abc...   # from @BotFather
unread bot run
```

**2. Fresh Linux VM** — one line, blank disk to running systemd service:
```bash
curl -fsSL https://raw.githubusercontent.com/maxbolgarin/unread/main/scripts/install-bot.sh | bash
```
Installs uv + ffmpeg + libpango, runs `unread init`, asks for the
`@BotFather` token, drops a `systemd --user` unit that auto-restarts
on crash and survives SSH disconnect.

**3. Docker** — pull the generic `unread` image from GHCR (same image
can also run one-off CLI commands; `command: ["unread","bot","run"]`
in the compose file specifies the bot mode):
```bash
cp .env.bot.example .env.bot && $EDITOR .env.bot
docker compose -f docker-compose.bot.yml --env-file .env.bot up -d
```

Reports default to PDF; set `UNREAD_BOT_REPORT_FORMAT=md` in `.env.bot`
to skip PDF rendering (`.md` upload instead). The first time you
message the bot with a `t.me/...` link it'll ask for `/upload_session`
— send your laptop's `~/.unread/storage/session.sqlite` as a Telegram
document and it's ready.

Full feature reference (slash commands, the confirm panel, what each
input kind does) is in [`docs/bot.md`](docs/bot.md). End-to-end VM
deployment guide covering all three paths is in
[`docs/bot-vm-deploy.md`](docs/bot-vm-deploy.md).


## Why this exists

I 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.

## The boring but real bits

- **Local-first.** SQLite under `~/.unread/`. 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.
- **Citations on every claim.** Reports link back to the source message / paragraph / timestamp. `--cite-context N` expands citations into `<details>` blocks 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` shows the hit rate.
- **Cost guardrails.** `--max-cost 0.50` aborts or confirms before you spend more than that. `--dry-run` estimates without calling the model. `unread stats` shows lifetime spend by chat / preset / day.
- **PII redaction.** `--redact` scrubs 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`, `--with-comments`, `--folder Work`.

Encryption modes (`keystore`, passphrase-derived `pass`), session
hygiene, and the threat model are documented in
[`docs/security.md`](docs/security.md).

## FAQ

**Does this ship my Telegram history to OpenAI?**
Only the messages in the window you asked about, only after PII
redaction if you set `--redact`, and only to the provider whose key you
configured. Nothing else leaves the machine. The local cache is in
your install dir; you can wipe it any time with `unread cache ai purge`.

**What if I don't use Telegram?**
Skip `unread init`'s Telegram step. `unread <url>` and `unread <file>`
work with only an AI key. Most of the codebase is source-agnostic.

**What languages does it actually support?**
Source content: anything Whisper auto-detects (audio) or your LLM can
read (text) — pretty much everything human languages cover. Reports:
anything your LLM can write. EN and RU get hand-tuned preset
structures; other report languages use the English preset as a
template that the LLM translates on the fly.

**Will it cost me money?**
Yes — your AI provider charges. `unread` itself is free. Per-call USD
is logged; `--max-cost N` caps a single run. Re-running an unchanged
chat is free (local cache hit). With cheap models (`gpt-5.4-mini`-class,
Gemini Flash, Claude Haiku) the bill is small enough that most users
stop reading the cost reports after a week.

**Is it actually fast?**
Fast enough that I stopped reading group chats. No benchmark table —
speed depends on chat size, model choice, and your network. Try it
with `unread @somegroup --last-days 1 --dry-run` to see the estimate
before any LLM call.

**Can I run it on a server / in cron?**
Yes. Non-TTY mode skips interactive prompts. `unread watch --interval 1h ...`
loops in the foreground (run under tmux / systemd / nohup). API keys
can come from env vars or `~/.unread/.env`. The passphrase backend
reads `UNREAD_PASSPHRASE` for headless unlock.

**Can I plug in my own preset / prompt?**
`--preset custom --prompt-file my-prompt.md`. Same frontmatter format
as the bundled ones in [`presets/`](presets/). Bump `prompt_version`
in the frontmatter when you edit, otherwise the cache won't notice.


## Deep docs

The full reference manual lives under `docs/`:

| Topic | File |
|---|---|
| Install on macOS / Linux / Windows + first-run setup + where files live | [`docs/install.md`](docs/install.md) |
| Sources: Telegram refs, YouTube, web pages, local files, forums, media enrichment, presets | [`docs/sources.md`](docs/sources.md) |
| Every CLI command, every flag, the wizard, `watch`, subscriptions | [`docs/reference.md`](docs/reference.md) |
| Languages, cost & caching, `config.toml`, maintenance, troubleshooting, architecture | [`docs/configuration.md`](docs/configuration.md) |
| Threat model, encryption backends, PII redaction, session hygiene | [`docs/security.md`](docs/security.md) |

Useful inline help: `unread --help`, `unread <subcommand> --help`,
`unread help`, `unread doctor`.

## Contributing

PRs welcome. Read [`CLAUDE.md`](CLAUDE.md) first — it's the contributor
map (DB invariants, cache keys, preset version bumps, the three
language axes). [`CONTRIBUTING.md`](CONTRIBUTING.md) covers the bench
(lint / format / tests). [`SECURITY.md`](SECURITY.md) for vulnerability
reports.

```bash
uv sync --extra dev
uv run pytest -q
uv run ruff check . && uv run ruff format --check .
```

Issues and feature requests: <https://github.com/maxbolgarin/unread/issues>.

## Credits

Standing on the shoulders of:
[Telethon](https://github.com/LonamiWebs/Telethon) for the Telegram side,
[OpenAI Whisper](https://platform.openai.com/docs/guides/speech-to-text) /
[Anthropic](https://www.anthropic.com/) /
[Google Gemini](https://ai.google.dev/) /
[OpenRouter](https://openrouter.ai/) /
[Ollama](https://ollama.com/) for the LLM side,
[yt-dlp](https://github.com/yt-dlp/yt-dlp) for YouTube,
[trafilatura](https://github.com/adbar/trafilatura) for article extraction,
[tiktoken](https://github.com/openai/tiktoken) for token counting,
[Typer](https://github.com/tiangolo/typer) /
[Rich](https://github.com/Textualize/rich) /
[structlog](https://www.structlog.org/) for the CLI shell,
and [uv](https://github.com/astral-sh/uv) for keeping all of the above
out of your system Python.

## License

Apache 2.0 — see [LICENSE](LICENSE).
