refactor(notebook): daemon-owned notebook loading — Phase 4 Tauri client#602
Merged
refactor(notebook): daemon-owned notebook loading — Phase 4 Tauri client#602
Conversation
…ayload Add initialize_notebook_sync_open and initialize_notebook_sync_create alongside the existing initialize_notebook_sync. These use connect_open_split/connect_create_split to delegate notebook loading to the daemon instead of parsing .ipynb locally. Extract setup_sync_receivers as the shared tail — stores the handle, spawns the 3 relay tasks (metadata, raw sync, broadcast), and emits daemon:ready with a DaemonReadyPayload containing notebook_id, cell_count, and needs_trust_approval. Add create_window_context_for_daemon which creates a WindowNotebookContext without requiring a fully-parsed NotebookState. Uses a minimal stub for transitional code that still reads notebook_state. Add runtime field to WindowNotebookContext so session save can read it directly instead of going through NotebookState. No callers yet — entry points are converted in subsequent commits.
…ading Switch open_notebook_window, spawn_new_notebook, and complete_onboarding to use create_notebook_window_for_daemon with OpenMode::Open/Create. - open_notebook_window: no longer calls load_notebook_state_for_path or parses .ipynb locally. Daemon loads the file. - spawn_new_notebook: no longer calls NotebookState::new_empty_with_runtime. Daemon creates the empty notebook. - complete_onboarding: same as spawn_new_notebook but with working_dir from ensure_notebooks_directory(). The old create_notebook_window/create_notebook_window_with_label are still used by run() startup and session restore (converted next).
…on-owned loading The main window and additional session windows now use daemon-owned loading instead of local NotebookState construction: - CLI path → OpenMode::Open (daemon loads .ipynb) - Session with path → OpenMode::Open (daemon loads) - Session untitled with env_id → OpenMode::Restore (reconnect to existing daemon room via old handshake) - No session, no path → OpenMode::Create (daemon creates empty notebook) Additional session windows use create_notebook_window_for_daemon instead of create_notebook_window_with_label, avoiding load_window_session_state and local .ipynb parsing. The async daemon sync init block now dispatches to the appropriate init function based on OpenMode instead of extracting cells/metadata from NotebookState. create_window_context (old version taking NotebookState) is now unused.
…oading When a .ipynb file is opened via Finder/dock icon on an empty main window, the handler now updates the context path and spawns initialize_notebook_sync_open instead of calling load_notebook_state_for_path. No local .ipynb parsing for the reuse-main-window case. The new-window case already goes through open_notebook_window (converted earlier).
Replace the get_cells() → FrontendCell conversion → initialize_notebook_sync chain with initialize_notebook_sync_open. The daemon just wrote the file, so OpenNotebook loads it right back without carrying cells across. This eliminates: - The last get_cells() call site on NotebookSyncHandle - The last FrontendCell usage in lib.rs - The CellSnapshot → FrontendCell conversion code - notebook_state.path sync-back (no longer needed) - Local notebook_id derivation in save-as (daemon canonicalizes) Dead code warnings now show: derive_notebook_id, notebook_state_for_window, create_notebook_window, create_notebook_window_with_label, create_window_context are all unused.
For saved notebooks, use initialize_notebook_sync_open (daemon reloads from disk). For untitled notebooks, use the old handshake with the notebook_id (env_id) so the daemon can find its persisted Automerge doc.
save_session now reads path from context.path, notebook_id from context.notebook_id (env_id for untitled), and runtime from context.runtime. No more locking NotebookState. Remove load_window_session_state — session restore now dispatches directly to OpenMode in run() without constructing NotebookState.
Remove all code that is no longer called now that every entry point uses daemon-owned loading: Deleted functions: - derive_notebook_id (daemon canonicalizes paths) - notebook_state_for_window (no code reads NotebookState) - create_notebook_window / create_notebook_window_with_label (replaced by _for_daemon) - create_new_notebook_state (daemon detects project files) - load_notebook_state_for_path (daemon loads .ipynb) - create_window_context (replaced by _for_daemon) Removed from WindowNotebookContext: - notebook_state field (session save reads Arc fields) Simplified initialize_notebook_sync: - Removed initial_cells and initial_metadata params (all callers passed empty) - Removed cell population loop (daemon populates the room) - Removed FrontendCell import (no longer used in lib.rs) The NotebookState stub in create_window_context_for_daemon is also gone — the context no longer holds any NotebookState. Net: -268 lines. Zero warnings.
…_window_for_daemon The placeholder_id was computed from path alone, which is None for Restore and Create variants — resulting in an empty notebook_id in the context. When reconnect_to_daemon later reads context.notebook_id, it connected to a room with empty ID instead of the env_id. Now derives placeholder_id from the OpenMode variant: - Open: canonical path (same as before) - Restore: notebook_id from the variant (the env_id) - Create: empty (daemon generates UUID) This fixes session restore for untitled notebooks showing as empty on reconnect.
new_fresh previously deleted all persisted docs unconditionally, treating .ipynb as the sole source of truth. For untitled notebooks (UUID-based notebook_ids), the persisted Automerge doc is their only content record — there's no .ipynb on disk. Now: for untitled notebooks, load the persisted doc if it exists so content survives daemon restarts. For saved notebooks, still delete the stale persisted doc and load from .ipynb (unchanged behavior). Add test verifying persisted docs are loaded for UUID notebook_ids.
rgbkrk
pushed a commit
that referenced
this pull request
Mar 8, 2026
rgbkrk
pushed a commit
that referenced
this pull request
Mar 8, 2026
Add findings from thorough analysis of all files: - Inconsistent daemon:ready for Restore path - Wrong runtime for opened notebooks - Heartbeat monitor connection churn and single-failure sensitivity - Empty notebook re-load issue - Error-path stream drain timeout - Silent poisoned mutex failures https://claude.ai/code/session_01H93XZZFaeq3fayDSwSdGkB
rgbkrk
pushed a commit
that referenced
this pull request
Mar 8, 2026
Add iopub task leak, doc write lock during I/O, runtime validation, and broadcast lag recovery gaps from daemon/kernel manager analysis. https://claude.ai/code/session_01H93XZZFaeq3fayDSwSdGkB
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.
Closes #598.
Switches all notebook creation/opening entry points from local
NotebookStateconstruction + relay population to daemon requests viaconnect_open_split/connect_create_split. Phases 1-3 and 5 were merged in PR #601; this PR completes Phases 4, 6, and 7.What changed
Every entry point that creates or opens a notebook now delegates to the daemon instead of parsing
.ipynblocally:open_notebook_windowload_notebook_state_for_path→ parse .ipynbOpenMode::Open→ daemon loadsspawn_new_notebook(Cmd-N)NotebookState::new_empty_with_runtimeOpenMode::Create→ daemon createscomplete_onboardingNotebookState::new_empty_with_runtimeOpenMode::Createrun()startup (CLI/session)load_notebook_state_for_pathornew_empty_with_runtimeOpenMode::Open/Create/Restoreload_window_session_state→ parse .ipynbOpenMode::Open/Create/Restoresave_notebook_asget_cells()→FrontendCellconversion → carry cellsinitialize_notebook_sync_open(daemon reloads from disk)load_notebook_state_for_pathinitialize_notebook_sync_openreconnect_to_daemoninitialize_notebook_sync_open(saved) or old handshake (untitled)What was deleted
notebook_statefield fromWindowNotebookContextderive_notebook_id— daemon canonicalizes pathscreate_notebook_window/create_notebook_window_with_label— replaced by_for_daemoncreate_new_notebook_state— daemon detects project filesload_notebook_state_for_path— daemon loads .ipynbcreate_window_context(old version) — replaced by_for_daemonload_window_session_statefromsession.rsinitialize_notebook_syncFrontendCellimport fromlib.rsget_cells()call insave_notebook_asArchitecture
Window creation is synchronous (appears immediately), daemon connection is async (spawned). The
notebook_idstarts as a placeholder and is updated when the daemon responds with the canonical ID.daemon:readynow carries aDaemonReadyPayload { notebook_id, cell_count, needs_trust_approval }.Untitled notebook session restore uses
OpenMode::Restorewhich reconnects via the legacyNotebookSynchandshake with the env_id — the daemon may have the Automerge doc persisted from the previous session.Test plan
New notebook creation
Opening existing notebooks
Save-as
[ ] Open the original path in a new window — old content still thereWe don't expose Save As as a base feature, it's just for untitled notebooks at the moment.Multi-window
Skipped due to existing bug for multiwindow
Session restore
Onboarding
~/.config/runt/settings.json) → onboarding flow → first notebook createdmacOS file associations
Skipping. Will test in Nightly release.
Reconnection
runt daemon stop), wait for disconnect banner, restart daemon — reconnectsEdge cases
Known limitations (deferred)
.ipynbnot persisted Automerge doc. Pre-existing behavior, tracked in fix: canonical document resolution on room creation (saved edits + trust) #604.NoDependenciesfor UUID paths. Tracked in fix: canonical document resolution on room creation (saved edits + trust) #604.Follow-ups
notebook_state.rsmodule still declared but unused fromlib.rs— delete in follow-updaemon:readypayload not consumed by frontend yet (feat: notebook loading state for daemon-owned doc population #599)