Skip to content

chore: production deploy - #7104

Merged
supabase-cli-releaser[bot] merged 94 commits into
mainfrom
develop
Oct 14, 2026
Merged

supabase-cli-releaser[bot] merged 94 commits into
mainfrom
develop

Conversation

@supabase-cli-releaser

Copy link
Copy Markdown
Contributor

7ttp and others added 30 commits October 6, 2026 17:15
…7017)

## TL;DR

reaps the containers a stack leaves behind once its directory is deleted

## whats introduced?

the orphan sweep now removes containers labelled with its state root
whose stack is no longer registered

`stack destroy --stack-id <full id>` removes them on demand, also for a
deleted `SUPABASE_HOME` when run with that home
the shared database volume is left as is

## ref

- closes: #6963
## TL;DR

fixes the live e2e ssl reboot flake and stops develop pushes from
cancelling a running live suite

- `ssl-enforcement update` reboots the database and `get` can report it
applied before the reboot ends, so the reboot landed in the next file
and killed `migration up` with `57P01`. the test now waits for a new
postmaster after the toggle and the restore, and `queryLiveDb` no longer
crashes when a restart drops an idle client

- merge queue bursts land develop pushes closer together than one live
run, so each push cancelled the running suite and turned its commit red.
pushes now share a lane that never cancels a running suite

## ref

- spotted in: [migration
up](https://github.com/supabase/cli/actions/runs/37284888772/job/111681321268)
[cancelled
run](https://github.com/supabase/cli/actions/runs/37296027587)
This bumps realtime from v2.140.10-r0 to v2.140.11-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.140.11-r0

Planned after supabase/slim-services published v2.140.11-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps storage from v1.79.36-r0 to v1.79.37-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.79.37-r0

Planned after supabase/slim-services published v1.79.37-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps realtime from v2.140.11-r0 to v2.141.0-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.141.0-r0

Planned after supabase/slim-services published v2.141.0-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps realtime from v2.141.0-r0 to v2.142.0-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.142.0-r0

Planned after supabase/slim-services published v2.142.0-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…) (#7028)

## TL;DR

fixes local `functions serve --env-file` and `--no-verify-jwt` failing
after a normal stack `supabase start`

## what's hurting?

studio gets its Functions URL through a binding that also makes it a
lifecycle dependent of Functions

that means Studio blocks the restart needed to apply a temporary
override, even when Studio is idle. the same guard blocks restoring the
saved configuration on exit..

## now fixed by:

keeping Studio’s Functions URL binding without making Functions a
startup prerequisite for studio
functions can use the existing restart and cleanup paths to apply the
override and restore its saved configuration
studio stays in its current state

## ref:

- closes: #7009
This bumps storage from v1.79.37-r0 to v1.79.38-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.79.38-r0

Planned after supabase/slim-services published v1.79.38-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…) (#7027)

## TL;DR

fixes local `functions serve` failing before startup in coding-agent
environments when no output format is passed

## prob/sol

agent detection defaults the CLI to `json`, but stack `functions serve`
only accepts `text` or `stream-json`.
so the command fails with `Functions serve requires text or stream-json
output`
unless the caller passes an output flag

now fixed by: defaulting stack `functions serve` to `stream-json` for
agents when no output format is chosen
explicit output choices still win...
## ref:

- closes: #7010
…#7029)

## TL;DR

fixes migrations with database webhook triggers failing on the stack
backend with `schema "supabase_functions" does not exist`

## whats broken?

the regular docker `supabase start` creates `supabase_functions` in its
postgres entrypoint, which neither stack runtime runs, so webhook
triggers failed on both `--runtime native` and `--runtime docker`

## now fixed by:

the stack catalog creates the schema, its tables, `http_request()` and
`supabase_functions_admin` before migrations, only when missing and
under an advisory lock, and leaves the image's own `pg_net` policy alone

existing stack databases get it on their next stop and start, and the
shadow cache key moves so `db diff` rebuilds its baseline.

> [!NOTE]
> a migration that recreates `supabase_functions`, like the workaround
in the issue
now fails on the stack as it does on the regular docker start, so delete
that migration file

## ref:

- closes: #7007
## TL;DR

fixes https requests from `http` and `pg_net` failing certificate
verification on the native runtime on macOS arm64.

## whats broken?

the OpenSSL bundled with native postgres looks for its CA bundle under
`/nix`, which a macOS host does not have, so `http_get` to an https url
failed with `unable to get local issuer certificate`.
the native launcher also kept a host `SSL_CERT_FILE` away from postgres,
so exporting one did not help.
## now fixed by:

the native postgres launch now forwards an exported `SSL_CERT_FILE` and
`SSL_CERT_DIR`, and when `SSL_CERT_FILE` is not exported it uses the
first CA bundle on the host, `/etc/ssl/cert.pem` on macOS.

## ref:

- closes: #7008
## Summary

The `fast-forward` job in `release.yml` fast-forwards `main` to
`develop` whenever an approving review is submitted on the develop →
main deploy PR, but it never checks who approved. On a public repo any
GitHub user can leave an approving review, so a drive-by approval on the
weekly "chore: production deploy" PR would fast-forward `main` and cut a
stable release.

The job now looks up the reviewer's repo permission first (`GET
/repos/{owner}/{repo}/collaborators/{username}/permission`, checking
both `permission` and `role_name`) and only mints the App token, checks
out and fast-forwards when it's `admin`, `maintain` or `write`. Anyone
else gets a `::notice::` and a green skip rather than a red run.
Maintainer approvals behave exactly as before.

While there, the head SHA moved out of the inline `run:` script into
`env:`.

Split out of CLI-2630 so it doesn't wait on the larger branching/release
PR, which also generalises this job.

## Linked issue

Linear: CLI-2630

- [x] The linked issue is **open** and carries the
`open-for-contribution` label (or I'm a Supabase maintainer).

## Checklist

- [x] The PR title follows [Conventional
Commits](https://www.conventionalcommits.org/) (e.g. `fix(cli): …`).
- [ ] Tests added or updated for the change. (Workflow-only change;
validated with `actionlint`. The permission lookup gets its first live
run on the next deploy PR approval, and fails closed if the lookup
errors.)
- [x] From the repository root, `pnpm check:all` passes; relevant
package tests pass for every touched workspace, and `pnpm types:check`
passes for each touched TypeScript workspace (or workspace declaring
it).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This bumps storage from v1.79.38-r0 to v1.80.0-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.80.0-r0

Planned after supabase/slim-services published v1.80.0-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
The AI Review "Post review" job fails on large PRs because it fetches
the PR diff from the pulls API, which returns 406 once a diff exceeds
20,000 lines or 300 files. See the failure on #7036:
https://github.com/supabase/cli/actions/runs/37609410161/job/112759286813

The review jobs already build the diff locally with
`generate-pr-diff.ts`, which has no size cap. The `adjudicate` job now
uploads that `pr.diff` as an artifact, and `post-review` anchors inline
comments against it instead of calling the API. Inline anchors now match
the exact diff the reviewers saw; if the PR head moves during the run,
the existing 422 fallback still folds unanchorable comments into the
review body.
## Summary

**TL;DR:** Two `LogForwarder` integration tests occasionally hit the 30
s timeout in CI because each assumed an ordering the forwarder doesn't
guarantee. Both tests now cover every ordering without sleeps. The
forwarder itself is unchanged.

**Why:** CI runs on #6942 timed out in:
- `pauses without advancing when Analytics refuses its credentials`
- `ships a record persisted while Analytics slept once it wakes on a new
port, …`

**What changed**

- **Credentials refusal:** the test armed its cursor-write gate only
after `logflare.next` returned. When the forwarder handled the 401 and
removed its cursor first, the gate never fired, and the paused forwarder
never slept `pollMillis`, so both race branches hung. The test now holds
the 401 answer with `logflare.hold` until the gate is armed. Delaying
the test fiber after `logflare.next` reproduces the hang reliably on the
old test.
- **Retarget to a new port:** when the held post is released, the
retired launch-1 session can reach the asleep record before the race
interrupts it. It then saves that record as pending to launch 1 and
fails `requireCurrent` without posting. The new session waits until the
saved post deadline plus the flush window before posting, but the test
expected the post without advancing the manual clock. The test now takes
that post with `nextPost`, which steps through stored-id polls until a
post arrives, so both orderings pass. Delaying the retarget side of the
race reproduces the hang reliably on the old test. In production this
ordering only delays shipping until that deadline plus the flush window
(about 10 s), so the forwarder is left as is.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…7039)

## TL;DR

fixes every pg_cron job run failing with `connection failed` on the
native runtime

## whats broken?

native postgres listens only on its socket, but pg_cron by default opens
a libpq connection to `localhost:5432` for each job. nothing listens
there, so every run failed with `connection failed`, or `job startup
timeout` on macOS.

## now fixed by:

native postgres now runs pg_cron jobs in background workers and defaults
`max_worker_processes` to 17
below your own config, `ALTER SYSTEM` and `[db.settings]`. supautils
stays preloaded so jobs keep their docker role policies
 shadow databases keep pg_cron's default mode
## ref:

- closes: #6977
## Summary

**TL;DR:** Database helpers now stay attached to the owning process. If
that process exits or is killed, the Docker client's stdin closes, the
helper exits, and Docker removes the container. A normal `docker stop`
also ends the helper.

### Before

Both shared-volume and per-instance helpers used detached `docker run
-d` containers with a shell that ignored TERM. They could remain after
the owner disappeared, and `docker stop` could not shut them down.

### After

Helpers start with `docker run --rm -i` and wait for a readiness signal
before commands use them. Their shell exits on stdin EOF or TERM.
Existing named helpers are replaced instead of being adopted without an
owner connection. The shared database volume is left intact when a
helper exits.

### What changed

- Give each helper a lifetime scope so its attached Docker client
remains open for as long as the helper is in use, including cleanup
during owner shutdown.
- Preserve startup cleanup when helper creation is interrupted, and
report Docker's startup error when available.
- Cover attached startup, helper scope behavior, and owner SIGKILL
cleanup in the storage and registry tests.

## Linked issue

Closes #6962

---------

Co-authored-by: avallete <andrew.valleteau@supabase.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Andrew Valleteau <avallete@users.noreply.github.com>
…ns (CLI-2630) (#7038)

## Summary

Sets up the branching and release machinery from
[CLI-2630](https://linear.app/supabase/issue/CLI-2630/gh-branch-and-release-process)
so we can start merging breaking-change work for v3. The design (and the
review rounds behind it) lives in the Linear issue; the canonical
runbook is now in `apps/cli/docs/release-process.md`, with ADR 0028
superseding ADR 0011's dist-tag section.

### What changes

**New `next` channel**
- `next` is a long-lived branch for breaking work. Breaking PRs target
it with a `type(scope)!:` title.
- semantic-release treats it as a `next` prerelease branch, so it
publishes `X.Y.Z-next.N`. It goes out to npm `next` and as a GitHub
prerelease, with no brew/scoop.
- In `release.yml`, a push to `next` runs `test.yml` first, and only
plans and releases once that passes.
- `-next.N` builds identify as "Supabase CLI (next channel)."

**Syncing (`sync-branches.yml`, replaces `sync-main-to-develop.yml`)**
- Two pairs only: main → develop after a stable release, and develop →
next on every develop push.
- A clean merge is pushed directly.
- On a conflict it opens a `sync/<source>-into-<target>` PR at the
source tip and pauses that pair until the PR closes. Someone resolves it
by merging the target in.

**Approve-to-fast-forward (`fast-forward.yml`, moved out of
`release.yml`)**
- Covers the deploy PR (develop → main), the major cut (next → develop),
and the two bot-authored sync PRs.
- Before pushing it checks:
  - the approver has write access
  - the approved commit is still the PR head
- the 4 required checks are green, read from this PR's own check rollup
so another PR's runs on the same commit don't count
- `--ff-only` (sync PRs re-sync and ask for re-approval if the target
moved)
- Anything that lands on `main` also refuses a major bump without the
`release-major` label.
- `test.yml` now runs on PRs into `main`, so the deploy PR head carries
the required checks. Hotfix PRs into `main` finally get CI too.

**Maintenance lines (`v<N>.x`)**
- Released by running `release.yml` on the branch itself (`gh workflow
run release.yml --ref v2.x -f channel=maintenance`). Its own frozen
workflow, scripts and live e2e tests are used.
- A wildcard semantic-release entry (`v+([0-9]).x`) maps `v2.x` to range
`2.x`, channel `v2.stable`.
- Publishes to npm `v<N>.stable`, Homebrew `supabase@<N>` (with
`conflicts_with "supabase"`) and Scoop `supabase-v<N>-stable`.
- Releases are published with `--latest=false`.
- The live e2e gate takes a branch input.

**Guards**
- Lint Pull Request hard-fails a breaking `!` title unless the base is
`next`. It runs the guard from the default branch, and the cut exemption
only applies to same-repo branches.
- `branch-policy.yml` adds two checks:
- `Require fast-forward`, which keeps the merge button off sync and cut
PRs
- `Check maintenance source`, which only allows same-repo `hotfix/*` or
`backport/*` into `v*.x`
- `bot-pr-auto-merge.yml` skips the two sync PRs.
- Manual `release.yml` runs:
  - refuse `stable`/`beta` from `next` or `v*.x`
  - only run a non-dry-run `stable` from `main` or `hotfix/*`
  - validate the version string

**Also**
- The AI review adds a non-blocking "Next impact (advisory)" section on
PRs into develop that conflict with work on `next`.
- Release scripts accept the `next` and `v<N>.stable` tags.
- Backfill/apply release notes understand `-next` and maintenance tags.
- Nightly live e2e also covers `main` and `next`.
- Root `AGENTS.md`, `MAINTAINERS.md` and `CONTRIBUTING.md` cover branch
targeting and the release-infra cherry-pick rule.

### Deliberately not here
- No `next` dist-tag move on stable releases, because publishing stays
OIDC-only (`npm dist-tag` would need a long-lived token).
- Brew/scoop `supabase-next`, a Linear `next` pipeline and an
`@supabase/config` next channel are deferred until someone asks.
- One writer may resolve *and* approve a sync conflict PR. That's an
accepted decision, documented in the runbook.

### After merge (manual, in this order)
1. Create `next` from the `develop` tip.
2. Ruleset "Default (next)": copy of develop's (squash merge queue, the
4 required checks, code-owner review), with the release App as bypass
actor.
3. Add `Require fast-forward` as a required check on `develop` and
`next`.
4. Ruleset for `refs/heads/v*.x` with `Check maintenance source`
required.
5. Create the `release-major` label.
6. Confirm the App is a bypass actor on `develop`, and that npm trusted
publishing isn't restricted by branch.

Details are in `.github/MAINTAINERS.md` → "Branches and releases".

### Heads-up
- #7035 (merged) added an approver check to the old fast-forward job in
`release.yml`. This PR removes that job, and `fast-forward.yml` carries
the same check (`.permission` exactly `admin | write`); the merge
conflict is already resolved on this branch.
- `lint-pull-request.yml` is `pull_request_target`, so the new title
guard only starts running once this is on `develop`.
- The fast-forward and sync paths can't be fully exercised before merge.
The first deploy PR approval and first develop push after `next` exists
are the real tests, so it's worth watching those runs.

## Linked issue

Linear:
[CLI-2630](https://linear.app/supabase/issue/CLI-2630/gh-branch-and-release-process)

- [x] The linked issue is **open** and carries the
`open-for-contribution` label (or I'm a Supabase maintainer).

## Checklist

- [x] The PR title follows [Conventional
Commits](https://www.conventionalcommits.org/) (e.g. `fix(cli): …`).
- [x] Tests added or updated for the change. (`.github/scripts`: 372 bun
tests incl. real-git temp repos for sync/fast-forward; `apps/cli` unit
tests for release channels, title analysis and the build channel.)
- [x] From the repository root, `pnpm check:all` passes; relevant
package tests pass for every touched workspace, and `pnpm types:check`
passes for each touched TypeScript workspace (or workspace declaring
it).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## TL;DR

Studio's Logs → API Gateway page was always empty on the experimental
stack, because the stack's API proxy logged nothing per request. The
proxy now writes one access line per request, persists it like service
logs, and ships it to Analytics in the shape Studio reads, so the page
lists every request with its status, method and path. `supabase stack
logs` shows the same lines.

Stacked on #6893.

## Before

```mermaid
flowchart LR
  C[Client] --> P["Stack API proxy"]
  P --> S["REST / Auth / Storage / Functions / Realtime"]
  S --> L["Service logs"]
  L --> A[Analytics]
  P -. "no access log" .-> X["Studio API Gateway: empty"]
```

## After

```mermaid
flowchart LR
  C[Client] --> P["Stack API proxy"]
  P --> S["REST / Auth / Storage / Functions / Realtime"]
  P --> G["gateway log stream<br/>one line per request"]
  G --> F["logs/gateway files"]
  F --> CLI["supabase stack logs --service gateway"]
  F --> A["Analytics cloudflare.logs.prod"]
  A --> U["Studio API Gateway"]
```

## Why

The legacy `supabase start` fills the API Gateway page from Kong's
access log (source `cloudflare.logs.prod`). The experimental stack has
no Kong: its shared API port is served by the owner's own HTTP proxy,
which had no access log, so the page showed "No data" however much
traffic the stack served.

## What changed

- The shared API proxy records one access line per request and per
websocket upgrade, in nginx combined format plus the duration. The
status is the one actually sent, including proxy-generated 404/502/503
and requests that wait for a lazy service to wake; a client that leaves
before the response is recorded as 499, and body bytes appear only for
responses that finished. Logging never delays a response.
- `apikey`, `access_token` and `token` query values are replaced by
`redacted` before the line is written; request headers such as
`Authorization` are not logged.
- The lines are kept as a `gateway` log stream under the stack's
`logs/gateway/` directory with the same rotation and retention as
service logs, survive owner restarts, and are removed with the stack.
- While Analytics is running and healthy, gateway lines ship to
`cloudflare.logs.prod` with the Kong request/response metadata Studio's
API Gateway list, detail panel and status filter read (the path without
its query, the query as `search`).
- `supabase stack logs` includes gateway lines by default when the stack
serves the shared API port, and `--service gateway` selects them;
reading works while the stack is stopped.
- Studio's per-function logs page stays empty: it filters on a function
id that local Studio regenerates on every call, and the local edge
runtime output does not carry the function name. The legacy start has
the same gap.

## Terminal captures

Recorded from this branch's source on macOS (Docker runtime): terminal
with vhs, Studio in headless Chrome, at the same time against the same
stack. Top: `stack logs -f --service gateway` (the `apikey` query value
is redacted); bottom: requests to REST, Auth, Storage and Functions;
right: Studio's API Gateway list filling in, then the error and warning
status filter. Before this change the page showed "No data".


![stack-gateway-docker](https://gist.githubusercontent.com/avallete/718fe0d60eab6b1000f85175cd6242bf/raw/stack-gateway-docker.gif)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ls (#7041)

## TL;DR

retries the network restrictions live update once when the platform
stalls it, and makes the analytics poll say what stalled

- `network-restrictions update` failed with `expected 1 to be +0` and no
stderr. the platform's `apply` stalled until the harness killed the cli
at the 60s exit guard. the update is now re-issued once when it was
killed before printing its result, the same way the restore already
retries, and a second stall fails naming the kill

- the Logflare stored id poll in `Owner.analytics` ran out with a bare
`NoSuchElementError` after Analytics left healthy mid test. it now fails
with `NotStoredError` naming the first or sentinel event, its id and the
poll count

## ref

- spotted in: [network
restrictions](https://github.com/supabase/cli/actions/runs/37436825182/job/112180576049)
[analytics](https://github.com/supabase/cli/actions/runs/37451747630/job/112229699817)
#7036)

## Why

`@supabase/stack` runs a local Supabase anywhere: in containers (Docker
or Podman) or as native processes on macOS and Linux, with several
stacks running side by side. This PR is an architecture and hardening
pass over that runtime and the experimental `supabase stack` commands
(still behind `SUPABASE_EXPERIMENTAL_STACK=1`).

The aim is a design that is robust because it is simple:

- one owner per fact;
- derive state instead of recording it;
- prevent conflicts by construction;
- rely on guarantees the OS and the engine already give: kernel locks,
atomic rename, pipe EOF and container labels.

Several mechanisms were deleted rather than patched. The legacy
`supabase start` path is untouched.

## What users stop hitting

| Situation | Before | After |
|---|---|---|
| `supabase stack stop` | Listeners closed first, so Vector couldn't
flush logs through the proxy and was force-killed after its grace
period. Every stop paid that delay, plus an analytics drain and a 10 s
hold for idle pooled connections. | Services stop in reverse dependency
order with their listeners still open. Each listener closes when its own
service has stopped. |
| A service crashes | The proxy could keep routing to the dead process
while cleanup ran, and a retried cleanup could lose the crash outcome. |
The crash is reported first, so routing stops at once. The service ends
`Failed` even across retried cleanup. It wakes again on demand, behind a
crash-loop breaker. |
| Restarting a stack | Public ports could change between `stop` and
`start`, breaking URLs embedded in apps. | Automatic ports are reserved
per OS user and kept across stop and restart and across state roots
until destroy. Configured ports are held only while the stack runs, so a
stopped project never blocks another. A conflict names the port, the
holding project and the setting to change. |
| Two native stacks on macOS | Wildcard binds let another stack's
same-port loopback bind shadow a service, so requests hit the wrong
stack ("Invalid JWT"). | Native services bind loopback only, and backend
ports come from a dedicated range below the OS ephemeral range. |
| Proxy retry after a backend restart | The retry reused the address
captured before the first attempt and could reach a foreign process that
took the port. | The address lives in the lifecycle's `Running` state
and is re-resolved on retry. A dead workload has no routable address. |
| Deleting a stack's state directory | The owner kept running and its
containers leaked. | The owner notices that it lost ownership, stops
only its own services without touching data or ports, and exits.
Leftover labelled containers are swept by the next container stack under
that state root, and `destroy --stack-id` reaches them on demand. |
| `destroy` | Helper containers and files under the data root could
survive, and open leases made destroy fail. | Everything labelled with
the stack is removed, owned data is removed by location, and destroy
succeeds despite open leases. |
| Engine not running | Startup and destroy failed in opaque ways. |
Startup and `destroy` fail with `runtime-unavailable`. `destroy` leaves
data and ports untouched and prints the exact command to retry once the
engine is back. |
| Podman | Not supported. | Podman is a first-class engine. The CLI
picks Docker, then Podman, then native. Rootless launches keep file
ownership with `--userns=keep-id`. |
| Changing stack credentials | A stopped consumer kept stale keys baked
into its saved config. | Credential changes refresh the stopped
consumers in the same locked save, keeping values set explicitly. |
| Concurrent native preparers | Two processes preparing the same
binaries could lose files. macOS temp-dir aging could empty a cached
generation. | Artifacts are immutable, content-addressed generations
published by rename into the user cache directory. |
| Config change on a saved stack | Rejected with an opaque error. | The
error names the changed settings and the exact recreate command. |

## How it works now

### One lifecycle owner per service

Start, stop, sleep, restart, crash handling and destroy used to have
separate writers. A single pure reducer now decides every transition
under one gate. The runtime only executes the step it is given, and late
outcomes are fenced by generation.

```mermaid
stateDiagram-v2
    [*] --> Stopped
    Stopped --> Starting: demand or explicit start
    Starting --> Running: session available
    Starting --> Failed: launch failed, cleanup confirmed
    Running --> Stopping: stop, restart, idle sleep or crash
    Stopping --> Stopped: stop / restart / sleep, cleanup confirmed
    Stopping --> Failed: crash, cleanup confirmed
    Stopping --> Stopping: cleanup failed, retried on request
    Failed --> Starting: demand, behind the breaker
    Failed --> Stopped: explicit stop
```

- **Routing.** An address exists only in `Running`, so traffic can't
reach a stopping or crashed workload.
- **Breaker.** It opens for 30 s after 3 failures, each within 5 minutes
of the previous one.
- **Wake waiters.** Requests that wake a sleeping service wait up to 120
s.
- **Dependencies.** Prerequisites stay awake while a dependent runs.

### Ordered stop instead of a listener drain

```mermaid
sequenceDiagram
    participant P as Stack proxy
    participant F as Functions
    participant A as Auth
    participant V as Vector
    participant DB as Postgres
    Note over P: Draining (one-way): wake-up traffic refused,<br/>traffic to running services still admitted
    P->>F: stop (dependents first)
    F-->>P: stopped, listener closes
    P->>A: stop
    A-->>P: stopped, listener closes
    V->>P: final log flush still reaches analytics
    P->>V: stop
    V-->>P: stopped, listener closes
    P->>DB: stop (prerequisites last)
    DB-->>P: stopped, listener closes
```

Draining is one-way. If stop or destroy fails, the stack stays
registered and the next command reclaims it under the lease. There are
no resume or recovery paths.

### Who owns what

```mermaid
flowchart TB
    subgraph user["Per OS user"]
        ports[("~/.supabase/ports.sqlite<br/>public port reservations")]
        cache["~/.cache artifact generations<br/>immutable, content-addressed"]
    end
    subgraph root["State root (listing is per root)"]
        lock["&lt;id&gt;/owner.lock<br/>SQLite lease = stack is live"]
        state["&lt;id&gt;/state.json<br/>registration and definitions"]
        data["&lt;id&gt;/data/&lt;instance&gt;<br/>owned by location"]
    end
    engine["Engine containers<br/>com.supabase.stack + com.supabase.stack-root labels"]
    owner(("Stack owner process"))
    owner -- holds --> lock
    owner -- polls --> state
    owner -- sweeps by label --> engine
    owner -- reserves --> ports
    owner -- removes on destroy --> data
```

- **Liveness.** A stack is live exactly while its lease is held, and the
OS releases the lease when the process exits for any reason.
- **Containers.** They are tracked only by two labels set atomically at
creation. The claims journal is gone.
- **Data.** Ownership is by location: everything under an instance or
data root is owned. Borrowed caller paths may not resolve inside it.
Destroy checks containment before removing.
- **Ports.** Reservations live only in the per-user registry;
`state.json` stores none. Automatic ports stay reserved until destroy;
configured ports are held only while their listener is open, and a
crashed holder's reservation is taken over.
- **Engines.** Each container stack pins one engine target (Docker
context or host, Podman connection or URL), and every engine call uses
it.

### Removed or intentionally unsupported

| Item | What changed |
|---|---|
| Resource-claims journal, listener-drain deadline, abandon mode and its
retry loop, in-process artifact lock registry | Replaced by labels,
ordered stop, an owner that exits when it loses ownership, and SQLite
file locks. |
| Stacks saved by earlier experimental releases | No migration. A saved
stack that can't be read fails with an error naming its directory to
remove. |
| Filesystems without hard links | Unsupported; the non-atomic fallback
was removed. |
| Native mode on Windows | Out of scope; Windows runs the stack in
containers. |
| Container sweeps in native mode | Native owners skip them; native mode
has no container concerns. |
| Port reservations across OS users | Not provided; kernel binds still
keep different users' running stacks apart. |
| Proxy completion window during stop | None; in-flight requests survive
as far as each service's own graceful stop carries them. |

## Size

240 files changed: +23,442 / −11,645 (**+11,797 net**). About two thirds
of the growth is tests.

| Area | Kind | Net lines |
|---|---|---:|
| `packages/stack` | Production code | +3,277 |
| | Integration tests | +3,960 |
| | Unit tests | +1,605 |
| | Test helpers | +1,288 |
| | E2E tests | +897 |
| | Docs | +64 |
| `apps/cli` | Production code | −90 |
| | Tests | +123 |
| | Docs | +44 |
| Repo root | Namespace import-boundary lint rules | +380 |
| | CI (Podman on rootless Linux, stress workflow) | +188 |
| | ADRs | +58 |
| **Total** | Production code | **+3,187** |
| | Tests | **+7,873** |

The production growth is in the stack runtime only. The CLI's production
code is slightly smaller.
This PR was automatically created to sync API types from the
infrastructure repository.

Changes were detected after refreshing `apps/cli-go/api/v1-openapi.yaml`
from the latest spec from infrastructure, and `apps/cli-go/pkg/api` is
regenerated from it. The snapshot diff is the upstream API change and is
worth reading: it is marked `linguist-generated`, so GitHub collapses it
behind a "Load diff" click rather than hiding it.

Co-authored-by: supabase-cli-releaser[bot] <246109035+supabase-cli-releaser[bot]@users.noreply.github.com>
)

## TL;DR

lets `stack destroy` take `--stack-id` more than once, destroying every
listed stack after a single confirmation

## whats introduced?

every id resolves before the prompt, so a missing one destroys nothing
and a prefix plus the full id of one stack count once. a stack that
fails to destroy doesn't stop the rest, and the command still exits 1
with one error naming the failed ids and a retry command

 example: 
```
$ supabase stack destroy --stack-id <a> --stack-id <b> --yes
Permanently destroying stack <a> at /work/app and its owned data; stack <b> at /work/app and its owned data. Storage upload files will be preserved.
Stack <a> destroyed.
Stack <b> destroyed.
```

> [!NOTE]
> a single id behaves exactly as before. with more than one `--stack-id`
json returns `stacks` and a partly failed batch emits one error envelope
carrying `destroyed_stacks`

## ref

- closes: #6964

---------

Co-authored-by: 7ttp <117663341+7ttp@users.noreply.github.com>
This PR was automatically created to sync the generated `@supabase/api`
package with the latest Management API OpenAPI document.

Changes were detected in the upstream OpenAPI documents exposed by
`https://api.supabase.com/api/v1-json` and
`https://api.supabase.com/api/v2-json`.

Co-authored-by: jgoux <1443499+jgoux@users.noreply.github.com>
**TL;DR**: develop's `supabase` type check fails since the Management
API sync in #7054 because the hand-kept project-config mirror lacks four
new `postgres_settings` keys. This adds them, and fixes the turbo cache
key that let the sync PR (and develop's merge-queue run) replay a cached
pass instead of type-checking.

**Before**

```mermaid
flowchart LR
  A["Sync PR changes packages/api"] --> B["supabase#types:check hash unchanged"]
  B --> C["Cache hit: replayed pass"]
  C --> D["Auto-merge; develop broken"]
```

**After**

```mermaid
flowchart LR
  A["Sync PR changes packages/api"] --> B["@supabase/api#transit hash changes"]
  B --> C["supabase#types:check re-runs"]
  C --> D["Drift guard fails the sync PR"]
```

## Why

On develop at 2286e8c, an uncached `pnpm run types:check` in
`apps/cli` fails:

```
src/shared/config/project-config-api-drift.unit.test.ts(45,3): error TS2344: Type '"autovacuum_max_workers" | "autovacuum_work_mem" | "pg_net_batch_size" | "pg_stat_statements_max"' does not satisfy the constraint 'never'.
```

Develop's CI showed green only because turbo replayed a cached
`supabase:types:check` ("cache hit, replaying logs") on the #7054
merge-queue run. `types:check` had no `dependsOn`, so its hash covered
only the package's own files: a change confined to `packages/api` (or
`packages/config`) never invalidated a dependent's cached type check.
Any PR that touches `apps/cli` misses the cache and fails "Check code
quality" (e.g. #6934). Sync PRs are auto-merged, so the drift guard has
to fail on the sync PR itself.

## What changed

- `packages/config` mirror (`ProjectConfigApiAttributes`): add
`autovacuum_max_workers`, `autovacuum_work_mem`, `pg_net_batch_size` and
`pg_stat_statements_max` as unmapped `Schema.Unknown` fields. They
follow their API-only siblings (`log_*`, `checkpoint_timeout`,
`hot_standby_feedback`, `cron_log_statement`): no `[db.settings]` key,
no Go CLI counterpart, still reachable through `_apiResponse`. Making
them configurable in `config.toml` would be a separate published-schema
change.
- `turbo.json`: add a `transit` task (`dependsOn: ["^transit"]`) and
make `types:check` (including `@supabase/docs#types:check`) depend on
it. Each workspace dependency's files now feed the dependent's cache key
without serialising the type checks.
- `packages/api/scripts/dependent-types-check-cache.unit.test.ts`: asks
turbo's dry-run graph whether every workspace that depends on
`@supabase/api` reaches `@supabase/api#transit` from its `types:check`.
It fails on the previous `turbo.json`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This bumps storage from v1.80.0-r0 to v1.80.2-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.80.2-r0

Planned after supabase/slim-services published v1.80.1-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…nt (CLI-2653) (#7045)

## TL;DR

brings the `db` connection string parser, `pgpass` and `pgservicefile`
under the effect lint

## whats introduced?

- `db-config.parse`, `pgpass` and `pgservicefile` join the allow list
file by file, so the rest of the `db` module waits for the later PRs in
this stack
- the parser reads `pgpass` and the service file through the
`FileSystem` and `Path` services, and its libpq env reads go through
`Config` once up front
- `parseConnectionString` and `poolerConfigFromConnectionString` become
effects, and every caller across `db`, `stack`, `test-db`, `migration
squash`, `gen types` and the pg-delta engine yields them
- an empty shell var still wins over the project `.env`, a missing
`pgpass` or service file still reads as absent, and every parse error
keeps its text
- unit tests run on temp dirs and a pinned `Config` env instead of
`process.env` writes, with a new case for the empty shell var

## ref

- related: CLI-2653
) (#7046)

## TL;DR

brings the `db` pg connection layer and few resolvers under the effect
lint

## whats introduced?

- `db-connection` and `db-dns` join the allow list
- the `sslrootcert`, `sslcert` and `sslkey` reads go through
`FileSystem`, keeping the BOM and the errno messages, and
`dbConnectionLayer` captures it at build so `DbConnection.connect` keeps
its type
- a cert path with a NUL byte, only reachable as `%00` in a DSN, now
reads `FileSystem.readFile: ...` instead of `TypeError
[ERR_INVALID_ARG_VALUE]: ...`, since the platform keeps only the message
for that throw
- `--dns-resolver https` sends the same request through `HttpClient`
with automatic HTTP tracing disabled, so no trace headers reach
Cloudflare, and keeps every failure text and the 10s timeout; a
`Db.resolveHostsOverHttps` span records the response status and answer
count
- tests pin the full cert read errors and cover the DoH resolver:
non-200, rejected request, no valid IP, invalid and empty JSON and the
timeout

## ref

- related: CLI-2653
…I-2653) (#7048)

## TL;DR

brings the `db` config toml reader under the effect lint

## whats introduced?

- `db-config.toml-read` joins the allow list
- shell env reads go through `Config` once, for the override names and
every `env(...)` ref in the toml, and the sync `envLookup` reads from
that snapshot
- `config push` drops its copy of the env ref helpers and uses the
reader's
- the toml parse runs before the env snapshot with the same failure
order and messages
- invalid signing keys files retain native JSON parser details in both
`config.toml` loading and `local-config-values`, with the same narrow
lint exception used by the SSO readers
- unit tests pin env through `Config` and temp dirs instead of
`process.env` writes, and the push, reset and start integration tests
pin the three values the reader now takes from `Config`

## ref

- related: CLI-2653
…I-2653) (#7049)

## TL;DR

brings the rest of the `db` module under the effect lint

## whats introduced?

- the per file `db-config.parse`, `db-config.toml-read`, `db-connection`
and `db-dns` entries collapse into `db-*.ts`, and `branch-target`,
`connect-errors`, `pooler-fallback` and `schema-flags` join, which
covers the whole `db` module
- `db-config.layer`, `db-pull-run` and `db-push-core` yield their errors
directly with the same classes and messages, and `branch-target`
recovers through `Effect.option` and `orElseSucceed`
- `db-config` integration tests feed env through `Config` instead of
`process.env` hooks, and `db-image` and `db-target-flags` move to
`it.effect`

## ref

- closes: CLI-2653
## Summary

Scoped personal access tokens let a user pick exactly which permissions
a token gets, so the CLI needs to say which permissions each command
requires. This continues the mapping work from the command permission
model; see
[CLI-2474](https://linear.app/supabase/issue/CLI-2474/proposal-derive-and-document-the-management-api-scopes-each-cli).

## What's in this PR

- Reusable permission building blocks for the Management API calls made
by shared modules rather than command handlers: the DB config resolver,
project ref picker, linked-project cache, link services, storage
credentials, project API keys, upgrade suggestion, branch ref and target
lookups, the login profile lookup, and linked service versions. Many
commands reach these modules, so each is mapped once and included by the
commands that use it instead of being repeated in every declaration.
Each block lives next to the module whose calls it describes.
- An integration test per block that runs the real module and checks the
requests it makes against the block, so the mapping can't drift from the
code. Command tests replace these modules with fakes, so they wouldn't
catch it. Each best-effort call also has a 403 case showing the module's
result survives, and the drift check verifies `request.query` qualifiers
against the recorded requests.
- Model additions the blocks needed:
- `{ flag, is }` tests a switch by its effective value, so
`--skip-pooler=false` is distinguished from omitting it. A flag given an
empty value counts as absent.
- `{ dbTarget }` conditions with `withDbTarget` select on the database a
run targets: `--db-url`, then `--local`, then `--linked`, then the
command's default. The DB config block applies only on the linked
target.
- `withKind` lets a command override a block's required or best-effort
label.
- `request.query` records request details such as `reveal=true` as data.

The blocks live in shipped modules and run `block()` when those modules
load, which adds a small amount of declaration data to the bundle and
changes nothing else at runtime. No command includes them yet; later PRs
map the commands that do.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Comment thread apps/cli/src/command-internal/link-services-core.integration.test.ts Dismissed
avallete and others added 3 commits October 13, 2026 12:56
…og tail (#7120)

## Summary

The sync repair agent only received the last 150 lines of each failed CI
job. Turbo interleaves package output, so on
#7112 the failing CLI integration
test landed mid-log, behind the `@supabase/stack` output, and the agent
reported it could not see the failure.

`failureExcerpt` now keeps 40 lines after every `##[error]` annotation
and vitest `FAIL` header, plus the existing tail, with ANSI codes and
timestamps stripped. Gaps are marked with `[...]`.

## Linked issue

- [x] I'm a Supabase maintainer.

## Checklist

- [x] The PR title follows Conventional Commits.
- [x] Tests added or updated for the change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Summary

Approving a sync PR required its branch to contain the latest source tip
(`develop` for `sync/develop-into-next`). A sync PR stays open while
`develop` keeps moving, so any new conflict sent it back to a human, as
on #7112 (comment).

- When only the source moved, the fast-forward job now lands the
approved head that CI tested.
- When the target moved, it merges only the latest target into the
approved head. A conflict there still asks for re-approval.
- Newer source commits arrive with the next `Sync branches` run, on the
next push to the source.

The release-process doc is updated to match.

### Before

```mermaid
flowchart LR
  A[sync PR approved] --> T{next moved?}
  T -- no --> S{develop moved?}
  S -- no --> F[fast-forward next]
  S -- yes --> M
  T -- yes --> M{merge latest next + develop cleanly?}
  M -- yes --> L[land merged head]
  M -- no --> H[human resolves conflict, re-approves]
```

### After

```mermaid
flowchart LR
  A[sync PR approved] --> T{next moved?}
  T -- no --> F[fast-forward next to approved head]
  T -- yes --> M{merge latest next cleanly?}
  M -- yes --> L[land merged head]
  M -- no --> H[human resolves conflict, re-approves]
  F --> D[next develop push: Sync branches brings the rest]
  L --> D
```

## Linked issue

- [x] I'm a Supabase maintainer.

## Checklist

- [x] The PR title follows Conventional Commits.
- [x] Tests added or updated for the change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The macOS native-scenarios job is the longest job in the Test workflow,
about twice any other. Most of it is `native: parallel stack isolation`,
which starts two full native stacks at once and is starved on the
standard `macos-latest` runner: it takes roughly 2x longer there than on
the 8 vCPU Linux native job running the same test. Sharding the scenario
files did not help (#7121), since Vitest already ran both files
concurrently.

This moves the job to the 6 vCPU Blacksmith macOS runner
(`blacksmith-6vcpu-macos-latest`) so the two stacks get enough CPU and
memory, keeping full macOS coverage.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Comment on lines +733 to +734
async (run) =>
`## ${run.name} (${run.conclusion})\n\n\`\`\`\`text\n${await jobFailureExcerpt(token, repository, run.id)}\n\`\`\`\`\n`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚪ Severity: LOW

An untrusted test can print attacker-controlled instructions into this fixed four-backtick block; failureExcerpt preserves fence delimiters, and this file is loaded into Claude's editable context. The injected text can steer the repair agent to commit malicious source changes as a bot, which may reach next after maintainer approval.
Helpful? Add 👍 / 👎

💡 Fix Suggestion

Suggestion: Don't wrap the CI failure excerpt in a hardcoded four-backtick fence. Use the existing codeFence() helper, which picks a fence longer than any backtick run in the text, so untrusted test output can't close the block and inject instructions. Compute the excerpt once, then build the section with codeFence(excerpt, "text").

⚠️ Experimental Feature: This code suggestion is automatically generated. Please review carefully.

Suggested change
async (run) =>
`## ${run.name} (${run.conclusion})\n\n\`\`\`\`text\n${await jobFailureExcerpt(token, repository, run.id)}\n\`\`\`\`\n`,
async (run) => {
const excerpt = await jobFailureExcerpt(token, repository, run.id);
return `## ${run.name} (${run.conclusion})\n\n${codeFence(excerpt, "text").join("\n")}\n`;
},

Coly010 and others added 3 commits October 13, 2026 14:32
…LI-2599) (#7115)

## Summary

Stable now warns on stderr for every flag that CLI-2596 removes in v3.
Each warning names the replacement and says the flag goes away in v3.

| Flag | Warning |
| -- | -- |
| `domains create\|get\|reverify\|activate\|delete --include-raw-output`
| `Flag --include-raw-output is deprecated and will be removed in v3,
use -o json instead.` (new, previously help text only) |
| `db pull --use-pg-delta` | `Flag --use-pg-delta is deprecated and will
be removed in v3, use --declarative with [experimental.pgdelta] enabled
= true in your config.toml instead.` (reworded) |
| `db pull --experimental` (structured dump) | ``The --experimental
structured-dump mode for `db pull` is deprecated and will be removed in
v3. Use --declarative instead to pull the remote schema as per-object
files.`` (reworded) |

- The domains warning fires only when the flag is set. It goes to
stderr, so `-o json` / stream-json stdout is unchanged.
- There are no other behaviour changes. `--include-raw-output` still
forces JSON output, and it is still inert on `delete`.
- Flag-level usage over the last 30 days is low: `--include-raw-output`
2 runs from 1 person, `--use-pg-delta` 47/30, `--experimental` 17/9. The
numbers are on CLI-2596.

The removal itself is in a separate PR against `next`.

## Linked issue

Closes CLI-2599

## Checklist

- [x] The PR title follows Conventional Commits.
- [x] Tests added or updated: each domains command's integration test
covers the warning with and without the flag, and the db pull tests
assert the new wording.
- [x] `pnpm check:all` passes. The apps/cli unit and integration suites
pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
…7106)

## Summary

Scoped personal access tokens let a user pick exactly which permissions
a token gets, so the CLI needs to say which permissions each command
requires. This maps the first commands onto the permission model; see
[CLI-2474](https://linear.app/supabase/issue/CLI-2474/proposal-derive-and-document-the-management-api-scopes-each-cli).

## What's in this PR

- Permission declarations for `secrets list`, `snippets list` and `db
query`, built from the shared building blocks (project ref picker,
linked-project cache, DB config). `db query` selects its Management API
call by database target, defaulting to local. These three work as the
worked example for mapping the remaining commands.
- Each command's integration test checks the requests it records against
its declaration, so the mapping can't drift from the code. The tests
also run the commands through the real linked-project cache layer, and
`secrets list` through the project picker, so a block dropped from a
declaration fails a test.
- `assertBlockDrift`, a drift check for building blocks that takes its
label from the block instead of a made-up command name. The existing
block tests use it, and `permission-drift.ts` has callers now, so its
`knip` entry is gone.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
`Run integration tests` ran every package's integration suite in one
job, with the stack suite as the long pole. This turns it into a matrix:
the stack suite in three Vitest shards, the CLI suite in two, and the
API suite plus the stack namespace e2e tests in their own entry. The
`Run unit and integration tests` summary gate still aggregates the
matrix result.

CLI e2e files run serially, so a shard can be no shorter than its
longest file, and `start.lifecycle.e2e.test.ts` alone set that floor.
Its two health-check scenarios move to `start.health.e2e.test.ts`, the
e2e timings are refreshed from a current run, and CLI e2e runs in five
shards instead of four.

## Effect on the Test workflow

Compared with the same workflow on `develop`, excluding time spent
waiting for a runner:

- The slowest integration job is about 55% shorter, so integration tests
are no longer on the critical path.
- The slowest CLI e2e shard spends about 15% less time in tests. One
shard still runs about 25% over the others, so the timing-based split is
not yet even.
- The workflow as a whole finishes about 20% sooner. It is now bounded
by the CLI and stack e2e jobs, which end within a few seconds of each
other.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
readFileSync(join(PROMPTS_DIR, "resolve-prompt.md"), "utf8"),
"## Conflicted files",
"",
...conflicts.map(({ path, kind }) => `- \`${path}\` (${kind})`),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚪ Severity: LOW

A contributor-controlled filename from a conflicting PR is interpolated into Claude's resolution prompt; a newline or escaped backtick can break out of the file-list entry and inject instructions. The edit-capable agent may then commit malicious source changes to the sync branch, which can be promoted after approval.
Helpful? Add 👍 / 👎

💡 Fix Suggestion

Suggestion: Don't interpolate the raw filename into the prompt. Serialize it with JSON.stringify so newlines, control characters and quotes are escaped, and drop the backtick code-span wrapper that a crafted filename could break out of. Optionally, add a line to resolve-prompt.md saying that the file names listed are untrusted data and not instructions.

⚠️ Experimental Feature: This code suggestion is automatically generated. Please review carefully.

Suggested change
...conflicts.map(({ path, kind }) => `- \`${path}\` (${kind})`),
...conflicts.map(({ path, kind }) => `- ${JSON.stringify(path)} (${kind})`),

7ttp and others added 15 commits October 13, 2026 16:33
… (#7117)

## TL;DR

brings the `migration` module under the effect lint

## whats introduced?

- the `migration*` and `migrate-and-seed` files join the allow list,
with the sql helpers they run through
- (`postgres-url`, `sql-split`, `param-introspection`,
`pg-net-guidance`, `drop-objects`, `pg-dump` and
`bundled-postgres-client`), and `postgres-client.run` widens to its
tests
- `checkScannerBufferSize` reads `SUPABASE_SCANNER_BUFFER_SIZE` through
`Config`, still ahead of the project env
- migration timestamps go through `DateTime`, and `migration fetch`
yields its errors directly with the same messages
- the migration and seed tests swap `node:fs` and `process.env` for
scoped temp dirs and `withConfigEnv`, and the `pg-dump` and some
`migration-history` tests move to `it.effect`

## ref

- related: CLI-2654
CLI-2654) (#7118)

## TL;DR

brings the `seed` and `pgdelta` modules under the effect lint

## whats introduced?

- the `seed*`, `pgdelta*` and `diff-engine` files join the allow list
- `isPgDeltaDebugEnabled` reads `PGDELTA_DEBUG` through `Config`, so `db
diff`, `db pull` and the declarative `generate` and `sync` yield it
- `seed-ops` fails the scanner check with `MigrationSeedError` instead
of a bare `Error`, with the same message
- `seed-buckets` yields its errors directly and recovers with
`orElseSucceed`
- the pgdelta tests pin `PGDELTA_DEBUG` through `withConfigEnv`, and the
ssl probe test owns its server through `acquireRelease`

## ref

- closes: CLI-2654
This bumps storage from v1.81.3-r0 to v1.81.4-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.81.4-r0

Planned after supabase/slim-services published v1.81.4-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps realtime from v2.143.3-r0 to v2.143.4-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.143.4-r0

Planned after supabase/slim-services published v2.143.4-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps storage from v1.81.4-r0 to v1.81.5-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.81.5-r0

Planned after supabase/slim-services published v1.81.5-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…2693) (#7122)

## TL;DR

moves the remaining commands that predate the effect skill onto it, with
no change in behaviour

## whats introduced?

<details>
<summary>commands covered</summary>

`start` `stop` `status` `services` `init` `link` `unlink` `bootstrap`
`db` `migration` `inspect` `seed` `test`
 & `stack`

</details>

- error recovery narrows to `catchTag`, `catchTags` and `catchReason`
instead of broad catches and `_tag` checks
- casts and non null assertions give way to `Predicate` narrowing,
exhaustive `Match` and schema decoding
- mutable state read by finalizers moves into `Ref`, and the shadow port
retry goes through `Schedule`
- the pg-delta services use `Effect.fn` under their existing span names,
adding `PgAdmin.diff` and two `stack start` spans
- tests run on `it.effect` and wait on `Deferred` instead of polling,
staying on `it.live` only where a real clock, process, server or backoff
is involved

## notes

- no user facing behaviour change..
- output, exit codes, errors and telemetry match develop,
and the new spans only appear in trace output and the `SUPABASE_DEBUG=1`
span console
- the shadow port probe now also closes its server when interrupted
instead of leaking it

## ref

- closes: CLI-2693
- extends: #7092
This PR was automatically created to sync the generated `@supabase/api`
package with the latest Management API OpenAPI document.

Changes were detected in the upstream OpenAPI documents exposed by
`https://api.supabase.com/api/v1-json` and
`https://api.supabase.com/api/v2-json`.

Co-authored-by: jgoux <1443499+jgoux@users.noreply.github.com>
…7135)

Maps `db start`, `db test`, `db lint`, `db advisors`, `db reset`, `db
push` and `seed buckets` to the Management API operations they can call,
so scoped PATs can be granted per command. Drift tests keep each
declaration in step with what the command does.

**Shared model change.** `withCondition` now accepts a database-target
condition as well as a flag condition, so a command can gate a block on
the target it selects (`--local`, `--db-url`, linked). `FlagCondition`
is no longer exported.

**Blocks used.** `dbConfig` (lint, advisors, reset, push, `db test`),
`linkedProjectCache` (all but `db start` and `db test`),
`storageCredentials` (`seed buckets`). `db advisors` adds its own
security and performance entries, keyed on `--type`; because `--type` is
optional, each operation has an entry for the listed values and one for
the flag being absent.

**Defaults.** `db lint`, `db advisors`, `db reset`, `db test` and `seed
buckets` default to the local target; `db push` defaults to linked. Each
handler reads its target from the command line, not from the parsed flag
values.

**Tests.** Lint, advisors, reset, push and `db test` run the real
database-config resolver and the real linked-project cache and check the
recorded requests; `--local` runs assert no Management API request.
`seed buckets` records the api-keys request (`reveal=true`) and the
cache fill. Also covered: `--password` skipping the login role, an
advisors 403 stopping before the performance call, and `--linked=false`
in lint and seed. The `node:net` mock the real-resolver tests need now
lives in one helper, `tests/helpers/refuse-invalid-db-hosts.ts`, and
replaces the copies in `db query` and the resolver tests.

**Not covered.**
- `--linked=false` on push, reset, advisors and `db test`.
- A default target declared linked when it is really local would not
fail a drift test: a local run records no requests.

Also corrects the API routes listed in the `db pull` and `db diff`
side-effects docs (`/cli/login-role`, `/config/database/pooler`, `POST
/network-bans/retrieve`); they listed paths the code does not call.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
This bumps storage from v1.81.5-r0 to v1.82.0-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.82.0-r0

Planned after supabase/slim-services published v1.82.0-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…ns (#7136)

Maps `db dump`, `db pull`, `db remote commit`, `db diff`, `db schema
declarative generate` and `db schema declarative sync` to the Management
API operations they can call, so scoped PATs can be granted per command.
Drift tests keep each declaration in step with what the command does.
Stacked on the previous db PR.

**Shared changes.**
- `dbConfigPoolerFallback` (new block): the pooler retry after a linked
dump, declarative export or pull diff fails with an IPv6 error against
the direct host. `dbConfig` is now built from a shared entries list with
the linked target prepended; its declaration is unchanged.
- `dbConfigLinked` (new block): the same calls without the target
condition, for commands that reach the linked path some other way.
- `withContext` (new builder): records a prompt choice or other non-flag
prerequisite on every entry of a fragment.

**Defaults.** `db dump`, `db pull` and `db remote commit` default to the
linked project; `db diff` defaults to local. `db dump`, `db pull` and
`db remote commit` declare `dbConfig`, the fallback block and the
linked-project cache. `db diff` declares `dbConfig` and the cache for
`--linked`, plus the linked calls for a `--from` or `--to` side set to
`linked`, which resolves the project without `--linked`. `generate`
declares them for `--linked` and for the target prompt (no target flag,
migrations present). `sync` has no target flags, so it declares them for
the bootstrap prompt only.

**Tests.** Each command runs the real database-config resolver and the
real linked-project cache and checks the recorded requests, including
`--password` skipping the login role and `--local` making no request.
Dump and pull also run the container IPv6 retry (login role, pooler
config, login role). `db diff` covers `--from linked`, `--to linked` and
both. The `node:net` mock gains a scoped `withReachableDirectHost`
helper for the direct-host path.

**Not covered.**
- `--use-pg-schema` on `db diff` hands off to Go before any TypeScript
call; it is declared as having no API effect here.
- The generate and sync prompt-path entries and the fallback entries
carry a prerequisite, so the exact check skips them; tests assert their
request sequences directly.
- `dbConfig` and `dbConfigPoolerFallback` cover the same operations
under the linked target in dump, pull and remote commit, so a drift test
cannot tell a missing `dbConfig` from a present one there. Both are
tested on their own.
- `db remote commit` has no retry test; it shares pull's code.
- `--linked=false` and `--local=false` on these commands rely on the
existing handler tests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
)

## Summary

**TL;DR** When a command dies on an unclassified Effect `PlatformError`
(a filesystem or stdio failure whose reason is not `NotFound`,
`PermissionDenied`, or `BadArgument`), telemetry now names the reason
and the Effect operation that raised it. Today every such failure
collapses into one `error:Defect:PlatformError` fingerprint, which
recent prereleases report on `status` / `stack status` for the new local
stack without any way to tell which call fails.

### Before

```mermaid
flowchart LR
  A["FileSystem / Stdio call fails"] --> B["PlatformError<br/>(Busy, Unknown, ...)"]
  B -->|orDie| C["error:Defect:PlatformError"]
```

### After

```mermaid
flowchart LR
  A["FileSystem / Stdio call fails"] --> B["PlatformError<br/>(Busy, Unknown, ...)"]
  B -->|orDie| C["error:Defect:PlatformError:<br/>Busy:FileSystem.readFile"]
```

### Why

The failures cluster right after `start` while other commands run in
parallel, and a retry succeeds, which points at a race on shared state
or on stdout. Several call sites turn a `PlatformError` into a defect,
so the fingerprint has to carry the operation before the cause can be
fixed.

### What changed

- A `PlatformError` defect fingerprints as
`error:Defect:PlatformError:<reason>:<Module>.<method>`, for example
`…:Busy:FileSystem.readFile`.
- Only the closed reason tag and Effect's module and method names are
read, as data descriptors; `pathOrDescriptor` and `description` never
reach telemetry. If any part is not a plain identifier, the fingerprint
stays `error:Defect:PlatformError`.
- `PlatformError` failures that are already classified (`not_found`,
`filesystem`, `bad_argument`) are unchanged.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…rlays (#7130)

## Summary

The published CLI reference describes pg-delta, but its source in this
repo still describes migra. The next release would regenerate the
reference and revert the September fixes made directly in
supabase/supabase. This PR moves those fixes into the overlays so the
generator produces the corrected text.

Three files under `apps/cli/docs/` change. No code changes.

- `db diff`: projects with `[experimental.pgdelta] enabled = true` use
pg-delta. Other projects run migra. Storage buckets are data, so no
engine diffs them. The known-miss list (publications, `security_invoker`
views) now applies to migra only, since pg-delta tracks both.
- `db pull`: initial-pull behavior is stated per engine. pg-delta diffs
against an empty shadow database. migra seeds the migration with
`pg_dump`. `--diff-engine pg-delta` is the single-run opt-in. Added the
managed-schemas paragraph (triggers on `auth.users`, RLS on
`storage.*`). Added a caveat for `--declarative` on projects without
pg-delta: it also sets `[db.migrations].schema_paths` and breaks `db
diff`.
- `db pull` examples: the CLI no longer prints "auth and storage schemas
are excluded" or "Try rerunning with --debug". The examples show current
output. The custom-schemas example uses `public,extensions` instead of
`auth,storage`.

Verification: ran `bun scripts/generate-docs-spec.ts` and diffed the `db
diff` and `db pull` sections against the yaml on supabase/supabase
`master`. No stale sentence remains. The only other differences are flag
descriptions, which come from the command code.

## Linked issue

Closes #

- [x] The linked issue is **open** and carries the
`open-for-contribution` label (or I'm a Supabase maintainer).

## Checklist

- [x] The PR title follows [Conventional
Commits](https://www.conventionalcommits.org/) (e.g. `fix(cli): …`).
- [ ] Tests added or updated for the change.
- [ ] From the repository root, `pnpm check:all` passes; relevant
package tests pass for every touched workspace, and `pnpm types:check`
passes for each touched TypeScript workspace (or workspace declaring
it).

---------

Co-authored-by: avallete <andrew.valleteau@supabase.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Andrew Valleteau <avallete@users.noreply.github.com>
This bumps storage from v1.82.0-r0 to v1.82.1-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.82.1-r0

Planned after supabase/slim-services published v1.82.1-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
`supabase stop` no longer fails when another stack on the same Docker
daemon is stopping at the same moment.

Docker runs one prune at a time per daemon and rejects a concurrent
container, volume, or network prune with `a prune operation is already
running`, even when the label filters differ. `stop` now runs that prune
again while Docker reports the conflict, with a short jittered wait and
a bounded number of attempts; any other prune failure still fails
immediately. The container CLI helper now also collects stderr so the
conflict can be recognised.

Split out of #7129, which runs CLI e2e files concurrently and depends on
this.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ows and macOS jobs (#7129)

Cuts CI time and cost: dependency and Docker caches come from Blacksmith
sticky disks that only protected branches write, more end-to-end work
runs in parallel, and PRs into `develop` run Windows and macOS jobs only
when they touch platform-sensitive code.

## Gains

### Whole run

Measured from every successful `test.yml` run between Oct 10 and Oct 14.
Run time counts from run creation to the last job finishing, so it
includes queueing. Values are median [range]; every run below ran the
Windows and macOS jobs.

| | Other branches, macOS native on `macos-latest` (Oct 10–13, 132 runs)
| Other branches, macOS native on Blacksmith macOS since #7126 (Oct
13–14, 52 runs) | This PR, warm disks (7 runs) | This PR, empty disks (2
runs) |
| --- | --- | --- | --- | --- |
| Run time | 8.5 min [4.5–22.6] | 5.0 min [3.9–9.4] | 3.3 min [2.7–4.8]
| 3.4–4.1 min |
| Slowest job | 8.1 min [4.4–11.1] | 4.6 min [3.6–7.9] | 2.8 min
[2.5–3.4] | 3.1–3.3 min |
| macOS native scenarios | 8.1 min [4.4–11.1], one job | 3.4 min
[2.9–7.9], one job | 2.1–3.4 min, slowest of up to four jobs | 1.7–1.9
min, slowest of four jobs |
| Total job time | 62 min, 20 jobs | 65 min, 26 jobs | 44–56 min, 29–33
jobs | 58–62 min, 33 jobs |

The macOS runner change in #7126 brought most of the drop between the
two baselines. On top of it, this PR brings a run to about 3 minutes
once disks are warm: the slowest Linux job goes from 4.3 min [3.6–5.0]
on other branches since Oct 14 to 2.7 min [2.5–3.3], and Linux is now
what bounds the run. One warm run took 15.9 min while its slowest job
took 2.8 min; the rest was runner queueing, so it is left out of the
range above. About half of PRs into `develop` will also skip the Windows
and macOS jobs.

### Warm vs empty disks

Measured on this PR by running the same commit twice: once with empty
sticky disks, then again after the fill workflow populated them.

| Linux jobs (Blacksmith) | Warm vs empty disks |
| --- | --- |
| Setup | ~80% faster |
| Code quality | ~40% faster |
| Unit tests | ~40% faster |
| Integration shards (average) | ~30% faster |
| CLI e2e shards (average) | ~25% faster |
| Stack e2e, native (average) | ~25% faster |
| Stack e2e, Docker (average) | ~20% faster |
| Stack e2e, Podman (average) | ~15% faster |

Compared with the base branch, Windows port tests setup is ~60% faster
and macOS port tests setup ~40% faster. Splitting the declarative sync
e2e into two files and letting its commands reuse the shadow baseline
cache makes the slowest of those files ~65% faster than the original
single file. Splitting the macOS native scenarios into four jobs and
caching their native artifacts makes the slowest of them ~35% faster
than the single job it replaces; with a warm cache the isolation job is
~45% faster than without. On warm disks every job finished in under
three minutes; remaining time is test work rather than setup.

## Changes

**Sticky disks.** On Blacksmith Linux runners, `test.yml` jobs mount the
pnpm store, Go caches, and (for container jobs) Docker's image store
from Blacksmith sticky disks instead of downloading them through
`actions/cache`. Test jobs always mount them read-only; only the fill
workflow commits, after pruning unused pnpm packages, containers, and
volumes. Native stack jobs also mount the native artifact cache. Jobs
that mount the Docker image disk stop Docker in a final step so the disk
unmounts cleanly; the fill workflow also prunes containers and volumes
first, even after a failure. Other workflows, including release builds,
keep `actions/cache`.

**Disk refill.** `fill-sticky-disks.yml` runs on pushes to protected
branches, daily, and on demand. It installs dependencies, downloads the
stack's native service artifacts, pulls both the `supabase start` images
and the stack package's catalog images, so every disk stays warm.
Default-branch fills also drop artifacts and images of older versions.
It is the only writer, so Blacksmith's sticky-disk branch protection can
be enabled. The disk keys are new, so the first fill after merge seeds
every disk from protected-branch code.

**Parallel CLI e2e.** CLI e2e files run four at a time in CI
(`SUPABASE_E2E_WORKERS`); local runs stay serial. Each worker takes free
ports only from its own slot, so a port one worker released is never
handed to another. Files that cannot share the daemon run one at a time
afterwards in an `e2e-exclusive` project: `start.health`, which tags a
broken Mailpit image, and the files that provision pg-delta shadow
databases on ports the CLI picks itself. Concurrent `supabase stop`
teardowns rely on the prune retry from #7143.

**Lighter Windows and macOS setup.** Port tests install only node, bun,
and pnpm through mise instead of the full toolchain. Windows also skips
the pnpm store archive because downloading packages is faster there than
unpacking it.

**Split slow e2e work.** The declarative sync e2e runs as two files that
shard independently, and their commands share one home with the shipped
shadow baseline cache on, so only the first sync provisions a cold
shadow. macOS native scenarios run as separate lifecycle, confinement,
idle, and isolation jobs, each restoring its native artifacts through
`actions/cache`.

**Windows and macOS on demand.** On PRs into `develop` or `next`, the
Windows and macOS port tests and macOS native scenarios run only when
the PR touches platform-sensitive paths (stack host, namespace, port,
process, internal and artifact code, the CLI commands the Windows job
covers, the lockfile, root config, and the test workflow). They always
run in the merge queue, on PRs into `main` or `v*.x`, on `next` release
runs, and when the `run-ci` label is added, which now also applies to
ready PRs into `develop` and `next`. Replaying the last 50 merged PRs,
about half would skip them. The summary jobs fail if change detection
fails, so a skipped platform job never hides an error.

**Concurrent whole-stack scenarios.** Stack e2e jobs run their scenarios
concurrently. The write-confinement scenario watches the whole temp
tree, so it runs in its own `confinement` job per runtime.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
w3b6x9 added a commit to supabase/supabase that referenced this pull request Oct 14, 2026
…havior (#51751)

## Problem

The two `supabase stack` guides describe behavior the CLI changed in
v2.120.0 (Oct 6) and v2.121.0 (deploy PR supabase/cli#7104 open). A
reader following them today hits different output than the pages
promise.

  | Guide says | CLI does | Since |
  | --- | --- | --- |
| `stack logs` streams live lines only, no history | Keeps history, adds
`--tail`, `--since`, `--service gateway`, reads while stopped
(supabase/cli#6893) | v2.120.0 |
| Rejected config change fails with `cannot change on the saved stack` |
Fails with `The saved stack cannot adopt these changes`
(supabase/cli#6944) | v2.120.0 |
| Port changes always need a new local project | A stopped project
re-plans ports on next start (supabase/cli#6950) | v2.121.0 |
| No bulk destroy | `destroy` accepts repeated `--stack-id`
(supabase/cli#7000) | v2.121.0 |
| OrioleDB unsupported | `db.orioledb_version` runs in both runtimes
(supabase/cli#6934) | v2.121.0 |
| Nothing about native `pg_cron` | Jobs run in background workers;
earlier versions fail every job (supabase/cli#7039) | v2.121.0 |

The CLI getting-started guide (#50736) also says a container runtime is
required and never mentions the native runtime.

  ## Solution

Updated both stack guides and added one sentence to the getting-started
prerequisites.

- v2.121.0-only behavior is marked "In CLI v2.121.0 or later", with the
earlier behavior stated beside it. The guides' baseline stays at
v2.119.0.
- Every claim was checked against supabase/cli `develop` source and the
commits above.
- The `supabase stack` commands stay out of the generated CLI reference
by design, so these guides remain the only place the flags are
documented.

Check all before review:

- [x] I have read
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
- [x] If I wrote a new docs topic or edited an existing topic, I used
the `/write-the-docs` or `/edit-the-docs` skill, which applies the docs
[style
guide](https://github.com/supabase/supabase/tree/master/apps/docs/style-guide)
…emoved in v3 (#7154)

## TL;DR

Users still relying on config keys, env vars or file conventions that v3
removes now get a warning on stable that says so.
`SUPABASE_EXPERIMENTAL_ORIOLEDB_VERSION` was silently ignored after the
rename to `SUPABASE_DB_ORIOLEDB_VERSION`; it now works as a deprecated
alias with a warning.

## Before

```mermaid
flowchart LR
  A["SUPABASE_EXPERIMENTAL_ORIOLEDB_VERSION set"] --> B[Ignored silently] --> C[Plain Postgres image]
```

## After

```mermaid
flowchart LR
  A["SUPABASE_DB_ORIOLEDB_VERSION set?"] -- yes --> D[OrioleDB image]
  A -- no --> E["SUPABASE_EXPERIMENTAL_ORIOLEDB_VERSION set?"]
  E -- yes --> F["Warn: removed in v3"] --> D
  E -- no --> G[config.toml value]
```

## Why

The v3 removals in CLI-2597 need a stable release that warns first.
Several existing warnings did not mention v3, `INBUCKET_URL` in `status`
had no warning, and a project using the old OrioleDB env var started
plain Postgres with no message.

## What changed

- `SUPABASE_EXPERIMENTAL_ORIOLEDB_VERSION` is used when
`SUPABASE_DB_ORIOLEDB_VERSION` is unset and prints a deprecation
warning; the new variable wins when both are set. Resolution lives in
one helper used by every reader.
- Warnings for `[inbucket]` / `[remotes.*.inbucket]`,
`experimental.orioledb_version`, the `linkedin` / `slack` auth providers
and `import_map.json` in `functions deploy` now say they will be removed
in v3 and name the replacement.
- `supabase status` warns that `INBUCKET_URL` is deprecated in favour of
`MAILPIT_URL` for output formats that include it.
- All warnings go to stderr; machine-readable stdout is unchanged.
- Also touches `packages/config` warning wording, so this cuts an
`@supabase/config` release.

## Terminal captures

Recorded with vhs from source (`bun apps/cli/src/main.ts`) against a
fresh `supabase init` project whose `config.toml` sets `[inbucket]`,
`experimental.orioledb_version` and `[auth.external.slack]`. Each GIF
runs `supabase stop` twice (it loads the config without a running
stack): first with `SUPABASE_EXPERIMENTAL_ORIOLEDB_VERSION` unset, then
with it set inline on the second run only.

Before (merge-base with develop):


![before-stop](https://gist.githubusercontent.com/avallete/12c7231c768ee9188655db9110b3a5dd/raw/before-stop.gif)

After:


![after-stop](https://gist.githubusercontent.com/avallete/12c7231c768ee9188655db9110b3a5dd/raw/after-stop.gif)

Closes CLI-2601
Closes CLI-2569

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@supabase-cli-releaser
supabase-cli-releaser Bot merged commit 8a549df into main Oct 14, 2026
157 of 159 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do not merge Approve to apply; do not merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants