Telegram bot built with Scala 3 and ZIO.
It polls engineering RSS and Atom feeds, stores state in local JSON files, publishes new posts to Telegram, and can forward published posts into NotebookLM through Telegram commands.
scala-bot/- main Scala applicationscala-bot/src/main/scala/bot/- feed fetching, state management, Telegram publishingscala-bot/src/main/scala/bot/notebooklm/- NotebookLM command handling and CLI integrationflake.nix- Nix development shell and helper commands
TELEGRAM_BOT_TOKEN
Optional:
TELEGRAM_CHAT_ID
If TELEGRAM_CHAT_ID is not set, send the bot any private message and it will register that chat automatically.
NotebookLM support uses the external notebooklm CLI from the unofficial notebooklm-py project.
Recommended setup with Nix:
nix develop
setup-notebooklm
export NOTEBOOKLM_COMMAND="$PWD/scala-bot/.venv-notebooklm/bin/notebooklm"
export PATH="$PWD/scala-bot/.venv-notebooklm/bin:$PATH"
export PLAYWRIGHT_BROWSERS_PATH="$PWD/scala-bot/.playwright-browsers"
notebooklm loginThis keeps the Python package and Playwright browser assets inside the project directory while system dependencies come from the Nix shell.
Common Telegram commands:
/nb create <title>
/nb notebooks
/nb switch <id|title>
/nb remember <id> [title]
/nb add https://example.com/post
/nb add
/nb ask <question>
/nb summary
/nb history
/nb sources
/nb report [--lang en] [--format study-guide] [--length ...] [--style ...] [instructions]
/nb artifacts
/nb artifact <id>
/nb forget
/clearnotes
Main reply flow:
- Let the bot publish a post.
- Reply to that Telegram message with
/nb add. - The bot sends the original article URL to your active NotebookLM notebook.
/clearnotes removes tracked NotebookLM commands and replies from the private chat without deleting published blog posts.
Example flow:
Published engineering post in Telegram:
Reply-based NotebookLM workflow in Telegram:
Generated NotebookLM study guide:
Report flags:
--langor--languagesets the NotebookLM output language--format briefing-doc|study-guide|blog-post|customselects the report format--length short|medium|longappends a length hint--style executive|technical|academic|briefappends a style hint unless it maps to a real NotebookLM report format
Examples:
/nb report --lang en --format study-guide
/nb report --lang en --length long --style executive Focus on risks and trade-offs
nix develop
cd scala-bot
export TELEGRAM_BOT_TOKEN=...
export NOTEBOOKLM_COMMAND="$PWD/.venv-notebooklm/bin/notebooklm"
sbt runcd scala-bot
export TELEGRAM_BOT_TOKEN=...
./run.shIf scala-bot/.env exists, run.sh loads it automatically.
export STATE_FILE=./data/state.json
export NOTEBOOK_STATE_FILE=./data/notebook_state.json
export FETCH_INTERVAL_MINUTES=30
export PUBLISH_INTERVAL_SECONDS=30
export POSTS_PER_PUBLISH_CYCLE=1
export MAX_POSTS_PER_SOURCE=1
export POST_DESCRIPTION_LENGTH=1200
export TELEGRAM_UPDATES_TIMEOUT_SECONDS=25
export PUBLISHED_TELEGRAM_MESSAGE_LIMIT=500
export NOTEBOOKLM_COMMAND=notebooklmThe bot stores:
- known post GUIDs
- unpublished post queue
- published post counter
- registered private chat id
- Telegram
getUpdatesoffset - recent Telegram
message_id -> blog post linkmappings - per-user NotebookLM state in
NOTEBOOK_STATE_FILE
Default state path: scala-bot/data/state.json.
Default behavior is intentionally conservative:
MAX_POSTS_PER_SOURCE=1POSTS_PER_PUBLISH_CYCLE=1PUBLISH_INTERVAL_SECONDS=30
Telegram limits still apply:
- text message limit:
4096characters - photo caption limit:
1024characters


