A Company Assistant That Lives Inside Slack — Technical Version

The problem

Your team asks the same questions every week. Where is the runbook. Who owns this project. What did we decide in that meeting.

The answers already exist somewhere in your systems. The real problem is finding them again, keeping the right people from seeing the wrong things, and getting the answer in front of someone without asking them to open a new app.

What we are building

An assistant that lives inside Slack and knows what your company knows. An employee tags Claude in any channel and asks a question. Claude searches your company’s data, finds the answer, and posts it back with links to the sources. The whole thing respects Slack permissions, so nobody sees anything they should not.

Nothing gets installed on anyone’s computer. It requires a one time setup in Slack. That is it.

How it works

We build three things, and we borrow one. This section covers each in more depth.

We build the pipes

Every source is a small program on a schedule that pulls information out of the source and writes it into one shared database. Slack sits at the center. A Socket Mode bot subscribes to message events, re-fetches the full thread every time a reply lands, and runs the thread through an LLM to extract a structured record: the question being asked, a short summary, the resolution if one was reached, systems mentioned, and code references. That structured record is what gets indexed, not the raw Slack text. The distinction matters, because raw chat is noisy and short messages beat detailed ones on similarity search.

Around Slack, connectors pull from Microsoft, Google Workspace, and your other existing sources. Each connector is generated by Printing Press, a framework that reads a service’s API docs and produces a working CLI in an hour instead of the two or three days it takes to hand-write one. Custom internal databases arrive as small Python plugins a team can submit in a pull request. Every source writes into the same row shape, so nothing downstream has to know which source a row came from.

We build the brain

One Postgres database with a pgvector column holds every row from every source. When a question comes in, four different search methods run in parallel: BM25 keyword matching for exact terms, vector similarity for meaning, rare-token scoring so a specific error message beats generic filler, and age decay so a fresh answer beats a stale one. Those four ranked lists get fused with a technique called reciprocal rank fusion, which favors results that show up near the top of multiple lists over results that dominate a single list. The top twenty get passed to a small reranker model that scores each candidate against the original question and picks the best ten. Those ten get their neighboring context added back in, so headings and preconditions do not get chopped away by the chunking.

For Slack specifically, we also index runs of consecutive same-author messages as their own records. This catches the case where the real answer is buried in a tangent partway through a long thread. The thread summary would miss it, but the burst embedding finds it.

Cerebras validated this exact recipe. Three months after they launched, their internal knowledge base handles 15,000 employee questions a day. Skipping any one of these steps costs answer quality in a way that shows up in results.

We build the permissions layer

Every row we store carries the list of Slack channels, shared folders, and repository scopes it belongs to. When a question comes in through Claude Tag, we know which channel it came from, and we only return results whose visibility list intersects with what that channel can see. Membership refreshes every ten minutes on a schedule, and immediately when a source fires a change webhook (Slack sends member_left_channel, Drive sends change notifications, other sources have equivalents).

The hard part of every enterprise knowledge base is the revocation staleness window: the gap between “someone loses access” and “the search index reflects it.” Every serious deployment lands somewhere between ten and sixty minutes, and the risk is a leaked result in that window. We initially target ten minutes and use channel scoping so a stale permission cannot leak across channels; the window can shift over time based on feedback and how the team actually uses the system. Glean’s engineering blog documents the same tradeoffs, and Onyx (formerly Danswer) is an open-source reference implementation in Python that we can borrow from directly.

We borrow the interface

Anthropic already ships an official Slack integration called Claude Tag. It handles the chat, the threading, the mobile app, the notifications, and the mentions. It also supports connecting to custom MCP servers, which is how our search tools plug in.

We expose seven tools to Claude Tag over MCP: a unified search across all sources, a search_slack, a search_docs, a who_knows that finds people with demonstrated expertise on a topic based on authorship signals, and a few others. Each tool is narrow and structured. It takes a query and returns raw evidence, with no LLM work happening inside the tool itself. Claude Tag handles the orchestration: it picks which tools to call, fans them out in parallel, and writes the final answer.

The same MCP server also works from Claude Desktop and Claude Code with a per-user login, which is how per-user access to private DMs or personal calendars works. Same brain behind both surfaces.

The design decision worth calling out

Claude Tag currently does not pass individual user identity to our MCP server. It operates as a shared bot identity inside each channel, per Anthropic’s agent identity documentation. That may be worth raising with the Claude team, since a per-user identity option would open up finer-grained personal access inside Slack.

Until then, the cleanest solution is to turn channel membership itself into the access boundary. Ask a question in #eng-platform and you draw from the data #eng-platform can see. Ask the same question in #sales-us and you draw from a different set. Employees already understand how Slack channels work, so this reuses a rule they already know. For questions that need per-person access, like private DMs or personal calendars, the same brain serves through Claude Desktop or Claude Code with a personal login.

There are also a few concrete Claude Tag limits worth designing around from day one. Context inside Slack is capped at 20 messages for channel mentions, 50 for threads, and 100 for forwards, so our MCP tools do their own retrieval rather than relying on Claude Tag to hold the knowledge context. Extended thinking and the Research feature are not available inside Slack. Billing is consumption-based on API tokens with organization-wide and per-channel spend limits (support page). Anthropic plans to replace the legacy Slack app with Claude Tag in August 2026, so we target Claude Tag directly rather than the app being retired.

Timeline

Two to four weeks for the initial build. The core loop could land closer to two weeks; four weeks gives room to ship it polished and documented, with the first two sources, the permissions layer, and Claude Tag all wired end to end.

Additional sources, a web dashboard, and admin analytics come after the core loop is working with real users.

Open question

Billing rate and model routing under Claude Tag on your existing Claude subscription. Anthropic charges by API tokens with per-channel spend caps, and the specific model behind Claude Tag affects both cost per query and answer quality. Worth a short conversation with the Claude team before kickoff.

References