Skip to content

Repository files navigation

image indigest
a Slack bot that curates messages into digestible RSS feeds & APIs while enabling cross-channel message forwarding via pub-sub style commands

how does this work?

  1. the bot is added to any channel
  2. a channel manager or bot admin runs /in pub
  3. messages get approved manually by posters ('yep'/'nope' buttons) or automatically (auto-approve) for high-trust channels
  4. approved messages are served via RSS/JSON/Webhooks
  5. if configured, extra metadata can be set through a Slack form modal
  6. managers of other channels can run /in sub to receive forwarded copies of approved messages
wait, but how does it do that?
  • ts
  • bun
  • hono
  • cf workers
  • postgres (hosted on hc infra / orchard)
  • oRPC
  • drizzle orm
  • zod
  • better auth
  • various slack sdks
  • vite
  • react (planning to switch to svelte or preact at some point)
  • react flow

map of the network

see a node graph mapping the channels currently using indigest in Hack Club at https://indigest.matmanna.dev

image

how do i use this?

tldr: if you forget what to do, run /in

image

Note

auto-publish will soon only be available to whitelisted "trusted" channels

command description
/in Show help message with all commands
/in pub Enable manual mode (buttons on every message)
/in pub auto Enable auto-approve for all users
/in pub auto @user Enable auto-approve for a specific user
/in pub manual Explicitly enable manual mode (clears auto-approve)
/in unpub Disable indigest for a channel
/in unpub auto [@user] Remove auto-approve for a user (or all users)
/in sub #channel Subscribe this channel to receive forwarded messages from #channel
/in unsub #channel Unsubscribe this channel from #channel
/in status Show pub status, feed URLs, subscriptions, and permissions
/in webhook <url> Set webhook URL for approved messages
/in webhook clear Remove webhook
/in auto list List auto-approve users
/in schema set <json> Set metadata schema (see below)
/in schema get View current metadata schema
/in schema clear Remove metadata schema
/in schema required on|off Require metadata before forwarding messages

publishing

manual, per-message, opt-in publishing:

image

permission structure:

  • channel manager - can run all commands unless lockdown mode enabled
  • lockdown override - listed in LOCKDOWN_USERS, can always run all commands
  • channel member - can only view status and public feed URLs
image

subscriptions

if channel A subscrbies to channel B, when a message is approved in channel B, it is automatically forwarded to channel A as a new Slack message (either posted as a forward or with the original author's name, message, and profile picture.

Note

exceptions to publishing: messages that are empty, contain only a link, or are @here/@channel pings (when recent substantive content exists) are not forwarded.

setting metadata

channel managers can define a metadata form that opens in a modal when someone clicks Yep! on a message in manual mode.

image
/in schema set {"title":"Message Metadata","fields":[
  {"action_id":"title","label":"Title","type":"plain_text_input","placeholder":"Enter a title"},
  {"action_id":"description","label":"Description","type":"plain_text_input","multiline":true},
  {"action_id":"priority","label":"Priority","type":"static_select","options":[{"label":"Low","value":"low"},{"label":"High","value":"high"}]},
  {"action_id":"due_date","label":"Due Date","type":"datepicker"}
]}

metadata field types:

Type Notes
plain_text_input Supports multiline, min_length, max_length, placeholder, initial_value
url_text_input URL validation built in
email_text_input Email validation built in
number_input Integer only
static_select Single select, requires options array with {label, value}
multi_static_select Multi-select, requires options array
datepicker Date picker
file_input File upload (uploaded to Hack Club CDN if key is set)

webhooks

when a message is approved, fires POST to the webhook URL:

{
  "event": "message.approved",
  "channel": { "id": "C123", "name": "general" },
  "message": {
    "ts": "1234567890.123456",
    "user_id": "U456",
    "user_name": "alice",
    "text": "the message text",
    "timestamp": "2025-01-01T00:00:00.000Z",
    "metadata": { "title": "My Title", "priority": "high" }
  }
}

feeds

  • RSS: https://your-host/feed/{channel_id}
  • JSON: https://your-host/feed/{channel_id}.json?limit=50&offset=0

query parameters: limit (max 200, default 50), offset (default 0).

REST API

interactive API docs can be found at https://indigest.matmanna.dev/docs.

development

use either docker or wrangler dev

# Drizzle Studio (browse DB)
docker compose run app bun run db:studio

# Cloudflare Worker
npx wrangler dev        # local dev
npx wrangler deploy     # deploy to Cloudflare

deploy

npx wrangler login
npx wrangler secret put SLACK_BOT_TOKEN
npx wrangler secret put SLACK_SIGNING_SECRET
npx wrangler secret put DATABASE_URL
npx wrangler deploy

env vars

see .env.example

horizons ai use

while blindly vibecoding was avoided, post-initial planning and feature abstraction, ai agents (eg opencode) were used significantly especially for prototyping features, implementing tests, performing database tasks.

About

privacy-concious slack bridge for api, webhook, rss, and pub/sub 🪠

Topics

Resources

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages