The Bolt Framework for Python - a comprehensive framework for building Slack applications with decorator-based API for handling events, actions, and interactive components
—
Decorator-based event handling for all Slack event types including messages, slash commands, interactive components, shortcuts, and view submissions. Supports event filtering, custom matchers, and argument injection.
Listen for message events in channels, direct messages, and threads.
def message(self, keyword=None, *matchers):
"""
Listen for message events.
Args:
keyword (str, optional): Text pattern to match in messages
*matchers: Additional listener matcher instances
Returns:
Decorator function for message handlers
"""
# Usage examples:
@app.message("hello") # Match messages containing "hello"
@app.message(re.compile(r"hi")) # Match with regex
@app.message() # Match all messages
def handle_message(message, say, client, logger):
"""
Message handler function.
Args:
message (dict): Message event data
say (callable): Function to send message to same channel
client (WebClient): Slack API client
logger (Logger): App logger instance
"""Handle slash command invocations.
def command(self, command, *matchers):
"""
Listen for slash command events.
Args:
command (str): Command name (e.g., "/weather", "/help")
*matchers: Additional listener matcher instances
Returns:
Decorator function for command handlers
"""
# Usage:
@app.command("/weather")
def handle_weather_command(ack, respond, command, logger):
"""
Command handler function.
Args:
ack (callable): Function to acknowledge the command (required)
respond (callable): Function to send response to user
command (dict): Command payload data
logger (Logger): App logger instance
"""
ack() # Must acknowledge within 3 seconds
location = command.get('text', 'San Francisco')
respond(f"Weather in {location}: Sunny ☀️")Listen for any Slack event type from the Events API.
def event(self, event_type, *matchers):
"""
Listen for Events API events.
Args:
event_type (str): Slack event type (e.g., "app_mention", "team_join")
*matchers: Additional listener matcher instances
Returns:
Decorator function for event handlers
"""
# Usage examples:
@app.event("app_mention")
@app.event("team_join")
@app.event("reaction_added")
def handle_app_mention(event, say, client):
"""
Event handler function.
Args:
event (dict): Event data from Slack
say (callable): Function to send message to event channel
client (WebClient): Slack API client
"""Handle clicks on buttons, select menus, and other interactive components.
def action(self, action_id, *matchers):
"""
Listen for interactive component actions.
Args:
action_id (str): Action ID of the interactive component
*matchers: Additional listener matcher instances
Returns:
Decorator function for action handlers
"""
def block_action(self, action_id, *matchers):
"""
Listen for Block Kit element actions (alias for action).
Args:
action_id (str): Action ID of the block element
*matchers: Additional listener matcher instances
"""
def attachment_action(self, callback_id, *matchers):
"""
Listen for legacy attachment actions.
Args:
callback_id (str): Callback ID of the attachment action
*matchers: Additional listener matcher instances
"""
# Usage:
@app.action("approve_button")
@app.action("user_select")
@app.block_action("priority_select")
def handle_button_click(ack, body, respond, client):
"""
Action handler function.
Args:
ack (callable): Function to acknowledge the action (required)
body (dict): Full request body
respond (callable): Function to update/respond to the interaction
client (WebClient): Slack API client
"""
ack() # Must acknowledge within 3 secondsHandle global shortcuts and message shortcuts.
def shortcut(self, callback_id, *matchers):
"""
Listen for shortcuts (both global and message shortcuts).
Args:
callback_id (str): Callback ID of the shortcut
*matchers: Additional listener matcher instances
"""
def global_shortcut(self, callback_id, *matchers):
"""
Listen specifically for global shortcuts.
Args:
callback_id (str): Callback ID of the global shortcut
*matchers: Additional listener matcher instances
"""
def message_shortcut(self, callback_id, *matchers):
"""
Listen specifically for message shortcuts.
Args:
callback_id (str): Callback ID of the message shortcut
*matchers: Additional listener matcher instances
"""
# Usage:
@app.global_shortcut("create_task")
@app.message_shortcut("save_message")
def handle_shortcut(ack, shortcut, client):
"""
Shortcut handler function.
Args:
ack (callable): Function to acknowledge the shortcut
shortcut (dict): Shortcut payload data
client (WebClient): Slack API client
"""Handle modal view submissions, closures, and interactions.
def view(self, callback_id, *matchers):
"""
Listen for view events (submissions and closures).
Args:
callback_id (str): Callback ID of the view
*matchers: Additional listener matcher instances
"""
def view_submission(self, callback_id, *matchers):
"""
Listen specifically for view submissions.
Args:
callback_id (str): Callback ID of the view
*matchers: Additional listener matcher instances
"""
def view_closed(self, callback_id, *matchers):
"""
Listen specifically for view closures.
Args:
callback_id (str): Callback ID of the view
*matchers: Additional listener matcher instances
"""
# Usage:
@app.view_submission("task_modal")
@app.view_closed("survey_modal")
def handle_view_submission(ack, body, view, client):
"""
View handler function.
Args:
ack (callable): Function to acknowledge the submission
body (dict): Full request body
view (dict): View payload data
client (WebClient): Slack API client
"""Handle dynamic option loading for select menus.
def options(self, action_id, *matchers):
"""
Listen for options loading requests.
Args:
action_id (str): Action ID of the select menu
*matchers: Additional listener matcher instances
"""
def block_suggestion(self, action_id, *matchers):
"""
Listen for block element suggestions (alias for options).
Args:
action_id (str): Action ID of the block element
*matchers: Additional listener matcher instances
"""
# Usage:
@app.options("user_select")
def load_user_options(ack, options, client):
"""
Options handler function.
Args:
ack (callable): Function to acknowledge with options
options (dict): Options request data
client (WebClient): Slack API client
"""
# Return options to populate the select menu
ack(options=[
{"text": {"type": "plain_text", "text": "Option 1"}, "value": "option1"},
{"text": {"type": "plain_text", "text": "Option 2"}, "value": "option2"}
])Handle legacy dialog interactions (deprecated, use modals instead).
def dialog_submission(self, callback_id, *matchers):
"""
Listen for dialog submissions (legacy).
Args:
callback_id (str): Callback ID of the dialog
*matchers: Additional listener matcher instances
"""
def dialog_cancellation(self, callback_id, *matchers):
"""
Listen for dialog cancellations (legacy).
Args:
callback_id (str): Callback ID of the dialog
*matchers: Additional listener matcher instances
"""
def dialog_suggestion(self, action_id, *matchers):
"""
Listen for dialog option suggestions (legacy).
Args:
action_id (str): Action ID of the dialog element
*matchers: Additional listener matcher instances
"""Handle custom function calls (Slack platform functions).
def function(self, callback_id, *matchers):
"""
Listen for custom function calls.
Args:
callback_id (str): Function callback ID
*matchers: Additional listener matcher instances
"""
# Usage:
@app.function("process_data")
def handle_function_call(ack, inputs, complete, fail, logger):
"""
Function handler.
Args:
ack (callable): Function to acknowledge the call
inputs (dict): Function input parameters
complete (callable): Function to mark completion with outputs
fail (callable): Function to mark failure with error
logger (Logger): App logger instance
"""Handle workflow step interactions.
def step(self, step):
"""
Add a workflow step to the app.
Args:
step: WorkflowStep instance
"""
# Usage with WorkflowStep:
from slack_bolt.workflows.step import WorkflowStep
def edit_step(ack, step, configure):
ack()
configure(blocks=[...]) # Configure step UI
def execute_step(step, complete, fail):
# Step execution logic
complete(outputs={"result": "success"})
ws = WorkflowStep(
callback_id="my_step",
edit=edit_step,
save=lambda ack, view: ack(),
execute=execute_step
)
app.step(ws)Custom matching logic for fine-grained event filtering:
from slack_bolt.listener_matcher import CustomListenerMatcher
def custom_matcher(body):
"""
Custom matcher function.
Args:
body (dict): Request body
Returns:
bool: True if listener should handle this request
"""
return body.get("event", {}).get("channel_type") == "im"
# Usage:
@app.message(CustomListenerMatcher(custom_matcher))
def handle_dm_only(message, say):
say("This only responds to direct messages!")Combine multiple matchers for complex filtering:
@app.message("hello", CustomListenerMatcher(lambda body: not body.get("event", {}).get("bot_id")))
def handle_human_hello(message, say):
say("Hello, human!")All listener functions support argument injection with these available parameters:
class Args:
"""Available argument names for dependency injection in listeners."""
# Core objects
logger: Logger
client: WebClient
context: BoltContext
body: dict
payload: dict
# Utility functions
ack: Ack
say: Say
respond: Respond
complete: Complete
fail: Fail
# Event-specific data
event: dict
message: dict
command: dict
action: dict
shortcut: dict
view: dict
options: dict
# Request metadata
request: BoltRequest
response: BoltResponse
# Multi-workspace data
enterprise_id: str
team_id: str
user_id: str
channel_id: str
# AI Assistant utilities
set_status: SetStatus
set_title: SetTitle
set_suggested_prompts: SetSuggestedPrompts
save_thread_context: SaveThreadContextListeners can use any combination of available arguments:
# Minimal signature
@app.message("hello")
def simple_handler(say):
say("Hello!")
# Full signature with all common arguments
@app.command("/complex")
def complex_handler(ack, body, command, respond, client, logger, context):
ack()
logger.info(f"Command received: {command}")
# Complex logic here...
# Event-specific arguments
@app.event("app_mention")
def mention_handler(event, say, user_id, channel_id):
say(f"Thanks for the mention in <#{channel_id}>, <@{user_id}>!")import re
# Exact text match
@app.message("help")
def show_help(say):
say("Here's how to use this bot...")
# Regex pattern
@app.message(re.compile(r"weather in (\w+)"))
def weather_query(message, say):
city = re.search(r"weather in (\w+)", message['text']).group(1)
say(f"The weather in {city} is sunny!")
# Multiple patterns
@app.message("hello")
@app.message("hi")
@app.message("hey")
def greet_user(message, say):
say(f"Hello <@{message['user']}>!")@app.command("/todo")
def todo_command(ack, respond, command):
ack()
text = command.get('text', '').strip()
parts = text.split(' ', 1)
subcommand = parts[0].lower() if parts else 'help'
if subcommand == 'add':
task = parts[1] if len(parts) > 1 else ''
respond(f"Added task: {task}")
elif subcommand == 'list':
respond("Here are your tasks: ...")
else:
respond("Usage: /todo [add|list] [task]")@app.action("open_modal")
def open_modal(ack, body, client):
ack()
client.views_open(
trigger_id=body["trigger_id"],
view={
"type": "modal",
"callback_id": "task_modal",
"title": {"type": "plain_text", "text": "Create Task"},
"blocks": [
{
"type": "input",
"block_id": "task_input",
"element": {
"type": "plain_text_input",
"action_id": "task_text"
},
"label": {"type": "plain_text", "text": "Task Description"}
}
],
"submit": {"type": "plain_text", "text": "Create"}
}
)
@app.view_submission("task_modal")
def handle_task_submission(ack, body, view, logger):
# Extract form data
task_text = view["state"]["values"]["task_input"]["task_text"]["value"]
# Process the task...
logger.info(f"Creating task: {task_text}")
# Acknowledge and close modal
ack()Install with Tessl CLI
npx tessl i tessl/pypi-slack-bolt