|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +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. |
| 8 | + |
| 9 | +## Environment Setup |
| 10 | + |
| 11 | +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. |
| 12 | + |
| 13 | +## Common Commands |
| 14 | + |
| 15 | +### Testing |
| 16 | +```bash |
| 17 | +# Run all tests (installs deps, formats, lints, tests, typechecks) |
| 18 | +./scripts/install_all_and_run_tests.sh |
| 19 | + |
| 20 | +# Run a single test file |
| 21 | +./scripts/run_tests.sh tests/scenario_tests/test_app.py |
| 22 | + |
| 23 | +# Run a single test directly (skip formatting) |
| 24 | +pytest -vv tests/scenario_tests/test_app.py |
| 25 | + |
| 26 | +# Run a single test function |
| 27 | +pytest -vv tests/scenario_tests/test_app.py::TestApp::test_name |
| 28 | +``` |
| 29 | + |
| 30 | +### Formatting, Linting, Type Checking |
| 31 | +```bash |
| 32 | +# Format (black, line-length=125) |
| 33 | +./scripts/format.sh --no-install |
| 34 | + |
| 35 | +# Lint (flake8, line-length=125, ignores: F841,F821,W503,E402) |
| 36 | +./scripts/lint.sh --no-install |
| 37 | + |
| 38 | +# Type check (mypy) |
| 39 | +./scripts/run_mypy.sh --no-install |
| 40 | +``` |
| 41 | + |
| 42 | +### First-Time Setup |
| 43 | +```bash |
| 44 | +pip install -U -e . |
| 45 | +pip install -U -r requirements/testing.txt |
| 46 | +pip install -U -r requirements/adapter.txt |
| 47 | +pip install -U -r requirements/adapter_testing.txt |
| 48 | +pip install -U -r requirements/tools.txt |
| 49 | +``` |
| 50 | + |
| 51 | +## Architecture |
| 52 | + |
| 53 | +### Request Processing Pipeline |
| 54 | + |
| 55 | +Incoming requests flow through a middleware chain before reaching listeners: |
| 56 | + |
| 57 | +1. **SSL Check** -> **Request Verification** (signature) -> **URL Verification** -> **Authorization** (token injection) -> **Ignoring Self Events** -> Custom middleware |
| 58 | +2. **Listener Matching** -- `ListenerMatcher` implementations check if a listener should handle the request |
| 59 | +3. **Listener Execution** -- listener-specific middleware runs, then `ack()` is called, then the handler executes |
| 60 | + |
| 61 | +For FaaS environments (`process_before_response=True`), long-running handlers execute as "lazy listeners" in a thread pool after the ack response is returned. |
| 62 | + |
| 63 | +### Core Abstractions |
| 64 | + |
| 65 | +- **`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. |
| 66 | +- **`Middleware`** (`slack_bolt/middleware/`) -- Abstract base with `process(req, resp, next)`. Built-in: authorization, request verification, SSL check, URL verification, assistant, self-event ignoring. |
| 67 | +- **`Listener`** (`slack_bolt/listener/`) -- Has matchers, middleware, and an ack/handler function. `CustomListener` is the main implementation. |
| 68 | +- **`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. |
| 69 | +- **`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`). |
| 70 | +- **`BoltRequest` / `BoltResponse`** (`slack_bolt/request/`, `slack_bolt/response/`) -- Request/response wrappers. Request has `mode` of "http" or "socket_mode". |
| 71 | + |
| 72 | +### Kwargs Injection |
| 73 | + |
| 74 | +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`. |
| 75 | + |
| 76 | +### Adapter System |
| 77 | + |
| 78 | +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. |
| 79 | + |
| 80 | +### Async Support |
| 81 | + |
| 82 | +`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`). |
| 83 | + |
| 84 | +### AI Agents & Assistants |
| 85 | + |
| 86 | +`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. |
| 87 | + |
| 88 | +## Test Organization |
| 89 | + |
| 90 | +- `tests/scenario_tests/` -- Integration-style tests with realistic Slack payloads |
| 91 | +- `tests/slack_bolt/` -- Unit tests mirroring the source structure |
| 92 | +- `tests/adapter_tests/` and `tests/adapter_tests_async/` -- Framework adapter tests |
| 93 | +- `tests/mock_web_api_server/` -- Mock Slack API server used by tests |
| 94 | +- Async test variants use `_async` suffix directories |
| 95 | + |
| 96 | +## Code Style |
| 97 | + |
| 98 | +- **Black** formatter, 125 char line length |
| 99 | +- **Flake8** linter, 125 char line length |
| 100 | +- **MyPy** with `force_union_syntax=true` and `warn_unused_ignores=true` (use `X | Y` union syntax, not `Union[X, Y]`) |
| 101 | +- pytest with `asyncio_mode = "auto"` |
0 commit comments