Social & Community Channels
Social media and community platform integrations.
Prerequisites
- A Reddit account and a registered Reddit API application (script type)
Reddit runs as an out-of-process Python sidecar adapter (librefang.sidecar.adapters.reddit, ships in librefang-sdk).
Setup
- Go to reddit.com/prefs/apps and create a new script application. Note the client ID (shown under the app name) and the client secret.
- Open the dashboard Channels page, pick Reddit, and fill the form — the dashboard writes
REDDIT_CLIENT_SECRETandREDDIT_PASSWORDto~/.librefang/secrets.envand the rest of the fields to the[sidecar_channels.env]table in~/.librefang/config.toml. Equivalent manual config:
[[sidecar_channels]]
name = "reddit"
command = "python3"
args = ["-m", "librefang.sidecar.adapters.reddit"]
channel_type = "reddit"
default_agent = "assistant"
[sidecar_channels.env]
REDDIT_CLIENT_ID = "abc123"
REDDIT_USERNAME = "librefang-bot"
REDDIT_SUBREDDITS = "mysubreddit,rust"
REDDIT_USER_AGENT = "myorg/1.0 (by /u/myactual-reddit-name)" # REQUIRED, see below
# REDDIT_ACCOUNT_ID = "prod" # optional, multi-bot routing key
# REDDIT_POLL_INTERVAL_SECS = "30" # optional, default 30, floor 5
Ban-avoidance — read before going live
Reddit is strict about bot behaviour. The adapter enforces what it can:
REDDIT_USER_AGENTis required. Reddit's API rules require the UA to identify a real maintainer (by /u/<your-reddit-handle>). The literal default placeholder is rejected at startup to prevent IP+account bans. Use your own Reddit username.- Default 30 s polling. Lower than 5 s burns the 60 req/min/account budget fast. The floor is 5 s; raise
REDDIT_POLL_INTERVAL_SECSfor less-active subs. - Automatic throttling. When Reddit reports
X-Ratelimit-Remaining < 10, the poller pre-emptively sleeps until the reset window. A 429 on polling backs off; a 429 on/api/commenthonoursRetry-Afterand retries once.
What the adapter cannot enforce — your responsibility:
- Bot account should be at least 30 days old with >100 comment karma; new accounts get shadowbanned quickly.
- Get mod approval before joining any subreddit. Reply-bots in unfamiliar subs are a common report-and-ban trigger.
- Gate triggers via
group_trigger_patternsin your agent's config so the bot only replies to/cmdor named-mention — replying to every new comment is the fastest way to a sitewide ban.
- Put the two secrets in
~/.librefang/secrets.env:
REDDIT_CLIENT_SECRET=your-client-secret
REDDIT_PASSWORD=your-reddit-password
- Restart the daemon.
How It Works
The Reddit sidecar adapter authenticates via OAuth2 (password grant for script-type apps), polls each configured subreddit's new-comments stream every five seconds, and posts replies as comments through POST /api/comment. Reddit allows one comment per parent, so a chunked reply joins with \n\n---\n\n rather than splitting into multiple comments.
Mastodon
Prerequisites
- A Mastodon account on any instance
- An application access token (from the instance's Preferences > Development page, see Mastodon API docs)
Mastodon runs as an out-of-process Python sidecar adapter (librefang.sidecar.adapters.mastodon, ships in librefang-sdk).
Setup
- On your Mastodon instance, go to Preferences > Development > New Application.
- Grant the scopes
readandwrite. - Copy the access token (this becomes
MASTODON_ACCESS_TOKEN). - Open the dashboard Channels page, pick Mastodon, and fill the instance URL and access token — the dashboard writes
MASTODON_ACCESS_TOKENto~/.librefang/secrets.envandMASTODON_INSTANCE_URLto the[sidecar_channels.env]table in~/.librefang/config.toml. Equivalent manual config:
[[sidecar_channels]]
name = "mastodon"
command = "python3"
args = ["-m", "librefang.sidecar.adapters.mastodon"]
channel_type = "mastodon"
[sidecar_channels.env]
MASTODON_INSTANCE_URL = "https://mastodon.social"
# MASTODON_VISIBILITY = "unlisted" # public | unlisted | private | direct
# MASTODON_MAX_MESSAGE_LEN = "500" # raise for higher-limit instances
# MASTODON_ACCOUNT_ID = "prod" # optional, multi-bot routing
- The daemon supervises the sidecar — no manual restart is needed; the kernel's hot-reload spawns or replaces the subprocess on config change.
How It Works
The Mastodon sidecar connects to the instance's user streaming API via Server-Sent Events (SSE) to receive mention notifications in real time. On SSE failure it falls back to REST polling of /api/v1/notifications. Outbound replies are posted as toots via POST /api/v1/statuses with in_reply_to_id chaining so a chunked reply stays as one thread.
Bluesky
Prerequisites
- A Bluesky account (see Bluesky API docs)
- An app password (generated in Bluesky Settings > App Passwords)
Bluesky runs as an out-of-process Python sidecar adapter (librefang.sidecar.adapters.bluesky, ships in librefang-sdk).
Setup
- In Bluesky, go to Settings > App Passwords and create a new app password.
- Add a
[[sidecar_channels]]entry:
[[sidecar_channels]]
name = "bluesky"
command = "python3"
args = ["-m", "librefang.sidecar.adapters.bluesky"]
channel_type = "bluesky"
[sidecar_channels.env]
BLUESKY_IDENTIFIER = "your-handle.bsky.social"
# BLUESKY_SERVICE_URL = "https://bsky.social" # custom PDS
# BLUESKY_ACCOUNT_ID = "prod" # optional, multi-bot routing key
- Set the app password via the dashboard's Channels page (writes
BLUESKY_APP_PASSWORDto~/.librefang/secrets.env), or place it directly in your vault /.env. - Restart the daemon.
How It Works
The sidecar authenticates with com.atproto.server.createSession and refreshes the session JWT before expiry. It polls app.bsky.notification.listNotifications every 5 s (filtering mention + reply reasons) and posts replies via com.atproto.repo.createRecord using the app.bsky.feed.post lexicon. An in-memory LRU cache (capacity 200) maps inbound notification URIs to their {root, parent} reply refs so outbound responses thread back to the originating post; on a chunked reply every chunk reuses the same reply ref to keep the thread tight.
Twitch
Prerequisites
- A Twitch account and an OAuth token with chat permissions (from the Twitch Developer Portal)
Twitch runs as an out-of-process Python sidecar adapter (librefang.sidecar.adapters.twitch, ships in librefang-sdk).
Setup
- Register an application on the Twitch Developer Console.
- Generate an OAuth token with the
chat:readandchat:editscopes (use a tool like twitchtokengenerator.com). - Open the dashboard Channels page, pick Twitch, and fill the form — the dashboard writes
TWITCH_OAUTH_TOKENto~/.librefang/secrets.envand the rest of the fields to the[sidecar_channels.env]table in~/.librefang/config.toml. Equivalent manual config:
[[sidecar_channels]]
name = "twitch"
command = "python3"
args = ["-m", "librefang.sidecar.adapters.twitch"]
channel_type = "twitch"
default_agent = "assistant"
[sidecar_channels.env]
TWITCH_NICK = "librefang-bot"
TWITCH_CHANNELS = "channel1,channel2" # comma-separated, no '#'
# TWITCH_ACCOUNT_ID = "prod" # optional, multi-bot routing
# TWITCH_RATE_LIMIT_MSGS = "20" # 20/30s for unmodded; 100 if bot is mod
# TWITCH_RATE_LIMIT_SECS = "30"
- Put the OAuth token in
~/.librefang/secrets.env:
TWITCH_OAUTH_TOKEN=oauth:your-token
The oauth: prefix is auto-added if you leave it off. Restart the daemon.
Security — read before going live
- TLS is the default. The sidecar connects to
irc.chat.twitch.tv:6697and wraps the socket withssl.create_default_context(). The previous in-process Rust adapter used plaintext port 6667, which leaked the OAuth token on every connect / reconnect — operators upgrading from a pre-migration release immediately get this fix. - Per-message reply threading is enabled. The sidecar requests the
twitch.tv/tagscapability so every inbound PRIVMSG carries an@idtag; outbound replies attach@reply-parent-msg-id=<id>so Twitch renders the bot's response threaded under the source message. - Send rate-limiter. Twitch's anti-spam logic drops a non-mod account from chat above 20 msgs / 30 s (100 / 30 s if mod). The sidecar throttles every PRIVMSG through an in-process token bucket. Operators with a mod-status bot can raise via
TWITCH_RATE_LIMIT_MSGS=100; multi-process operators should still keep one process per account because the throttle is local-only.
How It Works
The Twitch sidecar adapter holds a persistent TLS IRC connection to irc.chat.twitch.tv:6697, authenticates via PASS oauth:<token> / NICK, requests the twitch.tv/tags twitch.tv/commands capabilities, and joins every configured channel. It parses inbound PRIVMSG frames (including the IRCv3 @-tag block), surfaces the @id tag as thread_id for round-trip threading, dedupes by tag id, and routes /cmd / !cmd lines as Commands. Outbound on_send calls pass through the rate-limit bucket and emit PRIVMSG frames with the reply-parent tag when the daemon supplied a thread_id.