feat(runtimed): Phase 1.4 - delegate save-to-disk to daemon#545
Merged
Conversation
Part of Phase 1.4 - delegate save-to-disk to daemon. - Add `path: Option<String>` to `SaveNotebook` request - Add `path: String` to `NotebookSaved` response (returns saved path) - Refactor `save_notebook_to_disk()` to accept optional target path - Add `save(path=None)` to AsyncSession and Session Python bindings When `path` is provided, daemon saves to that path (with .ipynb appended if needed, converted to absolute). When `path` is None, saves to the room's original notebook_path.
Part of Phase 1.4 - daemon save is now required. - Remove local fallback from save_notebook - daemon save is now required - Update save_notebook_as to use daemon with path parameter - Remove NotebookState::serialize() calls from save commands - Daemon must be connected for save operations to succeed
Address reviewer feedback on PR #545: - 🔴 Format-on-save now writes to Automerge (not NotebookState) - Added format_notebook_cells() in daemon using ruff/deno fmt - Daemon updates Automerge doc with formatted sources - Removed client-side formatting loop from save_notebook/save_notebook_as - Clients send format_cells: true, receive synced formatted sources - High: Save As now uses daemon-returned path - Use saved_path from NotebookSaved response for nb.path, ctx.path, window title - Handles daemon normalizations (e.g., appending .ipynb extension) - Medium: Reject relative paths in daemon - Return error instead of joining with unpredictable daemon CWD - Clients (Tauri file dialog, Python SDK) should provide absolute paths
Address additional reviewer feedback: - Skip formatting for unknown kernelspec instead of defaulting to Python - Prevents incorrectly reformatting non-Python/Deno notebooks - Logs info message when skipping - Add tests for new save_notebook_to_disk behavior: - test_save_notebook_to_disk_with_target_path: absolute path saves - test_save_notebook_to_disk_appends_ipynb_extension: extension handling - test_save_notebook_to_disk_rejects_relative_path: error on relative - test_format_notebook_cells_skips_unknown_runtime: format skip behavior
The trust signature was being lost during Save As because it wasn't part of the typed RuntMetadata struct. When saving to a new path, the typed NotebookMetadataSnapshot serialization would omit trust fields that existed in the raw Automerge JSON. Adding trust_signature and trust_timestamp as optional fields to RuntMetadata ensures they are properly serialized/deserialized and preserved during Save As operations. This fixes notebooks showing as "Untrusted" after Save As even when the user had already approved the dependencies.
This was referenced Mar 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Moves notebook save-to-disk from the Tauri process to the daemon, eliminating the last major
NotebookStateconsumer. The daemon already owns the canonical Automerge document, making it the ideal place to serialize notebooks to disk.Key changes:
pathparameter toSaveNotebookprotocol requestNotebookSavedresponseNotebookState::serialize()fallback — daemon save is now requiredsave(path=None)to Python bindings for MCP server useImplementation details
save_notebook: Requires daemon connection; sendsSaveNotebook { path: None }to use room's notebook_pathsave_notebook_as: SendsSaveNotebook { path: Some(new_path) }to daemon, handles path updates and sync reconnectionsave_notebook_to_disk()to accept optional target path and return the saved pathAsyncSessionandSessionVerification
cargo fmt— Rust formattingnpx @biomejs/biome check --fix— TypeScript/JavaScript lintingcargo clippy --all-targets -- -D warnings— No clippy warningscargo test --verbose— All 171 tests passReviewer checklist:
session.save(path)returns absolute pathPR submitted by @rgbkrk's agent, Quill