Skip to content

refactor: extract NotebookWorkspace from AppFileRouter#9448

Open
mscolnick wants to merge 2 commits intomainfrom
ms/feature/notebook-workspace
Open

refactor: extract NotebookWorkspace from AppFileRouter#9448
mscolnick wants to merge 2 commits intomainfrom
ms/feature/notebook-workspace

Conversation

@mscolnick
Copy link
Copy Markdown
Contributor

Replaces the conflated AppFileRouter with a NotebookWorkspace abstraction
plus four focused subclasses, deleting marimo/_server/file_router.py.

  • New marimo/_server/workspace/ package: EmptyWorkspace, SingleFileWorkspace,
    FixedFilesWorkspace, DirectoryWorkspace, plus infer_workspace().
  • Renamed methods to a clearer vocabulary: single_file(), resolve(), load(),
    set_include_markdown() (mutating), invalidate(), register_allowed_path().
  • SessionManager.workspace replaces .file_router; capability dispatch via
    no-op base methods removes isinstance checks in session_manager and home.
  • home.py no longer reassigns session_manager.workspace; toggling markdown
    mutates in place.

Copilot AI review requested due to automatic review settings May 4, 2026 17:03
@vercel
Copy link
Copy Markdown

vercel Bot commented May 4, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment May 7, 2026 8:34pm

Request Review

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 38 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="marimo/_server/workspace/_empty.py">

<violation number="1" location="marimo/_server/workspace/_empty.py:43">
P2: `resolve` returns the raw `key` without normalizing it to an absolute path. The base-class contract specifies "Resolve a key to an absolute path" and the sibling workspaces (`SingleFileWorkspace`, `DirectoryWorkspace`) normalize via `normalize_path`. Returning a relative or non-canonical path here can cause mismatches in downstream comparisons (e.g., session lookups keyed on absolute paths).</violation>
</file>
Architecture diagram
sequenceDiagram
    participant CLI as CLI / Start Module
    participant SM as SessionManager
    participant WS as NotebookWorkspace (Abstract)
    participant SWS as Specific Workspace (Dir/Single/Fixed/Empty)
    participant AFM as AppFileManager

    Note over CLI, SWS: Initialization Flow
    CLI->>WS: NEW: infer_workspace(path)
    WS-->>CLI: Return Concrete Workspace (e.g., DirectoryWorkspace)
    CLI->>SM: Initialize SessionManager(workspace)

    Note over SM, SWS: File Listing & Capability Flow (Home API)
    SM->>SWS: CHANGED: invalidate() (if stale)
    SM->>SWS: NEW: set_include_markdown(bool)
    SWS->>SWS: Mutate scanner state in-place
    SM->>SWS: get files
    SWS-->>SM: Return List[FileInfo]

    Note over SM, AFM: Notebook Loading Flow
    SM->>WS: CHANGED: load(file_key, defaults)
    WS->>SWS: CHANGED: resolve(file_key)
    
    alt key is valid and allowed
        SWS-->>WS: Return absolute path
        WS->>AFM: Instantiate AppFileManager(resolved_path)
        AFM-->>WS: manager
        WS-->>SM: manager
    else key not in allowlist / directory
        SWS-->>WS: Raise HTTPException(404/403)
        WS-->>SM: Error
    end

    Note over SM, SWS: Runtime Allowlist Management (Edit Mode)
    opt NEW_FILE or new notebook created
        SM->>SWS: NEW: register_allowed_path(path)
        SWS->>SWS: Update internal allowlist
    end
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Comment thread marimo/_server/workspace/_empty.py
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the server’s notebook “file routing” into a new NotebookWorkspace abstraction with focused workspace implementations, removing the legacy AppFileRouter and updating server/CLI codepaths and tests accordingly.

Changes:

  • Introduces marimo._server.workspace with EmptyWorkspace, SingleFileWorkspace, FixedFilesWorkspace, DirectoryWorkspace, and infer_workspace().
  • Updates SessionManager, server startup, and API endpoints to depend on workspace capabilities (with no-op defaults) instead of file_router and isinstance branching.
  • Migrates and expands test coverage to validate workspace behavior and key security invariants (path traversal, temp-dir allowlisting, __new__ handling).

Reviewed changes

Copilot reviewed 38 out of 38 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/_server/test_workspace.py Migrates router tests to workspace tests; adds coverage for workspace security and capability no-ops.
tests/_server/test_sessions.py Updates session tests to construct SessionManager with SingleFileWorkspace.
tests/_server/test_session_manager.py Replaces AppFileRouter usage with EmptyWorkspace/infer_workspace/NEW_FILE.
tests/_server/test_file_manager_absolute_path.py Updates absolute/relative directory behavior tests to use DirectoryWorkspace.load().
tests/_server/rtc/test_rtc_doc.py Moves MarimoFileKey import to workspace module.
tests/_server/mocks.py Renames router-scoped helpers to workspace_scope / with_workspace.
tests/_server/api/endpoints/test_ws.py Uses session_manager.workspace for unique key and patching.
tests/_server/api/endpoints/test_ws_rtc.py Uses session_manager.workspace for RTC file keys.
tests/_server/api/endpoints/test_resume_session.py Switches to workspace.get_single_app_file_manager() / workspace.get_unique_file_key().
tests/_server/api/endpoints/test_home.py Updates home endpoint integration tests to swap DirectoryWorkspace / FixedFilesWorkspace.
tests/_server/api/endpoints/test_files.py Updates endpoint tests to reference workspace and its directory.
tests/_server/api/endpoints/test_file_explorer.py Updates file explorer test to use workspace.get_unique_file_key().
tests/_server/api/endpoints/test_assets.py Updates assets/index tests to use workspace_scope and workspace implementations.
tests/_cli/test_cli.py Updates CLI tests for _create_run_workspace() returning workspace implementations.
marimo/_session/session_repository.py Updates typing import to MarimoFileKey from workspace.
marimo/_server/workspace/_single.py Adds SingleFileWorkspace with allowlist + register_allowed_path() support.
marimo/_server/workspace/_fixed.py Adds FixedFilesWorkspace for fixed allowlists (run-mode snapshots / multi-file runs).
marimo/_server/workspace/_empty.py Adds EmptyWorkspace for marimo new semantics with permissive fallback.
marimo/_server/workspace/_directory.py Adds DirectoryWorkspace backed by DirectoryScanner + PathValidator + caching.
marimo/_server/workspace/_base.py Defines NotebookWorkspace API, NEW_FILE, shared helpers, and capability no-ops.
marimo/_server/workspace/init.py Exposes workspace implementations and infer_workspace().
marimo/_server/start.py Updates server start signature and logic to accept a NotebookWorkspace.
marimo/_server/session_manager.py Replaces file-router usage with workspace and capability dispatch.
marimo/_server/rtc/doc.py Updates typing import to MarimoFileKey from workspace.
marimo/_server/resume_strategies.py Updates typing import to MarimoFileKey from workspace.
marimo/_server/file_router.py Deletes legacy AppFileRouter implementation.
marimo/_server/asgi.py Updates ASGI file-app creation to use SingleFileWorkspace.
marimo/_server/api/lifespans.py Updates startup logging to use workspace and NEW_FILE.
marimo/_server/api/endpoints/ws/ws_rtc_handler.py Updates typing import to MarimoFileKey from workspace.
marimo/_server/api/endpoints/ws/ws_kernel_ready.py Updates typing import to MarimoFileKey from workspace.
marimo/_server/api/endpoints/ws/ws_connection_validator.py Uses workspace.get_unique_file_key() for default file key resolution.
marimo/_server/api/endpoints/home.py Uses workspace helpers; switches markdown toggling to in-place mutation.
marimo/_server/api/endpoints/files.py Resolves relative paths against workspace.directory.
marimo/_server/api/endpoints/file_explorer.py Uses workspace.directory as default root.
marimo/_server/api/endpoints/execution.py Uses workspace.get_unique_file_key() for restart/takeover/shutdown logic.
marimo/_server/api/endpoints/assets.py Uses workspace.resolve() and workspace.directory for thumbnails/index.
marimo/_cli/export/_common.py Imports flatten_files from workspace module.
marimo/_cli/cli.py Switches CLI to infer_workspace() / _create_run_workspace() and passes workspace into start().

mscolnick added 2 commits May 7, 2026 13:31
Replaces the conflated AppFileRouter with a NotebookWorkspace abstraction
plus four focused subclasses, deleting marimo/_server/file_router.py.

- New marimo/_server/workspace/ package: EmptyWorkspace, SingleFileWorkspace,
  FixedFilesWorkspace, DirectoryWorkspace, plus infer_workspace().
- Renamed methods to a clearer vocabulary: single_file(), resolve(), load(),
  set_include_markdown() (mutating), invalidate(), register_allowed_path().
- SessionManager.workspace replaces .file_router; capability dispatch via
  no-op base methods removes isinstance checks in session_manager and home.
- home.py no longer reassigns session_manager.workspace; toggling markdown
  mutates in place.
Match the base-class contract and sibling workspaces — relative keys could
otherwise mismatch with absolute paths in downstream session lookups.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants