Skip to content

Add optional Telegram capture bot companion app#60

Merged
imonroe merged 2 commits into
mainfrom
claude/ob1-capture-bot
Jun 5, 2026
Merged

Add optional Telegram capture bot companion app#60
imonroe merged 2 commits into
mainfrom
claude/ob1-capture-bot

Conversation

@imonroe
Copy link
Copy Markdown
Owner

@imonroe imonroe commented Jun 4, 2026

Summary

Adds an optional capture bot so you can save a thought into memory by sending a Telegram message — frictionless capture from your phone. Adapts the OB1 / Open Brain chat-capture integration (backlog issue #55) to this server.

It's a separate, port-less CapRover app (like backup//digest/). It long-polls the Telegram Bot API — no inbound webhook, no public port — and stores each message via POST /api/v1/memories, tagged agent_id=capture:telegram.

Security (single-user, high-trust store)

The bot only saves messages from an allowlist of Telegram chat IDs (TELEGRAM_ALLOWED_CHAT_IDS). With the allowlist blank it runs in discovery mode — it replies with your chat id and stores nothing — so you can authorize yourself on first run without leaking write access. Anyone not on the allowlist is refused.

How it works

long-poll getUpdates → for each message: classify → auth-check → POST /api/v1/memories → reply.

  • Plain text is saved as-is; /note <text> (and /save, /remember) also work; /start and /help show usage.
  • Self-contained (httpx only); nothing from app/ or the main image.
  • The run() loop is resilient: transient Telegram/API errors back off and retry, and one bad update can't kill the loop.

Files

  • capture/capture.py — pure helpers (parse_allowed_chat_ids, extract_message, classify, process_update) + run().
  • capture/Dockerfile (python:3.12-alpine long-running worker), requirements.txt, captain-definition.

Tests

  • tests/test_capture.py11 cases: allowlist parsing, message/edited-message extraction, command classification, respx-mocked getUpdates/post_memory (bearer + provenance)/sendMessage, and process_update for the authorized-save, unauthorized-reject, discovery-mode, help, empty-note, and non-text-update paths.
  • Full suite: 132 passed, ruff clean. Verified the required-env guard exits non-zero.

Docs

  • User Guide: "4. Deploy the capture bot (optional)" with the BotFather + discovery-mode setup flow, env-var table, a security note, and a docker run example; plus troubleshooting rows.
  • Developer Guide: project-layout entry. CLAUDE.md: companion-app note.

Architecture notes

No changes to the main app, its invariants, or runtime deps. The bot is just another authenticated REST client in its own container. Extending to Slack slash commands / Discord bots is straightforward: parse the inbound message, then call the same endpoint.

Closes #55.

https://claude.ai/code/session_017835DVrvURaYnbQiPQwzue


Generated by Claude Code

A separate, port-less CapRover app that lets you save a thought into memory by
sending a Telegram message. It long-polls the Telegram Bot API (no inbound
webhook/port needed) and stores each message via POST /api/v1/memories, tagged
agent_id=capture:telegram. Adapts the OB1 project's chat-capture integration.

Security: the store is single-user and high-trust, so the bot only saves
messages from an allowlist of chat IDs (TELEGRAM_ALLOWED_CHAT_IDS). With the
allowlist blank it runs in discovery mode — it replies with your chat id and
stores nothing — so you can authorize yourself on first run.

- capture/capture.py: pure, unit-tested helpers (parse_allowed_chat_ids,
  extract_message, classify, process_update) + a resilient run() long-poll loop
  that survives transient errors and bad updates. Self-contained (httpx only).
- capture/Dockerfile (python:3.12-alpine worker), requirements.txt, captain-definition.
- tests/test_capture.py: 11 cases (helpers + respx-mocked getUpdates/post_memory/
  sendMessage + process_update auth/discovery/help/empty/non-text paths).
- docs: USER_GUIDE deploy section (BotFather + discovery flow, env table,
  security note, docker run) + troubleshooting rows; DEVELOPER_GUIDE layout;
  CLAUDE.md companion-app note.

Closes #55.

https://claude.ai/code/session_017835DVrvURaYnbQiPQwzue
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds an optional, standalone “capture” companion app that long-polls the Telegram Bot API and forwards authorized chat messages to memserv via POST /api/v1/memories with provenance agent_id=capture:telegram, plus tests and documentation to support deployment and operation.

Changes:

  • Added a new capture/ companion app (Dockerized) implementing Telegram long-polling, allowlist/discovery-mode authorization, and REST writes to /api/v1/memories.
  • Added a dedicated pytest suite for capture parsing/classification and network interactions (Telegram + memserv) using respx.
  • Updated user/developer docs and CLAUDE.md to describe deploying and maintaining the new optional capture bot.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/test_capture.py Adds unit + mocked-network coverage for the capture bot helpers and update processing.
docs/USER_GUIDE.md Documents CapRover + Docker deployment, env vars, security notes, and troubleshooting for the capture bot.
docs/DEVELOPER_GUIDE.md Adds capture/ to the repository layout documentation.
CLAUDE.md Notes capture/ as a companion app and summarizes its behavior/config.
capture/requirements.txt Defines the capture app’s minimal dependency set (httpx).
capture/Dockerfile Builds a long-running worker image for the capture bot.
capture/capture.py Implements allowlist/discovery-mode auth, Telegram polling, message parsing/classification, and REST posting to memserv.
capture/captain-definition CapRover build descriptor for the capture app.
capture/__init__.py Marks capture/ as an importable package for the test suite.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread capture/capture.py
Comment thread capture/capture.py
Comment thread capture/capture.py
… validate poll timeout

- get_updates(): Telegram reports errors as HTTP 200 with {"ok": false}; treat
  non-ok / non-dict bodies as errors so the run loop logs and backs off instead
  of silently idling (e.g. on an invalid token).
- process_update(): on a save failure, send the user a stable, non-revealing
  message and keep the full exception in logs only (no URL/detail disclosure).
- TELEGRAM_POLL_TIMEOUT: parse via a validating _int_env() that fails fast with a
  clear message on a non-integer or non-positive value, instead of a traceback.
- tests: get_updates ok:false raises, _int_env validation, and the generic
  save-failure message (asserts no internal detail leaks).

https://claude.ai/code/session_017835DVrvURaYnbQiPQwzue
@imonroe imonroe merged commit c988306 into main Jun 5, 2026
1 check passed
@imonroe imonroe deleted the claude/ob1-capture-bot branch June 5, 2026 01:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Chat capture bot integration (Slack / Telegram / Discord → REST quick-capture)

3 participants