Feature Request: only_index_joined_channels option for the Slack (indexed) connector
Written by OnyxBot See chat
Is your feature request related to a problem?
Yes. The indexed Slack connector has no way to scope indexing to "channels the bot has been invited to."
Channel discovery is enumerate-then-join:
get_channels()callsconversations.listwithpublic_channel, which returns every public channel in the workspace regardless of bot membership.filter_channels()filters that list purely by name (include list → exclude list).is_memberis never a filter input.is_memberis only read in order to auto-join:
# join so that the bot can access messages
if not channel["is_member"]:
slack_client.join_channel(channel_id=channel["id"])
logger.info("Successfully joined '%s'", channel["name"])So bot membership is an output of the connector, never an input. Consequences:
- In a large workspace the connector joins and indexes hundreds of irrelevant channels (alerts, bots, social, archived-but-not-archived, etc.).
- Kicking the bot out of a channel doesn't stick — the next run re-joins it.
- The only way to scope is a name-based channels allowlist, which has to be maintained centrally. Because the admin UI config block is display-only, adding a channel means a PATCH to /api/manage/admin/connector/ with the full body — not something a channel owner can self-serve.
- Workspaces that rename channels or add them frequently need constant config churn.
The natural, Slack-native signal for "this channel should be indexed" is /invite @Onyx, and the connector can't use it.
Describe the solution you'd like
A boolean connector option, e.g. only_index_joined_channels (default false`, so existing behavior is unchanged): When true:
- Skip the auto-join entirely. Never call conversations.join.
- Filter on membership. In
filter_channels()(or immediatelyafterget_channels()), drop any channel whereis_memberisFalse. - Channels are therefore opted in by inviting the bot, and opted out by removing it.
channels/exclude_channelsshould still apply, composed as an AND: a channel is indexed iff (bot is a member) AND (matches include rules) AND (not excluded). That lets an admin set a hard boundary while still delegating opt-in to channel owners.- The
channels:joinscope becomes unnecessary in this mode. Onyx's Slack capability check already models this as a legitimate, non-required deployment("a bot manually invited to every configured channel indexes fine without the scope"), so the capability check could be made aware of the flag and suppress the warning when it's set.
Ideally exposed as a checkbox in the connector form, labelled something like "Only index channels the bot has been invited to".
Describe alternatives you've considered
channelsallowlist — works, but it's a central, API-edited list rather than an invite-driven workflow, and exact mode hard-fails the run on a typo'd/renamed channel (Channel 'X' not found in workspace).- Regex allowlist (
channel_regex_enabled) — only helps if the channels you want share a naming convention, and re.fullmatch semantics trip people up. Removing the channels:join scope — approximates the behavior, but by failing: every non-member public channel raises missing_scope, which surfaces as aConnectorFailure/EntityFailureon every single run. Permanent red index attempts that bury real errors, wasted rate-limit budget on calls guaranteed to fail, and it doesn't un-join anything the bot already joined. Using the failure list as the channel-config UI is inverted: an allowlist expresses intent, a pile ofmissing_scopeerrors expresses an accident. - Private channels — already have exactly these semantics, since
conversations.listwithprivate_channelonly returns channels the bot is a member of. Converting public channels to private just to get this behavior isn't viable. - Federated Slack connector — has search_all_channels: false + a glob-basedchannels list editable in the UI, which is easier to maintain, but it's still an allowlist (not invite-driven), and Onyx recommends the indexed connector for result quality.
Additional context
This was previously requested in #236 ("Index only channels that the bot has been invited to"), which was auto-closed as stale without being implemented.
The implementation looks small: gate the join_channel call and add an is_member
predicate to the channel filter. The trickiest part is probably deciding how it
composes with the existing include/exclude rules (proposal above: AND) and whether
already-indexed out-of-scope documents get cleaned up by the normal pruning path.
Relevant code:
backend/onyx/connectors/slack/connector.py
(get_channels, filter_channels, _load_from_checkpoint).Source: onyx-dot-app/onyx