···11+# bufo-bot
22+33+bluesky bot that listens to the firehose and quote-posts matching bufo images.
44+55+## how it works
66+77+1. connects to bluesky jetstream (firehose)
88+2. for each post, checks if text contains an exact phrase matching a bufo name
99+3. if matched, quote-posts with the corresponding bufo image
1010+1111+## matching logic
1212+1313+- extracts phrase from bufo filename (e.g., `bufo-hop-in-we-re-going` -> `hop in we re going`)
1414+- requires exact consecutive word match in post text
1515+- configurable minimum phrase length (default: 4 words)
1616+1717+## configuration
1818+1919+| env var | default | description |
2020+|---------|---------|-------------|
2121+| `BSKY_HANDLE` | required | bluesky handle (e.g., `find-bufo.com`) |
2222+| `BSKY_APP_PASSWORD` | required | app password from bsky settings |
2323+| `MIN_PHRASE_WORDS` | `4` | minimum words in phrase to match |
2424+| `POSTING_ENABLED` | `false` | must be `true` to actually post |
2525+| `JETSTREAM_ENDPOINT` | `jetstream2.us-east.bsky.network` | jetstream server |
2626+2727+## local dev
2828+2929+```bash
3030+# copy and edit .env
3131+cp .env.example .env
3232+3333+# run locally (dry run by default)
3434+uv run bufo-bot
3535+3636+# or test matching against firehose
3737+uv run python -m bufo_bot.dry_run
3838+```
3939+4040+## deploy
4141+4242+```bash
4343+# set secrets (once)
4444+fly secrets set BSKY_HANDLE=find-bufo.com BSKY_APP_PASSWORD=xxxx -a bufo-bot
4545+4646+# deploy
4747+fly deploy
4848+4949+# enable posting
5050+fly secrets set POSTING_ENABLED=true -a bufo-bot
5151+5252+# disable posting
5353+fly secrets set POSTING_ENABLED=false -a bufo-bot
5454+5555+# check logs
5656+fly logs -a bufo-bot
5757+```
+2-1
bot/fly.toml
···1818 cpus = 1
19192020# secrets to set via: fly secrets set KEY=value -a bufo-bot
2121-# - BSKY_HANDLE (e.g., findbufo.bsky.social)
2121+# - BSKY_HANDLE (e.g., find-bufo.com)
2222# - BSKY_APP_PASSWORD (app password from bsky settings)
2323+# - POSTING_ENABLED=true (to enable posting, default is false)