You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -16,6 +16,8 @@ Slack Bolt for Python -- a framework for building Slack apps in Python.
16
16
17
17
## Environment Setup
18
18
19
+
You can verify the venv is active by checking `echo $VIRTUAL_ENV`. If tools like `black`, `flake8`, `mypy` or `pytest` are not found, ask the user to activate the venv.
20
+
19
21
A python virtual environment (`venv`) should be activated before running any commands.
20
22
21
23
```bash
@@ -29,18 +31,30 @@ source .venv/bin/activate
29
31
./scripts/install.sh
30
32
```
31
33
32
-
You can verify the venv is active by checking `echo $VIRTUAL_ENV`. If tools like `black`, `flake8`, `mypy` or `pytest` are not found, ask the user to activate the venv.
33
-
34
34
## Common Commands
35
35
36
-
### Testing
36
+
### Pre-submission Checklist
37
37
38
-
Always use the project scripts instead of calling `pytest` directly:
38
+
Before considering any work complete, you MUST run these commands in order and confirm they all pass:
39
+
40
+
```bash
41
+
./scripts/format.sh --no-install # 1. Format
42
+
./scripts/lint.sh --no-install # 2. Lint
43
+
./scripts/run_tests.sh <relevant># 3. Run relevant tests (see Testing below)
44
+
./scripts/run_mypy.sh --no-install # 4. Type check
45
+
```
46
+
47
+
To run everything at once (installs deps + formats + lints + tests + typechecks):
39
48
40
49
```bash
41
-
# Install all dependencies and run all tests (formats, lints, tests, typechecks)
42
50
./scripts/install_all_and_run_tests.sh
51
+
```
43
52
53
+
### Testing
54
+
55
+
Always use the project scripts instead of calling `pytest` directly:
# Type check -- mypy, configured in pyproject.toml
61
75
./scripts/run_mypy.sh --no-install
62
76
```
63
77
78
+
## Critical Conventions
79
+
80
+
### Sync/Async Mirroring Rule
81
+
82
+
**When modifying any sync module, you MUST also update the corresponding async module (and vice versa).** This is the most important convention in this codebase.
83
+
84
+
Almost every module has both a sync and async variant. Async files use the `async_` prefix alongside their sync counterpart:
**Adapters are an exception:** Most adapters are sync-only or async-only depending on the framework. Async-native frameworks (FastAPI, Starlette, Sanic, Tornado, ASGI, Socket Mode) have `async_handler.py`. Sync-only frameworks (Flask, Django, Bottle, CherryPy, Falcon, Pyramid, AWS Lambda, Google Cloud Functions, WSGI) have `handler.py`.
107
+
108
+
### Prefer the Middleware Pattern
109
+
110
+
Middleware is the project's preferred approach for cross-cutting concerns. Before adding logic to individual listeners or utility functions, consider whether it belongs in the middleware chain.
111
+
112
+
**When to use middleware:**
113
+
114
+
- Cross-cutting concerns that apply to many or all requests (logging, metrics, observability)
115
+
- Request validation, transformation, or enrichment
116
+
- Authorization extensions beyond the built-in `SingleTeamAuthorization`/`MultiTeamsAuthorization`
117
+
- Feature-level request handling (the `Assistant` middleware in `slack_bolt/middleware/assistant/assistant.py` is the canonical example -- it intercepts assistant thread events and dispatches them to registered sub-listeners)
118
+
119
+
**How to implement middleware:**
120
+
121
+
1. Subclass `Middleware` (sync) and implement `process(self, *, req, resp, next)`. Call `next()` to continue the chain.
122
+
2. Subclass `AsyncMiddleware` (async) and implement `async_process(self, *, req, resp, next)`. Call `await next()` to continue.
123
+
3. Export from `slack_bolt/middleware/__init__.py` (sync) and `slack_bolt/middleware/async_builtins.py` (async).
124
+
4. Register via `App(middleware=[...])` or the `@app.middleware` decorator.
The core package depends ONLY on `slack_sdk` (defined in `pyproject.toml`). Never add runtime dependencies to `pyproject.toml`. Additional dependencies go in the appropriate `requirements/*.txt` file.
138
+
64
139
## Architecture
65
140
66
141
### Request Processing Pipeline
@@ -90,49 +165,12 @@ Listeners receive arguments by parameter name. The framework inspects function s
90
165
91
166
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.
92
167
93
-
### Sync/Async Mirroring Pattern
94
-
95
-
**This is the most important pattern in this codebase.** Almost every module has both a sync and async variant. When you modify one, you almost always must modify the other.
96
-
97
-
**File naming convention:** Async files use the `async_` prefix alongside their sync counterpart:
**Adapters are an exception:** Most adapters are sync-only or async-only depending on the framework. Async-native frameworks (FastAPI, Starlette, Sanic, Tornado, ASGI, Socket Mode) have `async_handler.py`. Sync-only frameworks (Flask, Django, Bottle, CherryPy, Falcon, Pyramid, AWS Lambda, Google Cloud Functions, WSGI) have `handler.py`.
123
-
124
168
### AI Agents & Assistants
125
169
126
170
`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.
127
171
128
172
## Key Development Patterns
129
173
130
-
### Adding or Modifying Middleware
131
-
132
-
1. Implement the sync version in `slack_bolt/middleware/` (subclass `Middleware`, implement `process()`)
133
-
2. Implement the async version with `async_` prefix (subclass `AsyncMiddleware`, implement `async_process()`)
134
-
3. Export built-in middleware from `slack_bolt/middleware/__init__.py` (sync) and `async_builtins.py` (async)
135
-
136
174
### Adding a Context Utility
137
175
138
176
Each context utility lives in its own subdirectory under `slack_bolt/context/`:
@@ -153,14 +191,21 @@ Then wire it into `BoltContext` (`slack_bolt/context/context.py`) and `AsyncBolt
153
191
2. Add `__init__.py` and `handler.py` (or `async_handler.py` for async frameworks)
154
192
3. The handler converts the framework's request to `BoltRequest`, calls `app.dispatch()`, and converts `BoltResponse` back
155
193
4. Add the framework to `requirements/adapter.txt` with version constraints
156
-
5. Add adapter tests in `tests/adapter_tests/` (or `tests/adapter_tests_async/`)
194
+
5. Add adapter tests in `tests/adapter_tests/` (sync) or `tests/adapter_tests_async/` (async)
157
195
158
196
### Adding a Kwargs-Injectable Argument
159
197
160
198
1. Add the new arg to `slack_bolt/kwargs_injection/args.py` and `async_args.py`
161
199
2. Update the `Args` class with the new property
162
200
3. Populate the arg in the appropriate context or listener setup code
163
201
202
+
## Security Considerations
203
+
204
+
-**Request Verification:** The built-in `RequestVerification` middleware validates `x-slack-signature` and `x-slack-request-timestamp` on every incoming HTTP request. Never disable this in production. It is automatically skipped for `socket_mode` requests.
205
+
-**Tokens & Secrets:**`SLACK_SIGNING_SECRET` and `SLACK_BOT_TOKEN` must come from environment variables. Never hardcode or commit secrets.
206
+
-**Authorization Middleware:**`SingleTeamAuthorization` and `MultiTeamsAuthorization` verify tokens and inject an authorized `WebClient` into the context. Do not bypass these.
207
+
-**Tests:** Always use mock servers (`tests/mock_web_api_server/`) and dummy values. Never use real tokens in tests.
208
+
164
209
## Dependencies
165
210
166
211
The core package has a **single required runtime dependency**: `slack_sdk` (defined in `pyproject.toml`). Do not add runtime dependencies.
@@ -176,7 +221,9 @@ The core package has a **single required runtime dependency**: `slack_sdk` (defi
176
221
177
222
When adding a new dependency: add it to the appropriate `requirements/*.txt` file with version constraints, never to `pyproject.toml``dependencies` (unless it's a core runtime dep, which is very rare).
178
223
179
-
## Test Organization
224
+
## Test Organization and CI
225
+
226
+
### Directory Structure
180
227
181
228
-`tests/scenario_tests/` -- Integration-style tests with realistic Slack payloads
182
229
-`tests/slack_bolt/` -- Unit tests mirroring the source structure
@@ -188,15 +235,19 @@ When adding a new dependency: add it to the appropriate `requirements/*.txt` fil
188
235
189
236
**Mock server:** Many tests use `tests/mock_web_api_server/` to simulate Slack API responses. Look at existing tests for usage patterns rather than making real API calls.
190
237
191
-
## Code Style
238
+
### CI Pipeline
239
+
240
+
GitHub Actions (`.github/workflows/ci-build.yml`) runs on every push to `main` and every PR:
192
241
193
-
-**Black**formatter configured in `pyproject.toml` (line-length=125)
194
-
-**Flake8**linter configured in `.flake8` (line-length=125, ignores: F841,F821,W503,E402)
195
-
-**MyPy**configured in `pyproject.toml`
196
-
-**pytest**configured in `pyproject.toml`
242
+
-**Lint**-- `./scripts/lint.sh` on latest Python
243
+
-**Typecheck**-- `./scripts/run_mypy.sh` on latest Python
244
+
-**Unit tests**-- full test suite across Python 3.7--3.14 matrix
245
+
-**Code coverage**-- uploaded to Codecov
197
246
198
-
## GitHub & CI/CD
247
+
## PR and Commit Guidelines
199
248
200
-
-`.github/` -- GitHub-specific configuration and documentation
201
-
-`.github/workflows/` -- Continuous integration pipeline definitions that run on GitHub Actions
202
-
-`.github/maintainers_guide.md` -- Maintainer workflows and release process
249
+
- PRs target the `main` branch
250
+
- You MUST run `./scripts/install_all_and_run_tests.sh` before submitting
0 commit comments