Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

feedbot

Posts project activity to Telegram and Discord:

  • GitHub (webhooks): published releases and pushes to the default branch
  • X (polled every 5 min): new posts from each project's account (no replies or retweets)
  • Daily digest to an internal Telegram chat: 24h activity per project + any delivery problems

Design: docs/superpowers/specs/2026-10-15-feedbot-design.md.

One-time setup

  1. Telegram bot: create it with @BotFather and put the token in TELEGRAM_BOT_TOKEN. Add the bot as an admin of each announcement channel, and as a member of the internal digest chat. Public channels can be addressed as @name. For private chats, use the numeric id (-100…): send a message in the chat, then open https://api.telegram.org/bot<token>/getUpdates and read chat.id.
  2. Discord: in the channel go to Settings → Integrations → Webhooks → New Webhook → Copy URL. Put the URL in .env (e.g. DISCORD_OGEE_WEBHOOK=...) and reference it in projects.yaml as ${DISCORD_OGEE_WEBHOOK}.
  3. X: create an app on developer.x.com with pay-per-use credits and copy the bearer token into X_BEARER_TOKEN. Reading costs about $0.005 per post returned, so expect a few dollars a month for 10 accounts. If the credits run out, the digest chat gets one alert.
  4. GitHub: add one webhook per project (repo or org settings → Webhooks):
    • Payload URL https://<domain>/github/<project-slug>, content type application/json, and that project's secret (shown in the admin panel). Imported v1 projects keep the old shared secret until it is rotated.
    • Events: Releases and Pushes only
    • GitHub sends a ping, and the webhook page should show a green tick.
    • Put [skip feed] in a commit message to keep that commit out of the channels.

Configure

Configuration now lives in the database and is managed in the admin panel (Plan 2).

.env holds only FEEDBOT_MASTER_KEY (create it with python -m feedbot gen-key), DB_PATH and LISTEN:

cp .env.example .env

Existing v1 setups migrate once with python -m feedbot --env .env import-yaml projects.yaml. projects.example.yaml documents that format, and the v1 variables (GITHUB_WEBHOOK_SECRET, TELEGRAM_BOT_TOKEN, X_BEARER_TOKEN, DISCORD_*_WEBHOOK) go into .env just for that import.

Feedbot refuses to start on invalid config and says why.

Run locally

python -m venv .venv && source .venv/Scripts/activate   # Linux: .venv/bin/activate
pip install -e ".[dev]"
python -m pytest -q
python -m feedbot gen-key                                # put the key in .env as FEEDBOT_MASTER_KEY
# also in .env: DB_PATH=feedbot-dev.db
python -m feedbot --env .env import-yaml projects.yaml   # optional: import a v1 projects.yaml
python -m feedbot --dry-run                              # prints messages instead of sending
# in a second terminal (the project's secret goes in GITHUB_WEBHOOK_SECRET):
python scripts/send_test_event.py release_published.json --url http://127.0.0.1:8081/github/<slug>

.env.example sets DB_PATH=/var/lib/feedbot/feedbot.db (the VPS path), so for local runs set DB_PATH=feedbot-dev.db in your .env. Use a separate dev database: --dry-run marks outbox rows as sent in whichever database it uses. It still polls the real X API (billed) when a project has an x handle.

python -m feedbot --digest-now sends the digest once and exits.

Deploy (VPS with nginx + certbot)

The admin panel is served at https://bot.bookrunner.tech/admin from the same VPS as Leveret (148.113.237.230). Point a DNS record for bot.bookrunner.tech at it first. For the first install and every update:

  1. Build the upload: scripts/vps/pack.sh
  2. Copy it over:
    ssh <vps> mkdir -p feedbot-upload
    scp dist/feedbot.tgz scripts/vps/install.sh <vps>:feedbot-upload/
  3. Install: ssh <vps> 'bash ~/feedbot-upload/install.sh'. On the first run this creates /opt/feedbot/.env with a newly generated master key (plus DB_PATH and LISTEN) and never overwrites it afterwards. Back it up (sudo cat /opt/feedbot/.env): without the master key the stored secrets cannot be decrypted.
  4. First time only, issue the certificate: sudo certbot --nginx -d bot.bookrunner.tech
  5. First time only, create the admin account with the command install.sh prints at the end (sudo -u feedbot bash -c 'set -a; . /opt/feedbot/.env; cd /opt/feedbot/app; /opt/feedbot/venv/bin/python -m feedbot --env /dev/null create-admin --email you@example.com').
  6. Open https://bot.bookrunner.tech/admin and log in. Set the Telegram token, X bearer and digest in Settings. Create customers in Users, then projects.
  7. Optional, for a v1 config: run import-yaml projects.yaml once as the feedbot user with the env loaded (same sudo -u feedbot bash -c '...' wrapper as above, with import-yaml <path> instead of create-admin). pack.sh includes projects.yaml only if the file exists; the service itself no longer reads it, since the database holds the config.

Upgrading from feedbot v1

  1. Back up /opt/feedbot/.env and the database (the DB_PATH file it names) first.
  2. Run install.sh as above. It appends a new FEEDBOT_MASTER_KEY to the existing .env (back up the file again afterwards). If /etc/nginx/sites-available/feedbot.conf is the v1 site (no /admin location), it stops before changing anything and prints how to replace it: move the old file aside, re-run install.sh, then re-run certbot --nginx -d bot.bookrunner.tech.
  3. Right after, run import-yaml with the old projects.yaml (step 7). It links the queued v1 messages to the imported channels. Until then the service holds them back and rechecks hourly, for up to 24h; after that they are marked failed with waiting for import-yaml.

pack.sh tars feedbot/, so the admin templates and static files are included. Check with tar -tzf dist/feedbot.tgz | grep -c admin/templates.

install.sh also installs the login rate-limit zone (/etc/nginx/conf.d/30-feedbot-ratelimit.conf, 5 requests per minute per IP with a burst of 5) before adding the site. The nginx site does not include snippets/security-headers.conf: that snippet is shared with another site on the VPS and may set its own Content-Security-Policy, which would stack with the app's. The app already sends CSP, X-Frame-Options, Referrer-Policy and nosniff for /admin and /static; nginx adds only Strict-Transport-Security, which takes effect once certbot adds TLS.

Admin panel

  • Roles: an admin manages everything: settings, users, all projects and the audit log. A customer sees and changes only the projects they own; another customer's project returns 404 and admin-only pages return 403.
  • Customers manage their own projects' channels and repo, and see the webhook URL and secret on the project page (the secret is revealed by an explicit action, which is audited).
  • To restrict /admin to your own addresses, uncomment the allow/deny lines in the location ^~ /admin block of scripts/vps/feedbot.conf (in /etc/nginx/sites-available/feedbot.conf on the VPS, since install.sh writes the site only once), then sudo nginx -t && sudo systemctl reload nginx.
  • Locked-out admin: python -m feedbot --env /dev/null reset-password --email you@example.com (run with the env loaded, as for create-admin) sets a one-time temporary password and clears the login lockout for that email. Reset password on the Users page does the same.

Operations

  • curl -s http://127.0.0.1:8081/healthz returns the last X poll time and the outbox backlog. It answers 503 if the last X poll is more than 15 minutes old.
  • journalctl -u feedbot -f shows the logs.
  • python -m feedbot --env /opt/feedbot/.env rotate-key re-encrypts all stored secrets under a new master key and prints it on the last line. Stop the service first, then put the new key in .env and start it again.
  • Failed deliveries are retried for 24h, then listed under ⚠️ in the next digest.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages