Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/ai-models.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$comment": "Model IDs by family and tier. A new model can also need the Claude Code or Codex CLI version pinned in the workflows that read this file bumped.",
"claude": {
"opus": "claude-opus-5-5",
"sonnet": "claude-sonnet-5-5",
"haiku": "claude-haiku-5-5"
},
"codex": {
"sol": "gpt-6.1-sol"
}
}
4 changes: 2 additions & 2 deletions .github/scripts/ai-review/post-review.ts
Original file line number Diff line number Diff line change
Expand Up @@ -603,8 +603,8 @@ export function renderInlineComment(finding: MergedFinding): string {
export interface ReviewFooterInfo {
trigger: Trigger;
runUrl: string;
/** e.g. `` `claude-fable-5` + `gpt-5.6-sol` ``. Sourced from the workflow's
* model env vars so there's one source of truth for the model names. */
/** e.g. `` `claude-fable-5` + `gpt-5.6-sol` ``. Sourced from
* `.github/ai-models.json` through the workflow's model env vars. */
modelsFooter: string;
}

Expand Down
26 changes: 18 additions & 8 deletions .github/workflows/ai-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,6 @@ on:

permissions: {}

# One source of truth for the model names; resolve, claude-review, codex-review, and
# post-review's footer all read these instead of hardcoding them separately.
env:
CLAUDE_MODEL: claude-opus-5-5
CODEX_MODEL: gpt-6.1-sol

# Non-command issue_comment events fire for every comment on every PR, so grouping by PR number
# alone would let any comment cancel an in-flight review; give those runs their own per-run
# group instead. The command check is exact equality (mirroring resolve.ts), so a near-miss like
Expand Down Expand Up @@ -73,6 +67,9 @@ jobs:
pr_number: ${{ steps.resolve.outputs.pr_number }}
head_ref: ${{ steps.resolve.outputs.head_ref }}
trigger: ${{ steps.resolve.outputs.trigger }}
# Read once here so every job in the run uses the same models, even if the file changes mid-run.
claude_model: ${{ steps.models.outputs.claude_model }}
codex_model: ${{ steps.models.outputs.codex_model }}
steps:
# Pinned to the default ref explicitly — this job must keep running only trusted repo code,
# even though the pull_request trigger above hands it PR-authored event payloads.
Expand All @@ -95,6 +92,9 @@ jobs:
COMMENT_AUTHOR_ASSOCIATION: ${{ github.event.comment.author_association }}
COMMENT_BODY: ${{ github.event.comment.body }}
run: bun .github/scripts/ai-review/resolve.ts
- name: Load AI models
id: models
run: jq -r '"claude_model=\(.claude.opus)", "codex_model=\(.codex.sol)"' .github/ai-models.json >> "$GITHUB_OUTPUT"

claude-review:
name: Claude review
Expand All @@ -110,6 +110,8 @@ jobs:
permissions:
contents: read
pull-requests: read
env:
CLAUDE_MODEL: ${{ needs.resolve.outputs.claude_model }}
steps:
- name: Checkout PR head (untrusted; review subject matter only)
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down Expand Up @@ -266,6 +268,8 @@ jobs:
pull-requests: read
timeout-minutes: 45
runs-on: ubuntu-latest
env:
CODEX_MODEL: ${{ needs.resolve.outputs.codex_model }}
steps:
- name: Checkout default branch (trusted; the only checkout this job needs)
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down Expand Up @@ -371,6 +375,8 @@ jobs:
pull-requests: read
timeout-minutes: 45
runs-on: ubuntu-latest
env:
CODEX_MODEL: ${{ needs.resolve.outputs.codex_model }}
steps:
- name: Checkout PR head (untrusted; read-only, for verify-by-reading)
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down Expand Up @@ -525,6 +531,9 @@ jobs:
timeout-minutes: 10
permissions:
pull-requests: write
env:
CLAUDE_MODEL: ${{ needs.resolve.outputs.claude_model }}
CODEX_MODEL: ${{ needs.resolve.outputs.codex_model }}
steps:
# Security-critical: this is the only job with write permission, so it must only ever
# execute trusted base-branch code — never the PR head. Checking out `develop` explicitly
Expand All @@ -537,6 +546,7 @@ jobs:
with:
ref: develop
persist-credentials: false

- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version-file: ".bun-version"
Expand All @@ -562,6 +572,6 @@ jobs:
PR_DIFF_PATH: /tmp/ai-review/pr.diff
TRIGGER: ${{ needs.resolve.outputs.trigger }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
# CLAUDE_MODEL / CODEX_MODEL are inherited from the workflow-level `env:` block above,
# so the footer never drifts from what actually ran.
# CLAUDE_MODEL / CODEX_MODEL are the job-level values from `resolve`, the same ones the
# review jobs ran with, so the footer never drifts from what actually ran.
run: bun .github/scripts/ai-review/post-review.ts post
8 changes: 6 additions & 2 deletions .github/workflows/sync-branches.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ jobs:
outputs:
resolved: ${{ steps.resolve.outputs.resolved }}
env:
CLAUDE_MODEL: claude-opus-5-5
OUTPUT_DIR: ${{ github.workspace }}/sync-agent
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
steps:
Expand All @@ -113,6 +112,9 @@ jobs:
path: trusted
persist-credentials: false

- name: Load Claude model
run: echo "CLAUDE_MODEL=$(jq -r .claude.opus trusted/.github/ai-models.json)" >> "$GITHUB_ENV"

- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: work
Expand Down Expand Up @@ -229,14 +231,16 @@ jobs:
permissions:
contents: read
env:
CLAUDE_MODEL: claude-opus-5-5
OUTPUT_DIR: ${{ github.workspace }}/sync-agent
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: trusted
persist-credentials: false

- name: Load Claude model
run: echo "CLAUDE_MODEL=$(jq -r .claude.opus trusted/.github/ai-models.json)" >> "$GITHUB_ENV"

- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: work
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/sync-repair.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ jobs:
checks: read
actions: read
env:
CLAUDE_MODEL: claude-opus-5-5
OUTPUT_DIR: ${{ github.workspace }}/sync-agent
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
steps:
Expand All @@ -50,6 +49,9 @@ jobs:
path: trusted
persist-credentials: false

- name: Load Claude model
run: echo "CLAUDE_MODEL=$(jq -r .claude.opus trusted/.github/ai-models.json)" >> "$GITHUB_ENV"

- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version-file: trusted/.bun-version
Expand Down
3 changes: 2 additions & 1 deletion apps/cli/docs/release-process.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ git push origin sync/develop-into-next

#### Claude-resolved `develop-into-next`

A `develop-into-next` conflict PR is resolved by Claude (`claude-opus-5-5`) in the same run. The `Resolve conflicts with Claude` job merges `next` into the sync branch and runs Claude Code with file read, search, and edit tools only: no shell, no web tools, no `.git` edits, and no GitHub write token. A `pnpm-lock.yaml` conflict keeps `next`'s lockfile, which the next job regenerates. `Run quick checks on the resolution` formats the merged tree and runs `check:all` and unit tests in a job with no secrets, and `Fix the quick checks with Claude` fixes what fails once, without re-running them. This catches code on one side that still uses something the other renamed or removed; integration and end-to-end failures are left to the PR's CI and the repair loop below. The jobs holding the Anthropic key never execute the merged tree, and the tree passes between jobs as a git bundle. The `Publish the resolution` job pushes the latest finished stage from a fresh checkout with the release App token, comments the resolution and any check that failed, and starts the AI review. Choices between `develop` and `next` behavior are listed as decisions for `@supabase/cli`. If Claude cannot resolve the merge, it comments why and the PR waits for a person as above.
A `develop-into-next` conflict PR is resolved by Claude (the `claude.opus` model in `.github/ai-models.json`) in the same run. The `Resolve conflicts with Claude` job merges `next` into the sync branch and runs Claude Code with file read, search, and edit tools only: no shell, no web tools, no `.git` edits, and no GitHub write token. A `pnpm-lock.yaml` conflict keeps `next`'s lockfile, which the next job regenerates. `Run quick checks on the resolution` formats the merged tree and runs `check:all` and unit tests in a job with no secrets, and `Fix the quick checks with Claude` fixes what fails once, without re-running them. This catches code on one side that still uses something the other renamed or removed; integration and end-to-end failures are left to the PR's CI and the repair loop below. The jobs holding the Anthropic key never execute the merged tree, and the tree passes between jobs as a git bundle. The `Publish the resolution` job pushes the latest finished stage from a fresh checkout with the release App token, comments the resolution and any check that failed, and starts the AI review. Choices between `develop` and `next` behavior are listed as decisions for `@supabase/cli`. If Claude cannot resolve the merge, it comments why and the PR waits for a person as above.

[`sync-repair.yml`](../../../.github/workflows/sync-repair.yml) (`Sync repair`) runs when a CI workflow or the AI review finishes, and hourly. Once every check on the PR head has finished and no `AI Review` run for the PR is still going, it gives Claude the failed jobs' log tails and the AI review's unanswered threads. Claude fixes what the merge broke and replies on each finding, declining findings the merge did not introduce. The fix is pushed as a `chore(repo)` commit, fixed threads are resolved, and a round comment is posted. A head gets another round only for new review findings. When a round leaves its head failing, or after two rounds, the bot asks `@supabase/cli` to take over and stops repairing that PR. The repair loop reads only CI output and the AI review's own threads, never other people's comments, and only acts on PRs Claude resolved.

Expand Down Expand Up @@ -487,6 +487,7 @@ Keep two to three stable majors supported at the same time, roughly six to twelv
- Live e2e workflows: `live-e2e.yml`, `live-e2e-suite.yml`, `live-e2e-gate.yml`, `live-e2e-notify.yml`.
- PR gating on `v*.x`: `test.yml`, `lint-pull-request.yml`, `run-ci.yml`, `branch-policy.yml`.
- Composite action `.github/actions/setup`.
- Model ids in `.github/ai-models.json`, read by `propose-release-notes.ts`.
- Scripts in `apps/cli/scripts/`: `build.ts`, `build-binary.ts`, `compile-options.ts`, `macos-signing.ts`, `publish.ts`, `release-channels.ts`, `sync-versions.ts`, `update-homebrew.ts`, `update-scoop.ts`, `upload-release-assets.ts`, `analyze-commits-title.js`, `backfill-release-notes.ts`, `propose-release-notes.ts`.
- The `release` block in `apps/cli/package.json` and the smoke tests under `apps/cli/tests/`.

Expand Down
3 changes: 2 additions & 1 deletion apps/cli/scripts/propose-release-notes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ import { existsSync } from "node:fs";
import path from "node:path";
import process from "node:process";
import { parseArgs } from "node:util";
import aiModels from "../../../.github/ai-models.json";

const { values } = parseArgs({
options: {
tag: { type: "string" },
"dry-run": { type: "boolean", default: false },
apply: { type: "boolean", default: false },
"render-only": { type: "boolean", default: false },
model: { type: "string", default: "claude-haiku-5-5" },
model: { type: "string", default: aiModels.claude.haiku },
},
strict: true,
});
Expand Down
Loading