Add Slack app_mention handling behind slack_duo_agent feature flag
What does this MR do and why?
We recently worked on a PoC for a Slack bot that allows to interact with Duo (e.g. creating issues from Slack).
We want to push this closer to production and this MR is the first step of a Duo Agent-powered Slack bot by handling @mention events — i.e. when a user @mentions the GitLab bot in Slack.
This is intentionally minimal: the bot echoes back the user's message as proof that the full pipeline works end-to-end.
The Duo Workflow integration will be wired in a follow-up MR to make this a MVC.
The feature is gated behind the slack_duo_agent beta feature flag (per-user actor), so it can be selectively enabled on GitLab.com without affecting other users or self-managed instances.
What's included:
- Routes
app_mentionSlack events through the existingSlackEventWorker -
AppMentionedServicehandles the full flow:- Unauthenticated users:
🔒 reaction + ephemeral prompt to connect their GitLab account - Authenticated users without the flag:
🔒 reaction + ephemeral "you do not have access" message - Authenticated users with the flag:
👀 reaction → echo reply →✅ reaction
- Unauthenticated users:
-
Slack::API#getadded to support future thread fetching and user lookups - Beta feature flag
slack_duo_agent(default off)
What's NOT included (follow-up MRs):
- Slack app manifest changes — the new bot uses a separate manually-configured Slack app for now (see setup instructions below)
- Thread context fetching (
conversations.replies) and user name resolution - Duo Workflow integration (the actual AI response)
Screenshots or screen recordings
Slack app manifest
This MR does not modify the downloadable Slack manifest (Slack::Manifest). To test or use this feature, manually configure a separate Slack app with the following manifest:
{
"display_information": {
"name": "GitLab Duo (gdk.test)",
"description": "Interact with GitLab Duo without leaving your Slack workspace!",
"background_color": "#171321"
},
"features": {
"app_home": {
"home_tab_enabled": true,
"messages_tab_enabled": false,
"messages_tab_read_only_enabled": true
},
"bot_user": {
"display_name": "Duo",
"always_online": true
},
"slash_commands": [
{
"command": "/gitlab",
"url": "https://<change-this-to-your-url>/api/v4/slack/trigger",
"description": "GitLab slash commands",
"usage_hint": "your-project-name-or-alias command",
"should_escape": false
}
]
},
"oauth_config": {
"redirect_urls": ["http://gdk.test:3000"],
"scopes": {
"bot": [
"app_mentions:read",
"commands",
"chat:write",
"chat:write.public",
"channels:history",
"groups:history",
"reactions:write",
"users:read"
]
}
},
"settings": {
"event_subscriptions": {
"request_url": "https://<change-this-to-your-url>/api/v4/integrations/slack/events",
"bot_events": ["app_home_opened", "app_mention"]
},
"interactivity": {
"is_enabled": true,
"request_url": "https://<change-this-to-your-url>/api/v4/integrations/slack/interactions",
"message_menu_options_url": "http://<change-this-to-your-url>/api/v4/integrations/slack/options"
},
"org_deploy_enabled": false,
"socket_mode_enabled": false,
"token_rotation_enabled": false
}
}
Note that you need to change the <change-this-to-your-url> to the URL that you expose your instance to (more in the testing section).
How to set up and validate locally
-
Configure a Slack app using the manifest above, pointed
<change-this-to-your-url>at your GDK tunnel URL (e.g. via Cloudflare Tunnel or ngrok) -
Make sure to start your rails app with
RAILS_HOSTS=<change-this-to-your-url> -
Install the Slack app to your workspace and connect it to a GitLab integration
-
Enable the feature flag for your user in the rails console:
Feature.enable(:slack_duo_agent, User.find_by(username: 'your-username')) -
Test unauthenticated flow: Remove any existing Slack-GitLab user link, then
@mentionthe bot. You should see a🔒 reaction and an ephemeral message prompting you to connect your GitLab account:ChatName.where(team_id: '<your-team-id>', chat_id: '<your-slack-user-id>').destroy_all -
Click the auth link and connect your GitLab account
-
Test flag-off flow: Disable the flag, then
@mentionthe bot. You should see a🔒 reaction and an ephemeral "you do not have access" message:Feature.disable(:slack_duo_agent) -
Test flag-on flow: Re-enable the flag,
@mentionthe bot with any message. You should see:-
👀 reaction appears - Bot replies in the thread: "You said: {your message}"
-
✅ reaction replaces👀
Feature.enable(:slack_duo_agent, User.find_by(username: 'your-username')) -