Slack support bot that answers from your Supabase knowledge base

When your bot is @mentioned in Slack, it answers from your Supabase knowledge base with cited sources, or files a Linear ticket when it isn't sure.

Agentic Task
Slack BotSupabaseLinearCustomer SupportFeedback Triage

Build a Slack support bot that answers questions from my Supabase knowledge base using retrieval-augmented generation, and escalates to Linear when it isn't confident.

Trigger: a Slack events webhook for app_mention. The workflow should fire whenever the bot is @mentioned in any channel it has been added to. Use the slackbot integration (bot token) so the bot has its own identity in the workspace.

When an @mention comes in, do the following:

1) Extract the user's question from the event text, stripping out the bot's own @mention. Capture channel, message ts, and thread_ts (fall back to ts if no thread_ts) so we can reply in the right thread.

2) Generate a vector embedding of the question. Use the same embedding model that was used to populate the knowledge base table (typically OpenAI text-embedding-3-small at 1536 dims). Make the embedding model configurable.

3) Call a Postgres function in Supabase via Call Function (RPC). The default function name is match_documents, taking arguments { query_embedding, match_threshold, match_count }. Defaults: match_threshold = 0.75, match_count = 5. The function is expected to run pgvector cosine similarity against a knowledge_base table and return ranked rows with at least these fields: id, content, title (or source/url), and similarity. Both the function name and the threshold should be tunable parameters at the top of the workflow.

4) Inspect the top result's similarity score. If it is at or above the threshold, synthesize a grounded answer using only the returned passages. The answer should be short and direct, cite the source doc titles inline (e.g. "Source: Refund policy"), and never invent facts that aren't in the passages. If multiple passages are relevant, weave them together rather than dumping them.

5) Post the answer back to Slack with slackbot's Send a Message operation, using the original channel and thread_ts so the reply lands inside the question's thread. Use Slack mrkdwn formatting (single asterisks for bold, <url|text> for links).

6) If the top similarity is below the threshold (low confidence), do NOT guess. Instead: (a) call Get Permalink on the original Slack message to get a thread link, (b) create a Linear issue using Create Issue with title "[Support] " plus a short version of the question, description containing the full question and the Slack permalink, and label "support-handoff". Default to the configured Linear team. Then post a short message in the Slack thread letting the user know a teammate has been pulled in, and include the Linear issue URL.

Configuration knobs the workflow should expose at the top: Supabase function name (default match_documents), confidence threshold (default 0.75), match_count (default 5), embedding model (default text-embedding-3-small), Linear team key, Linear label (default support-handoff), and an optional Linear default assignee.

Note for setup: the user is responsible for having a knowledge_base table with an embedding column (vector(1536) using pgvector) and a Postgres function that performs cosine similarity. The canonical version is in the Supabase pgvector RAG guide: a function that takes (query_embedding vector, match_threshold float, match_count int) and returns rows ordered by 1 - (embedding <=> query_embedding) descending. The agent should mention this in the setup notes if the function doesn't exist yet.

Edge cases to handle: ignore the Slack events url_verification challenge correctly, ignore mentions from the bot itself (bot_id present) to avoid loops, and ignore message_changed/edited subtypes. If the Supabase RPC returns zero rows, treat it as low confidence and escalate.

Additional information

What does this prompt do?
  • Listens for @mentions of your support bot in any Slack channel it has been added to
  • Searches your Supabase knowledge base by meaning, not just keywords, and pulls the most relevant passages
  • Posts a grounded answer back in the original thread with links to the source docs it used
  • If no good match exists, opens a Linear ticket tagged support-handoff so a human teammate can take over
What do I need to use this?
  • A Slack workspace where you can invite and @mention a bot
  • A Supabase project with your docs already loaded as embeddings, plus a small Postgres function (commonly called match_documents) that returns the closest matches for a question
  • A Linear workspace and a team you want support handoff tickets filed into
  • A confidence threshold you are comfortable with for when the bot should answer vs. escalate (we default to 0.75)
How can I customize it?
  • Raise or lower the confidence threshold to control how often the bot escalates vs. answers on its own
  • Point it at a different Supabase table or function name if your knowledge base lives somewhere other than match_documents
  • Change the Linear team, label, or default assignee that handoff tickets get filed into
  • Adjust the answer style, for example concise bullet points vs. longer prose, or whether to include source titles inline

Frequently asked questions

Do I need to load my docs into Supabase first?
Yes. The bot reads from a Supabase table where each row is a chunk of your docs plus a vector embedding. Most teams run a one-off script that splits their docs into chunks, generates embeddings, and inserts them into a table like knowledge_base. Supabase's own docs walk through this end to end.
What is match_documents and do I have to call it that?
It is a small Postgres function in your Supabase project that takes a question's embedding and returns the closest matching rows from your knowledge base. The name is a convention from the Supabase pgvector guide, but you can call yours anything. Just tell the workflow which function to use.
How does the bot decide when to escalate to Linear?
Every match comes back with a similarity score between 0 and 1. If the top score is below your confidence threshold (default 0.75), the bot opens a Linear ticket instead of guessing. You can raise the bar to escalate more, or lower it to let the bot answer more often.
Will the bot reply in the channel or in a thread?
Always in the thread, directly under the question. That keeps the channel tidy and scopes the conversation to a single issue, which makes it easy for a teammate to step in if needed.
Can I use this without Linear?
Yes. Swap Linear for any tracker your team uses, like Jira, GitHub Issues, or Notion, or have the bot DM a specific teammate instead of opening a ticket. Tell the workflow author what you want and it will wire it up.

Stop letting support questions slip through the cracks.

Connect Slack, Supabase, and Linear once. Geni answers from your own docs and routes the rest to a human.