Skip to main content

Local-first chat synopsis tool for Telegram and WhatsApp.

Project description

chat-synopsis

CI PyPI Python License: MIT

Chat synopsis tool for engineering managers. Works on Telegram and WhatsApp.

Cuts 10 to 20 minutes of manual chat review down to one command. Generates themed synopses of recent chats with teammates, grouped by project, pending action items at the top.

chat-synopsis angel
chat-synopsis angel last 7 days
chat-synopsis team
chat-synopsis angel,rohit,fasna since 2026-05-15

Renamed from telegram-synopsis in v1.2.0. The old tg-synopsis command still works as an alias for one release.

At a glance

Channel MCP server Extra deps
Telegram chigwell/telegram-mcp none
WhatsApp lharries/whatsapp-mcp Go ≥ 1.23, C compiler

Pick a channel in config.toml with channel = "telegram" or channel = "whatsapp". The MCP server has to be running before chat-synopsis can read messages.

Features

  • Multi-channel. Telegram and WhatsApp share the same pipeline, the same cache, and the same CLI. Channel comes from config.
  • Local SQLite cache. Append-only chat history is fetched once and served locally.
  • Voice note transcription. Gemini 2.5 Flash transcribes voice notes in ML + EN format.
  • Image and screenshot description. Gemini Vision describes photos and extracts on-screen text (OCR) so screenshots, dashboards, and UI mocks contribute real signal to the synopsis.
  • Video keyframe summarization (opt-in via --with-video). ffmpeg pulls 3 keyframes per clip, Gemini describes the whole thing in one call.
  • Needs Your Attention callout. Bidirectional ask detection surfaces what is pending on you vs them.
  • Themed synopsis. Groups messages by project or topic, not chronologically.
  • Alias pinning. chat-synopsis pin angel <id1>,<id2> resolves angel to a fixed set of one or more chats. Multi-chat pins produce a single chronologically-merged synopsis.
  • Team dashboard. chat-synopsis team aggregates pending items across all teammates.
  • Hybrid color output. Semantic ANSI with Ghostty truecolor accent support.
  • Content-fingerprinted cache. Re-runs return instantly when nothing in the chat has changed. No LLM call.
  • Cost log. Every LLM call lands in a cost_log SQLite table with tokens and dollars. chat-synopsis cost --since 7d for the breakdown.

Install

pip install chat-synopsis     # or: uv tool install chat-synopsis

# Install at least one MCP server (see below), then run guided setup
chat-synopsis init

# Check your setup
chat-synopsis doctor

Prerequisites:

  • ffmpeg. brew install ffmpeg. Only required when using --with-video.
  • GEMINI_API_KEY env var. For voice transcription and image / video description.
  • ANTHROPIC_API_KEY env var. For synopsis synthesis. The Claude Code skill bypasses this, see Claude Code skill.
  • One of the two MCP servers below.

Required MCP servers

chat-synopsis is a client for two MCP servers. Install at least one before running chat-synopsis init. Both are local-first: no chat data leaves your machine except the prompts you explicitly send to the LLM.

Telegram: chigwell/telegram-mcp

Repo: https://github.com/chigwell/telegram-mcp

git clone https://github.com/chigwell/telegram-mcp ~/Developer/telegram-mcp
cd ~/Developer/telegram-mcp && uv sync
export TELEGRAM_MCP_PATH=~/Developer/telegram-mcp

Register with Claude Code (optional, only needed if you also want to use it through Claude):

claude mcp add --scope user telegram-mcp -- uv --directory ~/Developer/telegram-mcp run main.py

First-run auth uses your phone number and an SMS code (Telethon).

WhatsApp: lharries/whatsapp-mcp

Repo: https://github.com/lharries/whatsapp-mcp

This one has a Go bridge (talks to WhatsApp Web) plus a Python MCP server. Both have to be built.

brew install go    # Go >= 1.23, also needs a C compiler for go-sqlite3

git clone https://github.com/lharries/whatsapp-mcp ~/Developer/whatsapp-mcp
cd ~/Developer/whatsapp-mcp/whatsapp-bridge && CGO_ENABLED=1 go build -o whatsapp-bridge .
cd ../whatsapp-mcp-server && uv sync
export WHATSAPP_MCP_PATH=~/Developer/whatsapp-mcp/whatsapp-mcp-server

Register with Claude Code (optional):

claude mcp add --scope user whatsapp-mcp -- uv --directory ~/Developer/whatsapp-mcp/whatsapp-mcp-server run main.py

First-run auth: run the bridge in a terminal, scan the QR code from WhatsApp on your phone (Settings → Linked Devices → Link a Device). Re-pair every ~20 days.

See docs/adapters.md for the full setup notes and the differences between channels.

Quick start

# First run indexes your chats (~60s for ~200 chats)
chat-synopsis angel

# Subsequent runs served from cache, ~5s (instant if nothing changed)
chat-synopsis angel

# Specific date range
chat-synopsis angel since 2026-05-15
chat-synopsis angel last 7 days

# Force re-fetch trailing 7 days
chat-synopsis --refresh angel

# Full team dashboard
chat-synopsis team

# HTML output
chat-synopsis angel --html

Alias pinning

When an alias matches multiple chats (say, both a group and a 1:1 with someone named Angel), chat-synopsis picks the most plausible one and prints a footer on stderr with the pin command:

⚠ 'angel' matched 2 chats. Used: Alice and Bob (-1001234567890).
  Other candidates: Angel Ros (-1234567890).
  To pin: chat-synopsis pin angel -1001234567890

Pin once and the disambiguation is gone:

chat-synopsis pin angel -1001234567890
chat-synopsis pin ta -1003619333886,-5077997134 --name "TA Project"   # up to 3 chats
chat-synopsis pins                                                     # list all pins
chat-synopsis unpin angel                                              # remove a pin

Multi-chat pins are the most useful trick here. Messages from all pinned chats merge chronologically, get a [chat: <title>] prefix, and summarize into one synopsis. Helpful when a project lives across multiple groups.

Multimedia: screenshots, photos, video

Photos and screenshots get described by Gemini Vision and inlined into the prompt, including OCR text from UI screenshots. This runs as part of any normal chat-synopsis <alias> invocation. Results are cached in media_descriptions. Once described, a message is never re-described unless you ask.

# Default: describe photos automatically, skip videos
chat-synopsis angel

# Opt in to video (3 keyframes per clip via ffmpeg)
chat-synopsis --with-video angel

# Opt in to PDF documents (inline, capped at 10 MB)
chat-synopsis --with-documents angel

# Preview what would be described and the estimated cost, no Gemini calls
chat-synopsis --describe-dry-run angel

# Re-describe everything (e.g. after upgrading the model)
chat-synopsis --reprocess-media angel

# Inspect the describe cache
chat-synopsis media-stats

# Purge cached media descriptions (and invalidate affected synopses)
chat-synopsis purge-media rohit --yes
chat-synopsis purge-media --kind unknown --yes
chat-synopsis purge-media --older-than 30d --dry-run
chat-synopsis purge-media --all                # prompts for typed PURGE

Budget caps. Every run is capped (defaults: $0.05 cost, 50 items, 100 MB of media). Overflow items stay as [media message] until the next run. Override in [media] config:

[media]
process_video = false                       # also set via CHAT_PROCESS_VIDEO env var
process_documents = false                   # also set via CHAT_PROCESS_DOCUMENTS env var
max_describe_cost_usd_per_run = 0.05
max_describe_items_per_run = 50
max_describe_bytes_per_run = 104857600      # bytes (100 MB)
max_pdf_bytes = 10485760                    # bytes (10 MB), hard skip for PDFs above this
max_extracted_text_chars = 2000             # OCR truncation BEFORE DB write

Privacy note. Image descriptions and OCR text land in ~/.local/share/chat-synopsis/cache.db.nosync alongside voice transcripts. The file is chmod 600 on creation and cache.db.nosync* is in .gitignore. If you need to scrub a chat's stored descriptions, the table is media_descriptions keyed by (chat_id, message_id).

Cost log

Every LLM call writes a row to cost_log with token counts, dollars, the op name, the channel, and the chat ID. Inspect with:

chat-synopsis cost                       # all-time, grouped by op
chat-synopsis cost --since 7d            # last 7 days
chat-synopsis cost --group-by model      # which model is costing you most
chat-synopsis cost --group-by chat       # which teammate is the most expensive
chat-synopsis cost --group-by day        # daily timeline

Unknown models log tokens but a NULL cost. To update prices, edit src/chat_synopsis/core/cost.py. Raw token counts are preserved so historical costs can be recomputed.

How it works

  1. Alias resolution. angelAlice and Bob (group chat) via local index. Honors user pins (source='user') first, falls back to auto-aliases otherwise.
  2. Sync. Gap detection fetches only the missing intervals from the channel.
  3. Transcription. Voice notes: Scribi bot first (Telegram only), then Gemini Flash, then local Whisper as fallback.
  4. Description. Photos via Gemini Vision (single image, JSON output with optional OCR). Videos via ffmpeg keyframes plus Gemini, opt-in.
  5. Synopsis. Anthropic model synthesizes a themed markdown report. Or Claude Code itself, when invoked through the skill.
  6. Cache. Keyed on (chat_ids set, from_utc, options). Content fingerprint is the freshness gate, so re-runs within the same range never call the LLM unless messages actually changed.

Schema

Stored in ~/.local/share/chat-synopsis/cache.db.nosync (SQLite, chmod 600). Current schema is v4. v2 and v3 databases auto-upgrade in place via additive ALTER TABLE. v1 databases are still refused (the v1 → v2 jump was destructive):

Schema v1 detected; v4 required. v1 → v2 was destructive; run: chat-synopsis reset-db

chat-synopsis reset-db deletes the database (and its WAL/SHM siblings). It prompts for the literal string WIPE for confirmation. No --yes shortcut.

Config

~/.config/chat-synopsis/config.toml:

self_name = "Cherian Thomas"
self_timezone = "America/Chicago"
channel = "telegram"                              # or "whatsapp"
telegram_mcp_args = ["--directory", "/path/to/telegram-mcp", "run", "main.py"]
whatsapp_mcp_args = ["--directory", "/path/to/whatsapp-mcp/whatsapp-mcp-server", "run", "main.py"]

[media]
process_video = false
max_describe_cost_usd_per_run = 0.05
max_describe_items_per_run = 50

[probes]
enabled = false              # off by default, opt-in for MCP capability probing
probe_chat_id = ""

See docs/config.md for the full schema.

Claude Code skill

The repository ships a Claude Code skill at claude-code-skill/chat/SKILL.md that drives chat-synopsis from a /chat <name> invocation. The skill uses --dump-prompt plus --ingest so Claude generates the synopsis itself. No ANTHROPIC_API_KEY is required when using the skill.

Install by symlinking (or copying) the skill into your Claude Code skills directory:

ln -s "$(pwd)/claude-code-skill/chat" ~/.claude/skills/chat

After that, /chat angel, /chat team, etc. work inside Claude Code.

Adapters

The ChannelAdapter Protocol lets future contributors add Slack, Discord, etc. without forking. See docs/adapters.md and CONTRIBUTING.md.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chat_synopsis-1.2.0.tar.gz (251.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

chat_synopsis-1.2.0-py3-none-any.whl (75.7 kB view details)

Uploaded Python 3

File details

Details for the file chat_synopsis-1.2.0.tar.gz.

File metadata

  • Download URL: chat_synopsis-1.2.0.tar.gz
  • Upload date:
  • Size: 251.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for chat_synopsis-1.2.0.tar.gz
Algorithm Hash digest
SHA256 f74b6c1265c4a262167ca646d59d8e29ae09c6331761ef75dc69887305425179
MD5 bbb40b9ec2aa40641c94a4a2f92036cf
BLAKE2b-256 6ba4f2fc62471f433d37231458ac2a62fc32e8cc86eb64c819d2d91cfe18e50a

See more details on using hashes here.

Provenance

The following attestation bundles were made for chat_synopsis-1.2.0.tar.gz:

Publisher: release.yml on Lascade-Co/chat-synopsis

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chat_synopsis-1.2.0-py3-none-any.whl.

File metadata

  • Download URL: chat_synopsis-1.2.0-py3-none-any.whl
  • Upload date:
  • Size: 75.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for chat_synopsis-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 24e54e7cf94d63c33b38b90cdff34a5ccdcebc40d3b9f716c07dcabc1793cde1
MD5 5ca317e39cfc0de31344e8aab24efa91
BLAKE2b-256 57162374813653c216a0cc1ede3631473307b0027357e4a432890f11d80fc30b

See more details on using hashes here.

Provenance

The following attestation bundles were made for chat_synopsis-1.2.0-py3-none-any.whl:

Publisher: release.yml on Lascade-Co/chat-synopsis

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page