Skip to content

feat(cli): add supabase notebooks pull - #6598

Merged
avallete merged 1 commit into
developfrom
notebooks/04-cli-notebooks-pull
Sep 23, 2026
Merged

avallete merged 1 commit into
developfrom
notebooks/04-cli-notebooks-pull

Conversation

@SaxonF

@SaxonF SaxonF commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Adds the supabase notebooks command family and its first subcommand, notebooks pull. Notebooks live in supabase/notebooks/<name>.json, one committed JSON file each, alongside supabase/functions/ and supabase/compute/.

supabase notebooks pull                    # write notebooks missing locally
supabase notebooks pull <notebook-id>      # replace one local copy

How to try it

supabase link --project-ref <ref>
supabase notebooks pull

The notebook id for the single-notebook form is the UUID in the notebook's dashboard URL.

Notebooks are behind a dashboard feature preview; switching it on lets you create and edit them in the dashboard, which is the quickest way to set up states worth pulling — several notebooks at once, charts and log cells, a notebook renamed or deleted after a pull, or two notebooks sharing a name.

Notes

  • Identity is the file name, not the uuid. A checkout is shared through git, where a uuid in a filename is unreadable. Names the filesystem cannot hold are reported and skipped rather than sanitised, since a sanitised name would push back later as a rename of somebody's notebook. Portable-filename aliases (Sales vs sales, NFC vs NFD) are refused before anything is written.
  • Duplicate names are refused, not guessed at. Worth knowing for review: the dashboard names new notebooks "New Notebook", so a project with a few unrenamed ones fails every command that lists notebooks until they are renamed.
  • Local files naming no project notebook get three answers — leave them, create them in the project, delete them locally — because such a file is either one somebody deleted in the dashboard or one somebody added locally, and the lists do not say which. An unattended run (non-TTY, machine output format, cancelled prompt) reports the divergence and changes nothing.
  • Files are published through a temp file plus a hard link, so an interrupted pull leaves no partial file. The list walk follows the server's links.next cursor and fails closed on a missing or repeated cursor. pull/SIDE_EFFECTS.md records the full side-effect surface.

@SaxonF
SaxonF added this pull request to stack #6600 September 14, 2026 11:20
@SaxonF
SaxonF force-pushed the notebooks/04-cli-notebooks-pull branch from 425d460 to dafd923 Compare September 15, 2026 00:12
@SaxonF
SaxonF force-pushed the notebooks/04-cli-notebooks-pull branch from dafd923 to 8812be5 Compare September 15, 2026 00:29
@SaxonF
SaxonF removed this pull request from stack #6600 September 15, 2026 00:30
@SaxonF
SaxonF changed the base branch from notebooks/03-cli-resource-output to notebooks/02-api-deepobject-query September 15, 2026 00:30
@SaxonF
SaxonF added this pull request to stack #6612 September 15, 2026 00:31
@SaxonF
SaxonF force-pushed the notebooks/04-cli-notebooks-pull branch from 8812be5 to 7635c7e Compare September 22, 2026 10:54
@SaxonF
SaxonF marked this pull request as ready for review September 22, 2026 10:55
@SaxonF
SaxonF requested a review from a team as a code owner September 22, 2026 10:55
@SaxonF
SaxonF force-pushed the notebooks/04-cli-notebooks-pull branch from 7635c7e to 771cf16 Compare September 22, 2026 11:12

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 AI Review

After verifying all 14 submitted findings against the checked-out code and trusted conventions, I deduplicated them into 13 findings: 11 confirmed and 2 refuted. The confirmed issues include one critical symlink-containment vulnerability, one major Unicode filename-collision/data-loss risk, an output-precedence bug, a rename race, and several minor documentation, portability, sanitization, testing, and maintainability concerns. The claimed missing generated API client is refuted because the required contracts and operations already exist in the workspace package; the claimed duplicate-name bug for explicit ID pulls is also refuted because that path deliberately identifies the remote notebook by ID and is documented as an explicit overwrite operation.

Findings

Severity Location Category Sources Claim
🔴 CRITICAL apps/cli/src/commands/notebooks/notebooks.shared.ts:226 security codex A symlinked supabase/notebooks directory can redirect notebook reads and writes outside the project root.
🟠 MAJOR apps/cli/src/commands/notebooks/notebooks.shared.ts:157 data-loss codex The portable filename collision key misses Unicode case-fold aliases, allowing explicit replacement to overwrite an aliased local notebook on some case-insensitive filesystems.
🟡 MINOR apps/cli/src/commands/notebooks/notebooks.shared.ts:113 security claude Several errors interpolate API-provided notebook names without applying the module's terminal-safe name sanitizer.
🟡 MINOR apps/cli/src/commands/notebooks/pull/SIDE_EFFECTS.md:12 documentation claude The side-effect contract omits credential/project-resolution reads and the linked-project cache write, and incorrectly says the notebooks directory is read only for broad pulls.
🟡 MINOR apps/cli/src/commands/notebooks/notebooks.shared.ts:148 correctness claude Non-portable local .json filenames are silently omitted from reconciliation and output.
🟡 MINOR apps/cli/src/commands/notebooks/notebooks.shared.ts:237 portability claude Broad pulls require hard-link support even though exclusive file creation could work on filesystems without hard links.
🟡 MINOR apps/cli/src/commands/notebooks/pull/pull.handler.ts:147 output-format codex An explicit -o pretty does not override --output-format json as required by the CLI output precedence contract.
🟡 MINOR apps/cli/src/commands/notebooks/pull/pull.handler.ts:98 correctness codex A notebook renamed between list and detail requests is written using the stale listed name.
⚪ NIT apps/cli/src/commands/notebooks/notebooks.output.ts:11 maintainability claude+codex The notebooks output policy duplicates a cross-family responsibility and justifies it with prohibited provenance and future-work commentary.
⚪ NIT apps/cli/src/commands/notebooks/notebooks.shared.ts:83 test-coverage claude The pure filename-safety predicate lacks focused unit coverage for several security and boundary cases.
⚪ NIT apps/cli/src/commands/notebooks/notebooks.integration.test.ts:32 testing claude The shared test runner accepts an unused command argument and names its notebook-ID argument name, obscuring that it always invokes pull.
Refuted findings (kept for transparency, not posted as review comments)
  • apps/cli/src/commands/notebooks/pull/pull.handler.ts:72 (correctness): An explicit notebooks pull incorrectly bypasses duplicate-name protection and may replace the local file associated with another same-named notebook.
    Refuted: The duplicate guard prevents guessing during broad name-based reconciliation. The by-ID path does not guess: the user identifies the remote notebook directly, and both handler documentation and the side-effect contract explicitly define this invocation as replacing the file selected by its returned name.
  • apps/cli/src/commands/notebooks/notebooks.shared.ts:3 (build): The PR cannot compile because the workspace API package lacks the notebook contracts and client methods used by the new command.
    Refuted: The checked-out workspace already contains and exports every cited schema and API operation. Their absence from this PR's diff does not make the command uncompilable because they are present in the base workspace package.

Stats

Claude findings: 8 · Codex findings: 6 · Confirmed: 11 · Refuted: 2 · Uncertain: 0


Models: claude-opus-5 + gpt-5.6-sol · Trigger: auto · Workflow run

This review runs once per PR. A maintainer can request another with a /ai-review comment.

Comment thread apps/cli/src/commands/notebooks/notebooks.shared.ts
Comment thread apps/cli/src/commands/notebooks/notebooks.shared.ts Outdated
Comment thread apps/cli/src/commands/notebooks/notebooks.shared.ts
Comment thread apps/cli/src/commands/notebooks/pull/SIDE_EFFECTS.md
Comment thread apps/cli/src/commands/notebooks/notebooks.shared.ts
Comment thread apps/cli/src/commands/notebooks/pull/pull.handler.ts
Comment thread apps/cli/src/commands/notebooks/pull/pull.handler.ts
Comment thread apps/cli/src/commands/notebooks/notebooks.output.ts
Comment thread apps/cli/src/commands/notebooks/notebooks.shared.ts
Comment thread apps/cli/src/commands/notebooks/notebooks.integration.test.ts
@SaxonF
SaxonF force-pushed the notebooks/04-cli-notebooks-pull branch 2 times, most recently from d8e9a44 to 00f1ae8 Compare September 22, 2026 11:39

@avallete avallete left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approve. Staging pull passed: by id, unsafe names skipped on a broad pull and rejected on an explicit pull, Sales vs sales refused, duplicate names refused, and pagination past 100.

Nits, not blocking:

  • -o pretty --output-format json prints JSON. emitNotebooksMachineOutput ignores pretty, then the handler follows output.format. compute.output.ts treats -o pretty as text. Worth aligning if a third caller shows up, not a problem for this command.
  • notebooks.output.ts copies compute.output.ts. The header says to wait for a third caller. Fine to keep here.
  • tests/helpers/notebooks.ts rebuilds the platform mock that mockCommandPlatformApi already provides.

@SaxonF
SaxonF added this pull request to the merge queue Sep 23, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue because a pull request earlier in the stack was removed Sep 23, 2026
@avallete
avallete force-pushed the notebooks/04-cli-notebooks-pull branch from 00f1ae8 to 3606436 Compare September 23, 2026 08:16
Comment thread apps/cli/src/command-internal/path-containment.ts
@avallete
avallete force-pushed the notebooks/04-cli-notebooks-pull branch from 3606436 to c2918b7 Compare September 23, 2026 10:09
Base automatically changed from notebooks/02-api-deepobject-query to develop September 23, 2026 10:30
@avallete
avallete force-pushed the notebooks/04-cli-notebooks-pull branch 2 times, most recently from 9646450 to 971c525 Compare September 23, 2026 11:14
Comment thread apps/cli/src/commands/notebooks/notebooks.shared.ts
@avallete
avallete force-pushed the notebooks/04-cli-notebooks-pull branch from 971c525 to e1d2c1a Compare September 23, 2026 11:55
Adds the `supabase notebooks` command family and its first subcommand.
`notebooks pull` writes the linked project's notebooks into
`supabase/notebooks/<name>.json`, one committed JSON file per notebook.

A notebook's identity across the two sides is its name, because a
checkout is shared through git and the API's uuid is unreadable in a
filename. Names the API allows but a filesystem cannot hold are reported
rather than sanitised, and portable-filename aliases are refused before
anything is written, so a pull never renames somebody's notebook by
accident.

Without an argument the checkout wins: only notebooks missing locally are
written, and existing files are left alone. A notebook id is the opt-in
overwrite path for a single notebook. Local files naming no project
notebook are the divergence the command asks about — leave them, delete
them, or create them in the project — and an unattended run reports the
divergence and leaves both sides alone rather than resolving it in a
direction nobody chose.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@avallete
avallete force-pushed the notebooks/04-cli-notebooks-pull branch from e1d2c1a to cb0a71b Compare September 23, 2026 14:04
@avallete
avallete added this pull request to the merge queue Sep 23, 2026
Merged via the queue into develop with commit 1634e6e Sep 23, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants