renovate Bot cd5a04a930
renovate/stability-days Updates have met minimum release age requirement
chore(deps): update ghcr.io/astral-sh/uv:python3.13-trixie-slim docker digest to e586c1c
2026-10-28 04:02:03 +00:00
2026-09-09 01:17:12 +02:00
2026-09-09 01:17:12 +02:00
2026-09-09 01:17:12 +02:00
2026-09-09 01:17:12 +02:00

beavergram

A Telegram client that keeps everything and writes nowhere but your own Saved Messages. A userbot on your own account logs every incoming message into Postgres, including the ones later deleted or edited, along with media, reactions, presence and stories. A web client reads that archive back, and an MCP server hands it to agents.

Useful on its own: a Telegram where nothing disappears. In the beaver setup it is one of the agent's hands - the dispatcher reads chat history by the chat_id stored in a person's card.

What it keeps

  • Messages with edits as versions and deletions as flags, so a message removed in Telegram is still in the archive with its history.
  • Media on disk, content-addressed, with the versions of a replaced photo.
  • Voice transcribed through Telegram's own transcription (Premium), queued when the quota runs out: your own and the played ones by themselves, any voice or round video on request.
  • Presence as a time series (TimescaleDB), read receipts, stories.
  • Capture policy from your Telegram folders with per-chat overrides: channels nothing, groups messages only, private chats everything, by default.
  • Annotations and watches: your notes on messages, with #tags and one list of them all, and rules that fire alerts, both yours to write in the web client.
  • Watched bots: bot tokens you add in the web client. Each one logs in over MTProto (auth.importBotAuthorization, the same door a bot-login client uses), backfills the history of the bot's dialogs once and then keeps the incoming stream: who writes to the bot, what, and when. A separate authorization, so it does not take getUpdates away from whoever runs that bot over the Bot API.

Nothing is ever deleted from the archive.

Parts

  • backend/ - userbot (kurigram, the capture loop and jobs), watcher (kurigram again, one bot-token session per watched bot) and api (FastAPI: the web API, the MCP server, and the built frontend as static files).
  • frontend/ - SvelteKit, adapter-static; a chat client over the archive: folders, chat list, thread with media, versions and the deleted messages inline, a feed of what was deleted or edited across chats, search, stories, presence graphs.
  • docker-compose.yml - includes backend/ (Postgres with TimescaleDB, userbot, api) and frontend/ (the dev server); profiles external and services.

MCP

Read: search_messages_tool, list_chats, get_chat_history (a readable transcript, deleted messages included) and get_chat_history_raw (the same as JSON), get_deleted_messages, get_feed (deleted and edited messages and profile changes across chats), get_message_versions, get_media, get_callbacks, get_read_info, presence_history, presence_stats, get_peer_history, get_person, get_stories, get_annotations, list_watches, list_alerts.

Act: transcribe_message asks Telegram for the transcript of any voice or round video, set_watch writes a rule, download_media pulls any attachment and leaves a public link to it for a day, visible and revocable in the web client. send_to_saved is the one thing that sends to Telegram, and only to your own Saved Messages: text, a file by URL (as a voice message when asked), or an archived message, forwarded while it lives and copied from the archive once it is gone. Send any OGG/Opus there as a voice and transcribe_message turns Telegram Premium into a free transcriber. There is no tool that edits, deletes or sends anywhere else.

The same over HTTP: POST /api/media/transcribe (wait seconds to hold for the text), GET /api/media/lookup?sha256= (where these exact bytes appear in the archive), POST /api/saved (multipart account_id, text, file, voice) and POST /api/saved/forward.

Run

make env                                  # .env and docker-compose.override.yml from the examples
make -C backend session                   # log the account in once; the session file stays in backend/sessions
make -C backend migrate                   # the schema
make recreate                             # build and start the services in COMPOSE_PROFILES

COMPOSE_PROFILES in .env selects what runs on the machine, docker-compose.override.yml in each part holds the published ports and the caddy network aliases. The web client and the MCP endpoint are served by api; the bearer for both is AUTH__TOKEN.

Develop

make fmt
make check
make -C frontend dev
S
Description
Server-side AyuGram with MCP
Readme
1.9 MiB
0 Stars 2 Watchers 0 Forks
Languages
Svelte 40%
Python 39.9%
TypeScript 16.2%
SCSS 2.3%
CSS 1.3%
Other 0.1%