Skip to content

feat(cli): configure storage access for detached cloud runs - #433

Draft
jamesbhobbs wants to merge 2 commits into
mainfrom
feat/cli-sessions
Draft

feat(cli): configure storage access for detached cloud runs#433
jamesbhobbs wants to merge 2 commits into
mainfrom
feat/cli-sessions

Conversation

@jamesbhobbs

@jamesbhobbsjamesbhobbs commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

What

  • Make full cloud notebook runs explicitly detached.
  • Add deepnote run --storage-mode read-write|readonly.
  • Keep block runs live and reject --storage-mode when --block is used.
  • Document the actual isolation boundary: detached runs isolate notebook state from the live editor, while project files remain shared unless readonly mode is selected; external systems remain live.
  • Add Bash, Zsh, and Fish completions and tests.

Why

The standard Runs API already provides detached execution and accepts detachedRunStorageMode. Using that mechanism avoids the additional lifecycle and orphaning risks of creating and managing interactive sessions solely to obtain notebook isolation.

This revision intentionally removes the proposed --session workflow. Snapshot-settling and shared HTTP cancellation/deadline fixes are being handled in a separate draft PR so their reliability policy can be reviewed independently.

Validation

  • pnpm test: 2785 passed, 1 skipped
  • pnpm typecheck
  • pnpm biome:check
  • pnpm prettier:check
  • pre-push cspell check

Summary by CodeRabbit

  • New Features

    • Added storage-mode controls for detached cloud notebook runs, supporting read-write and read-only project storage.
    • Read-only runs can access project files without persisting changes, while still supporting temporary files and external systems.
    • Added command-line completion suggestions for supported storage modes.
    • Block-scoped live runs remain available but cannot use storage-mode controls.
  • Documentation

    • Updated CLI and cloud-run guidance with storage behavior details and read-only examples.

@coderabbitai

coderabbitaiBot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a1498b35-5c66-4fd2-8806-9ba2c4c0bcfe

📥 Commits

Reviewing files that changed from the base of the PR and between 5479a93 and cd13aa5.

📒 Files selected for processing (2)
  • packages/cli/src/cli.test.ts
  • packages/cli/src/completions.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/cli/src/completions.ts
  • packages/cli/src/cli.test.ts

📝 Walkthrough

Walkthrough

The PR adds --storage-mode to deepnote run with read-write and readonly values. The CLI validates cloud-only usage and rejects combinations with block runs. Cloud requests serialize detached full-notebook runs and map read-write to read_write. The cloud package exports the storage mode type. Tests cover validation and request payloads. CLI completions and documentation describe the new behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
participant CLI
participant runInDeepnoteCloud
participant triggerNotebookRun
participant CloudAPI
CLI->>runInDeepnoteCloud: invoke deepnote run with --storage-mode
runInDeepnoteCloud->>runInDeepnoteCloud: validate cloud and block-run usage
runInDeepnoteCloud->>triggerNotebookRun: pass detached storage mode
triggerNotebookRun->>CloudAPI: send detached run request
CloudAPI-->>triggerNotebookRun: return run response
Loading

Possibly related PRs

Suggested reviewers:voyti

🚥 Pre-merge checks | ✅ 5 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 59.26% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly describes configuring storage access for detached cloud runs, which is the main change in the pull request.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
Updates Docs✅ PassedOSS docs cover --storage-mode, detached and live block runs, storage isolation, examples, and SDK usage; the private internal roadmap repo is unavailable, so confirm its update separately.

Comment @coderabbitai help to get the list of available commands.

@codecov

codecovBot commented Jul 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.78%. Comparing base (f9f89d5) to head (cd13aa5).

Additional details and impacted files
@@ Coverage Diff @@## main #433 +/- ##
=======================================
Coverage 87.78% 87.78% =======================================
Files 187 187 Lines 9927 9933 +6 Branches 2768 2772 +4 =======================================
+ Hits 8714 8720 +6 
Misses 1212 1212 Partials 1 1 

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitaicoderabbitaiBot 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.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/utils/run-in-cloud.test.ts`:
- Around line 258-268: Update the test “does not ask before pushing into a
session copy, which is discarded anyway” to explicitly mock or pin
process.stdin.isTTY to false for the test duration. Restore the original value
afterward so the test remains isolated, ensuring promptForBooleanField cannot
depend on the runner’s TTY state.
In `@packages/cli/src/utils/run-in-cloud.ts`:
- Around line 388-397: Move the createSession flow in the options.session branch
into the existing try/catch or otherwise ensure its rejection reaches the same
error-handling path that calls spinner?.fail. Preserve session and sessionRun
assignment and debug logging on success, while stopping the spinner when
createSession fails.
- Around line 415-430: Update the push target and confirmation logic around
pushLocalNotebook so a session is treated as safe only when
session?.sessionNotebookId is present. When that identifier is absent, target
the real notebook and keep confirmation enabled; only set skipConfirmation when
pushing to a valid session copy.
- Around line 455-458: Update the session submission flow in run-in-cloud.ts so
the submitSessionRun call in the options.push/blockIds branch includes the
parsed inputs alongside notebookId and blockIds. Preserve inputs for --session
--push and --session --block, and refactor the non-submission branch to avoid
the SubmittedRun cast by retaining the session/run pair together.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cc9f9be7-fbbb-4f79-a09d-8537db4c93a3

📥 Commits

Reviewing files that changed from the base of the PR and between befbb2c and 05a1f3b.

📒 Files selected for processing (14)
  • packages/cli/README.md
  • packages/cli/src/cli.test.ts
  • packages/cli/src/cli.ts
  • packages/cli/src/commands/run.ts
  • packages/cli/src/completions.ts
  • packages/cli/src/utils/push-to-cloud.test.ts
  • packages/cli/src/utils/push-to-cloud.ts
  • packages/cli/src/utils/run-in-cloud.test.ts
  • packages/cli/src/utils/run-in-cloud.ts
  • packages/cloud/README.md
  • packages/cloud/src/index.ts
  • packages/cloud/src/sessions.test.ts
  • packages/cloud/src/sessions.ts
  • skills/deepnote/references/cli-run.md

Comment threadpackages/cli/src/utils/run-in-cloud.test.ts Outdated
Comment threadpackages/cli/src/utils/run-in-cloud.ts Outdated
Comment threadpackages/cli/src/utils/run-in-cloud.ts Outdated
Comment threadpackages/cli/src/utils/run-in-cloud.ts Outdated
jamesbhobbs added a commit that referenced this pull request Jul 26, 2026
- **Critical:** `sessionNotebookId` is optional on the API's session object, and
`pushTarget` fell back to the *source* notebook when it was absent — while
`skipConfirmation` stayed true because a session existed. That is an
unconfirmed destructive sync into the user's real notebook, which is the one
outcome `--session` exists to rule out. It now refuses with a usage error, and
a test asserts no block write is issued.
- `submitSessionRun` dropped `inputs`, so `-i key=value` was lost on
`--session --push`: the session was created with them, but the post-push
submission is a new run and does not inherit them.
- A `createSession` failure escaped with the ora spinner still running, unlike
every other failure path.
- The "does not ask before pushing into a session copy" test relied on the
runner having no TTY. On a machine where Vitest inherits one it would have
reached the real prompt and hung rather than failed, so it now pins
`stdin.isTTY` and restores it.
Also drops an avoidable `as SubmittedRun` cast by narrowing on the session/run
pair together.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jamesbhobbs added a commit that referenced this pull request Jul 26, 2026
- **Critical:** `sessionNotebookId` is optional on the API's session object, and
`pushTarget` fell back to the *source* notebook when it was absent — while
`skipConfirmation` stayed true because a session existed. That is an
unconfirmed destructive sync into the user's real notebook, which is the one
outcome `--session` exists to rule out. It now refuses with a usage error, and
a test asserts no block write is issued.
- `submitSessionRun` dropped `inputs`, so `-i key=value` was lost on
`--session --push`: the session was created with them, but the post-push
submission is a new run and does not inherit them.
- A `createSession` failure escaped with the ora spinner still running, unlike
every other failure path.
- The "does not ask before pushing into a session copy" test relied on the
runner having no TTY. On a machine where Vitest inherits one it would have
reached the real prompt and hung rather than failed, so it now pins
`stdin.isTTY` and restores it.
Also drops an avoidable `as SubmittedRun` cast by narrowing on the session/run
pair together.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@coderabbitaicoderabbitaiBot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/utils/run-in-cloud.test.ts`:
- Around line 222-241: Update the test case around runInDeepnoteCloud to capture
the POST /v2/blocks request index from calls and assert it occurs before the
POST /v2/sessions/session-1/runs submission. Keep the existing creation,
interruption, and copy-read ordering assertions unchanged.
- Around line 212-220: Update runInDeepnoteCloud so the initial session-creation
run is interrupted whenever a block-scoped replacement run will be submitted,
including the --session --block path rather than only --push. Preserve the
existing no-replacement behavior, and extend the tests around the session run
assertions to verify interruption and prevent the unscoped run from executing
the whole notebook.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fec3ea13-891d-4ee8-aa7b-3263b8ecd986

📥 Commits

Reviewing files that changed from the base of the PR and between 3a24eb7 and 1aa007e.

📒 Files selected for processing (14)
  • packages/cli/README.md
  • packages/cli/src/cli.test.ts
  • packages/cli/src/cli.ts
  • packages/cli/src/commands/run.ts
  • packages/cli/src/completions.ts
  • packages/cli/src/utils/push-to-cloud.test.ts
  • packages/cli/src/utils/push-to-cloud.ts
  • packages/cli/src/utils/run-in-cloud.test.ts
  • packages/cli/src/utils/run-in-cloud.ts
  • packages/cloud/README.md
  • packages/cloud/src/index.ts
  • packages/cloud/src/sessions.test.ts
  • packages/cloud/src/sessions.ts
  • skills/deepnote/references/cli-run.md
🚧 Files skipped from review as they are similar to previous changes (11)
  • packages/cloud/src/index.ts
  • packages/cli/src/commands/run.ts
  • packages/cli/src/cli.ts
  • packages/cli/src/utils/push-to-cloud.ts
  • packages/cli/src/completions.ts
  • skills/deepnote/references/cli-run.md
  • packages/cloud/README.md
  • packages/cloud/src/sessions.ts
  • packages/cli/README.md
  • packages/cli/src/utils/run-in-cloud.ts
  • packages/cloud/src/sessions.test.ts

Comment threadpackages/cli/src/utils/run-in-cloud.test.ts Outdated
Comment threadpackages/cli/src/utils/run-in-cloud.test.ts Outdated
jamesbhobbs added a commit that referenced this pull request Jul 26, 2026
- **Critical:** `sessionNotebookId` is optional on the API's session object, and
`pushTarget` fell back to the *source* notebook when it was absent — while
`skipConfirmation` stayed true because a session existed. That is an
unconfirmed destructive sync into the user's real notebook, which is the one
outcome `--session` exists to rule out. It now refuses with a usage error, and
a test asserts no block write is issued.
- `submitSessionRun` dropped `inputs`, so `-i key=value` was lost on
`--session --push`: the session was created with them, but the post-push
submission is a new run and does not inherit them.
- A `createSession` failure escaped with the ora spinner still running, unlike
every other failure path.
- The "does not ask before pushing into a session copy" test relied on the
runner having no TTY. On a machine where Vitest inherits one it would have
reached the real prompt and hung rather than failed, so it now pins
`stdin.isTTY` and restores it.
Also drops an avoidable `as SubmittedRun` cast by narrowing on the session/run
pair together.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jamesbhobbs added a commit that referenced this pull request Jul 26, 2026
- **Critical:** `sessionNotebookId` is optional on the API's session object, and
`pushTarget` fell back to the *source* notebook when it was absent — while
`skipConfirmation` stayed true because a session existed. That is an
unconfirmed destructive sync into the user's real notebook, which is the one
outcome `--session` exists to rule out. It now refuses with a usage error, and
a test asserts no block write is issued.
- `submitSessionRun` dropped `inputs`, so `-i key=value` was lost on
`--session --push`: the session was created with them, but the post-push
submission is a new run and does not inherit them.
- A `createSession` failure escaped with the ora spinner still running, unlike
every other failure path.
- The "does not ask before pushing into a session copy" test relied on the
runner having no TTY. On a machine where Vitest inherits one it would have
reached the real prompt and hung rather than failed, so it now pins
`stdin.isTTY` and restores it.
Also drops an avoidable `as SubmittedRun` cast by narrowing on the session/run
pair together.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
coderabbitai[bot]
coderabbitaiBot previously approved these changes Jul 26, 2026
@jamesbhobbs
jamesbhobbs changed the base branch from feat/cli-push-blocks to mainJuly 27, 2026 16:14
@jamesbhobbs
jamesbhobbs dismissed coderabbitai[bot]’s stale reviewJuly 27, 2026 16:14

The base branch was changed.

@jamesbhobbsjamesbhobbs changed the title feat(cli): add --session to run in an interactive session on a scratch copyfeat(cli): add --session to run a notebook in an interactive sessionJul 27, 2026

@coderabbitaicoderabbitaiBot 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.

Actionable comments posted: 3

🧹 Nitpick comments (2)
packages/cli/src/utils/run-in-cloud.test.ts (1)

235-251: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Nothing pins which run id gets polled.

The fallback mock answers every GET with run-auto, so a regression that polled the session's initial run instead of the block-scoped replacement would still pass. Asserting the polled URL carries run-scoped closes that.

♻️ Suggested addition
 expect(calls.find(c => c.url.endsWith('/v2/sessions/session-1/runs'))?.body?.blockIds).toEqual(['blk-1'])
+ // The replacement run is the one reported, so it is the one that must be polled.+ expect(calls.some(c => c.method === 'GET' && c.url.includes('run-scoped'))).toBe(true)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/utils/run-in-cloud.test.ts` around lines 235 - 251,
Strengthen the test around runInDeepnoteCloud by asserting that the polling
request targets the block-scoped replacement run, specifically that its URL
includes the run-scoped identifier such as run-scoped. Update the session fetch
mock or call inspection so polling the initial run cannot satisfy the test,
while preserving the existing interrupt-before-submit and blockIds assertions.
packages/cloud/src/http.ts (1)

5-13: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Docstring overstates the error contract.

The module doc says every failure becomes an ApiError, but fetch() itself (line 76) and response.text() (line 90) aren't wrapped — network failures, aborts, and timeouts propagate as native TypeError/DOMException, not ApiError (confirmed by the test expecting { name: 'TimeoutError' } at http.test.ts line 162). A caller catching only ApiError would miss these. Either narrow the docstring's claim to "every response received" or wrap transport-level failures too.

Also applies to: 74-108

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cloud/src/http.ts` around lines 5 - 13, The module docstring
overstates the error contract: update the documentation around the shared HTTP
request flow to limit the ApiError guarantee to failures from received
responses, explicitly excluding transport failures from fetch and response.text
such as network errors, aborts, and timeouts. Do not change the existing error
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cloud/src/http.ts`:
- Around line 40-49: Update the package’s Node.js engine requirement from
>=22.14.0 to >=22.16.0 so combineSignals can safely use AbortSignal.any with
AbortSignal.timeout. Ensure all relevant package metadata and supported-runtime
declarations advertise the new floor consistently.
In `@skills/deepnote/references/cli-run.md`:
- Line 28: Update the `--session` option description in the CLI reference table
to state that it runs only with `--cloud`, preserving the existing behavior
description while adding “(with --cloud)”.
- Around line 114-115: Update the documentation around the --session behavior to
describe both supported workflows: use deepnote sync to push local edits to the
regular saved content, or combine --session with --push to synchronize edits
into the disposable session copy before execution.
---
Nitpick comments:
In `@packages/cli/src/utils/run-in-cloud.test.ts`:
- Around line 235-251: Strengthen the test around runInDeepnoteCloud by
asserting that the polling request targets the block-scoped replacement run,
specifically that its URL includes the run-scoped identifier such as run-scoped.
Update the session fetch mock or call inspection so polling the initial run
cannot satisfy the test, while preserving the existing interrupt-before-submit
and blockIds assertions.
In `@packages/cloud/src/http.ts`:
- Around line 5-13: The module docstring overstates the error contract: update
the documentation around the shared HTTP request flow to limit the ApiError
guarantee to failures from received responses, explicitly excluding transport
failures from fetch and response.text such as network errors, aborts, and
timeouts. Do not change the existing error behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 87b1e286-6ba1-4aed-b535-9bc6fa3de5b2

📥 Commits

Reviewing files that changed from the base of the PR and between 1aa007e and e35a3d5.

📒 Files selected for processing (15)
  • packages/cli/README.md
  • packages/cli/src/cli.test.ts
  • packages/cli/src/cli.ts
  • packages/cli/src/commands/run.ts
  • packages/cli/src/completions.ts
  • packages/cli/src/utils/run-in-cloud.test.ts
  • packages/cli/src/utils/run-in-cloud.ts
  • packages/cloud/README.md
  • packages/cloud/src/create-project.ts
  • packages/cloud/src/http.test.ts
  • packages/cloud/src/http.ts
  • packages/cloud/src/index.ts
  • packages/cloud/src/sessions.test.ts
  • packages/cloud/src/sessions.ts
  • skills/deepnote/references/cli-run.md
🚧 Files skipped from review as they are similar to previous changes (9)
  • packages/cli/src/commands/run.ts
  • packages/cloud/src/index.ts
  • packages/cli/src/cli.ts
  • packages/cli/README.md
  • packages/cli/src/cli.test.ts
  • packages/cli/src/completions.ts
  • packages/cloud/README.md
  • packages/cloud/src/sessions.test.ts
  • packages/cloud/src/sessions.ts

Comment threadpackages/cloud/src/http.ts Outdated
Comment threadskills/deepnote/references/cli-run.md Outdated
Comment threadskills/deepnote/references/cli-run.md Outdated
@jamesbhobbs
jamesbhobbsforce-pushed the feat/cli-sessions branch 2 times, most recently from 57417bf to 30325f0CompareJuly 27, 2026 16:41

@coderabbitaicoderabbitaiBot 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.

Actionable comments posted: 3

🧹 Nitpick comments (2)
packages/cli/src/utils/run-in-cloud.ts (1)

349-403: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Handler leak on the createSession-throws path is avoided, but consider process.once. Minor hardening: a second Ctrl-C during endSession() re-enters nothing today (handlers are removed first), so this is fine as-is — noting only that once would express the intent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/utils/run-in-cloud.ts` around lines 349 - 403, Update
installSignalHandlers to register each SIGINT and SIGTERM callback with
process.once instead of process.on, while preserving removeSignalHandlers and
the existing endSession cleanup and exit-code behavior.
packages/cli/src/utils/run-in-cloud.test.ts (1)

137-152: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Dead mock branches.--session --block is now rejected up front, so the interrupt and scoped-run handlers are unreachable; the suite only asserts they are never hit. Keep them as executable documentation of the API contract, or drop them — your call.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/utils/run-in-cloud.test.ts` around lines 137 - 152, The
interrupt and scoped-run mock handlers in the test are unreachable because
--session --block is rejected before those requests. Remove these dead branches,
or retain them only if the tests explicitly exercise them to document the API
contract; do not leave unreachable handlers that are merely asserted not to run.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cloud/README.md`:
- Line 80: Add getNotebook to the import block in the README example so the
existing call using session.sessionNotebookId resolves correctly when copied.
- Around line 67-68: Update the README wording near the storageMode discussion
to explicitly distinguish notebook-document isolation from shared project files
and external systems: state that the notebook document is isolated, while shared
files, databases, integrations, and other systems it accesses may remain
accessible or be affected. Keep the existing run-snapshot behavior intact.
In `@skills/deepnote/references/cli-run.md`:
- Line 28: Update the --session CLI documentation row to state that it requires
--cloud, matching the behavior enforced by assertCloudOnlyFlagsRequireCloud and
the neighboring cloud-only option descriptions.
---
Nitpick comments:
In `@packages/cli/src/utils/run-in-cloud.test.ts`:
- Around line 137-152: The interrupt and scoped-run mock handlers in the test
are unreachable because --session --block is rejected before those requests.
Remove these dead branches, or retain them only if the tests explicitly exercise
them to document the API contract; do not leave unreachable handlers that are
merely asserted not to run.
In `@packages/cli/src/utils/run-in-cloud.ts`:
- Around line 349-403: Update installSignalHandlers to register each SIGINT and
SIGTERM callback with process.once instead of process.on, while preserving
removeSignalHandlers and the existing endSession cleanup and exit-code behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d5dbcb70-a9fd-4a99-9023-d9f544ca51bd

📥 Commits

Reviewing files that changed from the base of the PR and between 67cf338 and 30325f0.

📒 Files selected for processing (15)
  • packages/cli/README.md
  • packages/cli/src/cli.test.ts
  • packages/cli/src/cli.ts
  • packages/cli/src/commands/run.ts
  • packages/cli/src/completions.ts
  • packages/cli/src/utils/run-in-cloud.test.ts
  • packages/cli/src/utils/run-in-cloud.ts
  • packages/cloud/README.md
  • packages/cloud/src/create-project.ts
  • packages/cloud/src/http.test.ts
  • packages/cloud/src/http.ts
  • packages/cloud/src/index.ts
  • packages/cloud/src/sessions.test.ts
  • packages/cloud/src/sessions.ts
  • skills/deepnote/references/cli-run.md
🚧 Files skipped from review as they are similar to previous changes (10)
  • packages/cloud/src/index.ts
  • packages/cli/README.md
  • packages/cli/src/completions.ts
  • packages/cli/src/commands/run.ts
  • packages/cli/src/cli.ts
  • packages/cloud/src/http.test.ts
  • packages/cloud/src/create-project.ts
  • packages/cloud/src/http.ts
  • packages/cloud/src/sessions.test.ts
  • packages/cloud/src/sessions.ts

Comment threadpackages/cloud/README.md Outdated
Comment threadpackages/cloud/README.md Outdated
Comment threadskills/deepnote/references/cli-run.md Outdated
coderabbitai[bot]
coderabbitaiBot previously approved these changes Jul 27, 2026
@jamesbhobbs

Copy link
Copy Markdown
ContributorAuthor

Verified against a live workspace

Ran it for real (workspace Deepnote, examples/1_hello_world.deepnoteprint("Hello world!"), no integrations). This was the outstanding item keeping the PR in draft.

The critical assumption holds. A session run is pollable via GET /v2/runs/{id}:

[debug] Created session 2260ab93-… (copy 82464908d08a4c9a8917e35ea803c163)
[debug] Started run 32ee15b3-… for notebook 7061f86dec6e4e11893288f295a82017
✓ Run 32ee15b3-… completed (success)
Snapshot saved to examples/snapshots/hello-world_…_latest.snapshot.deepnote

Exit 0. Snapshot contained the real Hello world! stdout. Session cleanup worked — GET /v2/sessions/{id}/status afterwards returns 404. The --session --block guard refuses before making any API call.

Two documented claims were wrong, corrected in 3621afc.

Source notebook before vs after:

beforeafter
blocks1 blockidentical✅ isolated
updatedAt2025-11-04T05:24:57.117Zunchanged✅ isolated
lastRunAtnull2026-07-27T17:29:38.031Zchanged
lastRunIdnull32ee15b3-…changed

And the run appears in the source notebook’s history:

GET /v2/notebooks/7061f86d…/runs
{"runs":[{"runId":"32ee15b3-…","notebookId":"82464908…","status":"success",}]}

— attributed to the copy, but listed under the source notebook. So the isolation covers the notebook’s content, not the fact that it ran: anyone looking at the notebook sees it was just run. The docs previously said the run "leaves that document untouched", and framed the not-private caveat as an inference from the spec rather than an observation. Both now state what was measured.

Test artifacts cleaned up; the repo is unchanged. The API key used for this has been reported back for revocation.

Nothing outstanding from my side now — this is ready to come out of draft whenever you are happy with it.

coderabbitai[bot]
coderabbitaiBot previously approved these changes Jul 27, 2026
coderabbitai[bot]
coderabbitaiBot previously approved these changes Jul 27, 2026
@jamesbhobbs

Copy link
Copy Markdown
ContributorAuthor

Second live pass — non-happy paths

Ran against a real workspace using a disposable project I created and deleted (zz-cli-session-test), so no existing notebooks were touched. Six paths, all previously unverified.

PathResult
--session + --notebook-id, no local file✅ works
Notebook that raises✗ error, exit 1, partial snapshot with the real ValueError traceback
-o json with --session✅ stdout stays pure JSON — no session chatter leaks in
--input with --sessiongreeting is OVERRIDDEN-VALUE — override reaches the run
storageMode: readonlyproven by A/B, see below
Ctrl-C mid-run✅ exit 130, session stopped, ~5s

readonly is real. Same notebook, same block (open("readonly_probe.txt","w")):

  • with --sessionOSError: [Errno 30] Read-only file system: 'readonly_probe.txt'
  • without --session → succeeds

Two defects this found — both mine, both fixed in 90a149d

1. The Ctrl-C fix I added yesterday was reporting false alarms.DELETE /v2/sessions/{id} routinely takes longer than the 5s signal deadline, because stopping a session means shutting a machine down. The session was gone every time (/status → 404), but the CLI printed "could not stop … it will keep running; stop it from the Deepnote UI". A timeout now says the stop was not confirmed and almost certainly worked; real failures keep the strong warning.

2. My justification for refusing --session --block was half wrong. I wrote that translating source block ids to the copy would be "positional guesswork". It is not — every block in the session copy carries metadata.source_block_id naming its origin, so it is a lookup. The refusal still stands, but on one ground rather than two: a session starts running the whole notebook on creation, so interrupting it to run a single block is a race the notebook can win. Corrected in the code comment and the docs, and noted in SubmitSessionRunBody.blockIds for anyone who does need the mapping (flagged as observed, not published schema).

Process note

The first Ctrl-C run appeared to pass — exit 130, session cleaned up — but the binary was stale: I had never rebuilt dist/ after the fix, so I was testing the previous version. The missing log line gave it away. Rebuilt and re-ran; that is when the false-alarm bug surfaced.

2686 tests green, exit 0. Scratch project deleted, repo clean. Everything I listed as unverified is now verified.

coderabbitai[bot]
coderabbitaiBot previously approved these changes Jul 27, 2026
coderabbitai[bot]
coderabbitaiBot previously approved these changes Jul 27, 2026
@jamesbhobbs
jamesbhobbs marked this pull request as ready for review July 27, 2026 18:24
@jamesbhobbs
jamesbhobbs requested a review from a team as a code ownerJuly 27, 2026 18:24

@dinohamzicdinohamzic 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 before manual testing:

I’d request changes on PR #433. The internal comparison invalidates the CLI flag’s main premise and exposes two lifecycle blockers.

Findings

  1. [P1] Full-notebook --cloud already provides the advertised notebook isolation.cloud-runs.ts relies on the API’s default detached: true; internal then duplicates the notebooks and executes the copy. Both ordinary detached and session runs update source run history. The real unique behavior here is read-only project storage, which ordinary /v2/runs already supports via detachedRunStorageMode: 'readonly' (internal contract). Exposing that field would avoid an interactive session’s overhead, feature gate, and cleanup lifecycle. --cloud --block is the exception because it switches to live mode.

  2. [P1] Ctrl-C or timeout during session creation can orphan a machine.run-in-cloud.ts awaits createSession() before installing signal handlers or retaining the session ID. If the process exits or the 30-second HTTP deadline fires while internal is still copying/dispatching, no DELETE can be issued and the session runs until expiry.

  3. [P1] Snapshot handling can turn successful sessions into failures. Internal commits terminal status before asynchronously finalizing the snapshot, but the CLI performs only one immediate retry at run-in-cloud.ts. There is also a deterministic case: empty/markdown-only sessions create a successful no-op run with no snapshot at all. Both paths become exit 1. Snapshot availability needs bounded polling, plus an explicit no-op artifact policy.

  4. [P2] The HTTP extraction leaves the exact timeout bug it claims to fix.cloud-runs.ts and line 330 still use options.signal ?? AbortSignal.timeout(...), so supplying a caller signal disables requestTimeoutMs. getRun and listNotebookRuns should migrate to the shared helper.

  5. [P2] Error-body reads suppress cancellation.http.ts catches every response.text() rejection. If a non-2xx body stalls, a timeout or caller abort is converted into an ApiError, contradicting the documented cancellation contract.

  6. [P2] The README imports a nonexistent getNotebook.packages/cloud/README.md cannot compile against this branch because that function is neither implemented nor exported.

  7. [P2] The README interrupts a submission before establishing its state. It queues a run, immediately interrupts, then claims the next run inherits the first submission’s state. Internal interrupt drains both running and pending runs for that notebook. The example must poll the submitted run to success first.

  8. [P3] Only Bash completion includes --session. The zsh and fish generators still omit it in completions.ts.

The remaining session endpoint paths, schemas, ID domains, statuses, and storageMode values match deepnote-internal.

@jamesbhobbs
jamesbhobbs marked this pull request as draft August 5, 2026 18:15
@coderabbitai

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@jamesbhobbsjamesbhobbs changed the title feat(cli): add --session to run a notebook in an interactive sessionfeat(cli): configure storage access for detached cloud runsAug 5, 2026

@coderabbitaicoderabbitaiBot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/completions.ts`:
- Line 118: Update the Bash completion generation around the COMPREPLY command
to detect when the previous token is --storage-mode and complete only the
read-write and readonly values instead of falling through to file completion.
Add an exact-output test covering this branch and its generated completion
script.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e42fdb0c-633f-47f3-bd4c-67865946362a

📥 Commits

Reviewing files that changed from the base of the PR and between f9f89d5 and 5479a93.

📒 Files selected for processing (12)
  • packages/cli/README.md
  • packages/cli/src/cli.test.ts
  • packages/cli/src/cli.ts
  • packages/cli/src/commands/run.ts
  • packages/cli/src/completions.ts
  • packages/cli/src/utils/run-in-cloud.test.ts
  • packages/cli/src/utils/run-in-cloud.ts
  • packages/cloud/README.md
  • packages/cloud/src/cloud-runs.test.ts
  • packages/cloud/src/cloud-runs.ts
  • packages/cloud/src/index.ts
  • skills/deepnote/references/cli-run.md

Comment threadpackages/cli/src/completions.ts
Sign up for freeto 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

@jamesbhobbs@dinohamzic