Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .claude/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CLAUDE.local.md
settings.local.json
worktrees/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
worktrees/
worktrees/
plans/

100 changes: 100 additions & 0 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Slack Bolt for Python -- a framework for building Slack apps. Built on top of `slack_sdk>=3.38.0,<4`. Supports both sync (`App`) and async (`AsyncApp`) patterns, with adapters for Flask, FastAPI, Django, AWS Lambda, and many other frameworks.

## Environment Setup

A virtual environment (`.venv`) should be activated before running any commands. If tools like `black`, `flake8`, or `pytest` are not found, ask the user to activate the venv.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my workflow I use various env_3.x. pattern in order quickly and easily test against different python versions locally 🤔

Suggested change
A virtual environment (`.venv`) should be activated before running any commands. If tools like `black`, `flake8`, or `pytest` are not found, ask the user to activate the venv.
A python virtual environment (`venv`) should be activated before running any commands. You can verify that the virtual environment is active by checking if the `$VIRTUAL_ENV` environment variable is set with `echo $VIRTUAL_ENV`.
If tools like `black`, `flake8`, 'mypy' or `pytest` are not found, ask the user to activate the venv.


## Common Commands

### Testing

Always use the project scripts instead of calling `pytest` directly:
```bash
# Run all tests (installs deps, formats, lints, tests, typechecks)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Run all tests (installs deps, formats, lints, tests, typechecks)
# Install all dependencies and run all tests (installs deps, formats, lints, tests, typechecks)

./scripts/install_all_and_run_tests.sh

# Run a single test file
./scripts/run_tests.sh tests/scenario_tests/test_app.py

# Run a single test function
./scripts/run_tests.sh tests/scenario_tests/test_app.py::TestApp::test_name
```

### Formatting, Linting, Type Checking
```bash
# Format (black, line-length=125)
./scripts/format.sh --no-install

# Lint (flake8, line-length=125, ignores: F841,F821,W503,E402)
./scripts/lint.sh --no-install

# Type check (mypy)
./scripts/run_mypy.sh --no-install
```

### First-Time Setup
```bash
pip install -U -e .
pip install -U -r requirements/testing.txt
pip install -U -r requirements/adapter.txt
pip install -U -r requirements/adapter_testing.txt
pip install -U -r requirements/tools.txt
```
Comment on lines +42 to +48
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about creating a scripts/install.sh that contains the following

#!/bin/bash
# Installs all dependencies of the project
# ./scripts/install.sh

# Update pip to prevent warnings
pip install -U pip

# The package causes a conflict with moto
pip uninstall python-lambda

pip install -U -e .
pip install -U -r requirements/testing.txt
pip install -U -r requirements/adapter.txt
pip install -U -r requirements/adapter_testing.txt
pip install -U -r requirements/tools.txt

# To avoid errors due to the old versions of click forced by Chalice
pip install -U pip click

Update the scripts/install_all_and_run_tests.sh to use it, that way we have one source of truth to install all dependencies

Suggested change
```bash
pip install -U -e .
pip install -U -r requirements/testing.txt
pip install -U -r requirements/adapter.txt
pip install -U -r requirements/adapter_testing.txt
pip install -U -r requirements/tools.txt
```
```bash
./scripts/install.sh


## Architecture

### Request Processing Pipeline

Incoming requests flow through a middleware chain before reaching listeners:

1. **SSL Check** -> **Request Verification** (signature) -> **URL Verification** -> **Authorization** (token injection) -> **Ignoring Self Events** -> Custom middleware
2. **Listener Matching** -- `ListenerMatcher` implementations check if a listener should handle the request
3. **Listener Execution** -- listener-specific middleware runs, then `ack()` is called, then the handler executes

For FaaS environments (`process_before_response=True`), long-running handlers execute as "lazy listeners" in a thread pool after the ack response is returned.

### Core Abstractions

- **`App` / `AsyncApp`** (`slack_bolt/app/`) -- Central class. Registers listeners via decorators (`@app.event()`, `@app.action()`, `@app.command()`, `@app.message()`, `@app.view()`, `@app.shortcut()`, `@app.options()`, `@app.function()`). Dispatches incoming requests through middleware to matching listeners.
- **`Middleware`** (`slack_bolt/middleware/`) -- Abstract base with `process(req, resp, next)`. Built-in: authorization, request verification, SSL check, URL verification, assistant, self-event ignoring.
- **`Listener`** (`slack_bolt/listener/`) -- Has matchers, middleware, and an ack/handler function. `CustomListener` is the main implementation.
- **`ListenerMatcher`** (`slack_bolt/listener_matcher/`) -- Determines if a listener handles a given request. Built-in matchers for events, actions, commands, messages (regex), shortcuts, views, options.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- **`ListenerMatcher`** (`slack_bolt/listener_matcher/`) -- Determines if a listener handles a given request. Built-in matchers for events, actions, commands, messages (regex), shortcuts, views, options.
- **`ListenerMatcher`** (`slack_bolt/listener_matcher/`) -- Determines if a listener handles a given request. Built-in matchers for events, actions, commands, messages (regex), shortcuts, views, options, functions.

- **`BoltContext`** (`slack_bolt/context/`) -- Dict-like object passed to listeners with `client`, `say()`, `ack()`, `respond()`, `complete()`, `fail()`, plus event metadata (`user_id`, `channel_id`, `team_id`).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- **`BoltContext`** (`slack_bolt/context/`) -- Dict-like object passed to listeners with `client`, `say()`, `ack()`, `respond()`, `complete()`, `fail()`, plus event metadata (`user_id`, `channel_id`, `team_id`).
- **`BoltContext`** (`slack_bolt/context/`) -- Dict-like object passed to listeners with `client`, `say()`, `ack()`, `respond()`, `complete()`, `fail()`, plus event metadata (`user_id`, `channel_id`, `team_id`, etc...).

- **`BoltRequest` / `BoltResponse`** (`slack_bolt/request/`, `slack_bolt/response/`) -- Request/response wrappers. Request has `mode` of "http" or "socket_mode".

### Kwargs Injection

Listeners receive arguments by parameter name. The framework inspects function signatures and injects matching args: `body`, `event`, `action`, `command`, `payload`, `context`, `client`, `ack`, `say`, `respond`, `logger`, `complete`, `fail`, `agent`, etc. Defined in `slack_bolt/kwargs_injection/args.py`.

### Adapter System

Each adapter in `slack_bolt/adapter/` converts between a web framework's request/response types and `BoltRequest`/`BoltResponse`. Adapters exist for: Flask, FastAPI, Django, Starlette, Sanic, Bottle, Tornado, CherryPy, Falcon, Pyramid, AWS Lambda, Google Cloud Functions, Socket Mode, WSGI, ASGI, and more.

### Async Support

`AsyncApp` mirrors `App` with async middleware, listeners, and context utilities. Located in `slack_bolt/app/async_app.py`. Requires `aiohttp`. All async variants live alongside their sync counterparts (e.g., `async_middleware.py` next to `middleware.py`).

### AI Agents & Assistants

`BoltAgent` (`slack_bolt/agent/`) provides `chat_stream()`, `set_status()`, and `set_suggested_prompts()` for AI-powered agents. `Assistant` middleware (`slack_bolt/middleware/assistant/`) handles assistant thread events.

## Test Organization

- `tests/scenario_tests/` -- Integration-style tests with realistic Slack payloads
- `tests/slack_bolt/` -- Unit tests mirroring the source structure
- `tests/adapter_tests/` and `tests/adapter_tests_async/` -- Framework adapter tests
- `tests/mock_web_api_server/` -- Mock Slack API server used by tests
- Async test variants use `_async` suffix directories

## Code Style

- **Black** formatter, 125 char line length
- **Flake8** linter, 125 char line length
- **MyPy** with `force_union_syntax=true` and `warn_unused_ignores=true` (use `X | Y` union syntax, not `Union[X, Y]`)
- pytest with `asyncio_mode = "auto"`
31 changes: 31 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"permissions": {
"allow": [
"Bash(./scripts/build_pypi_package.sh:*)",
"Bash(./scripts/format.sh:*)",
"Bash(./scripts/install_all_and_run_tests.sh:*)",
"Bash(./scripts/lint.sh:*)",
"Bash(./scripts/run_mypy.sh:*)",
"Bash(./scripts/run_tests.sh:*)",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"Bash(./scripts/run_tests.sh:*)",
"Bash(./scripts/run_tests.sh:*)",
"Bash(./scripts/install.sh:*)",
"Bash(echo $VIRTUAL_ENV)",

"Bash(gh issue view:*)",
"Bash(gh label list:*)",
"Bash(gh pr checks:*)",
"Bash(gh pr diff:*)",
"Bash(gh pr list:*)",
"Bash(gh pr status:*)",
"Bash(gh pr update-branch:*)",
"Bash(gh pr view:*)",
"Bash(gh search code:*)",
"Bash(git diff:*)",
"Bash(git grep:*)",
"Bash(git log:*)",
"Bash(git show:*)",
"Bash(git status:*)",
"Bash(grep:*)",
"Bash(ls:*)",
"Bash(tree:*)",
"WebFetch(domain:github.com)",
"WebFetch(domain:docs.slack.dev)"
]
}
}
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ venv/
.venv*
.env/

# claude
.claude/*.local.json

# codecov / coverage
.coverage
cov_*
Expand Down