From 80ae8c6c59a750a91cc832becb92fc4f30d408dc Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 1 Sep 2026 22:16:34 +0000
Subject: [PATCH 01/31] chore(deps-dev): bump ruff from 0.16.4 to 0.16.5
(#1573)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
requirements/dev_tools.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/dev_tools.txt b/requirements/dev_tools.txt
index 023bd9f62..d6121a782 100644
--- a/requirements/dev_tools.txt
+++ b/requirements/dev_tools.txt
@@ -4,4 +4,4 @@
mypy==2.3.0
# ruff
-ruff==0.16.4
+ruff==0.16.5
From 69bd90fc7f58b7e2570092014b7ea2587073cc94 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 2 Sep 2026 06:57:15 -0700
Subject: [PATCH 02/31] chore(deps): update moto requirement from <6,>=5.2.2 to
>=5.2.3,<6 (#1571)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
requirements/test_adapter.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/test_adapter.txt b/requirements/test_adapter.txt
index 702856aac..5b7713299 100644
--- a/requirements/test_adapter.txt
+++ b/requirements/test_adapter.txt
@@ -6,7 +6,7 @@
moto>=3,<5; python_version < "3.8"
moto>=3,<5.1; python_version >= "3.8" and python_version < "3.9"
moto>=3,<5.2; python_version >= "3.9" and python_version < "3.10"
-moto>=5.2.2,<6; python_version >= "3.10"
+moto>=5.2.3,<6; python_version >= "3.10"
# boddle
# Note: for Bottle app tests
From 50e711b5b8e843ae91b4d77250b25e32f414dd7c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 4 Sep 2026 08:20:19 -0700
Subject: [PATCH 03/31] chore(deps-dev): update tornado requirement from
<7,>=6.5.6 to >=6.5.8,<7 (#1572)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
requirements/adapter_dev.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/adapter_dev.txt b/requirements/adapter_dev.txt
index 34a96a911..dd688feb0 100644
--- a/requirements/adapter_dev.txt
+++ b/requirements/adapter_dev.txt
@@ -71,7 +71,7 @@ starlette>=0.49.3,<1; python_version >= "3.9"
# tornado
# Note: tornado 6.5.6 requires Python >=3.9; 3.7/3.8 stay on the older pinned release.
tornado>=6.2,<7; python_version < "3.9"
-tornado>=6.5.6,<7; python_version >= "3.9"
+tornado>=6.5.8,<7; python_version >= "3.9"
# websocket_client
# Note: Socket Mode 3rd party implementation
From 3b35e47159cb23bc01f84f7106bb26927fff3c09 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 4 Sep 2026 08:58:06 -0700
Subject: [PATCH 04/31] chore(deps-dev): update starlette requirement from
<1,>=0.49.3 to >=1.6.0,<2 (#1574)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: William Bergamin
Co-authored-by: William Bergamin
Co-authored-by: Claude
---
.claude/skills/managing-dependencies/SKILL.md | 4 +++-
requirements/adapter_dev.txt | 4 ++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/.claude/skills/managing-dependencies/SKILL.md b/.claude/skills/managing-dependencies/SKILL.md
index 8f67fccd8..fba850832 100644
--- a/.claude/skills/managing-dependencies/SKILL.md
+++ b/.claude/skills/managing-dependencies/SKILL.md
@@ -19,7 +19,7 @@ The convention resolves this without dropping old-Python support: pin each inter
## File-layout convention
-Each file starts with a `# pip install -r requirements/.txt` header, then lists **one dependency per section**: the name of the dependency (as a `# name` header), an optional rationale note (starting with `# Note:`, explaining why a version is pinned or split), then the requirement line(s), separated from the next section by a blank line. This makes every pin self-documenting.
+Each file starts with a `# pip install -r requirements/.txt` header, then lists **one dependency per section**: the name of the dependency (as a `# name` header), an **extremely optional** rationale note (starting with `# Note:` — see below), then the requirement line(s), separated from the next section by a blank line. This makes every pin self-documenting.
```
# pip install -r requirements/test.txt
@@ -34,6 +34,8 @@ pytest-cov>=7.1.0,<8; python_version >= "3.14"
Keep this layout when adding or editing dependencies. Never leave an empty trailing `;` (a fossil of a collapsed split; delete it — the old `pytest-asyncio<2;` line was exactly this).
+**On the `# Note:` — omit it by default.** The requirement lines and their `python_version` markers already state *what* is pinned and *which interpreter gets which release*, and this skill already establishes that an old-side ceiling marks a floor jump. A note must never restate any of that. Write one only to record rationale the lines cannot express on their own — a non-obvious cap, or a coupling invisible from the specifier. The archetype is the `tracerite` pin (see "a coupled companion dependency" below): a companion dependency that breaks with no `requires_python` metadata, which no reader could infer from the line itself. A routine floor-jump split (like `chalice`, `fastapi`, or `starlette`) needs no note at all. Several older sections still carry notes that merely restate their lines; treat those as legacy, not a template to copy.
+
## Which files need Python-version markers
A marker split is only needed for requirements files installed across the **full** Python matrix. Which file you are editing decides this. To see where a file is installed, read `.github/workflows/ci-build.yml`. It is the source of truth for which Python versions install which requirements files. Everything except `dev_tools.txt` is installed by the `unittest` matrix job across 3.7–3.14.
diff --git a/requirements/adapter_dev.txt b/requirements/adapter_dev.txt
index dd688feb0..beb6b1ace 100644
--- a/requirements/adapter_dev.txt
+++ b/requirements/adapter_dev.txt
@@ -64,9 +64,9 @@ sanic>=25.3.0,<25.12.0; python_version >= "3.9" and python_version < "3.10"
sanic>=25.12.1,<26; python_version >= "3.10"
# starlette
-# Note: starlette 0.49.3 requires Python >=3.9; 3.7/3.8 stay on the older pinned release.
starlette>=0.19.1,<0.45; python_version < "3.9"
-starlette>=0.49.3,<1; python_version >= "3.9"
+starlette>=0.49.3,<0.50; python_version >= "3.9" and python_version < "3.10"
+starlette>=1.6.0,<2; python_version >= "3.10"
# tornado
# Note: tornado 6.5.6 requires Python >=3.9; 3.7/3.8 stay on the older pinned release.
From 0f631956f3a665175d80a826d861c00fa03f9f26 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 4 Sep 2026 09:08:09 -0700
Subject: [PATCH 05/31] chore(deps-dev): update websocket-client requirement
from <2,>=1.9.0 to >=1.9.1,<2 (#1570)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: William Bergamin
Co-authored-by: William Bergamin
Co-authored-by: Claude
---
requirements/adapter_dev.txt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/requirements/adapter_dev.txt b/requirements/adapter_dev.txt
index beb6b1ace..502048a49 100644
--- a/requirements/adapter_dev.txt
+++ b/requirements/adapter_dev.txt
@@ -76,4 +76,5 @@ tornado>=6.5.8,<7; python_version >= "3.9"
# websocket_client
# Note: Socket Mode 3rd party implementation
websocket_client>=1.2.3,<1.9; python_version < "3.9"
-websocket_client>=1.9.0,<2; python_version >= "3.9"
+websocket_client>=1.9.0,<1.9.1; python_version >= "3.9" and python_version < "3.10"
+websocket_client>=1.9.1,<2; python_version >= "3.10"
From c793795bc32f553ecd204ac272a9627165ca0bf2 Mon Sep 17 00:00:00 2001
From: Luke Russell <31357343+lukegalbraithrussell@users.noreply.github.com>
Date: Tue, 8 Sep 2026 09:35:07 -0700
Subject: [PATCH 06/31] docs: removes quickstart (reducing to 1 quickstart on
site) | updates creating an app page (#1575)
---
docs/english/_sidebar.json | 5 -
docs/english/creating-an-app.md | 10 +-
docs/english/getting-started.md | 288 --------------------------------
3 files changed, 7 insertions(+), 296 deletions(-)
delete mode 100644 docs/english/getting-started.md
diff --git a/docs/english/_sidebar.json b/docs/english/_sidebar.json
index aa75b0c15..22a8ba69d 100644
--- a/docs/english/_sidebar.json
+++ b/docs/english/_sidebar.json
@@ -5,8 +5,6 @@
"label": "Bolt for Python",
"className": "sidebar-title"
},
- "tools/bolt-python/getting-started",
- { "type": "html", "value": "
" },
"tools/bolt-python/creating-an-app",
{
"type": "category",
@@ -102,7 +100,6 @@
"label": "Legacy",
"items": ["tools/bolt-python/legacy/steps-from-apps"]
},
- { "type": "html", "value": "
" },
{
"type": "category",
"label": "Tutorials",
@@ -116,13 +113,11 @@
"tools/bolt-python/tutorial/modals/modals"
]
},
- { "type": "html", "value": "
" },
{
"type": "link",
"label": "Reference",
"href": "https://docs.slack.dev/tools/bolt-python/reference/index.html"
},
- { "type": "html", "value": "
" },
{
"type": "category",
"label": "日本語 (日本)",
diff --git a/docs/english/creating-an-app.md b/docs/english/creating-an-app.md
index 66e1febee..0901588a8 100644
--- a/docs/english/creating-an-app.md
+++ b/docs/english/creating-an-app.md
@@ -4,10 +4,14 @@ sidebar_label: Creating an app
# Creating an app with Bolt for Python
-This guide is meant to walk you through getting up and running with a Slack app using Bolt for Python. Along the way, we’ll create a new Slack app, set up your local environment, and develop an app that listens and responds to messages from a Slack workspace.
+:::tip[More doing, less reading]
+This guide is a more thorough explanation on creating a Slack app. If you want a running app as fast as possible, follow our [Quickstart](/quickstart) that harnesses the power of Bolt and the [Slack CLI](/tools/slack-cli).
+:::
+
+Follow along to get up and running with a Slack app using Bolt for Python. Along the way, we’ll create a new Slack app, set up your local environment, and develop an app that listens and responds to messages from a Slack workspace.
When you're finished, you'll have created the [Getting Started app](https://github.com/slackapi/bolt-python/tree/main/examples/getting_started) to run, modify, and make your own. ⚡️
-
+
---
### Create a new app {#create-an-app}
@@ -15,7 +19,7 @@ First thing's first: before you start developing with Bolt, you'll want to [crea
:::tip[A place to test and learn]
-We recommend using a workspace where you won't disrupt real work getting done — [you can create a new one for free](https://slack.com/get-started#create).
+We recommend using a workspace where you won't disrupt real work getting done, like a [developer sandbox](/tools/developer-sandboxes).
:::
diff --git a/docs/english/getting-started.md b/docs/english/getting-started.md
deleted file mode 100644
index 8cfd7faf8..000000000
--- a/docs/english/getting-started.md
+++ /dev/null
@@ -1,288 +0,0 @@
----
-sidebar_label: Quickstart
-title: Quickstart guide with Bolt for Python
----
-
-This quickstart guide aims to help you get a Slack app using Bolt for Python up and running as soon as possible!
-
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-
-When complete, you'll have a local environment configured with a customized [app](https://github.com/slack-samples/bolt-python-getting-started-app) running to modify and make your own.
-
-:::tip[Reference for readers]
-
-In search of the complete guide to building an app from scratch? Check out the [building an app](/tools/bolt-python/creating-an-app) guide.
-
-:::
-
-#### Prerequisites
-
-A few tools are needed for the following steps. We recommend using the [**Slack CLI**](/tools/slack-cli/) for the smoothest experience, but other options remain available.
-
-You can also begin by installing git and downloading [Python 3.7 or later](https://www.python.org/downloads/), or the latest stable version of Python. Refer to [Python's setup and building guide](https://devguide.python.org/getting-started/setup-building/) for more details.
-
-Install the latest version of the Slack CLI to get started:
-
-- [Slack CLI for macOS & Linux](/tools/slack-cli/guides/installing-the-slack-cli-for-mac-and-linux)
-- [Slack CLI for Windows](/tools/slack-cli/guides/installing-the-slack-cli-for-windows)
-
-Then confirm a successful installation with the following command:
-
-```sh
-$ slack version
-```
-
-An authenticated login is also required if this hasn't been done before:
-
-```sh
-$ slack login
-```
-
-:::info[A place to belong]
-
-A workspace where development can happen is also needed.
-
-We recommend using [developer sandboxes](/tools/developer-sandboxes) to avoid disruptions where real work gets done.
-
-:::
-
-## Creating a project {#creating-a-project}
-
-With the toolchain configured, it's time to set up a new Bolt project. This contains the code that handles logic for your app.
-
-If you don’t already have a project, let’s create a new one!
-
-
-
-
-A starter template can be used to start with project scaffolding:
-
-```sh
-$ slack create first-bolt-app --template slack-samples/bolt-python-getting-started-app
-$ cd first-bolt-app
-```
-
-After a project is created you'll have a `requirements.txt` file for app dependencies and a `.slack` directory for Slack CLI configuration.
-
-A few other files exist too, but we'll visit these later.
-
-
-
-
-A starter template can be cloned to start with project scaffolding:
-
-```sh
-$ git clone https://github.com/slack-samples/bolt-python-getting-started-app first-bolt-app
-$ cd first-bolt-app
-```
-
-Outlines of a project are taking shape, so we can move on to running the app!
-
-
-
-
-We recommend using a [Python virtual environment](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/#creating-a-virtual-environment) to manage your project's dependencies. This is a great way to prevent conflicts with your system's Python packages. Let's create and activate a new virtual environment with [Python 3.7 or later](https://www.python.org/downloads/):
-
-```sh
-$ python3 -m venv .venv
-$ source .venv/bin/activate
-$ pip install -r requirements.txt
-```
-
-Confirm the virtual environment is active by checking that the path to `python3` is _inside_ your project ([a similar command is available on Windows](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/#activating-a-virtual-environment)):
-
-```sh
-$ which python3
-# Output: /path/to/first-bolt-app/.venv/bin/python3
-```
-
-## Running the app {#running-the-app}
-
-Before you can start developing with Bolt, you will want a running Slack app.
-
-
-
-
-The getting started app template contains a `manifest.json` file with details about an app that we will use to get started. Use the following command and select "Create a new app" to install the app to the team of choice:
-
-```sh
-$ slack run
-...
-⚡️ Bolt app is running!
-```
-
-With the app running, you can test it out with the following steps in Slack:
-
-1. Open a direct message with your app or invite the bot `@first-bolt-app (local)` to a public channel.
-2. Send "hello" to the current conversation and wait for a response.
-3. Click the attached button labelled "Click Me" to post another reply.
-
-After confirming the app responds, celebrate, then interrupt the process by pressing `CTRL+C` in the terminal to stop your app from running.
-
-
-
-
-Navigate to your list of apps and [create a new Slack app](https://api.slack.com/apps/new) using the "from a manifest" option:
-
-1. Select the workspace to develop your app in.
-2. Copy and paste the `manifest.json` file contents to create your app.
-3. Confirm the app features and click "Create".
-
-You'll then land on your app's **Basic Information** page, which is an overview of your app and which contains important credentials:
-
-
-
-To listen for events happening in Slack (such as a new posted message) without opening a port or exposing an endpoint, we will use [Socket Mode](/tools/bolt-python/concepts/socket-mode). This connection requires a specific app token:
-
-1. On the **Basic Information** page, scroll to the **App-Level Tokens** section and click **Generate Token and Scopes**.
-2. Name the token "Development" or something similar and add the `connections:write` scope, then click **Generate**.
-3. Save the generated `xapp` token as an environment variable within your project:
-
-```sh
-$ export SLACK_APP_TOKEN=
-```
-
-The above command works on Linux and macOS but [similar commands are available on Windows](https://superuser.com/questions/212150/how-to-set-env-variable-in-windows-cmd-line/212153#212153).
-
-:::warning[Keep it secret. Keep it safe.]
-
-Treat your tokens like a password and [keep it safe](/concepts/security). Your app uses these to retrieve and send information to Slack.
-
-:::
-
-A bot token is also needed to interact with the Web API methods as your app's bot user. We can gather this as follows:
-
-1. Navigate to the **OAuth & Permissions** on the left sidebar and install your app to your workspace to generate a token.
-2. After authorizing the installation, you'll return to the **OAuth & Permissions** page and find a **Bot User OAuth Token**:
-
-
-
-3. Copy the bot token beginning with `xoxb` from the **OAuth & Permissions page** and then store it in a new environment variable:
-
-```sh
-$ export SLACK_BOT_TOKEN=xoxb-
-```
-
-After saving tokens for the app you created, it is time to run it:
-
-```sh
-$ python3 app.py
-...
-⚡️ Bolt app is running!
-```
-
-With the app running, you can test it out with the following steps in Slack:
-
-1. Open a direct message with your app or invite the bot `@BoltApp` to a public channel.
-2. Send "hello" to the current conversation and wait for a response.
-3. Click the attached button labelled "Click Me" to post another reply.
-
-After confirming the app responds, celebrate, then interrupt the process by pressing `CTRL+C` in the terminal to stop your app from running.
-
-
-
-
-## Updating the app
-
-At this point, you've successfully run the getting started Bolt for Python [app](https://github.com/slack-samples/bolt-python-getting-started-app)!
-
-The defaults included leave opportunities abound, so to personalize this app let's now edit the code to respond with a kind farewell.
-
-#### Responding to a farewell
-
-Chat is a common thing apps do and responding to various types of messages can make conversations more interesting.
-
-Using an editor of choice, open the `app.py` file and add the following import to the top of the file, and message listener after the "hello" handler:
-
-```python
-import random
-
-@app.message("goodbye")
-def message_goodbye(say):
- responses = ["Adios", "Au revoir", "Farewell"]
- parting = random.choice(responses)
- say(f"{parting}!")
-```
-
-Once the file is updated, save the changes and then we'll make sure those changes are being used.
-
-
-
-
-Run the following command and select the app created earlier to start, or restart, your app with the latest changes:
-
-```sh
-$ slack run
-...
-⚡️ Bolt app is running!
-```
-
-After finding the above output appears, open Slack to perform these steps:
-
-1. Return to the direct message or public channel with your bot.
-2. Send "goodbye" to the conversation.
-3. Receive a parting response from before and repeat "goodbye" to find another one.
-
-Your app can be stopped again by pressing `CTRL+C` in the terminal to end these chats.
-
-
-
-
-Run the following command to start, or restart, your app with the latest changes:
-
-```sh
-$ python3 app.py
-...
-⚡️ Bolt app is running!
-```
-
-After finding the above output appears, open Slack to perform these steps:
-
-1. Return to the direct message or public channel with your bot.
-2. Send "goodbye" to the conversation.
-3. Receive a parting response from before and repeat "goodbye" to find another one.
-
-Your app can be stopped again by pressing `CTRL+C` in the terminal to end these chats.
-
-
-
-
-#### Customizing app settings
-
-The created app will have some placeholder values and a small set of [scopes](/reference/scopes) to start, but we recommend exploring the customizations possible on app settings.
-
-
-
-
-Open app settings for your app with the following command:
-
-```sh
-$ slack app settings
-```
-
-This will open the following page in a web browser:
-
-
-
-
-
-
-Browse to https://api.slack.com/apps and select your app "Getting Started Bolt App" from the list.
-
-This will open the following page:
-
-
-
-
-
-
-On these pages you're free to make changes such as updating your app icon, configuring app features, and perhaps even distributing your app!
-
-## Next steps {#next-steps}
-
-You can now continue customizing your app with various features to make it right for whatever job's at hand. Here are some ideas about what to explore next:
-
-- Follow along with the steps that went into making this app on the [creating an app](/tools/bolt-python/creating-an-app) guide for an educational overview.
-- Check out the [Agent quickstart](/ai/agent-quickstart) to get up and running with an agent.
-- Browse our [curated catalog of samples](/samples) for more apps to use as a starting point for development.
\ No newline at end of file
From eddc4766559e5dc623700015c70ea360d076dced Mon Sep 17 00:00:00 2001
From: William Bergamin
Date: Fri, 25 Sep 2026 15:53:05 -0400
Subject: [PATCH 07/31] docs(deps): simplify the managing-dependencies skill
(#1578)
Co-authored-by: Claude
---
.claude/skills/managing-dependencies/SKILL.md | 142 ++++++------------
1 file changed, 47 insertions(+), 95 deletions(-)
diff --git a/.claude/skills/managing-dependencies/SKILL.md b/.claude/skills/managing-dependencies/SKILL.md
index fba850832..335ac7d0a 100644
--- a/.claude/skills/managing-dependencies/SKILL.md
+++ b/.claude/skills/managing-dependencies/SKILL.md
@@ -1,129 +1,81 @@
---
name: managing-dependencies
description: >-
- Use when adding, updating, pinning, or reviewing any dependency in this repo's requirements/*.txt files, including taking a Dependabot bump or writing a requirement line by hand. Also use when a pip install fails on the older Python jobs while newer ones pass, or when CI errors with "Could not find a version that satisfies", "No matching distribution found", "Requires-Python >=3.x", or "ResolutionImpossible". Triggers include: "add to requirements", "bump/update ", "pin ", "fix this dependabot PR", "CI can't install on Python 3.7/3.8/3.9", "requires-python error in the install step". This skill defines the layout and version-constraint conventions to follow; reach for it before hand-editing any requirements/*.txt file.
+ Use when adding, bumping, pinning, or reviewing a dependency in requirements.txt or requirements/*.txt, including taking or fixing a Dependabot PR. Also use when pip install fails on some Python versions in CI but not others ("Could not find a version that satisfies the requirement", "No matching distribution found", "Requires-Python", "ResolutionImpossible"), including PyPy-only failures, and when dropping support for an old Python version.
---
# Managing dependencies
-## Overview
+This repo supports a range of Python versions, and one set of requirements files has to install on all of them. Dependabot proposes the newest release, so its bumps often raise a lower bound past what the oldest Pythons can install, and CI fails at the install step on those jobs only. The fix is to split the requirement with PEP 508 `python_version` markers so each Python gets the newest release it can install. Dropping an old Python to turn CI green is not the fix.
-Every `requirements/*.txt` file in this repo follows one layout convention and one version-constraint pattern. This keeps a single set of pins working across the whole Python matrix and every diff readable. The mechanism for making one line behave differently per interpreter is [PEP 508](https://peps.python.org/pep-0508/) environment markers. That spec is the authority for the marker syntax used throughout this skill.
+## Where the facts live
-Two facts about this repo drive everything below:
+Read these instead of trusting memory; they change often.
-- It supports **Python `>=3.7`** (`requires-python` and the classifiers in `pyproject.toml`). Its CI matrix in `.github/workflows/ci-build.yml` tests **CPython 3.7 through 3.14 only** — there is **no PyPy** (the classifiers list only `Programming Language :: Python :: Implementation :: CPython`).
-- Many popular packages keep raising their minimum Python. A bump that raises a dependency's **lower bound** to a release requiring a newer Python makes pip's resolver find nothing installable on the old interpreters. The install step then fails there before tests even run.
+- **Supported Pythons:** `requires-python` and the `Programming Language :: Python :: 3.X` classifiers in `pyproject.toml`, and the CI matrix.
+- **Who installs a file, on which Python:** `grep -rn requirements .github/workflows scripts requirements pyproject.toml`. This also catches `-r` includes. For a hit in a script, find the CI job that runs it and read its `python-version`.
+- **Whether a file ships to users:** a file that `pyproject.toml` reads into package metadata (`dependencies` or `optional-dependencies` under `[tool.setuptools.dynamic]`) ends up in the published wheel.
-The convention resolves this without dropping old-Python support: pin each interpreter to the newest release it can actually install, using PEP 508 `python_version` markers.
+## Workflow
-## File-layout convention
+- [ ] 1. Find which Pythons install the file. A file installed only on the newest Python takes the bump as-is.
+- [ ] 2. Find the newest release each affected Python can install (see "Finding the ceiling").
+- [ ] 3. If every Python the line covers can install the new lower bound, take the bump as one line. Done.
+- [ ] 4. Otherwise split the line (see "Splitting a line").
+- [ ] 5. Re-read the section: no Python matches two lines, and the newest line is open-ended.
-Each file starts with a `# pip install -r requirements/.txt` header, then lists **one dependency per section**: the name of the dependency (as a `# name` header), an **extremely optional** rationale note (starting with `# Note:` — see below), then the requirement line(s), separated from the next section by a blank line. This makes every pin self-documenting.
+Change only the section you are fixing; don't reformat other sections in the same change.
-```
-# pip install -r requirements/test.txt
-
-# pytest
-pytest<9.2
-
-# pytest-cov
-# Note: only needed to evaluate coverage on the latest supported python version
-pytest-cov>=7.1.0,<8; python_version >= "3.14"
-```
-
-Keep this layout when adding or editing dependencies. Never leave an empty trailing `;` (a fossil of a collapsed split; delete it — the old `pytest-asyncio<2;` line was exactly this).
-
-**On the `# Note:` — omit it by default.** The requirement lines and their `python_version` markers already state *what* is pinned and *which interpreter gets which release*, and this skill already establishes that an old-side ceiling marks a floor jump. A note must never restate any of that. Write one only to record rationale the lines cannot express on their own — a non-obvious cap, or a coupling invisible from the specifier. The archetype is the `tracerite` pin (see "a coupled companion dependency" below): a companion dependency that breaks with no `requires_python` metadata, which no reader could infer from the line itself. A routine floor-jump split (like `chalice`, `fastapi`, or `starlette`) needs no note at all. Several older sections still carry notes that merely restate their lines; treat those as legacy, not a template to copy.
-
-## Which files need Python-version markers
-
-A marker split is only needed for requirements files installed across the **full** Python matrix. Which file you are editing decides this. To see where a file is installed, read `.github/workflows/ci-build.yml`. It is the source of truth for which Python versions install which requirements files. Everything except `dev_tools.txt` is installed by the `unittest` matrix job across 3.7–3.14.
-
-| File | Installed on | Needs markers? |
-| ----------------------------- | ----------------------------------------------------- | ----------------------------------- |
-| `requirements/adapter_dev.txt` | full matrix (`unittest`; also `typecheck`/`codecov` @3.14) | **Yes, if a bump raises the floor** |
-| `requirements/async_dev.txt` | full matrix (`unittest`; also `typecheck`/`codecov` @3.14) | **Yes, if a bump raises the floor** |
-| `requirements/test.txt` | full matrix (`unittest`) | **Yes, if a bump raises the floor** |
-| `requirements/test_adapter.txt` | full matrix (`unittest`; `codecov` @3.14) | **Yes, if a bump raises the floor** |
-| `requirements/test_async.txt` | full matrix (`unittest`) | **Yes, if a bump raises the floor** |
-| `requirements/dev_tools.txt` | `lint` + `typecheck`, **latest Python only** (3.14) | No, just take the bump (`==` pins) |
-
-If the bump lands in a latest-Python-only file, take it as-is: no markers, no ceiling, just the layout convention above.
-
-Unlike some sibling repos, bolt-python has **no requirements file that feeds packaged wheel metadata**: `pyproject.toml` has no `[project.optional-dependencies]`, and `[tool.setuptools.dynamic]` resolves only `version` and `readme`. So there is no "special" file whose comments leak into a wheel — every `requirements/*.txt` file is dev/test-only.
-
-## The version-constraint pattern
+## File layout
-When a dependency's floor rises to a release that requires a newer Python, **do not** just take the bump, and **do not** drop old-Python support to make CI pass. Instead, split the requirement into `python_version`-marked lines that **partition the whole matrix**. Every interpreter matches exactly one line. Old interpreters keep the last compatible release (with an explicit ceiling), and the newest line is open-ended so future Pythons stay covered.
+Each file starts with a `# pip install -r ` header, then one section per dependency: a `# ` line, optional `# Note:` lines, the requirement line(s), and a blank line.
```
-# aiohttp
-aiohttp>=3,<4; python_version < "3.9"
-aiohttp>=3.13.5,<4; python_version >= "3.9"
-```
+# pip install -r requirements/testing.txt
-`aiohttp` 3.13.5 requires Python `>=3.9`, so Python 3.7/3.8 stay on the older line. The same 3.9 split appears for `falcon`, `fastapi`, `Flask`, `Werkzeug`, `starlette`, `tornado`, `websocket_client`, and (in `test_async.txt`) `asgiref`. The `Django` split lands at 3.8 instead — Django 4.x requires `>=3.8`, so 3.7 keeps the 3.2 line:
+# pkg
+pkg>=1.4,<2; python_version < "3.9"
+pkg>=2.0,<2.3; python_version == "3.9"
+pkg>=2.5.1,<3; python_version >= "3.10"
+# other-pkg
+# Note: other-pkg 4.x breaks on Python 3.8 but declares no requires_python, so pip can't filter it.
+other-pkg>=3,<4
```
-# Django
-Django>=3.2,<4; python_version < "3.8"
-Django>=4.2.30,<6; python_version >= "3.8"
-```
-
-## Canonical marker style
-
-Consistency matters because these lines are read and edited often, and a stray style makes diffs noisy. Standardize on this:
-
-- Spaces around every operator in the marker: `python_version >= "3.9"`, never `python_version>="3.9"`.
-- Double-quoted `major.minor` string: `"3.9"`. (`packaging` compares these version-aware, so `python_version >= "3.9"` correctly includes 3.10–3.14, no lexicographic surprise.)
-- Use `>=` / `<` for the Python boundary; avoid `>` / `<=` so the boundary version lands on exactly one side. **This rule is about the `python_version` marker, not the version specifier** — `boto3<=2` and `cheroot<12` are correct as written.
-- One space after the `;`, none before: `pkg>=1,<2; python_version >= "3.9"`.
-- The old-side line always carries an explicit upper bound (the floor-jump version).
-- The marker set must be **exhaustive and mutually exclusive** across the matrix. The newest line ends open-ended (`>= "X.Y"`), never a bare `==` that leaves future Pythons unmatched.
-
-## Deriving the versions to pin
-You need two numbers: the **floor** (which Python the new release requires) and the old-side **ceiling** (the first release that raised that floor).
+**Notes:** write one only for what the lines can't say: a cap that isn't obvious, a coupling with another package, or a release with wrong metadata. Don't restate versions or which Python gets which release; a routine split needs no note. Existing notes that only restate their lines are legacy: drop one when you edit its section, and don't copy it.
-1. **Floor.** Read the metadata for the _exact target version_ at `https://pypi.org/pypi///json`. The `info.requires_python` field gives the new minimum (e.g. `">=3.9"`). A `null` there means the release declares no floor.
+## Finding the ceiling
-2. **Ceiling.** Walk the release history at `https://pypi.org/pypi//json` and find the **first version that raised the floor above the oldest matrix Python**. The old-side ceiling is `< `. For example, if a package jumped to `>=3.9` at version **4.0.0**, the old-side cap is `<4` even if the target is `4.2.0` (pinning `<4.2.0` would wrongly admit 4.0.0–4.1.x, which are also 3.9-only).
+An old Python's ceiling is the first release that dropped it, not the release Dependabot proposes. If `pkg` dropped 3.9 at 2.3 and the target is 2.5.1, the 3.9 line is `<2.3`, since 2.3 through 2.5.0 are 3.10-only too.
-Why an explicit ceiling instead of trusting pip to filter by `Requires-Python`? Because that filtering only holds if every future release keeps its metadata correct; a single mis-tagged release would silently float onto an untested interpreter. An explicit ceiling makes the intent self-documenting and robust.
+- **From a red CI job:** the failing install log is ground truth. The lowest version on its `Ignored the following versions that require a different python version` line is that Python's ceiling.
+- **For any Python:** `pip index versions --python-version 3.9` lists what 3.9 can install, newest first. Run it again for the next Python up; the first release newer than 3.9's newest is 3.9's ceiling.
+- **The pre-bump lower bound** is in the Dependabot PR title (`update pkg requirement from <3,>=2.0 to >=2.5.1,<3`) or `git diff`.
-`tracerite` is the cautionary case: its releases after 1.1.2 break on Python `<= 3.8`, yet those releases publish **no `requires_python` metadata at all** (verify: `https://pypi.org/pypi/tracerite/1.1.3/json` shows `requires_python: null`). So pip filtering offers zero protection on the old interpreters, and the explicit `tracerite<1.1.2` ceiling is load-bearing, not decorative.
+## Splitting a line
-**If you arrived here from a red CI job:** the failing _install_ log is ground truth. It names the interpreter that failed and the versions pip was actually offered, e.g.:
+Split only the Pythons that the bumped line covers and the new lower bound excludes. Leave existing bands for older Pythons alone, even when they are coarser than they could be.
-```
-ERROR: Ignored the following versions that require a different python version: 4.2.0 Requires-Python >=3.9
-ERROR: Could not find a version that satisfies the requirement falcon>=4.2.0 (from versions: ..., 3.1.3)
-```
-
-Cross-check the PyPI value against that log so you are never guessing. (If instead the failure is a real test failure, or hits _every_ Python version, this pattern does not apply, so investigate the bump normally.)
+- Lines run oldest Python to newest. The newest line takes the bump and stays open-ended (`>= "X.Y"`).
+- Each band that splits off keeps the line's pre-bump lower bound and gets its ceiling from "Finding the ceiling". Pythons that share a ceiling share a band.
+- Marker style: `pkg>=1,<2; python_version == "3.9"`. Spaces around operators, double-quoted `"X.Y"`, one space after `;`. A one-Python band is `== "X.Y"`; a band spanning several is `>= "X.Y" and < "X.Z"`, or `< "X.Z"` when it is the oldest. Boundaries use `>=` and `<` so each Python lands on exactly one side. `python_version` is major.minor only (3.9.5 reports `"3.9"`), so `== "3.9"` covers every 3.9 patch; don't use `python_full_version` here, where `== "3.9"` matches only 3.9.0.
-## One harder shape: a coupled companion dependency
+A section with a single gated line (installed only on the newest Python, or only on PyPy) is intentional; don't fill in the other Pythons.
-Sometimes a package drags in another distribution with loose or wildcard versions that you must co-pin on the same boundary. `Sanic` imports `tracerite` with wildcard versions, so `tracerite` is pinned right beside it:
-
-```
-# sanic
-# Note: Sanic pulls in tracerite via a wildcard version, so tracerite is co-pinned here.
-# Note: tracerite > 1.1.2 is incompatible with Python <= 3.8 and ships no requires_python, so an explicit ceiling is required.
-tracerite<1.1.2; python_version < "3.9"
-sanic>=21,<24; python_version < "3.9"
-sanic>=25.3.0,<26; python_version >= "3.9"
-```
+## Gotchas
-The split boundary here (3.9) is driven by `tracerite`, **not** by Sanic itself — Sanic 25.3 supports Python 3.8 (`requires_python: >=3.8`). Python 3.8 is kept on old Sanic only because tracerite breaks there. When a companion transitive dependency is the thing that breaks, pin it explicitly rather than hoping the parent's resolver picks a compatible version, and keep it in the same section so the coupling stays visible.
+- **Dependabot rewrites only the last line** of a split section, the open-ended one. When it bumps a split package, check which Pythons that line covers; the new lower bound may exclude the oldest of them, which then splits off.
+- **Releases with no `requires_python`** can't be filtered by pip, so they install on Pythons they don't support and fail at import or test time rather than at install. `pip index` lists them too. Pin an explicit ceiling with a note saying why. When the culprit comes in loosely through another package, pin it in that package's section so the coupling stays visible.
+- **Only PyPy jobs fail:** the release usually dropped PyPy wheels. Gate on the implementation instead of downgrading CPython: `pkg<46; implementation_name == "pypy" and python_version == "3.10"`. Lowercase `pypy`, and `implementation_name`, not `platform_python_implementation`. No unmarked companion line is needed.
+- **Files that ship:** full-line comments only; an inline comment breaks the package build. Their lower bounds are the minimum users must install, so raise one only for a reason.
+- **Not this pattern:** a real test failure, or an install failure on every Python. Investigate the bump normally.
-## Collapse when a Python is dropped
+## Dropping a Python version
-Marker splits are maintenance cost, so remove them when they stop earning their keep. When a Python version is dropped from the CI matrix (and from `requires-python` / the classifiers), collapse any split whose only reason was that version back into a single unmarked line, and delete the trailing `;`. For example, if 3.7 is dropped, the `Django>=3.2,<4; python_version < "3.8"` line has no interpreter left to serve, and the section collapses to a single `Django` line. A leaner file is easier for both humans and Dependabot to reason about.
+When a Python leaves the classifiers and the CI matrix, merge any band that only served it into its neighbor. If a section is left with one line, remove its marker and the `;`.
-## What to leave alone
+## Leave alone
-- **Do not touch `requires-python` or the CI matrix.** Keeping 3.7 working on old dependency versions is the entire point; changing the floor is a separate, deliberate decision.
-- **Do not add runtime dependencies to `pyproject.toml`.** The core package depends only on `slack_sdk` (see the "Single Runtime Dependency Rule" in `AGENTS.md`); everything else belongs in `requirements/*.txt`.
-- **Prefer markers over a Dependabot `ignore`.** An `ignore` rule freezes newer Pythons on the old version too, and hides the version knowledge in config. Reserve `ignore` for the rare dep that must stay pinned everywhere for reproducible output.
+- `requires-python`, the classifiers, and the CI matrix. Changing which Pythons are supported is its own decision.
+- Packages under `ignore` in `.github/dependabot.yml`: maintainers bump those by hand on purpose. Prefer a marker split over adding a new `ignore`, which freezes the package on every Python.
From e4be52bf0b1dedb329bbd0cdfad69f4e44bbf5f9 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 1 Oct 2026 22:16:31 +0000
Subject: [PATCH 08/31] chore(deps): bump codecov/codecov-action from 7.0.0 to
7.1.1 (#1582)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.github/workflows/ci-build.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml
index dd2119b8c..230de3d39 100644
--- a/.github/workflows/ci-build.yml
+++ b/.github/workflows/ci-build.yml
@@ -126,7 +126,7 @@ jobs:
pytest tests/scenario_tests_async/ --junitxml=reports/test_scenario_async.xml
- name: Upload test results to Codecov
if: ${{ !cancelled() }}
- uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
+ uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
with:
directory: ./reports/
fail_ci_if_error: false
@@ -162,7 +162,7 @@ jobs:
run: |
pytest --cov=./slack_bolt/ --cov-report=xml
- name: Upload coverage to Codecov
- uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
+ uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
with:
fail_ci_if_error: true
report_type: coverage
From 3ca19a00886c5abe924d3d0af990ca4d8711ecfd Mon Sep 17 00:00:00 2001
From: Haley Elmendorf <31392893+haleychaas@users.noreply.github.com>
Date: Tue, 6 Oct 2026 10:20:26 -0500
Subject: [PATCH 09/31] docs: fix broken getting-started links (#1585)
Co-authored-by: Claude
---
README.md | 2 +-
docs/english/index.md | 2 +-
docs/english/tutorial/ai-chatbot/ai-chatbot.md | 2 +-
.../tutorial/custom-steps-for-jira/custom-steps-for-jira.md | 2 +-
.../custom-steps-workflow-builder-new.md | 2 +-
docs/english/tutorial/modals/modals.md | 2 +-
6 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index 39747df40..d46490693 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@
-A Python framework to build Slack apps in a flash with the latest platform features. Read the [getting started guide](https://docs.slack.dev/tools/bolt-python/getting-started) and look at our [code examples](https://github.com/slackapi/bolt-python/tree/main/examples) to learn how to build apps using Bolt. The Python module documents are available [here](https://docs.slack.dev/tools/bolt-python/reference/).
+A Python framework to build Slack apps in a flash with the latest platform features. Read the [Creating an app guide](https://docs.slack.dev/tools/bolt-python/creating-an-app) and look at our [code examples](https://github.com/slackapi/bolt-python/tree/main/examples) to learn how to build apps using Bolt. The Python module documents are available [here](https://docs.slack.dev/tools/bolt-python/reference/).
## Setup
diff --git a/docs/english/index.md b/docs/english/index.md
index 60df4ec1c..d38ecd274 100644
--- a/docs/english/index.md
+++ b/docs/english/index.md
@@ -1,6 +1,6 @@
# Bolt for Python
-Bolt for Python is a Python framework to build Slack apps with the latest Slack platform features. Read the [Getting Started Guide](/tools/bolt-python/getting-started) to set up and run your first Bolt app.
+Bolt for Python is a Python framework to build Slack apps with the latest Slack platform features. Read the [Creating an app guide](/tools/bolt-python/creating-an-app) to set up and run your first Bolt app.
Then, explore the rest of the pages within the Guides section. The documentation there will help you build a Bolt app for whatever use case you may have.
diff --git a/docs/english/tutorial/ai-chatbot/ai-chatbot.md b/docs/english/tutorial/ai-chatbot/ai-chatbot.md
index 2fcc16e9a..013aeec47 100644
--- a/docs/english/tutorial/ai-chatbot/ai-chatbot.md
+++ b/docs/english/tutorial/ai-chatbot/ai-chatbot.md
@@ -241,5 +241,5 @@ You can also navigate to **Bolty** in your **Apps** list and select the **Messag
Congratulations! You've successfully integrated the power of AI into your workspace. Check out these links to take the next steps in your Bolt for Python journey.
-- To learn more about Bolt for Python, refer to the [Getting started](/tools/bolt-python/getting-started) documentation.
+- To learn more about Bolt for Python, refer to the [Creating an app](/tools/bolt-python/creating-an-app) documentation.
- For more details about creating workflow steps using the Bolt SDK, refer to the [workflow steps for Bolt](/workflows/workflow-steps) guide.
\ No newline at end of file
diff --git a/docs/english/tutorial/custom-steps-for-jira/custom-steps-for-jira.md b/docs/english/tutorial/custom-steps-for-jira/custom-steps-for-jira.md
index d74b82b8e..3aaff96f9 100644
--- a/docs/english/tutorial/custom-steps-for-jira/custom-steps-for-jira.md
+++ b/docs/english/tutorial/custom-steps-for-jira/custom-steps-for-jira.md
@@ -167,6 +167,6 @@ When finished, you can click the **Disconnect Account** button in the home tab t
Congratulations! You've successfully customized your workspace with custom steps in Workflow Builder. Check out these links to take the next steps in your journey.
-* To learn more about Bolt for Python, refer to the [getting started](/tools/bolt-python/getting-started) documentation.
+* To learn more about Bolt for Python, refer to the [Creating an app](/tools/bolt-python/creating-an-app) documentation.
* For more details about creating workflow steps using the Bolt SDK, refer to the [workflow steps for Bolt](/workflows/workflow-steps) guide.
* For information about custom steps dynamic options, refer to [custom steps dynamic options in Workflow Builder](/tools/bolt-python/concepts/custom-steps-dynamic-options).
diff --git a/docs/english/tutorial/custom-steps-workflow-builder-new/custom-steps-workflow-builder-new.md b/docs/english/tutorial/custom-steps-workflow-builder-new/custom-steps-workflow-builder-new.md
index 75be7aa32..d8941f70f 100644
--- a/docs/english/tutorial/custom-steps-workflow-builder-new/custom-steps-workflow-builder-new.md
+++ b/docs/english/tutorial/custom-steps-workflow-builder-new/custom-steps-workflow-builder-new.md
@@ -70,7 +70,7 @@ All of your app's settings can be configured within these screens. By creating a
Navigate to **Event Subscriptions** and expand **Subscribe to bot events** to see that we have subscribed to the `function_executed` event. This is also a requirement for adding workflow steps to our app, as it lets our app know when a step has been triggered, allowing our app to respond to it.
-Another configuration setting to note is **Socket Mode**. We have turned this on for our local development, but socket mode is not intended for use in a production environment. When you are satisfied with your app and ready to deploy it to a production environment, you should switch to using public HTTP request URLs. Read more about getting started with HTTP in [Bolt for Python here](/tools/bolt-python/getting-started).
+Another configuration setting to note is **Socket Mode**. We have turned this on for our local development, but socket mode is not intended for use in a production environment. When you are satisfied with your app and ready to deploy it to a production environment, you should switch to using public HTTP request URLs. Read more about getting started with HTTP in [Bolt for Python here](/tools/bolt-python/creating-an-app).
Clicking on **Workflow Steps** in the left nav will show you that one workflow step has been added! This reflects the `function` defined in our manifest: functions are workflow steps. We will get to this step's implementation later.
diff --git a/docs/english/tutorial/modals/modals.md b/docs/english/tutorial/modals/modals.md
index d25470b97..6e2aa11ee 100644
--- a/docs/english/tutorial/modals/modals.md
+++ b/docs/english/tutorial/modals/modals.md
@@ -131,4 +131,4 @@ All done! 🎉 You've created your first slash command using Block Kit and modal
## Next steps {#next-steps}
-If you want to learn more about Bolt for Python, refer to the [Getting Started guide](https://docs.slack.dev/tools/bolt-python/getting-started).
\ No newline at end of file
+If you want to learn more about Bolt for Python, refer to the [Creating an app guide](https://docs.slack.dev/tools/bolt-python/creating-an-app).
\ No newline at end of file
From a9dee3b76e938c0d3e6bb3a9c3405f89a3106c44 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 6 Oct 2026 19:56:02 +0000
Subject: [PATCH 10/31] chore(deps-dev): bump mypy from 2.3.0 to 2.4.0 (#1584)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
requirements/dev_tools.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/dev_tools.txt b/requirements/dev_tools.txt
index d6121a782..b95285f7b 100644
--- a/requirements/dev_tools.txt
+++ b/requirements/dev_tools.txt
@@ -1,7 +1,7 @@
# pip install -r requirements/dev_tools.txt
# mypy
-mypy==2.3.0
+mypy==2.4.0
# ruff
ruff==0.16.5
From c62ff892430fa7721183bb481d924a5b8119787c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 7 Oct 2026 09:47:16 -0700
Subject: [PATCH 11/31] chore(deps-dev): update falcon requirement from
<5,>=4.2.0 to >=4.4.0,<5 (#1583)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
requirements/adapter_dev.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/adapter_dev.txt b/requirements/adapter_dev.txt
index 502048a49..d55cb9af8 100644
--- a/requirements/adapter_dev.txt
+++ b/requirements/adapter_dev.txt
@@ -28,7 +28,7 @@ Django>=5.2.15,<6; python_version >= "3.10"
# falcon
# Note: falcon 4.2.0 requires Python >=3.9; 3.7/3.8 stay on the older pinned release.
falcon>=2,<4; python_version < "3.9"
-falcon>=4.2.0,<5; python_version >= "3.9"
+falcon>=4.4.0,<5; python_version >= "3.9"
# fastapi
fastapi>=0.70.0,<1; python_version < "3.9"
From 028bb771760a91acccf2552f9dbbeba9e446cc6f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 7 Oct 2026 16:51:43 +0000
Subject: [PATCH 12/31] chore(deps-dev): update starlette requirement from
<2,>=1.6.0 to >=1.7.0,<2 (#1581)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
requirements/adapter_dev.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/adapter_dev.txt b/requirements/adapter_dev.txt
index d55cb9af8..5d6d06083 100644
--- a/requirements/adapter_dev.txt
+++ b/requirements/adapter_dev.txt
@@ -66,7 +66,7 @@ sanic>=25.12.1,<26; python_version >= "3.10"
# starlette
starlette>=0.19.1,<0.45; python_version < "3.9"
starlette>=0.49.3,<0.50; python_version >= "3.9" and python_version < "3.10"
-starlette>=1.6.0,<2; python_version >= "3.10"
+starlette>=1.7.0,<2; python_version >= "3.10"
# tornado
# Note: tornado 6.5.6 requires Python >=3.9; 3.7/3.8 stay on the older pinned release.
From 1a9ea16481cefb4ea5938644242c5c74c7eea995 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 7 Oct 2026 17:45:33 +0000
Subject: [PATCH 13/31] chore(deps-dev): update websocket-client requirement
from <2,>=1.9.1 to >=1.9.2,<2 (#1579)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
requirements/adapter_dev.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/adapter_dev.txt b/requirements/adapter_dev.txt
index 5d6d06083..6d705d389 100644
--- a/requirements/adapter_dev.txt
+++ b/requirements/adapter_dev.txt
@@ -77,4 +77,4 @@ tornado>=6.5.8,<7; python_version >= "3.9"
# Note: Socket Mode 3rd party implementation
websocket_client>=1.2.3,<1.9; python_version < "3.9"
websocket_client>=1.9.0,<1.9.1; python_version >= "3.9" and python_version < "3.10"
-websocket_client>=1.9.1,<2; python_version >= "3.10"
+websocket_client>=1.9.2,<2; python_version >= "3.10"
From 377439296cec14aff8ae20681a79ba323c04754d Mon Sep 17 00:00:00 2001
From: William Bergamin
Date: Thu, 8 Oct 2026 16:14:47 -0400
Subject: [PATCH 14/31] docs: fix broken links (#1588)
Co-authored-by: Claude
---
.../concepts/custom-steps-dynamic-options.md | 20 +++++++++----------
.../english/tutorial/ai-chatbot/ai-chatbot.md | 2 +-
.../concepts/updating-pushing-views.md | 2 +-
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/docs/english/concepts/custom-steps-dynamic-options.md b/docs/english/concepts/custom-steps-dynamic-options.md
index 9a152daa0..dfe95a323 100644
--- a/docs/english/concepts/custom-steps-dynamic-options.md
+++ b/docs/english/concepts/custom-steps-dynamic-options.md
@@ -88,13 +88,13 @@ The `inputs` attribute defines the parameters to be passed as inputs to the step
The following format can be used to reference any input parameter defined by the step: `{{input_parameters.}}`.
-In addition, the `{{client.query}}` parameter can be used as a placeholder for an input value. The `{{client.builder_context}}` parameter will inject the [`slack#/types/user_context`](/tools/deno-slack-sdk/reference/slack-types/#usercontext) of the user building the workflow as the value to the input parameter.
+In addition, the `{{client.query}}` parameter can be used as a placeholder for an input value. The `{{client.builder_context}}` parameter will inject the [`slack#/types/user_context`](/reference/types/user_context-type) of the user building the workflow as the value to the input parameter.
### Types of dynamic options UIs {#dynamic-option-UIs}
The above example demonstrates one possible UI to be rendered for builders: a single-select drop-down menu of dynamic options. However, dynamic options in Workflow Builder can be rendered in one of two ways: as a drop-down menu (single-select or multi-select), or as a set of fields.
-The type is dictated by the output parameter of the custom step used as a dynamic option. In order to use a custom step in a dynamic option context, its output must adhere to a defined interface, that is, it must have an `options` parameter of type [`options_select`](/tools/deno-slack-sdk/reference/slack-types#options_select) or [`options_field`](/tools/deno-slack-sdk/reference/slack-types#options_field), as shown in the following code snippet.
+The type is dictated by the output parameter of the custom step used as a dynamic option. In order to use a custom step in a dynamic option context, its output must adhere to a defined interface, that is, it must have an `options` parameter of type [`options_select`](/reference/types/options_select-type) or [`options_field`](/reference/types/options_field-type), as shown in the following code snippet.
```js
"output_parameters": {
@@ -109,9 +109,9 @@ The type is dictated by the output parameter of the custom step used as a dynami
#### Drop-down menus {#drop-down}
-Your dynamic input parameter can be rendered as a drop-down menu, which will use the options obtained from a custom step with an `options` output parameter of the type [`options_select`](/tools/deno-slack-sdk/reference/slack-types#options_select).
+Your dynamic input parameter can be rendered as a drop-down menu, which will use the options obtained from a custom step with an `options` output parameter of the type [`options_select`](/reference/types/options_select-type).
-The drop-down menu UI component can be rendered in two ways: single-select, or multi-select. To render the dynamic input as a single-select menu, the input parameter defining the dynamic option must be of the type [`string`](/tools/deno-slack-sdk/reference/slack-types#string).
+The drop-down menu UI component can be rendered in two ways: single-select, or multi-select. To render the dynamic input as a single-select menu, the input parameter defining the dynamic option must be of the type [`string`](/reference/types/string-type).
```js
"step-with-dynamic-input": {
@@ -133,7 +133,7 @@ The drop-down menu UI component can be rendered in two ways: single-select, or m
}
```
-To render the dynamic input as a multi-select menu, the input parameter defining the dynamic option must be of the type [`array`](/tools/deno-slack-sdk/reference/slack-types#array), and its `items` must be of type [`string`](/tools/deno-slack-sdk/reference/slack-types#string).
+To render the dynamic input as a multi-select menu, the input parameter defining the dynamic option must be of the type [`array`](/reference/types/array-type), and its `items` must be of type [`string`](/reference/types/string-type).
```js
"step-with-dynamic-input": {
@@ -159,9 +159,9 @@ To render the dynamic input as a multi-select menu, the input parameter defining
#### Fields {#fields}
-In the code snippet below, the input parameter is rendered as a set of fields with keys and values. The option fields are obtained from a custom step with an `options` output parameter of type [`options_field`](/tools/deno-slack-sdk/reference/slack-types#options_field).
+In the code snippet below, the input parameter is rendered as a set of fields with keys and values. The option fields are obtained from a custom step with an `options` output parameter of type [`options_field`](/reference/types/options_field-type).
-The input parameter that defines the dynamic option must be of type [`object`](/tools/deno-slack-sdk/reference/slack-types#object), as the completed set of fields in Workflow Builder will be passed to the custom step as an [untyped object](/tools/deno-slack-sdk/reference/slack-types#untyped-object) during workflow execution.
+The input parameter that defines the dynamic option must be of type [`object`](/reference/types/object-type), as the completed set of fields in Workflow Builder will be passed to the custom step as an [untyped object](/reference/types/object-type#untyped-object) during workflow execution.
```js
"test-field-dynamic-options": {
@@ -185,15 +185,15 @@ The input parameter that defines the dynamic option must be of type [`object`](/
### Dynamic option types {#dynamic-option-types}
-As mentioned earlier, in order to use a custom step as a dynamic option, its output must adhere to a defined interface: it must have an `options` output parameter of the type either [`options_select`](/tools/deno-slack-sdk/reference/slack-types#options_select) or [`options_field`](/tools/deno-slack-sdk/reference/slack-types#options_field).
+As mentioned earlier, in order to use a custom step as a dynamic option, its output must adhere to a defined interface: it must have an `options` output parameter of the type either [`options_select`](/reference/types/options_select-type) or [`options_field`](/reference/types/options_field-type).
-To take a look at these in more detail, refer to our [Options Slack type](/tools/deno-slack-sdk/reference/slack-types#options) documentation.
+To take a look at these in more detail, refer to our [Options Slack type](/reference/types) documentation.
## Dynamic options handler {#dynamic-option-handler}
Each custom step defined in the manifest needs a corresponding handler in your Slack app. Although implemented similarly to existing function execution event handlers, there are two key differences between regular custom step invocations and those used for dynamic options:
-* The custom step must have an `options` output parameter that is of type [`options_select`](/tools/deno-slack-sdk/reference/slack-types#options_select) or [`options_field`](/tools/deno-slack-sdk/reference/slack-types#options_field).
+* The custom step must have an `options` output parameter that is of type [`options_select`](/reference/types/options_select-type) or [`options_field`](/reference/types/options_field-type).
* The [`function_executed`](/reference/events/function_executed) event must be handled synchronously. This optimizes the response time of returned dynamic options and provides a crisp builder experience.
### Asynchronous event handling {#async}
diff --git a/docs/english/tutorial/ai-chatbot/ai-chatbot.md b/docs/english/tutorial/ai-chatbot/ai-chatbot.md
index 013aeec47..427d626bc 100644
--- a/docs/english/tutorial/ai-chatbot/ai-chatbot.md
+++ b/docs/english/tutorial/ai-chatbot/ai-chatbot.md
@@ -195,7 +195,7 @@ To test this, leave the channel you just invited Bolty to and rejoin it. This wi

-The central part of this functionality is shown in the following code snippet. Note the use of the [`user_context`](/tools/deno-slack-sdk/reference/slack-types#usercontext) object, a Slack type that represents the user who is interacting with our workflow, as well as the `history` of the channel that will be summarized, which includes the ten most recent messages.
+The central part of this functionality is shown in the following code snippet. Note the use of the [`user_context`](/reference/types/user_context-type) object, a Slack type that represents the user who is interacting with our workflow, as well as the `history` of the channel that will be summarized, which includes the ten most recent messages.
```python
from ai.providers import get_provider_response
diff --git a/docs/japanese/concepts/updating-pushing-views.md b/docs/japanese/concepts/updating-pushing-views.md
index 2bbaf5ae5..c9e3fb2e6 100644
--- a/docs/japanese/concepts/updating-pushing-views.md
+++ b/docs/japanese/concepts/updating-pushing-views.md
@@ -8,7 +8,7 @@
**`views_push`**
-既存のモーダルの上に新しいモーダルをスタックのように追加する場合は、組み込みのクライアントで `views_push` API を呼び出します。この API 呼び出しでは、有効な `trigger_id` と新しい[ビューのペイロード](/reference/interaction-payloads/view-interactions-payload/#view_submission)を指定します。`views_push` の引数は [モーダルの開始](#creating-modals) と同じです。モーダルを開いた後、このモーダルのスタックに追加できるモーダルビューは 2 つまでです。
+既存のモーダルの上に新しいモーダルをスタックのように追加する場合は、組み込みのクライアントで `views_push` API を呼び出します。この API 呼び出しでは、有効な `trigger_id` と新しい[ビューのペイロード](/reference/interaction-payloads/view-interactions-payload/#view_submission)を指定します。`views_push` の引数は [モーダルの開始](/tools/bolt-python/ja-jp/concepts/opening-modals) と同じです。モーダルを開いた後、このモーダルのスタックに追加できるモーダルビューは 2 つまでです。
モーダルの更新と多重表示に関する詳細は、[API ドキュメント](/surfaces/modals)を参照してください。
From 698687cd5be2136a549dd04504968ba7ea4cf7f4 Mon Sep 17 00:00:00 2001
From: Sahil Jagtap
Date: Thu, 8 Oct 2026 17:10:07 -0400
Subject: [PATCH 15/31] fix(aws_lambda): handle null headers, query string, and
body in API Gateway events (#1587)
Co-authored-by: Ale Mercado <104795114+srtaalej@users.noreply.github.com>
---
slack_bolt/adapter/aws_lambda/handler.py | 18 ++++----
tests/adapter_tests/aws/test_aws_lambda.py | 50 ++++++++++++++++++++++
2 files changed, 59 insertions(+), 9 deletions(-)
diff --git a/slack_bolt/adapter/aws_lambda/handler.py b/slack_bolt/adapter/aws_lambda/handler.py
index 4d155e58f..270d48831 100644
--- a/slack_bolt/adapter/aws_lambda/handler.py
+++ b/slack_bolt/adapter/aws_lambda/handler.py
@@ -71,22 +71,22 @@ def handle(self, event, context):
def to_bolt_request(event) -> BoltRequest:
- body = event.get("body", "")
- if event["isBase64Encoded"]:
+ body = event.get("body") or ""
+ if event.get("isBase64Encoded") is True and body:
body = base64.b64decode(body).decode("utf-8")
- cookies: Sequence[str] = event.get("cookies", [])
- if cookies is None or len(cookies) == 0:
+ cookies: Sequence[str] = event.get("cookies") or []
+ if len(cookies) == 0:
# In the case of format v1
- multiValueHeaders = event.get("multiValueHeaders", {})
- cookies = multiValueHeaders.get("cookie", [])
+ multiValueHeaders = event.get("multiValueHeaders") or {}
+ cookies = multiValueHeaders.get("cookie") or []
if len(cookies) == 0:
# Try using uppercase
- cookies = multiValueHeaders.get("Cookie", [])
- headers = event.get("headers", {})
+ cookies = multiValueHeaders.get("Cookie") or []
+ headers = dict(event.get("headers") or {})
headers["cookie"] = cookies
return BoltRequest(
body=body,
- query=event.get("queryStringParameters", {}),
+ query=event.get("queryStringParameters") or {},
headers=headers,
)
diff --git a/tests/adapter_tests/aws/test_aws_lambda.py b/tests/adapter_tests/aws/test_aws_lambda.py
index c2e888fb7..3827af9b8 100644
--- a/tests/adapter_tests/aws/test_aws_lambda.py
+++ b/tests/adapter_tests/aws/test_aws_lambda.py
@@ -1,3 +1,4 @@
+import base64
import json
from time import time
from urllib.parse import quote
@@ -70,6 +71,55 @@ def test_not_found(self):
response = not_found()
assert response["statusCode"] == 404
+ def test_null_fields_in_api_gateway_event(self):
+ app = App(client=self.web_client, signing_secret=self.signing_secret)
+ event = {
+ "httpMethod": "POST",
+ "requestContext": {"httpMethod": "POST"},
+ "headers": None,
+ "multiValueHeaders": None,
+ "queryStringParameters": None,
+ "body": "{}",
+ "isBase64Encoded": False,
+ }
+ response = SlackRequestHandler(app).handle(event, self.context)
+ assert response["statusCode"] == 401
+ assert event["headers"] is None
+
+ def test_missing_is_base64_encoded_and_null_body(self):
+ app = App(client=self.web_client, signing_secret=self.signing_secret)
+ event = {"requestContext": {"http": {"method": "POST"}}, "headers": {}, "body": "{}"}
+ assert SlackRequestHandler(app).handle(event, self.context)["statusCode"] == 401
+ event = {"requestContext": {"http": {"method": "POST"}}, "headers": {}, "body": None, "isBase64Encoded": True}
+ assert SlackRequestHandler(app).handle(event, self.context)["statusCode"] == 401
+
+ def test_base64_encoded_body(self):
+ app = App(client=self.web_client, signing_secret=self.signing_secret)
+
+ def event_handler():
+ pass
+
+ app.event("app_mention")(event_handler)
+ input = {
+ "token": "verification_token",
+ "team_id": "T111",
+ "api_app_id": "A111",
+ "event": {"type": "app_mention", "text": "<@W111> Hi", "user": "W222", "team": "T111", "channel": "C111"},
+ "type": "event_callback",
+ "event_id": "Ev111",
+ "event_time": 1595926230,
+ }
+ timestamp, body = str(int(time())), json.dumps(input)
+ event = {
+ "body": base64.b64encode(body.encode("utf-8")).decode("ascii"),
+ "queryStringParameters": None,
+ "headers": self.build_headers(timestamp, body),
+ "requestContext": {"http": {"method": "POST"}},
+ "isBase64Encoded": True,
+ }
+ response = SlackRequestHandler(app).handle(event, self.context)
+ assert response["statusCode"] == 200
+
def test_first_value(self):
assert _first_value({"foo": [1, 2, 3]}, "foo") == 1
assert _first_value({"foo": []}, "foo") is None
From abb695018d9ecdee4b1967bbf44c44c0ff486130 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 9 Oct 2026 20:13:00 +0000
Subject: [PATCH 16/31] chore(deps): update asgiref requirement from
<4,>=3.11.1 to >=3.12.1,<4 (#1580)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
requirements/test_async.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/requirements/test_async.txt b/requirements/test_async.txt
index 5dc51a201..3d1b3ab4c 100644
--- a/requirements/test_async.txt
+++ b/requirements/test_async.txt
@@ -3,9 +3,9 @@
-r async_dev.txt
# asgiref
-# Note: asgiref 3.11.1 requires Python >=3.9; 3.7/3.8 stay on the older pinned release.
asgiref>=3.7.2,<3.8; python_version < "3.9"
-asgiref>=3.11.1,<4; python_version >= "3.9"
+asgiref>=3.11.1,<3.12; python_version >= "3.9" and python_version < "3.10"
+asgiref>=3.12.1,<4; python_version >= "3.10"
# pytest-asyncio
pytest-asyncio<2
From 649cfc8632254559d4ad133c99b02d60f1b0d15f Mon Sep 17 00:00:00 2001
From: William Bergamin
Date: Fri, 16 Oct 2026 15:29:25 -0400
Subject: [PATCH 17/31] chore: support python 3.15 (#1600)
Co-authored-by: Claude
---
.github/workflows/ci-build.yml | 3 ++-
AGENTS.md | 4 ++--
pyproject.toml | 1 +
scripts/install_all_and_run_tests.sh | 2 +-
4 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml
index 230de3d39..e3211b3c9 100644
--- a/.github/workflows/ci-build.yml
+++ b/.github/workflows/ci-build.yml
@@ -10,7 +10,7 @@ on:
workflow_dispatch:
env:
- LATEST_SUPPORTED_PY: "3.14"
+ LATEST_SUPPORTED_PY: "3.15"
jobs:
lint:
@@ -74,6 +74,7 @@ jobs:
- "3.12"
- "3.13"
- "3.14"
+ - "3.15"
permissions:
contents: read
steps:
diff --git a/AGENTS.md b/AGENTS.md
index cc6ba8198..37084fa15 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -214,7 +214,7 @@ The core package has a **single required runtime dependency**: `slack_sdk` (defi
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).
-Before adding, bumping, pinning, or reviewing any dependency in `requirements/*.txt` -- whether a Dependabot PR or a manual edit -- follow the `managing-dependencies` skill in `.claude/skills/`. It defines the layout and `python_version` marker conventions that keep one set of pins working across the full CPython 3.7--3.14 matrix.
+Before adding, bumping, pinning, or reviewing any dependency in `requirements/*.txt` -- whether a Dependabot PR or a manual edit -- follow the `managing-dependencies` skill in `.claude/skills/`. It defines the layout and `python_version` marker conventions that keep one set of pins working across the full CPython 3.7--3.15 matrix.
## Test Organization and CI
@@ -236,7 +236,7 @@ GitHub Actions (`.github/workflows/ci-build.yml`) runs on every push to `main` a
- **Lint** -- `./scripts/lint.sh` on latest Python
- **Typecheck** -- `./scripts/run_mypy.sh` on latest Python
-- **Unit tests** -- full test suite across Python 3.7--3.14 matrix
+- **Unit tests** -- full test suite across Python 3.7--3.15 matrix
- **Code coverage** -- uploaded to Codecov
## PR and Commit Guidelines
diff --git a/pyproject.toml b/pyproject.toml
index bf43e3d70..c69aa016c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -16,6 +16,7 @@ classifiers = [
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
+ "Programming Language :: Python :: 3.15",
"Programming Language :: Python :: Implementation :: CPython",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
diff --git a/scripts/install_all_and_run_tests.sh b/scripts/install_all_and_run_tests.sh
index 939e71ffd..d4601df0c 100755
--- a/scripts/install_all_and_run_tests.sh
+++ b/scripts/install_all_and_run_tests.sh
@@ -9,7 +9,7 @@ cd ${script_dir}/..
test_target="${1:-tests/}"
# keep in sync with LATEST_SUPPORTED_PY in .github/workflows/ci-build.yml
-LATEST_SUPPORTED_PY="3.14"
+LATEST_SUPPORTED_PY="3.15"
current_py=$(python --version | sed -E 's/Python ([0-9]+\.[0-9]+).*/\1/')
./scripts/install.sh
From d1bd9549fe1e526d8ffa7153d3e8c72f1ee2f239 Mon Sep 17 00:00:00 2001
From: Eden Zimbelman
Date: Fri, 23 Oct 2026 17:14:00 -0700
Subject: [PATCH 18/31] chore: set gus team and product tag in code owners
(#1604)
Co-authored-by: Claude
---
.github/CODEOWNERS | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 4a08579c2..f152f56e8 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,7 +1,7 @@
# Salesforce Open Source project configuration
# Learn more: https://github.com/salesforce/oss-template
#ECCN:Open Source
-#GUSINFO:Open Source,Open Source Workflow
+#GUSINFO:Slack Developer Experience,Open Source
# @slackapi/slack-platform-python
# are code reviewers for all changes in this repo.
From dfde5104e75adc5287b5a4f9ba6e26f564fc9085 Mon Sep 17 00:00:00 2001
From: David Reed
Date: Mon, 26 Oct 2026 18:04:49 -0600
Subject: [PATCH 19/31] chore(examples): floor certifi at 2026.10.19 for Google
Cloud Functions (#1601)
Co-authored-by: Claude
Co-authored-by: Eden Zimbelman
---
examples/google_cloud_functions/requirements.txt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/examples/google_cloud_functions/requirements.txt b/examples/google_cloud_functions/requirements.txt
index 7ebbe8ab2..edcb53ad3 100644
--- a/examples/google_cloud_functions/requirements.txt
+++ b/examples/google_cloud_functions/requirements.txt
@@ -1,3 +1,4 @@
Flask>1
slack_bolt
-google-cloud-datastore>=2.1.0,<3
\ No newline at end of file
+google-cloud-datastore>=2.1.0,<3
+certifi>=2026.10.19
\ No newline at end of file
From b915daa8c35937a9e8cf63181f686bf634740287 Mon Sep 17 00:00:00 2001
From: David Reed
Date: Mon, 26 Oct 2026 18:04:55 -0600
Subject: [PATCH 20/31] chore(examples): move Docker images to bases with fixed
ca-certificates (#1602)
Co-authored-by: Claude
Co-authored-by: Eden Zimbelman
Co-authored-by: Michael Brooks
---
examples/docker/aiohttp/Dockerfile | 8 ++++++--
examples/docker/asgi/Dockerfile | 6 ++++--
examples/docker/fastapi-gunicorn/Dockerfile | 4 ++++
examples/docker/flask-gunicorn/Dockerfile | 8 ++++++--
examples/docker/flask-uwsgi/Dockerfile | 10 +++++++---
examples/docker/sanic/Dockerfile | 8 ++++++--
examples/google_cloud_run/aiohttp/Dockerfile | 7 ++++++-
examples/google_cloud_run/flask-gunicorn/Dockerfile | 7 ++++++-
examples/google_cloud_run/sanic/Dockerfile | 7 ++++++-
9 files changed, 51 insertions(+), 14 deletions(-)
diff --git a/examples/docker/aiohttp/Dockerfile b/examples/docker/aiohttp/Dockerfile
index a7b78ed12..7ebb18246 100644
--- a/examples/docker/aiohttp/Dockerfile
+++ b/examples/docker/aiohttp/Dockerfile
@@ -1,13 +1,17 @@
#
# docker build . -t your-repo/hello-bolt
#
-FROM python:3.8.5-slim-buster as builder
+FROM python:3.8-slim-bookworm as builder
RUN apt-get update && apt-get clean
COPY requirements.txt /build/
WORKDIR /build/
RUN pip install -U pip && pip install -r requirements.txt
-FROM python:3.8.5-slim-buster as app
+FROM python:3.8-slim-bookworm as app
+# Refresh the OS trust store so the image gets the latest ca-certificates.
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends ca-certificates \
+ && rm -rf /var/lib/apt/lists/*
COPY --from=builder /build/ /app/
COPY --from=builder /usr/local/lib/ /usr/local/lib/
WORKDIR /app/
diff --git a/examples/docker/asgi/Dockerfile b/examples/docker/asgi/Dockerfile
index cef704967..0334461ba 100644
--- a/examples/docker/asgi/Dockerfile
+++ b/examples/docker/asgi/Dockerfile
@@ -1,12 +1,14 @@
#
# docker build . -t your-repo/hello-bolt
#
-FROM python:3.11-alpine3.17 as builder
+FROM python:3.11-alpine3.20 as builder
COPY requirements.txt /build/
WORKDIR /build/
RUN pip install -U pip && pip install -r requirements.txt
-FROM python:3.11-alpine3.17 as app
+FROM python:3.11-alpine3.20 as app
+# Refresh the OS trust store so the image gets the latest ca-certificates.
+RUN apk add --no-cache --upgrade ca-certificates ca-certificates-bundle
WORKDIR /app/
COPY --from=builder /usr/local/bin/ /usr/local/bin/
COPY --from=builder /usr/local/lib/ /usr/local/lib/
diff --git a/examples/docker/fastapi-gunicorn/Dockerfile b/examples/docker/fastapi-gunicorn/Dockerfile
index c8f8b94e3..4938b4b5b 100644
--- a/examples/docker/fastapi-gunicorn/Dockerfile
+++ b/examples/docker/fastapi-gunicorn/Dockerfile
@@ -2,6 +2,10 @@
# docker build . -t your-repo/hello-bolt
#
FROM tiangolo/uvicorn-gunicorn:python3.8-slim
+# Refresh the OS trust store so the image gets the latest ca-certificates.
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends ca-certificates \
+ && rm -rf /var/lib/apt/lists/*
WORKDIR /app/
COPY *.py /app/
COPY requirements.txt /app/
diff --git a/examples/docker/flask-gunicorn/Dockerfile b/examples/docker/flask-gunicorn/Dockerfile
index e788cb388..a7a0f2362 100644
--- a/examples/docker/flask-gunicorn/Dockerfile
+++ b/examples/docker/flask-gunicorn/Dockerfile
@@ -1,12 +1,16 @@
#
# docker build . -t your-repo/hello-bolt
#
-FROM python:3.8.5-slim-buster as builder
+FROM python:3.8-slim-bookworm as builder
COPY requirements.txt /build/
WORKDIR /build/
RUN pip install -U pip && pip install -r requirements.txt
-FROM python:3.8.5-slim-buster as app
+FROM python:3.8-slim-bookworm as app
+# Refresh the OS trust store so the image gets the latest ca-certificates.
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends ca-certificates \
+ && rm -rf /var/lib/apt/lists/*
WORKDIR /app/
COPY --from=builder /usr/local/bin/ /usr/local/bin/
COPY --from=builder /usr/local/lib/ /usr/local/lib/
diff --git a/examples/docker/flask-uwsgi/Dockerfile b/examples/docker/flask-uwsgi/Dockerfile
index 14ddfb41b..f5d7e6863 100644
--- a/examples/docker/flask-uwsgi/Dockerfile
+++ b/examples/docker/flask-uwsgi/Dockerfile
@@ -1,15 +1,19 @@
#
# docker build . -t your-repo/hello-bolt
#
-FROM python:3.8.5-slim-buster as builder
+FROM python:3.8-slim-bookworm as builder
RUN apt-get update \
- && apt-get -y install build-essential libpcre3-dev \
+ && apt-get -y install build-essential libpcre2-dev \
&& apt-get clean
COPY requirements.txt /build/
WORKDIR /build/
RUN pip install -U pip && pip install -r requirements.txt
-FROM python:3.8.5-slim-buster as app
+FROM python:3.8-slim-bookworm as app
+# Refresh the OS trust store so the image gets the latest ca-certificates.
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends ca-certificates \
+ && rm -rf /var/lib/apt/lists/*
WORKDIR /app/
COPY --from=builder /usr/local/bin/ /usr/local/bin/
COPY --from=builder /usr/local/lib/ /usr/local/lib/
diff --git a/examples/docker/sanic/Dockerfile b/examples/docker/sanic/Dockerfile
index 4606e68bd..c24d81b5c 100644
--- a/examples/docker/sanic/Dockerfile
+++ b/examples/docker/sanic/Dockerfile
@@ -1,12 +1,16 @@
#
# docker build . -t your-repo/hello-bolt
#
-FROM python:3.8.5-slim-buster as builder
+FROM python:3.8-slim-bookworm as builder
COPY requirements.txt /build/
WORKDIR /build/
RUN pip install -U pip && pip install -r requirements.txt
-FROM python:3.8.5-slim-buster as app
+FROM python:3.8-slim-bookworm as app
+# Refresh the OS trust store so the image gets the latest ca-certificates.
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends ca-certificates \
+ && rm -rf /var/lib/apt/lists/*
WORKDIR /app/
COPY *.py /app/
COPY --from=builder /usr/local/bin/ /usr/local/bin/
diff --git a/examples/google_cloud_run/aiohttp/Dockerfile b/examples/google_cloud_run/aiohttp/Dockerfile
index e4432e3a2..77a656180 100644
--- a/examples/google_cloud_run/aiohttp/Dockerfile
+++ b/examples/google_cloud_run/aiohttp/Dockerfile
@@ -11,7 +11,12 @@
# ----------------------------------------------
# Use the official lightweight Python image.
# https://hub.docker.com/_/python
-FROM python:3.8.5-slim-buster
+FROM python:3.8-slim-bookworm
+
+# Refresh the OS trust store so the image gets the latest ca-certificates.
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends ca-certificates \
+ && rm -rf /var/lib/apt/lists/*
# Allow statements and log messages to immediately appear in the Knative logs
ENV PYTHONUNBUFFERED True
diff --git a/examples/google_cloud_run/flask-gunicorn/Dockerfile b/examples/google_cloud_run/flask-gunicorn/Dockerfile
index 8342e3a8b..01dd32523 100644
--- a/examples/google_cloud_run/flask-gunicorn/Dockerfile
+++ b/examples/google_cloud_run/flask-gunicorn/Dockerfile
@@ -11,7 +11,12 @@
# ----------------------------------------------
# Use the official lightweight Python image.
# https://hub.docker.com/_/python
-FROM python:3.8.5-slim-buster
+FROM python:3.8-slim-bookworm
+
+# Refresh the OS trust store so the image gets the latest ca-certificates.
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends ca-certificates \
+ && rm -rf /var/lib/apt/lists/*
# Allow statements and log messages to immediately appear in the Knative logs
ENV PYTHONUNBUFFERED True
diff --git a/examples/google_cloud_run/sanic/Dockerfile b/examples/google_cloud_run/sanic/Dockerfile
index d71ddef67..15c38fe1e 100644
--- a/examples/google_cloud_run/sanic/Dockerfile
+++ b/examples/google_cloud_run/sanic/Dockerfile
@@ -11,7 +11,12 @@
# ----------------------------------------------
# Use the official lightweight Python image.
# https://hub.docker.com/_/python
-FROM python:3.8.5-slim-buster
+FROM python:3.8-slim-bookworm
+
+# Refresh the OS trust store so the image gets the latest ca-certificates.
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends ca-certificates \
+ && rm -rf /var/lib/apt/lists/*
# Allow statements and log messages to immediately appear in the Knative logs
ENV PYTHONUNBUFFERED True
From 7dd4bb4429a98e6df1313ff146d740761efc52d0 Mon Sep 17 00:00:00 2001
From: David Reed
Date: Mon, 26 Oct 2026 18:09:35 -0600
Subject: [PATCH 21/31] chore(examples): move the App Engine example to
python311 (#1603)
Co-authored-by: Claude
Co-authored-by: Eden Zimbelman
Co-authored-by: Michael Brooks
---
examples/google_app_engine/flask/app.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/google_app_engine/flask/app.yaml b/examples/google_app_engine/flask/app.yaml
index dfe7de530..ecc2ab272 100644
--- a/examples/google_app_engine/flask/app.yaml
+++ b/examples/google_app_engine/flask/app.yaml
@@ -1,4 +1,4 @@
-runtime: python38
+runtime: python311
inbound_services:
- warmup
From e98bcb82b4f9a964b2872ad4693feb6239f085b3 Mon Sep 17 00:00:00 2001
From: Ale Mercado <104795114+srtaalej@users.noreply.github.com>
Date: Fri, 30 Oct 2026 10:00:52 -0600
Subject: [PATCH 22/31] docs: update Block Kit Builder links to app.slack.com
(#1605)
---
docs/english/concepts/message-sending.md | 2 +-
docs/english/concepts/shortcuts.md | 4 ++--
docs/japanese/concepts/message-sending.md | 2 +-
docs/japanese/concepts/shortcuts.md | 4 ++--
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/docs/english/concepts/message-sending.md b/docs/english/concepts/message-sending.md
index c4d1b0467..67b70d9b0 100644
--- a/docs/english/concepts/message-sending.md
+++ b/docs/english/concepts/message-sending.md
@@ -17,7 +17,7 @@ def ask_who(message, say):
`say()` accepts more complex message payloads to make it easy to add functionality and structure to your messages.
-To explore adding rich message layouts to your app, read through [the guide on our API site](/messaging/#structure) and look through templates of common app flows [in the Block Kit Builder](https://api.slack.com/tools/block-kit-builder?template=1).
+To explore adding rich message layouts to your app, read through [the guide on our API site](/messaging/#structure) and look through templates of common app flows [in the Block Kit Builder](https://app.slack.com/block-kit-builder).
```python
# Sends a section block with datepicker when someone reacts with a 📅 emoji
diff --git a/docs/english/concepts/shortcuts.md b/docs/english/concepts/shortcuts.md
index b28f0b352..86186e035 100644
--- a/docs/english/concepts/shortcuts.md
+++ b/docs/english/concepts/shortcuts.md
@@ -40,7 +40,7 @@ def open_modal(ack, shortcut, client):
"elements": [
{
"type": "mrkdwn",
- "text": "Psssst this modal was designed using "
+ "text": "Psssst this modal was designed using "
}
]
}
@@ -79,7 +79,7 @@ def open_modal(ack, shortcut, client):
"elements": [
{
"type": "mrkdwn",
- "text": "Psssst this modal was designed using "
+ "text": "Psssst this modal was designed using "
}
]
}
diff --git a/docs/japanese/concepts/message-sending.md b/docs/japanese/concepts/message-sending.md
index ace67051b..b724960ce 100644
--- a/docs/japanese/concepts/message-sending.md
+++ b/docs/japanese/concepts/message-sending.md
@@ -16,7 +16,7 @@ def ask_who(message, say):
`say()` は、より複雑なメッセージペイロードを受け付けるので、メッセージに機能やリッチな構造を与えることが容易です。
-リッチなメッセージレイアウトをアプリに追加する方法については、[API サイトのガイド](/messaging/#structure)を参照してください。また、[Block Kit ビルダー](https://api.slack.com/tools/block-kit-builder?template=1)の一般的なアプリフローのテンプレートも見てみてください。
+リッチなメッセージレイアウトをアプリに追加する方法については、[API サイトのガイド](/messaging/#structure)を参照してください。また、[Block Kit ビルダー](https://app.slack.com/block-kit-builder)の一般的なアプリフローのテンプレートも見てみてください。
```python
# ユーザーが 📅 のリアクションをつけたら、日付ピッカーのついた section ブロックを送信
diff --git a/docs/japanese/concepts/shortcuts.md b/docs/japanese/concepts/shortcuts.md
index 39fb10ba8..22e16fd53 100644
--- a/docs/japanese/concepts/shortcuts.md
+++ b/docs/japanese/concepts/shortcuts.md
@@ -40,7 +40,7 @@ def open_modal(ack, shortcut, client):
"elements": [
{
"type": "mrkdwn",
- "text":"Psssst this modal was designed using "
+ "text":"Psssst this modal was designed using "
}
]
}
@@ -80,7 +80,7 @@ def open_modal(ack, shortcut, client):
"elements": [
{
"type": "mrkdwn",
- "text":"Psssst this modal was designed using "
+ "text":"Psssst this modal was designed using "
}
]
}
From 8f0d9c647d219fdc591a10e07a5f13eba80aa684 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sun, 1 Nov 2026 22:15:26 +0000
Subject: [PATCH 23/31] chore(deps): bump pypa/gh-action-pypi-publish from
1.14.2 to 1.14.3 (#1606)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.github/workflows/pypi-release.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml
index 2d0f7630a..4aecc9a87 100644
--- a/.github/workflows/pypi-release.yml
+++ b/.github/workflows/pypi-release.yml
@@ -60,7 +60,7 @@ jobs:
- name: Publish release distributions to test.pypi.org
# Using OIDC for PyPI publishing (no API tokens needed)
# See: https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-pypi
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
+ uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
with:
repository-url: https://test.pypi.org/legacy/
@@ -84,4 +84,4 @@ jobs:
- name: Publish release distributions to pypi.org
# Using OIDC for PyPI publishing (no API tokens needed)
# See: https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-pypi
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
+ uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
From 7f6983543f8c289591b4b044f1b6220a0dc6a477 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sun, 1 Nov 2026 22:20:28 +0000
Subject: [PATCH 24/31] chore(deps): bump actions/setup-python from 7.0.0 to
7.1.0 (#1607)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.github/workflows/ci-build.yml | 8 ++++----
.github/workflows/pypi-release.yml | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml
index e3211b3c9..0cb3e60d1 100644
--- a/.github/workflows/ci-build.yml
+++ b/.github/workflows/ci-build.yml
@@ -24,7 +24,7 @@ jobs:
with:
persist-credentials: false
- name: Set up Python ${{ env.LATEST_SUPPORTED_PY }}
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
+ uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: ${{ env.LATEST_SUPPORTED_PY }}
- name: Run lint verification
@@ -41,7 +41,7 @@ jobs:
with:
persist-credentials: false
- name: Set up Python ${{ env.LATEST_SUPPORTED_PY }}
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
+ uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: ${{ env.LATEST_SUPPORTED_PY }}
- name: Install synchronous dependencies
@@ -82,7 +82,7 @@ jobs:
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
+ uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: ${{ matrix.python-version }}
- name: Install synchronous dependencies
@@ -149,7 +149,7 @@ jobs:
with:
persist-credentials: false
- name: Set up Python ${{ env.LATEST_SUPPORTED_PY }}
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
+ uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: ${{ env.LATEST_SUPPORTED_PY }}
- name: Install dependencies
diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml
index 4aecc9a87..25aec9795 100644
--- a/.github/workflows/pypi-release.yml
+++ b/.github/workflows/pypi-release.yml
@@ -24,7 +24,7 @@ jobs:
persist-credentials: false
- name: Set up Python
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
+ uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: "3.x"
From ccf0890911de53c23804e70c16ee3042e431bf3d Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sun, 1 Nov 2026 22:25:34 +0000
Subject: [PATCH 25/31] chore(deps): bump actions/upload-artifact from 7.0.1 to
7.0.2 (#1609)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.github/workflows/pypi-release.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml
index 25aec9795..087046242 100644
--- a/.github/workflows/pypi-release.yml
+++ b/.github/workflows/pypi-release.yml
@@ -33,7 +33,7 @@ jobs:
scripts/build_pypi_package.sh
- name: Persist dist folder
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: release-dist
path: dist/
From 7c9020bde10cb85b48c8eaea3b85cafad9b448e3 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sun, 1 Nov 2026 22:31:48 +0000
Subject: [PATCH 26/31] chore(deps): bump actions/download-artifact from 8.0.1
to 8.0.2 (#1608)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.github/workflows/pypi-release.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml
index 087046242..7ef27db4d 100644
--- a/.github/workflows/pypi-release.yml
+++ b/.github/workflows/pypi-release.yml
@@ -52,7 +52,7 @@ jobs:
steps:
- name: Retrieve dist folder
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: release-dist
path: dist/
@@ -76,7 +76,7 @@ jobs:
steps:
- name: Retrieve dist folder
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: release-dist
path: dist/
From 51d8ba7893c1931992600902d13370c73afed847 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 2 Nov 2026 02:39:57 +0000
Subject: [PATCH 27/31] chore(deps-dev): bump mypy from 2.4.0 to 2.4.1 (#1613)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Michael Brooks
---
requirements/dev_tools.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/dev_tools.txt b/requirements/dev_tools.txt
index b95285f7b..9f38287ef 100644
--- a/requirements/dev_tools.txt
+++ b/requirements/dev_tools.txt
@@ -1,7 +1,7 @@
# pip install -r requirements/dev_tools.txt
# mypy
-mypy==2.4.0
+mypy==2.4.1
# ruff
ruff==0.16.5
From 2d4cb1b010191494e29e01c7df0684fd097df23f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 2 Nov 2026 02:44:36 +0000
Subject: [PATCH 28/31] chore(deps-dev): bump ruff from 0.16.5 to 0.17.3
(#1611)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Michael Brooks
---
requirements/dev_tools.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/dev_tools.txt b/requirements/dev_tools.txt
index 9f38287ef..94780cda6 100644
--- a/requirements/dev_tools.txt
+++ b/requirements/dev_tools.txt
@@ -4,4 +4,4 @@
mypy==2.4.1
# ruff
-ruff==0.16.5
+ruff==0.17.3
From 52b96d17658befe04da94247db5c1fdae7a78671 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sun, 1 Nov 2026 19:51:37 -0700
Subject: [PATCH 29/31] chore(deps-dev): update django requirement from
<6,>=5.2.15 to >=5.2.18,<6 (#1610)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Michael Brooks
---
requirements/adapter_dev.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/adapter_dev.txt b/requirements/adapter_dev.txt
index 6d705d389..38604a8b0 100644
--- a/requirements/adapter_dev.txt
+++ b/requirements/adapter_dev.txt
@@ -23,7 +23,7 @@ CherryPy>=18.10.0,<19
# Note: Django 5.x requires Python >=3.10 and 4.x requires >=3.8, so 3.8/3.9 stay on the 4.2 LTS line and 3.7 stays on the 3.2 line.
Django>=3.2,<4; python_version < "3.8"
Django>=4.2.30,<5; python_version >= "3.8" and python_version < "3.10"
-Django>=5.2.15,<6; python_version >= "3.10"
+Django>=5.2.18,<6; python_version >= "3.10"
# falcon
# Note: falcon 4.2.0 requires Python >=3.9; 3.7/3.8 stay on the older pinned release.
From b014f0db5772361dbf76eb526fb12eb9bf174e9a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 2 Nov 2026 02:55:07 +0000
Subject: [PATCH 30/31] chore(deps-dev): update fastapi requirement from
<1,>=0.141.1 to >=0.162.0,<1 (#1614)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Michael Brooks
---
requirements/adapter_dev.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/adapter_dev.txt b/requirements/adapter_dev.txt
index 38604a8b0..554dce34a 100644
--- a/requirements/adapter_dev.txt
+++ b/requirements/adapter_dev.txt
@@ -33,7 +33,7 @@ falcon>=4.4.0,<5; python_version >= "3.9"
# fastapi
fastapi>=0.70.0,<1; python_version < "3.9"
fastapi>=0.128.8,<0.129.0; python_version >= "3.9" and python_version < "3.10"
-fastapi>=0.141.1,<1; python_version >= "3.10"
+fastapi>=0.162.0,<1; python_version >= "3.10"
# Flask
# Note: Flask 3.1.3 requires Python >=3.9; 3.7/3.8 stay on the older pinned release.
From efc36b1f381854268276a9cb384c22cfe1f63072 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 2 Nov 2026 16:36:48 +0000
Subject: [PATCH 31/31] chore(deps-dev): update aiohttp requirement from
<4,>=3.13.5 to >=3.14.5,<4 (#1612)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Michael Brooks
---
requirements/async_dev.txt | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/requirements/async_dev.txt b/requirements/async_dev.txt
index 32dff305b..29d0efc59 100644
--- a/requirements/async_dev.txt
+++ b/requirements/async_dev.txt
@@ -1,9 +1,13 @@
# pip install -r requirements/async_dev.txt
# aiohttp
-# Note: aiohttp 3.13.5 requires Python >=3.9; 3.7/3.8 stay on the older pinned release.
+# Newer aiohttp releases drop older Python versions, so each one gets its own floor:
+# - Python 3.7 and 3.8: any aiohttp 3.x
+# - Python 3.9: aiohttp 3.13.5 or later
+# - Python 3.10 and later: aiohttp 3.14.5 or later
aiohttp>=3,<4; python_version < "3.9"
-aiohttp>=3.13.5,<4; python_version >= "3.9"
+aiohttp>=3.13.5,<4; python_version == "3.9"
+aiohttp>=3.14.5,<4; python_version >= "3.10"
# websockets
websockets<17