Specialized14 min read

Slack Knowledge Bases: Messages, Channels & Search

Build searchable knowledge bases from Slack. Learn OAuth setup, message ingestion, entity extraction from conversations, and semantic search patterns.

Slack contains years of institutional knowledge buried in channels. Graphlit turns Slack history into a searchable knowledge base—find answers, extract insights, and build RAG chatbots that know what your team knows.

What You'll Learn

  • Slack OAuth setup (bot tokens, scopes)
  • Syncing channels, messages, threads
  • Entity extraction from conversations
  • Searching Slack history semantically
  • Building Slack-powered RAG
  • Production patterns for multi-channel feeds

Part 1: Slack OAuth Setup

Step 1: Create Slack App

  1. Go to api.slack.com/apps
  2. Click "Create New App" → "From scratch"
  3. Name it (e.g., "Graphlit Knowledge Base")
  4. Select your workspace

Step 2: Add OAuth Scopes

Navigate to "OAuth & Permissions" and add:

Required scopes:

  • channels:read - List public channels
  • channels:history - Read public messages
  • users:read - Get user info

Optional (for private channels):

  • groups:read - List private channels
  • groups:history - Read private messages

Step 3: Install App

  1. Click "Install to Workspace"
  2. Authorize the app
  3. Copy Bot User OAuth Token (starts with xoxb-)
// Save token securely
const SLACK_BOT_TOKEN = 'xoxb-your-token-here';

Part 2: Listing Available Channels

Before creating a feed, query available channels:

import { Graphlit } from 'graphlit-client';

const graphlit = new Graphlit();

// List channels
const channels = await graphlit.querySlackChannels({
  token: SLACK_BOT_TOKEN
});

console.log('Available channels:');
channels.slackChannels.forEach(channel => {
  console.log(`  #${channel.name} (${channel.id})`);
});

Example output:

Available channels:
  #general (C01234ABCDE)
  #engineering (C56789FGHIJ)
  #product (C98765KLMNO)

Part 3: Creating Slack Feed

Basic Feed (Single Channel)

import { FeedServiceTypes } from 'graphlit-client/dist/generated/graphql-types';

// Create feed for #engineering channel
const feed = await graphlit.createFeed({
  name: 'Engineering Slack',
  type: FeedServiceTypes.Slack,
  slack: {
    token: SLACK_BOT_TOKEN,
    channels: ['engineering'],  // Channel names
    readMessages: true,
    readThreads: true,
    readLimit: 500  // Last 500 messages
  }
});

console.log('Feed created:', feed.createFeed.id);

// Wait for initial sync
let isDone = false;
while (!isDone) {
  const status = await graphlit.isFeedDone(feed.createFeed.id);
  isDone = status.isFeedDone.result;
  
  if (!isDone) {
    console.log('Syncing Slack history...');
    await new Promise(r => setTimeout(r, 10000));
  }
}

console.log('✓ Slack history synced!');

Multi-Channel Feed

// Sync multiple channels
const multiChannelFeed = await graphlit.createFeed({
  name: 'All Engineering Channels',
  type: FeedServiceTypes.Slack,
  slack: {
    token: SLACK_BOT_TOKEN,
    channels: ['engineering', 'backend', 'frontend', 'devops'],
    readMessages: true,
    readThreads: true,
    readLimit: 1000
  }
});

Feed with Entity Extraction

import { 
  FilePreparationServiceTypes,
  EntityExtractionServiceTypes,
  ObservableTypes
} from 'graphlit-client/dist/generated/graphql-types';

// Create workflow for entity extraction
const workflow = await graphlit.createWorkflow({
  name: "Slack Entities",
  preparation: {
    jobs: [{
      connector: {
        type: FilePreparationServiceTypes.Message
      }
    }]
  },
  extraction: {
    jobs: [{
      connector: {
        type: EntityExtractionServiceTypes.ModelText,
        extractedTypes: [
          ObservableTypes.Person,        // @mentions
          ObservableTypes.Organization,  // Company names
          ObservableTypes.Product,       // Products discussed
          ObservableTypes.Event          // Meetings, launches
        ]
      }
    }]
  }
});

// Create feed with workflow
const feedWithEntities = await graphlit.createFeed({
  name: 'Slack with Entities',
  type: FeedServiceTypes.Slack,
  slack: {
    token: SLACK_BOT_TOKEN,
    channels: ['engineering'],
    readMessages: true,
    readThreads: true,
    readLimit: 500
  },
  workflow: { id: workflow.createWorkflow.id }
});

What gets extracted:

  • People mentioned (@alice, @bob)
  • Companies discussed (Acme Corp, OpenAI)
  • Products/projects (Project Phoenix, Dashboard v2)
  • Events (Q4 Launch, All-Hands)

Part 4: Searching Slack History

Basic Search

import { ContentTypes } from 'graphlit-client/dist/generated/graphql-types';

// Search Slack messages
const results = await graphlit.queryContents({
  search: 'API rate limiting',
  filter: {
    types: [ContentTypes.Message]  // Only Slack messages
  }
});

console.log(`Found ${results.contents.results.length} messages`);

results.contents.results.forEach(msg => {
  console.log(`\n${msg.message?.author}: ${msg.message?.message}`);
  console.log(`  Channel: #${msg.message?.channelName}`);
  console.log(`  Date: ${msg.message?.timestamp}`);
});

Example output:

Found 8 messages

alice: We're hitting rate limits on the GitHub API. Should we add exponential backoff?
  Channel: #engineering
  Date: 2024-01-15T10:30:00Z

bob: I implemented rate limiting in the API service last week. Check PR #234.
  Channel: #backend
  Date: 2024-01-16T14:20:00Z

Search with Time Filters

// Messages from last 30 days
const recent = await graphlit.queryContents({
  search: 'deployment',
  filter: {
    types: [ContentTypes.Message],
    creationDateRange: {
      from: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString()
    }
  }
});

Search by Channel

// Search only in #engineering
const engineeringMsgs = await graphlit.queryContents({
  search: 'kubernetes',
  filter: {
    types: [ContentTypes.Message],
    // Note: Channel filtering requires custom metadata filtering
  }
});

Part 5: Building Slack RAG

Chat with Slack History

// Create conversation
const conversation = await graphlit.createConversation('Slack Chat');

// Ask questions about Slack history
const response = await graphlit.promptConversation(
  'What did the team discuss about API rate limiting?',
  conversation.createConversation.id
);

const answer = response.promptConversation?.message?.message;
const citations = response.promptConversation?.message?.citations;

console.log('Answer:', answer);
console.log('\nSources:');
citations?.forEach((citation, i) => {
  console.log(`[${i + 1}] ${citation.content?.name} in #${citation.content?.message?.channelName}`);
});

Example answer:

Answer: The team discussed API rate limiting on January 15-16. Alice raised concerns about hitting GitHub API limits and suggested implementing exponential backoff. Bob mentioned he had already implemented rate limiting in the API service (PR #234), and Carol added that they should also consider request batching for efficiency.

Sources:
[1] Slack message in #engineering
[2] Slack message in #backend
[3] Slack message in #engineering

Entity-Filtered Slack Search

// Find Alice's entity
const aliceEntity = await graphlit.queryObservables({
  filter: {
    searchText: "Alice",
    types: [ObservableTypes.Person]
  }
});

const aliceId = aliceEntity.observables?.results?.[0]?.observable.id;

// Chat filtered to Alice's messages
const aliceChat = await graphlit.promptConversation(
  'What is Alice working on?',
  conversationId,
  undefined,
  undefined,
  {
    observations: {
      observables: [{ id: aliceId }]
    }
  }
);

Part 6: Production Patterns

Pattern 1: Continuous Sync

Feeds continuously monitor for new messages:

// Feed runs indefinitely
const feed = await graphlit.createFeed({
  name: 'Live Slack Feed',
  type: FeedServiceTypes.Slack,
  slack: {
    token: SLACK_BOT_TOKEN,
    channels: ['engineering'],
    readMessages: true,
    readThreads: true,
    readLimit: 100  // Only last 100 on initial sync
  },
  schedulePolicy: {
    recurrenceType: 'HOURLY',  // Check every hour
    interval: 1
  }
});

// New messages appear automatically

Pattern 2: Multi-Workspace

// Separate feeds per workspace
const workspaces = [
  { name: 'Engineering', token: ENGINEERING_TOKEN, channels: ['general', 'backend'] },
  { name: 'Product', token: PRODUCT_TOKEN, channels: ['general', 'roadmap'] }
];

for (const workspace of workspaces) {
  const feed = await graphlit.createFeed({
    name: `${workspace.name} Slack`,
    type: FeedServiceTypes.Slack,
    slack: {
      token: workspace.token,
      channels: workspace.channels,
      readMessages: true,
      readThreads: true
    }
  });
  
  console.log(`Created feed for ${workspace.name}`);
}

Pattern 3: Slack Bot Integration

import { App } from '@slack/bolt';

const slackApp = new App({
  token: SLACK_BOT_TOKEN,
  signingSecret: SLACK_SIGNING_SECRET
});

// Answer questions from Slack
slackApp.message(/^@bot (.+)/, async ({ message, say }) => {
  const question = message.text.replace(/^@bot /, '');
  
  // Query Graphlit
  const response = await graphlit.promptConversation(question, conversationId);
  
  // Reply in Slack
  await say({
    text: response.promptConversation?.message?.message,
    thread_ts: message.ts  // Reply in thread
  });
});

Common Issues & Solutions

Issue: No Messages Synced

Problem: Feed created but no content appears.

Solutions:

  1. Check OAuth scopes:
// Verify token has required scopes
const test = await graphlit.querySlackChannels({ token: SLACK_BOT_TOKEN });
console.log('Channels accessible:', test.slackChannels.length);
  1. Verify bot is in channels:
# Bot must be invited to private channels
/invite @YourBot

Issue: Missing Threads

Problem: Only top-level messages synced, replies missing.

Solution: Enable readThreads:

slack: {
  readThreads: true  // Must be true
}

Issue: Slow Initial Sync

Problem: 10,000 messages takes 30+ minutes.

Solutions:

  1. Lower readLimit for initial sync:
readLimit: 500  // Not 10000
  1. Use webhooks instead of polling:
webhookUrl: 'https://yourapp.com/webhooks/graphlit'

What's Next?

You now have a searchable Slack knowledge base. Next steps:

  1. Build Slack bot that answers questions
  2. Extract entities to find who's working on what
  3. Create dashboards showing team activity

Related guides:

Happy Slacking! 💬

Ready to Build with Graphlit?

Start building AI-powered applications with our API-first platform. Free tier includes 100 credits/month — no credit card required.

No credit card required • 5 minutes to first API call

Slack Knowledge Bases: Messages, Channels & Search | Graphlit Developer Guides