This is an automated email from the ASF dual-hosted git repository.

vatsrahul1001 pushed a commit to branch backport-322-66311
in repository https://gitbox.apache.org/repos/asf/airflow.git

commit 14a5e3d719b849b117c18d6ed4bda869aa05f5ea
Author: Jarek Potiuk <[email protected]>
AuthorDate: Sun May 3 19:04:09 2026 +0200

    Breeze: make `breeze down` discover and stop every compose project (#66311)
    
    Discovers running docker compose projects via the
    `com.docker.compose.project` label and brings down every one matching
    a known breeze prefix (`breeze`, `prek`, `docker-compose`, `docs`, `db`,
    `providers`, plus `breeze-`, `airflow-test`, `constraints-`, `providers-`).
    One `breeze down` now leaves the host clean regardless of which breeze
    commands, prek hooks, or CI steps were running.
    
    Two new flags: `--all-projects` also catches compose projects that don't
    match any known breeze prefix (off by default to avoid wiping unrelated
    host projects); `--project-name <name>` restricts cleanup to a single
    project (useful in CI).
    
    Single-use cleanup gaps fixed:
    - `run_command_via_breeze_shell` (used by every breeze-shell-based prek
      hook) now wraps the subprocess in try/finally and passes `--volumes`
      to the down call, so prek runs no longer leak DB volumes between hooks
      and KeyboardInterrupt no longer skips cleanup.
    - `breeze registry extract-data` and `breeze registry backfill-data`
      added try/finally cleanup of their unique compose projects (previously
      leaked `breeze-registry-*` and `breeze-backfill-*` on every invocation).
    - `breeze doctor` now uses the same label-based cleanup.
    
    (cherry picked from commit 263549590ecbb0c489fb0166caefa456dfe9b8d4)
---
 dev/breeze/doc/03_developer_tasks.rst              | 13 +++
 dev/breeze/doc/images/output-commands.svg          | 84 ++++++++++---------
 dev/breeze/doc/images/output_down.svg              | 67 +++++++++++----
 dev/breeze/doc/images/output_down.txt              |  2 +-
 .../airflow_breeze/commands/developer_commands.py  | 59 +++++++++++--
 .../commands/developer_commands_config.py          |  7 ++
 .../airflow_breeze/commands/registry_commands.py   | 30 ++++---
 dev/breeze/src/airflow_breeze/global_constants.py  | 22 +++++
 .../airflow_breeze/utils/docker_command_utils.py   | 79 ++++++++++++++++++
 dev/breeze/tests/test_docker_command_utils.py      | 97 ++++++++++++++++++++++
 scripts/ci/prek/common_prek_utils.py               | 31 ++++---
 11 files changed, 405 insertions(+), 86 deletions(-)

diff --git a/dev/breeze/doc/03_developer_tasks.rst 
b/dev/breeze/doc/03_developer_tasks.rst
index 37dff9045ad..cc951edb1f2 100644
--- a/dev/breeze/doc/03_developer_tasks.rst
+++ b/dev/breeze/doc/03_developer_tasks.rst
@@ -694,6 +694,19 @@ You can always stop it via:
 
    breeze down
 
+``breeze down`` discovers every running docker compose project that breeze 
knows
+about — ``breeze shell``, ``breeze testing``, ``breeze build-docs``, ``breeze 
db``,
+release-management, registry, ``breeze run``, and prek-hook compose projects — 
by
+reading the ``com.docker.compose.project`` label that compose sets on every 
container
+it creates. Each matching project is brought down with ``--remove-orphans`` and
+``--volumes`` (unless ``--preserve-volumes`` is passed). One ``breeze down`` is
+enough to leave the host clean.
+
+If you have an unrelated docker compose project running on the host that does 
not
+match any breeze prefix, it is left alone by default. Pass ``--all-projects`` 
to
+also bring those down. To restrict the cleanup to a single named project 
(useful
+in CI steps), pass ``--project-name <name>``.
+
 These are all available flags of ``down`` command:
 
 .. image:: ./images/output_down.svg
diff --git a/dev/breeze/doc/images/output-commands.svg 
b/dev/breeze/doc/images/output-commands.svg
index d6cd7ad2284..e5762bf56c8 100644
--- a/dev/breeze/doc/images/output-commands.svg
+++ b/dev/breeze/doc/images/output-commands.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 2538.7999999999997" 
xmlns="http://www.w3.org/2000/svg";>
+<svg class="rich-terminal" viewBox="0 0 1482 2563.2" 
xmlns="http://www.w3.org/2000/svg";>
     <!-- Generated with Rich https://www.textualize.io -->
     <style>
 
@@ -43,7 +43,7 @@
 
     <defs>
     <clipPath id="breeze-help-clip-terminal">
-      <rect x="0" y="0" width="1463.0" height="2487.7999999999997" />
+      <rect x="0" y="0" width="1463.0" height="2512.2" />
     </clipPath>
     <clipPath id="breeze-help-line-0">
     <rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -348,9 +348,12 @@
 <clipPath id="breeze-help-line-100">
     <rect x="0" y="2441.5" width="1464" height="24.65"/>
             </clipPath>
+<clipPath id="breeze-help-line-101">
+    <rect x="0" y="2465.9" width="1464" height="24.65"/>
+            </clipPath>
     </defs>
 
-    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="2536.8" rx="8"/><text 
class="breeze-help-title" fill="#c5c8c6" text-anchor="middle" x="740" 
y="27">Breeze&#160;commands</text>
+    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="2561.2" rx="8"/><text 
class="breeze-help-title" fill="#c5c8c6" text-anchor="middle" x="740" 
y="27">Breeze&#160;commands</text>
             <g transform="translate(26,22)">
             <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
             <circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -423,45 +426,46 @@
 </text><text class="breeze-help-r5" x="0" y="1484" textLength="12.2" 
clip-path="url(#breeze-help-line-60)">│</text><text class="breeze-help-r4" 
x="24.4" y="1484" textLength="280.6" 
clip-path="url(#breeze-help-line-60)">start-airflow&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="1484" textLength="1110.2" 
clip-path="url(#breeze-help-line-60)">Enter&#160;breeze&#160;environment&#160;and&#160;starts&#160;all&#160;Airflow&#160;comp
 [...]
 </text><text class="breeze-help-r5" x="0" y="1508.4" textLength="12.2" 
clip-path="url(#breeze-help-line-61)">│</text><text class="breeze-help-r1" 
x="329.4" y="1508.4" textLength="1110.2" 
clip-path="url(#breeze-help-line-61)">Compile&#160;assets&#160;if&#160;contents&#160;of&#160;www&#160;directory&#160;changed.&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 [...]
 </text><text class="breeze-help-r5" x="0" y="1532.8" textLength="12.2" 
clip-path="url(#breeze-help-line-62)">│</text><text class="breeze-help-r4" 
x="24.4" y="1532.8" textLength="280.6" 
clip-path="url(#breeze-help-line-62)">build-docs&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="1532.8" textLength="1110.2" 
clip-path="url(#breeze-help-line-62)">Build&#160;documents.&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#1
 [...]
-</text><text class="breeze-help-r5" x="0" y="1557.2" textLength="12.2" 
clip-path="url(#breeze-help-line-63)">│</text><text class="breeze-help-r4" 
x="24.4" y="1557.2" textLength="280.6" 
clip-path="url(#breeze-help-line-63)">down&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="1557.2" textLength="1110.2" 
clip-path="url(#breeze-help-line-63)">Stop&#160;running&#160;breeze&#160;e [...]
-</text><text class="breeze-help-r5" x="0" y="1581.6" textLength="12.2" 
clip-path="url(#breeze-help-line-64)">│</text><text class="breeze-help-r4" 
x="24.4" y="1581.6" textLength="280.6" 
clip-path="url(#breeze-help-line-64)">shell&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="1581.6" textLength="1110.2" 
clip-path="url(#breeze-help-line-64)">Enter&#160;breeze&#160;environment.&#160; 
[...]
-</text><text class="breeze-help-r5" x="0" y="1606" textLength="12.2" 
clip-path="url(#breeze-help-line-65)">│</text><text class="breeze-help-r4" 
x="24.4" y="1606" textLength="280.6" 
clip-path="url(#breeze-help-line-65)">exec&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="1606" textLength="1110.2" 
clip-path="url(#breeze-help-line-65)">Joins&#160;the&#160;interactive&#160;shell
 [...]
-</text><text class="breeze-help-r5" x="0" y="1630.4" textLength="12.2" 
clip-path="url(#breeze-help-line-66)">│</text><text class="breeze-help-r4" 
x="24.4" y="1630.4" textLength="280.6" 
clip-path="url(#breeze-help-line-66)">run&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="1630.4" textLength="1110.2" 
clip-path="url(#breeze-help-line-66)">Run&#160;a&#160;command&#160;in [...]
-</text><text class="breeze-help-r5" x="0" y="1654.8" textLength="12.2" 
clip-path="url(#breeze-help-line-67)">│</text><text class="breeze-help-r4" 
x="24.4" y="1654.8" textLength="280.6" 
clip-path="url(#breeze-help-line-67)">cleanup&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="1654.8" textLength="1110.2" 
clip-path="url(#breeze-help-line-67)">Cleans&#160;the&#160;cache&#160;of&#160;parameters,
 [...]
-</text><text class="breeze-help-r5" x="0" y="1679.2" textLength="12.2" 
clip-path="url(#breeze-help-line-68)">│</text><text class="breeze-help-r4" 
x="24.4" y="1679.2" textLength="280.6" 
clip-path="url(#breeze-help-line-68)">generate-migration-file</text><text 
class="breeze-help-r1" x="329.4" y="1679.2" textLength="1110.2" 
clip-path="url(#breeze-help-line-68)">Autogenerate&#160;the&#160;alembic&#160;migration&#160;file&#160;for&#160;the&#160;ORM&#160;changes.&#160;&#160;&#160;&#160;&#160;&
 [...]
-</text><text class="breeze-help-r5" x="0" y="1703.6" textLength="12.2" 
clip-path="url(#breeze-help-line-69)">│</text><text class="breeze-help-r4" 
x="24.4" y="1703.6" textLength="280.6" 
clip-path="url(#breeze-help-line-69)">doctor&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="1703.6" textLength="1110.2" 
clip-path="url(#breeze-help-line-69)">Auto-healing&#160;of&#160;breeze&#160;&#160;&#
 [...]
-</text><text class="breeze-help-r5" x="0" y="1728" textLength="1464" 
clip-path="url(#breeze-help-line-70)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-help-r1" x="1464" y="1728" textLength="12.2" 
clip-path="url(#breeze-help-line-70)">
-</text><text class="breeze-help-r5" x="0" y="1752.4" textLength="24.4" 
clip-path="url(#breeze-help-line-71)">╭─</text><text class="breeze-help-r5" 
x="24.4" y="1752.4" textLength="219.6" 
clip-path="url(#breeze-help-line-71)">&#160;Testing&#160;commands&#160;</text><text
 class="breeze-help-r5" x="244" y="1752.4" textLength="1195.6" 
clip-path="url(#breeze-help-line-71)">──────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="bree [...]
-</text><text class="breeze-help-r5" x="0" y="1776.8" textLength="12.2" 
clip-path="url(#breeze-help-line-72)">│</text><text class="breeze-help-r4" 
x="24.4" y="1776.8" textLength="183" 
clip-path="url(#breeze-help-line-72)">testing&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="231.8" y="1776.8" textLength="1207.8" 
clip-path="url(#breeze-help-line-72)">Tools&#160;that&#160;developers&#160;can&#160;use&#160;to&#160;run&#160;tests&#160;&#160;&#160;&#160;
 [...]
-</text><text class="breeze-help-r5" x="0" y="1801.2" textLength="12.2" 
clip-path="url(#breeze-help-line-73)">│</text><text class="breeze-help-r4" 
x="24.4" y="1801.2" textLength="183" 
clip-path="url(#breeze-help-line-73)">k8s&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="231.8" y="1801.2" textLength="1207.8" 
clip-path="url(#breeze-help-line-73)">Tools&#160;that&#160;developers&#160;use&#160;to&#160;run&#160;Kubernetes&#160;te
 [...]
+</text><text class="breeze-help-r5" x="0" y="1557.2" textLength="12.2" 
clip-path="url(#breeze-help-line-63)">│</text><text class="breeze-help-r4" 
x="24.4" y="1557.2" textLength="280.6" 
clip-path="url(#breeze-help-line-63)">down&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="1557.2" textLength="1110.2" 
clip-path="url(#breeze-help-line-63)">Stop&#160;every&#160;docker&#160;com [...]
+</text><text class="breeze-help-r5" x="0" y="1581.6" textLength="12.2" 
clip-path="url(#breeze-help-line-64)">│</text><text class="breeze-help-r1" 
x="329.4" y="1581.6" textLength="805.2" 
clip-path="url(#breeze-help-line-64)">`com.docker.compose.project`&#160;label&#160;and&#160;brings&#160;each&#160;one&#160;down&#160;with&#160;`</text><text
 class="breeze-help-r4" x="1134.6" y="1581.6" textLength="195.2" 
clip-path="url(#breeze-help-line-64)">--remove-orphans</text><text 
class="breeze-help [...]
+</text><text class="breeze-help-r5" x="0" y="1606" textLength="12.2" 
clip-path="url(#breeze-help-line-65)">│</text><text class="breeze-help-r1" 
x="329.4" y="1606" textLength="12.2" 
clip-path="url(#breeze-help-line-65)">`</text><text class="breeze-help-r4" 
x="341.6" y="1606" textLength="109.8" 
clip-path="url(#breeze-help-line-65)">--volumes</text><text 
class="breeze-help-r1" x="451.4" y="1606" textLength="122" 
clip-path="url(#breeze-help-line-65)">`&#160;unless&#160;`</text><text class="b 
[...]
+</text><text class="breeze-help-r5" x="0" y="1630.4" textLength="12.2" 
clip-path="url(#breeze-help-line-66)">│</text><text class="breeze-help-r1" 
x="329.4" y="1630.4" textLength="1110.2" 
clip-path="url(#breeze-help-line-66)">testing`,&#160;`breeze&#160;build-docs`,&#160;`breeze&#160;db`,&#160;release-management,&#160;registry,&#160;and&#160;prek-hook&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r5" x="1451.8" y="1630.4" textLength="12.2" 
clip-path="url(#breeze-help-line-66)">│< [...]
+</text><text class="breeze-help-r5" x="0" y="1654.8" textLength="12.2" 
clip-path="url(#breeze-help-line-67)">│</text><text class="breeze-help-r1" 
x="329.4" y="1654.8" textLength="1110.2" 
clip-path="url(#breeze-help-line-67)">compose&#160;projects&#160;in&#160;a&#160;single&#160;command.&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&
 [...]
+</text><text class="breeze-help-r5" x="0" y="1679.2" textLength="12.2" 
clip-path="url(#breeze-help-line-68)">│</text><text class="breeze-help-r4" 
x="24.4" y="1679.2" textLength="280.6" 
clip-path="url(#breeze-help-line-68)">shell&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="1679.2" textLength="1110.2" 
clip-path="url(#breeze-help-line-68)">Enter&#160;breeze&#160;environment.&#160; 
[...]
+</text><text class="breeze-help-r5" x="0" y="1703.6" textLength="12.2" 
clip-path="url(#breeze-help-line-69)">│</text><text class="breeze-help-r4" 
x="24.4" y="1703.6" textLength="280.6" 
clip-path="url(#breeze-help-line-69)">exec&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="1703.6" textLength="1110.2" 
clip-path="url(#breeze-help-line-69)">Joins&#160;the&#160;interactive&#160 [...]
+</text><text class="breeze-help-r5" x="0" y="1728" textLength="12.2" 
clip-path="url(#breeze-help-line-70)">│</text><text class="breeze-help-r4" 
x="24.4" y="1728" textLength="280.6" 
clip-path="url(#breeze-help-line-70)">run&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="1728" textLength="1110.2" 
clip-path="url(#breeze-help-line-70)">Run&#160;a&#160;command&#160;in&#160; 
[...]
+</text><text class="breeze-help-r5" x="0" y="1752.4" textLength="12.2" 
clip-path="url(#breeze-help-line-71)">│</text><text class="breeze-help-r4" 
x="24.4" y="1752.4" textLength="280.6" 
clip-path="url(#breeze-help-line-71)">cleanup&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="1752.4" textLength="1110.2" 
clip-path="url(#breeze-help-line-71)">Cleans&#160;the&#160;cache&#160;of&#160;parameters,
 [...]
+</text><text class="breeze-help-r5" x="0" y="1776.8" textLength="12.2" 
clip-path="url(#breeze-help-line-72)">│</text><text class="breeze-help-r4" 
x="24.4" y="1776.8" textLength="280.6" 
clip-path="url(#breeze-help-line-72)">generate-migration-file</text><text 
class="breeze-help-r1" x="329.4" y="1776.8" textLength="1110.2" 
clip-path="url(#breeze-help-line-72)">Autogenerate&#160;the&#160;alembic&#160;migration&#160;file&#160;for&#160;the&#160;ORM&#160;changes.&#160;&#160;&#160;&#160;&#160;&
 [...]
+</text><text class="breeze-help-r5" x="0" y="1801.2" textLength="12.2" 
clip-path="url(#breeze-help-line-73)">│</text><text class="breeze-help-r4" 
x="24.4" y="1801.2" textLength="280.6" 
clip-path="url(#breeze-help-line-73)">doctor&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="1801.2" textLength="1110.2" 
clip-path="url(#breeze-help-line-73)">Auto-healing&#160;of&#160;breeze&#160;&#160;&#
 [...]
 </text><text class="breeze-help-r5" x="0" y="1825.6" textLength="1464" 
clip-path="url(#breeze-help-line-74)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-help-r1" x="1464" y="1825.6" textLength="12.2" 
clip-path="url(#breeze-help-line-74)">
-</text><text class="breeze-help-r5" x="0" y="1850" textLength="24.4" 
clip-path="url(#breeze-help-line-75)">╭─</text><text class="breeze-help-r5" 
x="24.4" y="1850" textLength="195.2" 
clip-path="url(#breeze-help-line-75)">&#160;Image&#160;commands&#160;</text><text
 class="breeze-help-r5" x="219.6" y="1850" textLength="1220" 
clip-path="url(#breeze-help-line-75)">────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="breeze-hel [...]
-</text><text class="breeze-help-r5" x="0" y="1874.4" textLength="12.2" 
clip-path="url(#breeze-help-line-76)">│</text><text class="breeze-help-r4" 
x="24.4" y="1874.4" textLength="207.4" 
clip-path="url(#breeze-help-line-76)">ci-image&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="256.2" y="1874.4" textLength="1183.4" 
clip-path="url(#breeze-help-line-76)">Tools&#160;that&#160;developers&#160;can&#160;use&#160;to&#160;manually&#160;manage&#160;CI&
 [...]
-</text><text class="breeze-help-r5" x="0" y="1898.8" textLength="12.2" 
clip-path="url(#breeze-help-line-77)">│</text><text class="breeze-help-r4" 
x="24.4" y="1898.8" textLength="207.4" 
clip-path="url(#breeze-help-line-77)">prod-image&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="256.2" y="1898.8" textLength="1183.4" 
clip-path="url(#breeze-help-line-77)">Tools&#160;that&#160;developers&#160;can&#160;use&#160;to&#160;manually&#160;manage&#160;PROD&#160;ima
 [...]
+</text><text class="breeze-help-r5" x="0" y="1850" textLength="24.4" 
clip-path="url(#breeze-help-line-75)">╭─</text><text class="breeze-help-r5" 
x="24.4" y="1850" textLength="219.6" 
clip-path="url(#breeze-help-line-75)">&#160;Testing&#160;commands&#160;</text><text
 class="breeze-help-r5" x="244" y="1850" textLength="1195.6" 
clip-path="url(#breeze-help-line-75)">──────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="breeze-hel [...]
+</text><text class="breeze-help-r5" x="0" y="1874.4" textLength="12.2" 
clip-path="url(#breeze-help-line-76)">│</text><text class="breeze-help-r4" 
x="24.4" y="1874.4" textLength="183" 
clip-path="url(#breeze-help-line-76)">testing&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="231.8" y="1874.4" textLength="1207.8" 
clip-path="url(#breeze-help-line-76)">Tools&#160;that&#160;developers&#160;can&#160;use&#160;to&#160;run&#160;tests&#160;&#160;&#160;&#160;
 [...]
+</text><text class="breeze-help-r5" x="0" y="1898.8" textLength="12.2" 
clip-path="url(#breeze-help-line-77)">│</text><text class="breeze-help-r4" 
x="24.4" y="1898.8" textLength="183" 
clip-path="url(#breeze-help-line-77)">k8s&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="231.8" y="1898.8" textLength="1207.8" 
clip-path="url(#breeze-help-line-77)">Tools&#160;that&#160;developers&#160;use&#160;to&#160;run&#160;Kubernetes&#160;te
 [...]
 </text><text class="breeze-help-r5" x="0" y="1923.2" textLength="1464" 
clip-path="url(#breeze-help-line-78)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-help-r1" x="1464" y="1923.2" textLength="12.2" 
clip-path="url(#breeze-help-line-78)">
-</text><text class="breeze-help-r5" x="0" y="1947.6" textLength="24.4" 
clip-path="url(#breeze-help-line-79)">╭─</text><text class="breeze-help-r5" 
x="24.4" y="1947.6" textLength="353.8" 
clip-path="url(#breeze-help-line-79)">&#160;Release&#160;management&#160;commands&#160;</text><text
 class="breeze-help-r5" x="378.2" y="1947.6" textLength="1061.4" 
clip-path="url(#breeze-help-line-79)">───────────────────────────────────────────────────────────────────────────────────────</text><text
 clas [...]
-</text><text class="breeze-help-r5" x="0" y="1972" textLength="12.2" 
clip-path="url(#breeze-help-line-80)">│</text><text class="breeze-help-r4" 
x="24.4" y="1972" textLength="280.6" 
clip-path="url(#breeze-help-line-80)">release-management&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="1972" textLength="1110.2" 
clip-path="url(#breeze-help-line-80)">Tools&#160;that&#160;release&#160;managers&#160;can&#160;use&#160;to&#160;prepare&#160;and&#160;manage&#160;Airf
 [...]
-</text><text class="breeze-help-r5" x="0" y="1996.4" textLength="12.2" 
clip-path="url(#breeze-help-line-81)">│</text><text class="breeze-help-r4" 
x="24.4" y="1996.4" textLength="280.6" 
clip-path="url(#breeze-help-line-81)">sbom&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="1996.4" textLength="1110.2" 
clip-path="url(#breeze-help-line-81)">Tools&#160;that&#160;release&#160;ma [...]
-</text><text class="breeze-help-r5" x="0" y="2020.8" textLength="12.2" 
clip-path="url(#breeze-help-line-82)">│</text><text class="breeze-help-r4" 
x="24.4" y="2020.8" textLength="280.6" 
clip-path="url(#breeze-help-line-82)">workflow-run&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="2020.8" textLength="1110.2" 
clip-path="url(#breeze-help-line-82)">Tools&#160;to&#160;manage&#160;Airflow&#160;repository&#160;workflows&#160;&
 [...]
-</text><text class="breeze-help-r5" x="0" y="2045.2" textLength="1464" 
clip-path="url(#breeze-help-line-83)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-help-r1" x="1464" y="2045.2" textLength="12.2" 
clip-path="url(#breeze-help-line-83)">
-</text><text class="breeze-help-r5" x="0" y="2069.6" textLength="24.4" 
clip-path="url(#breeze-help-line-84)">╭─</text><text class="breeze-help-r5" 
x="24.4" y="2069.6" textLength="158.6" 
clip-path="url(#breeze-help-line-84)">&#160;CI&#160;commands&#160;</text><text 
class="breeze-help-r5" x="183" y="2069.6" textLength="1256.6" 
clip-path="url(#breeze-help-line-84)">───────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="bree [...]
-</text><text class="breeze-help-r5" x="0" y="2094" textLength="12.2" 
clip-path="url(#breeze-help-line-85)">│</text><text class="breeze-help-r4" 
x="24.4" y="2094" textLength="61" 
clip-path="url(#breeze-help-line-85)">ci&#160;&#160;&#160;</text><text 
class="breeze-help-r1" x="109.8" y="2094" textLength="1329.8" 
clip-path="url(#breeze-help-line-85)">Tools&#160;that&#160;CI&#160;workflows&#160;use&#160;to&#160;cleanup/manage&#160;CI&#160;environment&#160;&#160;&#160;&#160;&#160;&#160;&#160;&
 [...]
-</text><text class="breeze-help-r5" x="0" y="2118.4" textLength="1464" 
clip-path="url(#breeze-help-line-86)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-help-r1" x="1464" y="2118.4" textLength="12.2" 
clip-path="url(#breeze-help-line-86)">
-</text><text class="breeze-help-r5" x="0" y="2142.8" textLength="24.4" 
clip-path="url(#breeze-help-line-87)">╭─</text><text class="breeze-help-r5" 
x="24.4" y="2142.8" textLength="231.8" 
clip-path="url(#breeze-help-line-87)">&#160;Registry&#160;commands&#160;</text><text
 class="breeze-help-r5" x="256.2" y="2142.8" textLength="1183.4" 
clip-path="url(#breeze-help-line-87)">─────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="br [...]
-</text><text class="breeze-help-r5" x="0" y="2167.2" textLength="12.2" 
clip-path="url(#breeze-help-line-88)">│</text><text class="breeze-help-r4" 
x="24.4" y="2167.2" textLength="256.2" 
clip-path="url(#breeze-help-line-88)">registry&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="305" y="2167.2" textLength="1134.6" 
clip-path="url(#breeze-help-line-88)">Tools&#160;for&#160;the&#160;Airflow&#160;Provider&#160;Registry&#160;
 [...]
-</text><text class="breeze-help-r5" x="0" y="2191.6" textLength="1464" 
clip-path="url(#breeze-help-line-89)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-help-r1" x="1464" y="2191.6" textLength="12.2" 
clip-path="url(#breeze-help-line-89)">
-</text><text class="breeze-help-r5" x="0" y="2216" textLength="24.4" 
clip-path="url(#breeze-help-line-90)">╭─</text><text class="breeze-help-r5" 
x="24.4" y="2216" textLength="158.6" 
clip-path="url(#breeze-help-line-90)">&#160;UI&#160;commands&#160;</text><text 
class="breeze-help-r5" x="183" y="2216" textLength="1256.6" 
clip-path="url(#breeze-help-line-90)">───────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="breeze-hel [...]
-</text><text class="breeze-help-r5" x="0" y="2240.4" textLength="12.2" 
clip-path="url(#breeze-help-line-91)">│</text><text class="breeze-help-r4" 
x="24.4" y="2240.4" textLength="85.4" 
clip-path="url(#breeze-help-line-91)">ui&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="134.2" y="2240.4" textLength="1305.4" 
clip-path="url(#breeze-help-line-91)">Tools&#160;for&#160;UI&#160;development&#160;and&#160;maintenance&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
-</text><text class="breeze-help-r5" x="0" y="2264.8" textLength="1464" 
clip-path="url(#breeze-help-line-92)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-help-r1" x="1464" y="2264.8" textLength="12.2" 
clip-path="url(#breeze-help-line-92)">
-</text><text class="breeze-help-r5" x="0" y="2289.2" textLength="24.4" 
clip-path="url(#breeze-help-line-93)">╭─</text><text class="breeze-help-r5" 
x="24.4" y="2289.2" textLength="207.4" 
clip-path="url(#breeze-help-line-93)">&#160;Issues&#160;commands&#160;</text><text
 class="breeze-help-r5" x="231.8" y="2289.2" textLength="1207.8" 
clip-path="url(#breeze-help-line-93)">───────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="br [...]
-</text><text class="breeze-help-r5" x="0" y="2313.6" textLength="12.2" 
clip-path="url(#breeze-help-line-94)">│</text><text class="breeze-help-r4" 
x="24.4" y="2313.6" textLength="231.8" 
clip-path="url(#breeze-help-line-94)">issues&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="280.6" y="2313.6" textLength="1159" 
clip-path="url(#breeze-help-line-94)">Tools&#160;for&#160;managing&#160;GitHub&#160;issues.&#160;&#160;&#160;&
 [...]
-</text><text class="breeze-help-r5" x="0" y="2338" textLength="1464" 
clip-path="url(#breeze-help-line-95)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-help-r1" x="1464" y="2338" textLength="12.2" 
clip-path="url(#breeze-help-line-95)">
-</text><text class="breeze-help-r5" x="0" y="2362.4" textLength="24.4" 
clip-path="url(#breeze-help-line-96)">╭─</text><text class="breeze-help-r5" 
x="24.4" y="2362.4" textLength="158.6" 
clip-path="url(#breeze-help-line-96)">&#160;PR&#160;commands&#160;</text><text 
class="breeze-help-r5" x="183" y="2362.4" textLength="1256.6" 
clip-path="url(#breeze-help-line-96)">───────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="bree [...]
-</text><text class="breeze-help-r5" x="0" y="2386.8" textLength="12.2" 
clip-path="url(#breeze-help-line-97)">│</text><text class="breeze-help-r4" 
x="24.4" y="2386.8" textLength="85.4" 
clip-path="url(#breeze-help-line-97)">pr&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="134.2" y="2386.8" textLength="1305.4" 
clip-path="url(#breeze-help-line-97)">Tools&#160;for&#160;managing&#160;GitHub&#160;pull&#160;requests.&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
-</text><text class="breeze-help-r5" x="0" y="2411.2" textLength="1464" 
clip-path="url(#breeze-help-line-98)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-help-r1" x="1464" y="2411.2" textLength="12.2" 
clip-path="url(#breeze-help-line-98)">
-</text><text class="breeze-help-r5" x="0" y="2435.6" textLength="24.4" 
clip-path="url(#breeze-help-line-99)">╭─</text><text class="breeze-help-r5" 
x="24.4" y="2435.6" textLength="195.2" 
clip-path="url(#breeze-help-line-99)">&#160;Setup&#160;commands&#160;</text><text
 class="breeze-help-r5" x="219.6" y="2435.6" textLength="1220" 
clip-path="url(#breeze-help-line-99)">────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="bree [...]
-</text><text class="breeze-help-r5" x="0" y="2460" textLength="12.2" 
clip-path="url(#breeze-help-line-100)">│</text><text class="breeze-help-r4" 
x="24.4" y="2460" textLength="146.4" 
clip-path="url(#breeze-help-line-100)">setup&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="195.2" y="2460" textLength="1244.4" 
clip-path="url(#breeze-help-line-100)">Tools&#160;that&#160;developers&#160;can&#160;use&#160;to&#160;configure&#160;Breeze&#160;&#160;&#160;&#160;&#
 [...]
-</text><text class="breeze-help-r5" x="0" y="2484.4" textLength="1464" 
clip-path="url(#breeze-help-line-101)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-help-r1" x="1464" y="2484.4" textLength="12.2" 
clip-path="url(#breeze-help-line-101)">
+</text><text class="breeze-help-r5" x="0" y="1947.6" textLength="24.4" 
clip-path="url(#breeze-help-line-79)">╭─</text><text class="breeze-help-r5" 
x="24.4" y="1947.6" textLength="195.2" 
clip-path="url(#breeze-help-line-79)">&#160;Image&#160;commands&#160;</text><text
 class="breeze-help-r5" x="219.6" y="1947.6" textLength="1220" 
clip-path="url(#breeze-help-line-79)">────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="bree [...]
+</text><text class="breeze-help-r5" x="0" y="1972" textLength="12.2" 
clip-path="url(#breeze-help-line-80)">│</text><text class="breeze-help-r4" 
x="24.4" y="1972" textLength="207.4" 
clip-path="url(#breeze-help-line-80)">ci-image&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="256.2" y="1972" textLength="1183.4" 
clip-path="url(#breeze-help-line-80)">Tools&#160;that&#160;developers&#160;can&#160;use&#160;to&#160;manually&#160;manage&#160;CI&#160;i
 [...]
+</text><text class="breeze-help-r5" x="0" y="1996.4" textLength="12.2" 
clip-path="url(#breeze-help-line-81)">│</text><text class="breeze-help-r4" 
x="24.4" y="1996.4" textLength="207.4" 
clip-path="url(#breeze-help-line-81)">prod-image&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="256.2" y="1996.4" textLength="1183.4" 
clip-path="url(#breeze-help-line-81)">Tools&#160;that&#160;developers&#160;can&#160;use&#160;to&#160;manually&#160;manage&#160;PROD&#160;ima
 [...]
+</text><text class="breeze-help-r5" x="0" y="2020.8" textLength="1464" 
clip-path="url(#breeze-help-line-82)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-help-r1" x="1464" y="2020.8" textLength="12.2" 
clip-path="url(#breeze-help-line-82)">
+</text><text class="breeze-help-r5" x="0" y="2045.2" textLength="24.4" 
clip-path="url(#breeze-help-line-83)">╭─</text><text class="breeze-help-r5" 
x="24.4" y="2045.2" textLength="353.8" 
clip-path="url(#breeze-help-line-83)">&#160;Release&#160;management&#160;commands&#160;</text><text
 class="breeze-help-r5" x="378.2" y="2045.2" textLength="1061.4" 
clip-path="url(#breeze-help-line-83)">───────────────────────────────────────────────────────────────────────────────────────</text><text
 clas [...]
+</text><text class="breeze-help-r5" x="0" y="2069.6" textLength="12.2" 
clip-path="url(#breeze-help-line-84)">│</text><text class="breeze-help-r4" 
x="24.4" y="2069.6" textLength="280.6" 
clip-path="url(#breeze-help-line-84)">release-management&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="2069.6" textLength="1110.2" 
clip-path="url(#breeze-help-line-84)">Tools&#160;that&#160;release&#160;managers&#160;can&#160;use&#160;to&#160;prepare&#160;and&#160;manage&#16
 [...]
+</text><text class="breeze-help-r5" x="0" y="2094" textLength="12.2" 
clip-path="url(#breeze-help-line-85)">│</text><text class="breeze-help-r4" 
x="24.4" y="2094" textLength="280.6" 
clip-path="url(#breeze-help-line-85)">sbom&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="2094" textLength="1110.2" 
clip-path="url(#breeze-help-line-85)">Tools&#160;that&#160;release&#160;managers
 [...]
+</text><text class="breeze-help-r5" x="0" y="2118.4" textLength="12.2" 
clip-path="url(#breeze-help-line-86)">│</text><text class="breeze-help-r4" 
x="24.4" y="2118.4" textLength="280.6" 
clip-path="url(#breeze-help-line-86)">workflow-run&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="329.4" y="2118.4" textLength="1110.2" 
clip-path="url(#breeze-help-line-86)">Tools&#160;to&#160;manage&#160;Airflow&#160;repository&#160;workflows&#160;&
 [...]
+</text><text class="breeze-help-r5" x="0" y="2142.8" textLength="1464" 
clip-path="url(#breeze-help-line-87)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-help-r1" x="1464" y="2142.8" textLength="12.2" 
clip-path="url(#breeze-help-line-87)">
+</text><text class="breeze-help-r5" x="0" y="2167.2" textLength="24.4" 
clip-path="url(#breeze-help-line-88)">╭─</text><text class="breeze-help-r5" 
x="24.4" y="2167.2" textLength="158.6" 
clip-path="url(#breeze-help-line-88)">&#160;CI&#160;commands&#160;</text><text 
class="breeze-help-r5" x="183" y="2167.2" textLength="1256.6" 
clip-path="url(#breeze-help-line-88)">───────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="bree [...]
+</text><text class="breeze-help-r5" x="0" y="2191.6" textLength="12.2" 
clip-path="url(#breeze-help-line-89)">│</text><text class="breeze-help-r4" 
x="24.4" y="2191.6" textLength="61" 
clip-path="url(#breeze-help-line-89)">ci&#160;&#160;&#160;</text><text 
class="breeze-help-r1" x="109.8" y="2191.6" textLength="1329.8" 
clip-path="url(#breeze-help-line-89)">Tools&#160;that&#160;CI&#160;workflows&#160;use&#160;to&#160;cleanup/manage&#160;CI&#160;environment&#160;&#160;&#160;&#160;&#160;&#160;&
 [...]
+</text><text class="breeze-help-r5" x="0" y="2216" textLength="1464" 
clip-path="url(#breeze-help-line-90)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-help-r1" x="1464" y="2216" textLength="12.2" 
clip-path="url(#breeze-help-line-90)">
+</text><text class="breeze-help-r5" x="0" y="2240.4" textLength="24.4" 
clip-path="url(#breeze-help-line-91)">╭─</text><text class="breeze-help-r5" 
x="24.4" y="2240.4" textLength="231.8" 
clip-path="url(#breeze-help-line-91)">&#160;Registry&#160;commands&#160;</text><text
 class="breeze-help-r5" x="256.2" y="2240.4" textLength="1183.4" 
clip-path="url(#breeze-help-line-91)">─────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="br [...]
+</text><text class="breeze-help-r5" x="0" y="2264.8" textLength="12.2" 
clip-path="url(#breeze-help-line-92)">│</text><text class="breeze-help-r4" 
x="24.4" y="2264.8" textLength="256.2" 
clip-path="url(#breeze-help-line-92)">registry&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="305" y="2264.8" textLength="1134.6" 
clip-path="url(#breeze-help-line-92)">Tools&#160;for&#160;the&#160;Airflow&#160;Provider&#160;Registry&#160;
 [...]
+</text><text class="breeze-help-r5" x="0" y="2289.2" textLength="1464" 
clip-path="url(#breeze-help-line-93)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-help-r1" x="1464" y="2289.2" textLength="12.2" 
clip-path="url(#breeze-help-line-93)">
+</text><text class="breeze-help-r5" x="0" y="2313.6" textLength="24.4" 
clip-path="url(#breeze-help-line-94)">╭─</text><text class="breeze-help-r5" 
x="24.4" y="2313.6" textLength="158.6" 
clip-path="url(#breeze-help-line-94)">&#160;UI&#160;commands&#160;</text><text 
class="breeze-help-r5" x="183" y="2313.6" textLength="1256.6" 
clip-path="url(#breeze-help-line-94)">───────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="bree [...]
+</text><text class="breeze-help-r5" x="0" y="2338" textLength="12.2" 
clip-path="url(#breeze-help-line-95)">│</text><text class="breeze-help-r4" 
x="24.4" y="2338" textLength="85.4" 
clip-path="url(#breeze-help-line-95)">ui&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="134.2" y="2338" textLength="1305.4" 
clip-path="url(#breeze-help-line-95)">Tools&#160;for&#160;UI&#160;development&#160;and&#160;maintenance&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
+</text><text class="breeze-help-r5" x="0" y="2362.4" textLength="1464" 
clip-path="url(#breeze-help-line-96)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-help-r1" x="1464" y="2362.4" textLength="12.2" 
clip-path="url(#breeze-help-line-96)">
+</text><text class="breeze-help-r5" x="0" y="2386.8" textLength="24.4" 
clip-path="url(#breeze-help-line-97)">╭─</text><text class="breeze-help-r5" 
x="24.4" y="2386.8" textLength="207.4" 
clip-path="url(#breeze-help-line-97)">&#160;Issues&#160;commands&#160;</text><text
 class="breeze-help-r5" x="231.8" y="2386.8" textLength="1207.8" 
clip-path="url(#breeze-help-line-97)">───────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="br [...]
+</text><text class="breeze-help-r5" x="0" y="2411.2" textLength="12.2" 
clip-path="url(#breeze-help-line-98)">│</text><text class="breeze-help-r4" 
x="24.4" y="2411.2" textLength="231.8" 
clip-path="url(#breeze-help-line-98)">issues&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="280.6" y="2411.2" textLength="1159" 
clip-path="url(#breeze-help-line-98)">Tools&#160;for&#160;managing&#160;GitHub&#160;issues.&#160;&#160;&#160;&
 [...]
+</text><text class="breeze-help-r5" x="0" y="2435.6" textLength="1464" 
clip-path="url(#breeze-help-line-99)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-help-r1" x="1464" y="2435.6" textLength="12.2" 
clip-path="url(#breeze-help-line-99)">
+</text><text class="breeze-help-r5" x="0" y="2460" textLength="24.4" 
clip-path="url(#breeze-help-line-100)">╭─</text><text class="breeze-help-r5" 
x="24.4" y="2460" textLength="195.2" 
clip-path="url(#breeze-help-line-100)">&#160;Setup&#160;commands&#160;</text><text
 class="breeze-help-r5" x="219.6" y="2460" textLength="1220" 
clip-path="url(#breeze-help-line-100)">────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="breeze- [...]
+</text><text class="breeze-help-r5" x="0" y="2484.4" textLength="12.2" 
clip-path="url(#breeze-help-line-101)">│</text><text class="breeze-help-r4" 
x="24.4" y="2484.4" textLength="146.4" 
clip-path="url(#breeze-help-line-101)">setup&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-help-r1" x="195.2" y="2484.4" textLength="1244.4" 
clip-path="url(#breeze-help-line-101)">Tools&#160;that&#160;developers&#160;can&#160;use&#160;to&#160;configure&#160;Breeze&#160;&#160;&#160;&#
 [...]
+</text><text class="breeze-help-r5" x="0" y="2508.8" textLength="1464" 
clip-path="url(#breeze-help-line-102)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-help-r1" x="1464" y="2508.8" textLength="12.2" 
clip-path="url(#breeze-help-line-102)">
 </text>
     </g>
     </g>
diff --git a/dev/breeze/doc/images/output_down.svg 
b/dev/breeze/doc/images/output_down.svg
index 4375f66f8db..84dd611651f 100644
--- a/dev/breeze/doc/images/output_down.svg
+++ b/dev/breeze/doc/images/output_down.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 416.0" 
xmlns="http://www.w3.org/2000/svg";>
+<svg class="rich-terminal" viewBox="0 0 1482 635.5999999999999" 
xmlns="http://www.w3.org/2000/svg";>
     <!-- Generated with Rich https://www.textualize.io -->
     <style>
 
@@ -38,11 +38,12 @@
 .breeze-down-r4 { fill: #68a0b3;font-weight: bold }
 .breeze-down-r5 { fill: #868887 }
 .breeze-down-r6 { fill: #98a84b;font-weight: bold }
+.breeze-down-r7 { fill: #8d7b39 }
     </style>
 
     <defs>
     <clipPath id="breeze-down-clip-terminal">
-      <rect x="0" y="0" width="1463.0" height="365.0" />
+      <rect x="0" y="0" width="1463.0" height="584.5999999999999" />
     </clipPath>
     <clipPath id="breeze-down-line-0">
     <rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -86,9 +87,36 @@
 <clipPath id="breeze-down-line-13">
     <rect x="0" y="318.7" width="1464" height="24.65"/>
             </clipPath>
+<clipPath id="breeze-down-line-14">
+    <rect x="0" y="343.1" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-down-line-15">
+    <rect x="0" y="367.5" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-down-line-16">
+    <rect x="0" y="391.9" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-down-line-17">
+    <rect x="0" y="416.3" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-down-line-18">
+    <rect x="0" y="440.7" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-down-line-19">
+    <rect x="0" y="465.1" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-down-line-20">
+    <rect x="0" y="489.5" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-down-line-21">
+    <rect x="0" y="513.9" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-down-line-22">
+    <rect x="0" y="538.3" width="1464" height="24.65"/>
+            </clipPath>
     </defs>
 
-    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="414" rx="8"/><text class="breeze-down-title" 
fill="#c5c8c6" text-anchor="middle" x="740" y="27">Command:&#160;down</text>
+    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="633.6" rx="8"/><text class="breeze-down-title" 
fill="#c5c8c6" text-anchor="middle" x="740" y="27">Command:&#160;down</text>
             <g transform="translate(26,22)">
             <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
             <circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -101,18 +129,27 @@
     <text class="breeze-down-r1" x="1464" y="20" textLength="12.2" 
clip-path="url(#breeze-down-line-0)">
 </text><text class="breeze-down-r2" x="12.2" y="44.4" textLength="73.2" 
clip-path="url(#breeze-down-line-1)">Usage:</text><text class="breeze-down-r3" 
x="97.6" y="44.4" textLength="134.2" 
clip-path="url(#breeze-down-line-1)">breeze&#160;down</text><text 
class="breeze-down-r1" x="244" y="44.4" textLength="12.2" 
clip-path="url(#breeze-down-line-1)">[</text><text class="breeze-down-r4" 
x="256.2" y="44.4" textLength="85.4" 
clip-path="url(#breeze-down-line-1)">OPTIONS</text><text class="breez [...]
 </text><text class="breeze-down-r1" x="1464" y="68.8" textLength="12.2" 
clip-path="url(#breeze-down-line-2)">
-</text><text class="breeze-down-r1" x="12.2" y="93.2" textLength="390.4" 
clip-path="url(#breeze-down-line-3)">Stop&#160;running&#160;breeze&#160;environment.</text><text
 class="breeze-down-r1" x="1464" y="93.2" textLength="12.2" 
clip-path="url(#breeze-down-line-3)">
-</text><text class="breeze-down-r1" x="1464" y="117.6" textLength="12.2" 
clip-path="url(#breeze-down-line-4)">
-</text><text class="breeze-down-r5" x="0" y="142" textLength="24.4" 
clip-path="url(#breeze-down-line-5)">╭─</text><text class="breeze-down-r5" 
x="24.4" y="142" textLength="146.4" 
clip-path="url(#breeze-down-line-5)">&#160;Down&#160;flags&#160;</text><text 
class="breeze-down-r5" x="170.8" y="142" textLength="1268.8" 
clip-path="url(#breeze-down-line-5)">────────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="breeze-down-r5 [...]
-</text><text class="breeze-down-r5" x="0" y="166.4" textLength="12.2" 
clip-path="url(#breeze-down-line-6)">│</text><text class="breeze-down-r4" 
x="24.4" y="166.4" textLength="256.2" 
clip-path="url(#breeze-down-line-6)">--preserve-volumes&#160;&#160;&#160;</text><text
 class="breeze-down-r6" x="305" y="166.4" textLength="24.4" 
clip-path="url(#breeze-down-line-6)">-p</text><text class="breeze-down-r1" 
x="353.8" y="166.4" textLength="634.4" 
clip-path="url(#breeze-down-line-6)">Skip&#160;remo [...]
-</text><text class="breeze-down-r5" x="0" y="190.8" textLength="12.2" 
clip-path="url(#breeze-down-line-7)">│</text><text class="breeze-down-r4" 
x="24.4" y="190.8" textLength="256.2" 
clip-path="url(#breeze-down-line-7)">--cleanup-mypy-cache&#160;</text><text 
class="breeze-down-r6" x="305" y="190.8" textLength="24.4" 
clip-path="url(#breeze-down-line-7)">-c</text><text class="breeze-down-r1" 
x="353.8" y="190.8" textLength="390.4" 
clip-path="url(#breeze-down-line-7)">Additionally&#160;cleanu [...]
-</text><text class="breeze-down-r5" x="0" y="215.2" textLength="12.2" 
clip-path="url(#breeze-down-line-8)">│</text><text class="breeze-down-r4" 
x="24.4" y="215.2" textLength="256.2" 
clip-path="url(#breeze-down-line-8)">--cleanup-build-cache</text><text 
class="breeze-down-r6" x="305" y="215.2" textLength="24.4" 
clip-path="url(#breeze-down-line-8)">-b</text><text class="breeze-down-r1" 
x="353.8" y="215.2" textLength="512.4" 
clip-path="url(#breeze-down-line-8)">Additionally&#160;cleanup&#16 [...]
-</text><text class="breeze-down-r5" x="0" y="239.6" textLength="1464" 
clip-path="url(#breeze-down-line-9)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-down-r1" x="1464" y="239.6" textLength="12.2" 
clip-path="url(#breeze-down-line-9)">
-</text><text class="breeze-down-r5" x="0" y="264" textLength="24.4" 
clip-path="url(#breeze-down-line-10)">╭─</text><text class="breeze-down-r5" 
x="24.4" y="264" textLength="195.2" 
clip-path="url(#breeze-down-line-10)">&#160;Common&#160;options&#160;</text><text
 class="breeze-down-r5" x="219.6" y="264" textLength="1220" 
clip-path="url(#breeze-down-line-10)">────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="breeze-down-r [...]
-</text><text class="breeze-down-r5" x="0" y="288.4" textLength="12.2" 
clip-path="url(#breeze-down-line-11)">│</text><text class="breeze-down-r4" 
x="24.4" y="288.4" textLength="109.8" 
clip-path="url(#breeze-down-line-11)">--verbose</text><text 
class="breeze-down-r6" x="158.6" y="288.4" textLength="24.4" 
clip-path="url(#breeze-down-line-11)">-v</text><text class="breeze-down-r1" 
x="207.4" y="288.4" textLength="585.6" 
clip-path="url(#breeze-down-line-11)">Print&#160;verbose&#160;information [...]
-</text><text class="breeze-down-r5" x="0" y="312.8" textLength="12.2" 
clip-path="url(#breeze-down-line-12)">│</text><text class="breeze-down-r4" 
x="24.4" y="312.8" textLength="109.8" 
clip-path="url(#breeze-down-line-12)">--dry-run</text><text 
class="breeze-down-r6" x="158.6" y="312.8" textLength="24.4" 
clip-path="url(#breeze-down-line-12)">-D</text><text class="breeze-down-r1" 
x="207.4" y="312.8" textLength="719.8" 
clip-path="url(#breeze-down-line-12)">If&#160;dry-run&#160;is&#160;set,&# [...]
-</text><text class="breeze-down-r5" x="0" y="337.2" textLength="12.2" 
clip-path="url(#breeze-down-line-13)">│</text><text class="breeze-down-r4" 
x="24.4" y="337.2" textLength="109.8" 
clip-path="url(#breeze-down-line-13)">--help&#160;&#160;&#160;</text><text 
class="breeze-down-r6" x="158.6" y="337.2" textLength="24.4" 
clip-path="url(#breeze-down-line-13)">-h</text><text class="breeze-down-r1" 
x="207.4" y="337.2" textLength="329.4" 
clip-path="url(#breeze-down-line-13)">Show&#160;this&#160; [...]
-</text><text class="breeze-down-r5" x="0" y="361.6" textLength="1464" 
clip-path="url(#breeze-down-line-14)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-down-r1" x="1464" y="361.6" textLength="12.2" 
clip-path="url(#breeze-down-line-14)">
+</text><text class="breeze-down-r1" x="12.2" y="93.2" textLength="1439.6" 
clip-path="url(#breeze-down-line-3)">Stop&#160;every&#160;docker&#160;compose&#160;project&#160;breeze&#160;knows&#160;about.&#160;Discovers&#160;running&#160;projects&#160;via&#160;the&#160;`com.docker.compose.project`&#160;</text><text
 class="breeze-down-r1" x="1464" y="93.2" textLength="12.2" 
clip-path="url(#breeze-down-line-3)">
+</text><text class="breeze-down-r1" x="12.2" y="117.6" textLength="451.4" 
clip-path="url(#breeze-down-line-4)">label&#160;and&#160;brings&#160;each&#160;one&#160;down&#160;with&#160;`</text><text
 class="breeze-down-r4" x="463.6" y="117.6" textLength="195.2" 
clip-path="url(#breeze-down-line-4)">--remove-orphans</text><text 
class="breeze-down-r1" x="658.8" y="117.6" textLength="97.6" 
clip-path="url(#breeze-down-line-4)">`&#160;(and&#160;`</text><text 
class="breeze-down-r4" x="756.4" y="117 [...]
+</text><text class="breeze-down-r1" x="12.2" y="142" textLength="1366.4" 
clip-path="url(#breeze-down-line-5)">`breeze&#160;shell`,&#160;`breeze&#160;testing`,&#160;`breeze&#160;build-docs`,&#160;`breeze&#160;db`,&#160;release-management,&#160;registry,&#160;and&#160;prek-hook&#160;</text><text
 class="breeze-down-r1" x="1464" y="142" textLength="12.2" 
clip-path="url(#breeze-down-line-5)">
+</text><text class="breeze-down-r1" x="12.2" y="166.4" textLength="451.4" 
clip-path="url(#breeze-down-line-6)">compose&#160;projects&#160;in&#160;a&#160;single&#160;command.</text><text
 class="breeze-down-r1" x="1464" y="166.4" textLength="12.2" 
clip-path="url(#breeze-down-line-6)">
+</text><text class="breeze-down-r1" x="1464" y="190.8" textLength="12.2" 
clip-path="url(#breeze-down-line-7)">
+</text><text class="breeze-down-r5" x="0" y="215.2" textLength="24.4" 
clip-path="url(#breeze-down-line-8)">╭─</text><text class="breeze-down-r5" 
x="24.4" y="215.2" textLength="146.4" 
clip-path="url(#breeze-down-line-8)">&#160;Down&#160;flags&#160;</text><text 
class="breeze-down-r5" x="170.8" y="215.2" textLength="1268.8" 
clip-path="url(#breeze-down-line-8)">────────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="breeze-d [...]
+</text><text class="breeze-down-r5" x="0" y="239.6" textLength="12.2" 
clip-path="url(#breeze-down-line-9)">│</text><text class="breeze-down-r4" 
x="24.4" y="239.6" textLength="256.2" 
clip-path="url(#breeze-down-line-9)">--preserve-volumes&#160;&#160;&#160;</text><text
 class="breeze-down-r6" x="305" y="239.6" textLength="24.4" 
clip-path="url(#breeze-down-line-9)">-p</text><text class="breeze-down-r1" 
x="353.8" y="239.6" textLength="634.4" 
clip-path="url(#breeze-down-line-9)">Skip&#160;remo [...]
+</text><text class="breeze-down-r5" x="0" y="264" textLength="12.2" 
clip-path="url(#breeze-down-line-10)">│</text><text class="breeze-down-r4" 
x="24.4" y="264" textLength="256.2" 
clip-path="url(#breeze-down-line-10)">--cleanup-mypy-cache&#160;</text><text 
class="breeze-down-r6" x="305" y="264" textLength="24.4" 
clip-path="url(#breeze-down-line-10)">-c</text><text class="breeze-down-r1" 
x="353.8" y="264" textLength="390.4" 
clip-path="url(#breeze-down-line-10)">Additionally&#160;cleanup&#1 [...]
+</text><text class="breeze-down-r5" x="0" y="288.4" textLength="12.2" 
clip-path="url(#breeze-down-line-11)">│</text><text class="breeze-down-r4" 
x="24.4" y="288.4" textLength="256.2" 
clip-path="url(#breeze-down-line-11)">--cleanup-build-cache</text><text 
class="breeze-down-r6" x="305" y="288.4" textLength="24.4" 
clip-path="url(#breeze-down-line-11)">-b</text><text class="breeze-down-r1" 
x="353.8" y="288.4" textLength="512.4" 
clip-path="url(#breeze-down-line-11)">Additionally&#160;cleanup [...]
+</text><text class="breeze-down-r5" x="0" y="312.8" textLength="1464" 
clip-path="url(#breeze-down-line-12)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-down-r1" x="1464" y="312.8" textLength="12.2" 
clip-path="url(#breeze-down-line-12)">
+</text><text class="breeze-down-r5" x="0" y="337.2" textLength="24.4" 
clip-path="url(#breeze-down-line-13)">╭─</text><text class="breeze-down-r5" 
x="24.4" y="337.2" textLength="231.8" 
clip-path="url(#breeze-down-line-13)">&#160;Project&#160;selection&#160;</text><text
 class="breeze-down-r5" x="256.2" y="337.2" textLength="1183.4" 
clip-path="url(#breeze-down-line-13)">─────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="breez [...]
+</text><text class="breeze-down-r5" x="0" y="361.6" textLength="12.2" 
clip-path="url(#breeze-down-line-14)">│</text><text class="breeze-down-r4" 
x="24.4" y="361.6" textLength="170.8" 
clip-path="url(#breeze-down-line-14)">--all-projects</text><text 
class="breeze-down-r1" x="219.6" y="361.6" textLength="1220" 
clip-path="url(#breeze-down-line-14)">Also&#160;bring&#160;down&#160;docker&#160;compose&#160;projects&#160;whose&#160;names&#160;do&#160;not&#160;match&#160;any&#160;known&#160;breez
 [...]
+</text><text class="breeze-down-r5" x="0" y="386" textLength="12.2" 
clip-path="url(#breeze-down-line-15)">│</text><text class="breeze-down-r1" 
x="219.6" y="386" textLength="1220" 
clip-path="url(#breeze-down-line-15)">default&#160;to&#160;avoid&#160;touching&#160;unrelated&#160;projects&#160;on&#160;the&#160;host.&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
+</text><text class="breeze-down-r5" x="0" y="410.4" textLength="12.2" 
clip-path="url(#breeze-down-line-16)">│</text><text class="breeze-down-r4" 
x="24.4" y="410.4" textLength="170.8" 
clip-path="url(#breeze-down-line-16)">--project-name</text><text 
class="breeze-down-r1" x="219.6" y="410.4" textLength="1220" 
clip-path="url(#breeze-down-line-16)">Restrict&#160;the&#160;cleanup&#160;to&#160;a&#160;single&#160;docker&#160;compose&#160;project&#160;name&#160;and&#160;skip&#160;discovery.&#160
 [...]
+</text><text class="breeze-down-r5" x="0" y="434.8" textLength="12.2" 
clip-path="url(#breeze-down-line-17)">│</text><text class="breeze-down-r1" 
x="219.6" y="434.8" textLength="549" 
clip-path="url(#breeze-down-line-17)">that&#160;want&#160;to&#160;bring&#160;exactly&#160;one&#160;project&#160;down.&#160;</text><text
 class="breeze-down-r7" x="768.6" y="434.8" textLength="73.2" 
clip-path="url(#breeze-down-line-17)">(TEXT)</text><text class="breeze-down-r5" 
x="1451.8" y="434.8" textLength=" [...]
+</text><text class="breeze-down-r5" x="0" y="459.2" textLength="1464" 
clip-path="url(#breeze-down-line-18)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-down-r1" x="1464" y="459.2" textLength="12.2" 
clip-path="url(#breeze-down-line-18)">
+</text><text class="breeze-down-r5" x="0" y="483.6" textLength="24.4" 
clip-path="url(#breeze-down-line-19)">╭─</text><text class="breeze-down-r5" 
x="24.4" y="483.6" textLength="195.2" 
clip-path="url(#breeze-down-line-19)">&#160;Common&#160;options&#160;</text><text
 class="breeze-down-r5" x="219.6" y="483.6" textLength="1220" 
clip-path="url(#breeze-down-line-19)">────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="breeze- [...]
+</text><text class="breeze-down-r5" x="0" y="508" textLength="12.2" 
clip-path="url(#breeze-down-line-20)">│</text><text class="breeze-down-r4" 
x="24.4" y="508" textLength="109.8" 
clip-path="url(#breeze-down-line-20)">--verbose</text><text 
class="breeze-down-r6" x="158.6" y="508" textLength="24.4" 
clip-path="url(#breeze-down-line-20)">-v</text><text class="breeze-down-r1" 
x="207.4" y="508" textLength="585.6" 
clip-path="url(#breeze-down-line-20)">Print&#160;verbose&#160;information&#160;ab
 [...]
+</text><text class="breeze-down-r5" x="0" y="532.4" textLength="12.2" 
clip-path="url(#breeze-down-line-21)">│</text><text class="breeze-down-r4" 
x="24.4" y="532.4" textLength="109.8" 
clip-path="url(#breeze-down-line-21)">--dry-run</text><text 
class="breeze-down-r6" x="158.6" y="532.4" textLength="24.4" 
clip-path="url(#breeze-down-line-21)">-D</text><text class="breeze-down-r1" 
x="207.4" y="532.4" textLength="719.8" 
clip-path="url(#breeze-down-line-21)">If&#160;dry-run&#160;is&#160;set,&# [...]
+</text><text class="breeze-down-r5" x="0" y="556.8" textLength="12.2" 
clip-path="url(#breeze-down-line-22)">│</text><text class="breeze-down-r4" 
x="24.4" y="556.8" textLength="109.8" 
clip-path="url(#breeze-down-line-22)">--help&#160;&#160;&#160;</text><text 
class="breeze-down-r6" x="158.6" y="556.8" textLength="24.4" 
clip-path="url(#breeze-down-line-22)">-h</text><text class="breeze-down-r1" 
x="207.4" y="556.8" textLength="329.4" 
clip-path="url(#breeze-down-line-22)">Show&#160;this&#160; [...]
+</text><text class="breeze-down-r5" x="0" y="581.2" textLength="1464" 
clip-path="url(#breeze-down-line-23)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-down-r1" x="1464" y="581.2" textLength="12.2" 
clip-path="url(#breeze-down-line-23)">
 </text>
     </g>
     </g>
diff --git a/dev/breeze/doc/images/output_down.txt 
b/dev/breeze/doc/images/output_down.txt
index c0200cc3228..9c1280841b6 100644
--- a/dev/breeze/doc/images/output_down.txt
+++ b/dev/breeze/doc/images/output_down.txt
@@ -1 +1 @@
-5c5712f40f3397d077afce24bc6b5d4d
+cde032283bb58d1cf97ee92f145f1ea8
diff --git a/dev/breeze/src/airflow_breeze/commands/developer_commands.py 
b/dev/breeze/src/airflow_breeze/commands/developer_commands.py
index afb22da6355..d1d9b30d269 100644
--- a/dev/breeze/src/airflow_breeze/commands/developer_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/developer_commands.py
@@ -113,6 +113,7 @@ from airflow_breeze.params.shell_params import ShellParams
 from airflow_breeze.utils.confirm import Answer, user_confirm
 from airflow_breeze.utils.console import console_print
 from airflow_breeze.utils.docker_command_utils import (
+    bring_all_compose_projects_down,
     bring_compose_project_down,
     check_docker_resources,
     enter_shell,
@@ -904,7 +905,17 @@ def build_docs(
     sys.exit(result.returncode)
 
 
[email protected](name="down", help="Stop running breeze environment.")
[email protected](
+    name="down",
+    help=(
+        "Stop every docker compose project breeze knows about. Discovers 
running "
+        "projects via the `com.docker.compose.project` label and brings each 
one "
+        "down with `--remove-orphans` (and `--volumes` unless 
`--preserve-volumes` "
+        "is passed). Covers `breeze shell`, `breeze testing`, `breeze 
build-docs`, "
+        "`breeze db`, release-management, registry, and prek-hook compose 
projects "
+        "in a single command."
+    ),
+)
 @click.option(
     "-p",
     "--preserve-volumes",
@@ -923,12 +934,46 @@ def build_docs(
     help="Additionally cleanup Build (pip/uv) cache.",
     is_flag=True,
 )
[email protected](
+    "--all-projects",
+    help=(
+        "Also bring down docker compose projects whose names do not match any 
known "
+        "breeze prefix. Off by default to avoid touching unrelated projects on 
the host."
+    ),
+    is_flag=True,
+)
[email protected](
+    "--project-name",
+    help=(
+        "Restrict the cleanup to a single docker compose project name and skip 
"
+        "discovery. Useful in CI steps that want to bring exactly one project 
down."
+    ),
+    default=None,
+)
 @option_verbose
 @option_dry_run
-def down(preserve_volumes: bool, cleanup_mypy_cache: bool, 
cleanup_build_cache: bool):
+def down(
+    preserve_volumes: bool,
+    cleanup_mypy_cache: bool,
+    cleanup_build_cache: bool,
+    all_projects: bool,
+    project_name: str | None,
+):
     perform_environment_checks()
-    shell_params = ShellParams(backend="all", 
include_mypy_volume=cleanup_mypy_cache)
-    bring_compose_project_down(preserve_volumes=preserve_volumes, 
shell_params=shell_params)
+    brought_down, skipped = bring_all_compose_projects_down(
+        preserve_volumes=preserve_volumes,
+        include_unknown=all_projects,
+        only_project=project_name,
+    )
+    if not brought_down and not project_name:
+        console_print("[info]No running breeze-managed docker compose projects 
found.[/]")
+    elif brought_down:
+        console_print(f"[success]Brought down {len(brought_down)} compose 
project(s): {brought_down}[/]")
+    if skipped:
+        console_print(
+            f"[warning]Left {len(skipped)} unrelated compose project(s) 
running: {skipped}\n"
+            f"Use `breeze down --all-projects` to also bring those down.[/]"
+        )
     if cleanup_mypy_cache:
         command_to_execute = ["docker", "volume", "rm", "--force", 
"mypy-cache-volume"]
         run_command(command_to_execute)
@@ -1071,8 +1116,9 @@ def doctor(ctx):
     if not get_dry_run() and given_answer == Answer.YES:
         cleanup_python_generated_files()
 
-    shell_params = ShellParams(backend="all", include_mypy_volume=True)
-    bring_compose_project_down(preserve_volumes=False, 
shell_params=shell_params)
+    # Doctor is the heal-everything command, so it sweeps EVERY compose project
+    # on the host (not only the known-prefix ones that `breeze down` defaults 
to).
+    bring_all_compose_projects_down(preserve_volumes=False, 
include_unknown=True)
 
     given_answer = user_confirm("Are you sure with the removal of mypy cache 
and build cache dir?")
     if given_answer == Answer.YES:
@@ -1178,7 +1224,6 @@ def run(
     from airflow_breeze.params.shell_params import ShellParams
     from airflow_breeze.utils.ci_group import ci_group
     from airflow_breeze.utils.docker_command_utils import (
-        bring_compose_project_down,
         execute_command_in_shell,
         fix_ownership_using_docker,
         remove_docker_networks,
diff --git 
a/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py 
b/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py
index 73059f22a06..74ca92841a1 100644
--- a/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py
+++ b/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py
@@ -347,6 +347,13 @@ DEVELOPER_PARAMETERS: dict[str, list[dict[str, str | 
list[str]]]] = {
                 "--cleanup-build-cache",
             ],
         },
+        {
+            "name": "Project selection",
+            "options": [
+                "--all-projects",
+                "--project-name",
+            ],
+        },
     ],
     "breeze build-docs": [
         {
diff --git a/dev/breeze/src/airflow_breeze/commands/registry_commands.py 
b/dev/breeze/src/airflow_breeze/commands/registry_commands.py
index 900ce65f2de..70cb6949734 100644
--- a/dev/breeze/src/airflow_breeze/commands/registry_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/registry_commands.py
@@ -31,7 +31,12 @@ from airflow_breeze.commands.common_options import 
option_dry_run, option_python
 from airflow_breeze.params.shell_params import ShellParams
 from airflow_breeze.utils.ci_group import ci_group
 from airflow_breeze.utils.click_utils import BreezeGroup
-from airflow_breeze.utils.docker_command_utils import 
execute_command_in_shell, fix_ownership_using_docker
+from airflow_breeze.utils.docker_command_utils import (
+    bring_compose_project_down,
+    execute_command_in_shell,
+    fix_ownership_using_docker,
+    remove_docker_networks,
+)
 from airflow_breeze.utils.path_utils import AIRFLOW_ROOT_PATH
 from airflow_breeze.utils.run_utils import run_command
 
@@ -111,15 +116,18 @@ def extract_data(python: str, provider: str | None, 
allow_unreleased: bool):
         f"python dev/registry/extract_connections.py{provider_flag}"
     )
 
-    with ci_group("Extracting registry data"):
-        result = execute_command_in_shell(
-            shell_params=shell_params,
-            project_name=unique_project_name,
-            command=command,
-            preserve_backend=True,
-        )
-
-    fix_ownership_using_docker()
+    try:
+        with ci_group("Extracting registry data"):
+            result = execute_command_in_shell(
+                shell_params=shell_params,
+                project_name=unique_project_name,
+                command=command,
+                preserve_backend=True,
+            )
+    finally:
+        bring_compose_project_down(preserve_volumes=False, 
shell_params=shell_params)
+        remove_docker_networks([f"{unique_project_name}_default"])
+        fix_ownership_using_docker()
     sys.exit(result.returncode)
 
 
@@ -336,6 +344,8 @@ def _backfill_docker(
                 failed.append(f"{version}/docker-extraction")
     finally:
         shutil.rmtree(backfill_tmp_dir, ignore_errors=True)
+        bring_compose_project_down(preserve_volumes=False, 
shell_params=shell_params)
+        remove_docker_networks([f"{unique_project_name}_default"])
         fix_ownership_using_docker()
 
     return failed
diff --git a/dev/breeze/src/airflow_breeze/global_constants.py 
b/dev/breeze/src/airflow_breeze/global_constants.py
index d64ca7464ff..8f0ae4dbd16 100644
--- a/dev/breeze/src/airflow_breeze/global_constants.py
+++ b/dev/breeze/src/airflow_breeze/global_constants.py
@@ -146,6 +146,28 @@ AUTOCOMPLETE_ALL_INTEGRATIONS = sorted(
 ALLOWED_TTY = ["auto", "enabled", "disabled"]
 ALLOWED_TERMINAL_MULTIPLEXERS = ["mprocs", "tmux"]
 ALLOWED_DOCKER_COMPOSE_PROJECTS = ["breeze", "prek", "docker-compose"]
+
+# Every docker compose project name that any breeze command, prek hook, or
+# CI workflow uses. `breeze down` discovers running compose projects via the
+# `com.docker.compose.project` label and only touches the ones that match
+# either an exact entry in `KNOWN_DOCKER_COMPOSE_PROJECT_NAMES` or one of the
+# prefixes in `KNOWN_DOCKER_COMPOSE_PROJECT_PREFIXES`. When you add a new
+# project_name pattern anywhere (new breeze command, new prek hook, new CI
+# step), update this list so `breeze down` stays a one-shot cleanup.
+KNOWN_DOCKER_COMPOSE_PROJECT_NAMES = [
+    "breeze",  # default `breeze shell` / `breeze start-airflow`
+    "prek",  # prek hooks (see scripts/ci/prek/common_prek_utils.py)
+    "docker-compose",  # legacy name kept for migration_tests CI
+    "docs",  # `breeze build-docs`
+    "db",  # `breeze db ...`
+    "providers",  # release-management providers builds
+]
+KNOWN_DOCKER_COMPOSE_PROJECT_PREFIXES = [
+    "breeze-",  # breeze-registry-*, breeze-backfill-*, *-run-*
+    "airflow-test",  # airflow-test, airflow-test-<test-type>
+    "constraints-",  # constraints-<python-version>
+    "providers-",  # providers-<index> (parallel provider builds)
+]
 ALLOWED_LOG_LEVELS = ["INFO", "DEBUG", "WARNING", "ERROR", "CRITICAL"]
 DEFAULT_LOG_LEVEL = ALLOWED_LOG_LEVELS[0]
 
diff --git a/dev/breeze/src/airflow_breeze/utils/docker_command_utils.py 
b/dev/breeze/src/airflow_breeze/utils/docker_command_utils.py
index 4cb8356169b..d95ae33fc1f 100644
--- a/dev/breeze/src/airflow_breeze/utils/docker_command_utils.py
+++ b/dev/breeze/src/airflow_breeze/utils/docker_command_utils.py
@@ -54,6 +54,8 @@ from airflow_breeze.global_constants import (
     ALLOWED_DEBIAN_VERSIONS,
     DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
     DOCKER_DEFAULT_PLATFORM,
+    KNOWN_DOCKER_COMPOSE_PROJECT_NAMES,
+    KNOWN_DOCKER_COMPOSE_PROJECT_PREFIXES,
     MIN_DOCKER_COMPOSE_VERSION,
     MIN_DOCKER_VERSION,
 )
@@ -833,6 +835,83 @@ def bring_compose_project_down(preserve_volumes: bool, 
shell_params: ShellParams
     )
 
 
+def discover_running_compose_projects() -> set[str]:
+    """
+    Return the set of compose project names of every container on the host.
+
+    Reads the ``com.docker.compose.project`` label that ``docker compose``
+    sets on every container/network/volume it creates. Returns an empty set
+    if docker is unreachable or no compose-managed containers exist.
+    """
+    result = run_command(
+        [
+            "docker",
+            "ps",
+            "--all",
+            "--filter",
+            "label=com.docker.compose.project",
+            "--format",
+            '{{ index .Labels "com.docker.compose.project" }}',
+        ],
+        capture_output=True,
+        text=True,
+        check=False,
+    )
+    if result.returncode != 0 or not result.stdout:
+        return set()
+    return {line.strip() for line in result.stdout.splitlines() if 
line.strip()}
+
+
+def is_known_breeze_compose_project(name: str) -> bool:
+    """Return True if ``name`` matches a project breeze knows it owns."""
+    if name in KNOWN_DOCKER_COMPOSE_PROJECT_NAMES:
+        return True
+    return any(name.startswith(prefix) for prefix in 
KNOWN_DOCKER_COMPOSE_PROJECT_PREFIXES)
+
+
+def bring_all_compose_projects_down(
+    *,
+    preserve_volumes: bool = False,
+    include_unknown: bool = False,
+    only_project: str | None = None,
+) -> tuple[list[str], list[str]]:
+    """
+    Discover and bring down every docker compose project breeze manages.
+
+    :param preserve_volumes: if True, pass ``--volumes`` is omitted so DB
+        volumes survive (matches the existing ``--preserve-volumes`` flag
+        on ``breeze down``).
+    :param include_unknown: if True, also bring down projects whose names
+        do not match any known breeze prefix. Useful as an emergency
+        cleanup; can wipe out unrelated docker compose projects on the
+        host, so off by default.
+    :param only_project: if set, restrict to exactly this project name and
+        skip discovery entirely (for the ``--project-name`` flag).
+    :returns: ``(brought_down, skipped)`` lists of project names, both
+        sorted, suitable for printing in a session summary.
+    """
+    if only_project:
+        targets = {only_project}
+        skipped: set[str] = set()
+    else:
+        running = discover_running_compose_projects()
+        if include_unknown:
+            targets = running
+            skipped = set()
+        else:
+            targets = {name for name in running if 
is_known_breeze_compose_project(name)}
+            skipped = running - targets
+    brought_down: list[str] = []
+    for name in sorted(targets):
+        console_print(f"[info]Bringing down docker compose project: {name}[/]")
+        cmd = ["docker", "compose", "--project-name", name, "down", 
"--remove-orphans"]
+        if not preserve_volumes:
+            cmd.append("--volumes")
+        run_command(cmd, text=True, check=False)
+        brought_down.append(name)
+    return brought_down, sorted(skipped)
+
+
 def execute_command_in_shell(
     shell_params: ShellParams,
     project_name: str,
diff --git a/dev/breeze/tests/test_docker_command_utils.py 
b/dev/breeze/tests/test_docker_command_utils.py
index 7c832813186..f08862e047d 100644
--- a/dev/breeze/tests/test_docker_command_utils.py
+++ b/dev/breeze/tests/test_docker_command_utils.py
@@ -24,8 +24,11 @@ import pytest
 
 from airflow_breeze.utils.docker_command_utils import (
     autodetect_docker_context,
+    bring_all_compose_projects_down,
     check_docker_compose_version,
     check_docker_version,
+    discover_running_compose_projects,
+    is_known_breeze_compose_project,
 )
 
 
@@ -292,3 +295,97 @@ SOCKET_INFO_DESKTOP_LINUX = json.dumps(
         }
     ]
 )
+
+
[email protected](
+    ("name", "expected"),
+    [
+        ("breeze", True),
+        ("prek", True),
+        ("docker-compose", True),
+        ("docs", True),
+        ("db", True),
+        ("providers", True),
+        ("breeze-registry-abcd1234", True),
+        ("breeze-backfill-deadbeef", True),
+        ("breeze-run-12345678", True),
+        ("airflow-test", True),
+        ("airflow-test-providers-google", True),
+        ("constraints-3-12", True),
+        ("providers-7", True),
+        ("my-other-project", False),
+        ("airflow", False),
+        ("doc", False),
+        ("", False),
+    ],
+)
+def test_is_known_breeze_compose_project(name, expected):
+    assert is_known_breeze_compose_project(name) is expected
+
+
[email protected]("airflow_breeze.utils.docker_command_utils.run_command")
+def 
test_discover_running_compose_projects_parses_label_output(mock_run_command):
+    mock_run_command.return_value = mock.Mock(
+        returncode=0,
+        stdout="breeze\nbreeze\nairflow-test-providers-amazon\n   \n",
+    )
+    assert discover_running_compose_projects() == {"breeze", 
"airflow-test-providers-amazon"}
+    cmd = mock_run_command.call_args.args[0]
+    assert cmd[:2] == ["docker", "ps"]
+    assert "label=com.docker.compose.project" in cmd
+
+
[email protected]("airflow_breeze.utils.docker_command_utils.run_command")
+def 
test_discover_running_compose_projects_returns_empty_on_failure(mock_run_command):
+    mock_run_command.return_value = mock.Mock(returncode=1, stdout="")
+    assert discover_running_compose_projects() == set()
+
+
[email protected]("airflow_breeze.utils.docker_command_utils.console_print")
[email protected]("airflow_breeze.utils.docker_command_utils.run_command")
[email protected]("airflow_breeze.utils.docker_command_utils.discover_running_compose_projects")
+def test_bring_all_compose_projects_down_filters_unknown_by_default(
+    mock_discover, mock_run_command, _mock_console
+):
+    mock_discover.return_value = {"breeze", "providers-3", "my-app"}
+    brought_down, skipped = bring_all_compose_projects_down()
+    assert brought_down == ["breeze", "providers-3"]
+    assert skipped == ["my-app"]
+    down_calls = [c for c in mock_run_command.call_args_list if c.args[0][:2] 
== ["docker", "compose"]]
+    assert len(down_calls) == 2
+    for c in down_calls:
+        assert "--volumes" in c.args[0]
+        assert "--remove-orphans" in c.args[0]
+
+
[email protected]("airflow_breeze.utils.docker_command_utils.console_print")
[email protected]("airflow_breeze.utils.docker_command_utils.run_command")
[email protected]("airflow_breeze.utils.docker_command_utils.discover_running_compose_projects")
+def test_bring_all_compose_projects_down_include_unknown(mock_discover, 
mock_run_command, _mock_console):
+    mock_discover.return_value = {"breeze", "my-app"}
+    brought_down, skipped = 
bring_all_compose_projects_down(include_unknown=True)
+    assert brought_down == ["breeze", "my-app"]
+    assert skipped == []
+
+
[email protected]("airflow_breeze.utils.docker_command_utils.console_print")
[email protected]("airflow_breeze.utils.docker_command_utils.run_command")
[email protected]("airflow_breeze.utils.docker_command_utils.discover_running_compose_projects")
+def test_bring_all_compose_projects_down_only_project_skips_discovery(
+    mock_discover, mock_run_command, _mock_console
+):
+    brought_down, skipped = 
bring_all_compose_projects_down(only_project="my-app")
+    assert brought_down == ["my-app"]
+    assert skipped == []
+    mock_discover.assert_not_called()
+
+
[email protected]("airflow_breeze.utils.docker_command_utils.console_print")
[email protected]("airflow_breeze.utils.docker_command_utils.run_command")
[email protected]("airflow_breeze.utils.docker_command_utils.discover_running_compose_projects")
+def test_bring_all_compose_projects_down_preserve_volumes(mock_discover, 
mock_run_command, _mock_console):
+    mock_discover.return_value = {"breeze"}
+    bring_all_compose_projects_down(preserve_volumes=True)
+    down_call = next(c for c in mock_run_command.call_args_list if 
c.args[0][:2] == ["docker", "compose"])
+    assert "--volumes" not in down_call.args[0]
+    assert "--remove-orphans" in down_call.args[0]
diff --git a/scripts/ci/prek/common_prek_utils.py 
b/scripts/ci/prek/common_prek_utils.py
index f28923b78bc..45f38b5d3c6 100644
--- a/scripts/ci/prek/common_prek_utils.py
+++ b/scripts/ci/prek/common_prek_utils.py
@@ -374,19 +374,24 @@ def run_command_via_breeze_shell(
             print(f"Running command: {' '.join([shlex.quote(item) for item in 
subprocess_cmd])}")
             print("With environment:")
             print(new_env)
-    result = subprocess.run(
-        subprocess_cmd,
-        check=False,
-        text=True,
-        **other_popen_kwargs,
-        env=new_env,
-    )
-    # Stop remaining containers
-    down_command = ["docker", "compose", "--progress", "quiet"]
-    if project_name:
-        down_command.extend(["--project-name", project_name])
-    down_command.extend(["down", "--remove-orphans"])
-    subprocess.run(down_command, check=False, stdout=subprocess.DEVNULL, 
stderr=subprocess.DEVNULL)
+    try:
+        result = subprocess.run(
+            subprocess_cmd,
+            check=False,
+            text=True,
+            **other_popen_kwargs,
+            env=new_env,
+        )
+    finally:
+        # Always clean up containers, networks, and volumes the breeze shell
+        # invocation created — even if the subprocess raised 
(KeyboardInterrupt,
+        # OSError, etc.). Without --volumes the next prek run inherits state
+        # from the previous run, which is the bug this finally clause prevents.
+        down_command = ["docker", "compose", "--progress", "quiet"]
+        if project_name:
+            down_command.extend(["--project-name", project_name])
+        down_command.extend(["down", "--remove-orphans", "--volumes"])
+        subprocess.run(down_command, check=False, stdout=subprocess.DEVNULL, 
stderr=subprocess.DEVNULL)
     return result
 
 


Reply via email to