From e6f0e8d2fa1e5b9b00bccbc1b75097b683605dee Mon Sep 17 00:00:00 2001 From: Riya Sinha Date: Thu, 9 Oct 2025 22:44:27 -0500 Subject: [PATCH 1/7] add build for docker with updated fe --- docker/Dockerfile | 4 +- docker/Dockerfile.local | 67 ++++++++++++ docker/Dockerfile.simple | 35 ++++++ docker/README_AGENTS.md | 223 +++++++++++++++++++++++++++++++++++++++ docker/build_agents.sh | 89 ++++++++++++++++ pyproject.toml | 2 +- 6 files changed, 417 insertions(+), 3 deletions(-) create mode 100644 docker/Dockerfile.local create mode 100644 docker/Dockerfile.simple create mode 100644 docker/README_AGENTS.md create mode 100755 docker/build_agents.sh diff --git a/docker/Dockerfile b/docker/Dockerfile index 1d93de836c8..c7fd1737925 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -9,10 +9,10 @@ RUN useradd -m appuser WORKDIR /app -ARG marimo_version=0.12.8 +ARG marimo_version=0.16.5.1 ENV MARIMO_SKIP_UPDATE_CHECK=1 ENV UV_SYSTEM_PYTHON=1 -RUN uv pip install --no-cache-dir marimo==${marimo_version} && \ +RUN uv pip install --no-cache-dir marimo_agents==${marimo_version} && \ mkdir -p /app/data && \ chown -R appuser:appuser /app diff --git a/docker/Dockerfile.local b/docker/Dockerfile.local new file mode 100644 index 00000000000..014c74038b3 --- /dev/null +++ b/docker/Dockerfile.local @@ -0,0 +1,67 @@ +# syntax=docker/dockerfile:1.12 +FROM node:20-slim AS frontend-builder + +# Build frontend assets +WORKDIR /app +COPY package.json pnpm-lock.yaml pnpm-workspace.yaml tsconfig.json turbo.json ./ +COPY frontend/package.json frontend/tsconfig.json frontend/vite.config.mts frontend/tailwind.config.cjs frontend/postcss.config.cjs ./frontend/ +COPY packages/*/package.json ./packages/*/ +COPY patches ./patches + +# Install pnpm and dependencies +RUN npm install -g pnpm +RUN pnpm install --frozen-lockfile + +# Copy frontend source and build +COPY frontend ./frontend +COPY packages ./packages +RUN cd frontend && pnpm build + +# Python build stage +FROM python:3.13-slim AS python-builder + +# Make `uv` available +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ + +WORKDIR /app + +# Copy Python source +COPY pyproject.toml ./ +COPY marimo ./marimo +COPY README.md LICENSE ./ + +# Copy built frontend assets from previous stage +COPY --from=frontend-builder /app/frontend/dist ./marimo/_static + +# Install the package +ENV UV_SYSTEM_PYTHON=1 +RUN uv pip install --no-cache-dir -e . + +# Runtime stage +FROM python:3.13-slim AS runtime + +# Make `uv` available +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ + +# Create non-root user +RUN useradd -m appuser + +# Copy installed package from builder +COPY --from=python-builder /usr/local/lib/python3.13/site-packages /usr/local/lib/python3.13/site-packages +COPY --from=python-builder /usr/local/bin /usr/local/bin + +WORKDIR /app + +# Copy tutorials +COPY --chown=appuser:appuser marimo/_tutorials tutorials +RUN rm -rf tutorials/__init__.py + +# Set up directories and permissions +RUN mkdir -p /app/data && chown -R appuser:appuser /app + +ENV PORT=8080 +EXPOSE $PORT +ENV HOST=0.0.0.0 +ENV MARIMO_SKIP_UPDATE_CHECK=1 + +CMD ["marimo", "edit", "--no-token", "-p", "8080", "--host", "0.0.0.0"] \ No newline at end of file diff --git a/docker/Dockerfile.simple b/docker/Dockerfile.simple new file mode 100644 index 00000000000..6490b28a877 --- /dev/null +++ b/docker/Dockerfile.simple @@ -0,0 +1,35 @@ +# syntax=docker/dockerfile:1.12 +FROM python:3.13-slim AS runtime + +# Make `uv` available +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ + +WORKDIR /app + +# Copy Python source +COPY pyproject.toml README.md LICENSE ./ +COPY marimo ./marimo + +# Install the package with pre-built frontend assets +ENV UV_SYSTEM_PYTHON=1 +RUN uv pip install --no-cache-dir -e . + +# Create non-root user +RUN useradd -m appuser + +# Copy tutorials +COPY --chown=appuser:appuser marimo/_tutorials tutorials +RUN rm -rf tutorials/__init__.py + +# Set up directories and permissions +RUN mkdir -p /app/data && chown -R appuser:appuser /app + +ENV PORT=8080 +EXPOSE $PORT +ENV HOST=0.0.0.0 +ENV MARIMO_SKIP_UPDATE_CHECK=1 + +# Switch to non-root user +USER appuser + +CMD ["marimo", "edit", "--no-token", "-p", "8080", "--host", "0.0.0.0"] \ No newline at end of file diff --git a/docker/README_AGENTS.md b/docker/README_AGENTS.md new file mode 100644 index 00000000000..1d2c5ebb568 --- /dev/null +++ b/docker/README_AGENTS.md @@ -0,0 +1,223 @@ +# Marimo Agents Docker Setup + +This directory contains Docker configurations and scripts for building and running marimo with agents functionality. + +## Overview + +The marimo-agents fork includes AI agent functionality with a complete frontend. This setup provides Docker containers that include both the Python backend and the bundled frontend assets. + +## Architecture + +The build process follows these key steps: + +1. **Frontend Build**: Build the React/TypeScript frontend locally using pnpm +2. **Asset Bundling**: Copy frontend assets to `marimo/_static/` for packaging +3. **Docker Build**: Create container with Python package including bundled assets +4. **Distribution**: Publish to PyPI with complete frontend included + +## Files + +- `Dockerfile.simple` - Simplified Docker build that uses pre-built frontend assets +- `Dockerfile.local` - Full Docker build with frontend compilation (may have dependency issues) +- `build_agents.sh` - Complete build script for marimo-agents +- `run_agents.sh` - Script to run the marimo-agents Docker container +- `README_AGENTS.md` - This documentation + +## Quick Start + +### Option 1: Use Pre-built Package from PyPI + +```bash +# Build Docker image using published package +docker build -t marimo-agents-simple -f docker/Dockerfile.simple . + +# Run the container +docker run -p 8081:8080 marimo-agents-simple + +# Access marimo at http://localhost:8081 +``` + +### Option 2: Build Complete Package Locally + +```bash +# Run the complete build process +./docker/build_agents.sh + +# Run the container +./docker/run_agents.sh + +# Access marimo at http://localhost:8081 +``` + +## Build Process Details + +### 1. Frontend Build + +The frontend is built using pnpm and Turbo: + +```bash +cd frontend +pnpm install +pnpm build +``` + +This generates ~36MB of assets including: + +- Main JavaScript bundle (~629KB) +- React Plotly bundle (~4.7MB) +- Node SQL Parser bundle (~2.6MB) +- Hundreds of additional language and theme assets + +### 2. Asset Integration + +Frontend assets are copied to the Python package: + +```bash +bash scripts/buildfrontend.sh +``` + +This script: + +- Removes old static files from `marimo/_static/` +- Copies new built assets from `frontend/dist/` +- Results in ~36MB of bundled frontend assets + +### 3. Package Building + +The Python package is built with bundled assets: + +```bash +python -m build +``` + +This creates a ~33MB wheel file containing both Python code and frontend assets. + +### 4. Docker Image + +The Docker image includes: + +- Python 3.11+ runtime +- Complete marimo-agents package +- All frontend assets +- Agent functionality + +## Docker Images + +### Dockerfile.simple (Recommended) + +Uses the pre-built package from PyPI or local wheel: + +```dockerfile +FROM python:3.11-slim +RUN pip install marimo-agents +EXPOSE 8080 +CMD ["marimo", "edit", "--host", "0.0.0.0", "--port", "8080", "--no-token"] +``` + +**Pros:** + +- Fast build time +- Reliable (uses tested package) +- Small final image + +**Cons:** + +- Requires package to be published or locally built + +### Dockerfile.local + +Builds everything from source including frontend: + +```dockerfile +# Multi-stage build with Node.js and Python +``` + +**Pros:** + +- Self-contained build +- No external dependencies + +**Cons:** + +- Complex dependency resolution +- Longer build time +- May fail on frontend dependencies + +## Agent Functionality + +The Docker image includes full agent support: + +```python +import marimo as mo + +# Register an agent +def my_agent(query: str) -> str: + return f"Agent response to: {query}" + +mo.ai.agents.register_agent(my_agent, name="my-agent") + +# Use in cells +result = mo.ai.agents.run_agent("my-agent", "Hello!") +``` + +## Troubleshooting + +### Frontend Build Issues + +If local frontend build fails: + +```bash +# Clean and rebuild +cd frontend +rm -rf node_modules dist +pnpm install +pnpm build +``` + +### Docker Build Issues + +If Docker build fails: + +1. Ensure frontend assets are built locally first +2. Use `Dockerfile.simple` instead of `Dockerfile.local` +3. Check that `marimo/_static/assets` contains ~36MB of files + +### Container Runtime Issues + +If container won't start: + +1. Check Python version compatibility (requires 3.10+) +2. Verify frontend assets are included +3. Check port conflicts (default 8081) + +## Development Workflow + +For active development: + +1. Make code changes +2. Rebuild frontend: `cd frontend && pnpm build` +3. Copy assets: `bash scripts/buildfrontend.sh` +4. Rebuild Docker: `docker build -t marimo-agents-simple -f docker/Dockerfile.simple .` +5. Test: `docker run -p 8081:8080 marimo-agents-simple` + +## Production Deployment + +For production use: + +1. Build and publish package: `python -m build && hatch publish` +2. Use published package in Dockerfile.simple +3. Deploy with proper networking and persistence configurations + +## Package Sizes + +- Frontend assets: ~36MB +- Python wheel: ~33MB +- Docker image: ~150MB (with Python runtime) +- Published PyPI package: ~35MB + +## Compatibility + +- **Python**: 3.10+ (uses modern union syntax `str | None`) +- **Node.js**: 20+ (for frontend build) +- **Docker**: Any recent version +- **Browsers**: Modern browsers with ES2020+ support diff --git a/docker/build_agents.sh b/docker/build_agents.sh new file mode 100755 index 00000000000..511d863fc8b --- /dev/null +++ b/docker/build_agents.sh @@ -0,0 +1,89 @@ +#!/bin/bash +set -e + +echo "🚀 Building marimo-agents complete package..." + +# Check if we're in the right directory +if [[ ! -f "pyproject.toml" ]]; then + echo "❌ Error: Must run from marimo project root directory" + exit 1 +fi + +# Check if frontend directory exists +if [[ ! -d "frontend" ]]; then + echo "❌ Error: frontend directory not found" + exit 1 +fi + +echo "📦 Step 1: Installing frontend dependencies..." +cd frontend +if ! command -v pnpm &> /dev/null; then + echo "❌ Error: pnpm not found. Please install pnpm first:" + echo " npm install -g pnpm" + exit 1 +fi + +pnpm install + +echo "🔨 Step 2: Building frontend assets..." +pnpm build + +echo "📁 Frontend build completed. Assets generated in frontend/dist/" + +cd .. + +echo "📋 Step 3: Copying frontend assets to marimo/_static/..." +if [[ ! -f "scripts/buildfrontend.sh" ]]; then + echo "❌ Error: scripts/buildfrontend.sh not found" + exit 1 +fi + +bash scripts/buildfrontend.sh + +echo "✅ Frontend assets copied to marimo/_static/" + +echo "📦 Step 4: Building Python package..." +if ! command -v python &> /dev/null; then + echo "❌ Error: python not found" + exit 1 +fi + +# Install build if not available +if ! python -c "import build" 2>/dev/null; then + echo "Installing build package..." + pip install build +fi + +python -m build + +echo "📊 Step 5: Checking package size..." +if [[ -d "dist" ]]; then + latest_wheel=$(ls -t dist/*.whl | head -1) + if [[ -n "$latest_wheel" ]]; then + wheel_size=$(du -h "$latest_wheel" | cut -f1) + echo "✅ Package built: $latest_wheel ($wheel_size)" + fi +fi + +echo "🐳 Step 6: Building Docker image..." +docker build -t marimo-agents-simple -f docker/Dockerfile.simple . + +echo "✅ Step 7: Verifying Docker image..." +echo "Testing Docker image startup..." +timeout 10s docker run --rm marimo-agents-simple marimo --help > /dev/null || true + +echo "" +echo "🎉 Build complete!" +echo "" +echo "📋 What was built:" +echo " • Frontend assets: $(du -sh marimo/_static/assets | cut -f1)" +echo " • Python package: $(ls -t dist/*.whl | head -1)" +echo " • Docker image: marimo-agents-simple" +echo "" +echo "🚀 To run:" +echo " docker run -p 8081:8080 marimo-agents-simple" +echo " Then visit: http://localhost:8081" +echo "" +echo "📦 To publish to PyPI:" +echo " hatch publish" +echo "" \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 206b9ffbaec..454842809d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "uv_build" [project] name = "marimo-agents" -version = "0.16.5.0" +version = "0.16.5.1" description = "A Marimo concept fork with some support for LLM execution as cells" # We try to keep dependencies to a minimum, to avoid conflicts with # user environments;we need a very compelling reason for each dependency added. From 9f5b6797c33a5101c579d06a53d177662a0bad56 Mon Sep 17 00:00:00 2001 From: Riya Sinha Date: Fri, 10 Oct 2025 14:25:46 -0500 Subject: [PATCH 2/7] add option to lock homepage during marimo edit --- .../editor/actions/useNotebookActions.tsx | 8 +++-- frontend/src/core/config/config-schema.ts | 7 +++- frontend/src/core/config/config.ts | 26 ++++++++++++++ frontend/src/core/islands/main.ts | 4 +++ marimo/_cli/cli.py | 10 ++++++ marimo/_config/config.py | 4 +++ marimo/_config/settings.py | 1 + marimo/_server/api/endpoints/assets.py | 12 +++++++ marimo/_server/api/endpoints/config.py | 35 +++++++++++++++++++ 9 files changed, 103 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/editor/actions/useNotebookActions.tsx b/frontend/src/components/editor/actions/useNotebookActions.tsx index 748ea3de4f1..b135e10d671 100644 --- a/frontend/src/components/editor/actions/useNotebookActions.tsx +++ b/frontend/src/components/editor/actions/useNotebookActions.tsx @@ -55,7 +55,7 @@ import { useCellActions, } from "@/core/cells/cells"; import { disabledCellIds, enabledCellIds } from "@/core/cells/utils"; -import { useResolvedMarimoConfig } from "@/core/config/config"; +import { useResolvedMarimoConfig, useServerConfig } from "@/core/config/config"; import { Constants } from "@/core/constants"; import { useLayoutActions, useLayoutState } from "@/core/layout/layout"; import { useTogglePresenting } from "@/core/layout/useTogglePresenting"; @@ -97,6 +97,7 @@ export function useNotebookActions() { const kioskMode = useAtomValue(kioskModeAtom); const hideAllMarkdownCode = useHideAllMarkdownCode(); const [resolvedConfig] = useResolvedMarimoConfig(); + const serverConfig = useServerConfig(); const { updateCellConfig, @@ -512,8 +513,9 @@ export function useNotebookActions() { icon: , label: "Return home", // If file is in the url, then we ran `marimo edit` - // without a specific file - hidden: !location.search.includes("file"), + // without a specific file, or if homepage is disabled + hidden: + !location.search.includes("file") || serverConfig.disable_home_page, handle: () => { const withoutSearch = document.baseURI.split("?")[0]; window.open(withoutSearch, "_self"); diff --git a/frontend/src/core/config/config-schema.ts b/frontend/src/core/config/config-schema.ts index c1b8007c0d0..4990989f45c 100644 --- a/frontend/src/core/config/config-schema.ts +++ b/frontend/src/core/config/config-schema.ts @@ -182,7 +182,11 @@ export const UserConfigSchema = z }) // Pass through so that we don't remove any extra keys that the user has added. .prefault(() => ({})), - server: z.looseObject({}).prefault(() => ({})), + server: z + .looseObject({ + disable_home_page: z.boolean().optional(), + }) + .prefault(() => ({})), sharing: z .looseObject({ html: z.boolean().optional(), @@ -218,6 +222,7 @@ export type LSPConfig = UserConfig["language_servers"]; export type DiagnosticsConfig = UserConfig["diagnostics"]; export type DisplayConfig = UserConfig["display"]; export type AiConfig = UserConfig["ai"]; +export type ServerConfig = UserConfig["server"]; export const AppTitleSchema = z.string(); export const SqlOutputSchema = z diff --git a/frontend/src/core/config/config.ts b/frontend/src/core/config/config.ts index c786acdeb9c..bc7ced4d725 100644 --- a/frontend/src/core/config/config.ts +++ b/frontend/src/core/config/config.ts @@ -3,6 +3,8 @@ import { atom, useAtom, useAtomValue, useSetAtom } from "jotai"; import { merge } from "lodash-es"; import { OverridingHotkeyProvider } from "../hotkeys/hotkeys"; import { type Platform, resolvePlatform } from "../hotkeys/shortcuts"; +import { Logger } from "../../utils/Logger"; +import { API } from "../network/api"; import { store } from "../state/jotai"; import { type AppConfig, @@ -48,6 +50,26 @@ export const aiAtom = atom((get) => { return get(resolvedMarimoConfigAtom).ai; }); +export const serverConfigAtom = atom(async () => { + try { + const response = await API.get<{ disable_home_page: boolean }>( + "/kernel/server_config", + ); + return { + disable_home_page: response?.disable_home_page ?? false, + browser: "default", + follow_symlink: false, + }; + } catch (error) { + Logger.warn("Failed to fetch server config:", error); + return { + disable_home_page: false, + browser: "default", + follow_symlink: false, + }; + } +}); + export const completionAtom = atom((get) => { return get(resolvedMarimoConfigAtom).completion; }); @@ -74,6 +96,10 @@ export function getResolvedMarimoConfig() { return store.get(resolvedMarimoConfigAtom); } +export function useServerConfig() { + return useAtomValue(serverConfigAtom); +} + export const aiEnabledAtom = atom((get) => { return isAiEnabled(get(resolvedMarimoConfigAtom)); }); diff --git a/frontend/src/core/islands/main.ts b/frontend/src/core/islands/main.ts index 288ca9ad2c0..9cb7ebeeb51 100644 --- a/frontend/src/core/islands/main.ts +++ b/frontend/src/core/islands/main.ts @@ -183,6 +183,10 @@ export async function initialize() { case "query-params-clear": queryParamHandlers.clear(); return; + case "suggestions": + // Handle suggestions - this might be for AI prompts or other UI suggestions + // For now, we'll just log them as they may not be relevant in islands mode + return; case "reconnected": return; default: diff --git a/marimo/_cli/cli.py b/marimo/_cli/cli.py index 87d3eb8c622..0bd026c8948 100644 --- a/marimo/_cli/cli.py +++ b/marimo/_cli/cli.py @@ -475,6 +475,14 @@ def _get_stdin_contents() -> str | None: hidden=True, help="Custom asset URL for loading static resources. Can include {version} placeholder.", ) +@click.option( + "--disable-home-page", + is_flag=True, + default=False, + show_default=True, + type=bool, + help="Disable the home page, return 404 for root path when no file is specified.", +) @click.option( "--timeout", required=False, @@ -509,6 +517,7 @@ def edit( mcp: bool, server_startup_command: Optional[str], asset_url: Optional[str], + disable_home_page: bool, timeout: Optional[float], name: Optional[str], args: tuple[str, ...], @@ -580,6 +589,7 @@ def edit( return GLOBAL_SETTINGS.PROFILE_DIR = profile_dir + GLOBAL_SETTINGS.DISABLE_HOME_PAGE = disable_home_page if not skip_update_check and os.getenv("MARIMO_SKIP_UPDATE_CHECK") != "1": GLOBAL_SETTINGS.CHECK_STATUS_UPDATE = True # Check for version updates diff --git a/marimo/_config/config.py b/marimo/_config/config.py index df340e88bd6..8e0bdfc6543 100644 --- a/marimo/_config/config.py +++ b/marimo/_config/config.py @@ -213,10 +213,13 @@ class ServerConfig(TypedDict): with Python's webbrowser module (eg, `"firefox"` or `"chrome"`) - `follow_symlink`: if true, the server will follow symlinks it finds inside its static assets directory. + - `disable_home_page`: if true, the server will return 404 for the root path + when no file is specified, preventing access to the home page """ browser: Union[Literal["default"], str] follow_symlink: bool + disable_home_page: bool @dataclass @@ -651,6 +654,7 @@ class PartialMarimoConfig(TypedDict, total=False): "server": { "browser": "default", "follow_symlink": False, + "disable_home_page": False, }, "language_servers": { "pylsp": { diff --git a/marimo/_config/settings.py b/marimo/_config/settings.py index 23b928c1100..433c26ef74c 100644 --- a/marimo/_config/settings.py +++ b/marimo/_config/settings.py @@ -21,6 +21,7 @@ class GlobalSettings: IN_SECURE_ENVIRONMENT: bool = os.getenv( "MARIMO_IN_SECURE_ENVIRONMENT", "false" ) in ("true", "1") + DISABLE_HOME_PAGE: bool = False GLOBAL_SETTINGS = GlobalSettings() diff --git a/marimo/_server/api/endpoints/assets.py b/marimo/_server/api/endpoints/assets.py index f78e3c16312..7e087d4aa80 100644 --- a/marimo/_server/api/endpoints/assets.py +++ b/marimo/_server/api/endpoints/assets.py @@ -85,6 +85,18 @@ async def index(request: Request) -> HTMLResponse: html = index_html.read_text() if not file_key: + # Check if home page is disabled in user configuration or CLI flag + user_config = app_state.config_manager.get_user_config() + from marimo._config.settings import GLOBAL_SETTINGS + + # Access config as dictionary since MarimoConfig is a TypedDict + server_config = user_config.get("server", {}) + disable_home_page_config = server_config.get("disable_home_page", False) + + if disable_home_page_config or GLOBAL_SETTINGS.DISABLE_HOME_PAGE: + LOGGER.debug("Home page disabled by configuration, returning 404") + raise HTTPException(status_code=404, detail="Home page is disabled") + # We don't know which file to use, so we need to render a homepage LOGGER.debug("No file key provided, serving homepage") html = home_page_template( diff --git a/marimo/_server/api/endpoints/config.py b/marimo/_server/api/endpoints/config.py index ffdc1c89229..10213346e3f 100644 --- a/marimo/_server/api/endpoints/config.py +++ b/marimo/_server/api/endpoints/config.py @@ -122,3 +122,38 @@ async def handle_background_tasks() -> None: content=asdict(SuccessResponse()), background=background_task, ) + + +@router.get("/server_config") +@requires("edit") +async def get_server_config(request: Request) -> JSONResponse: + """ + Get server runtime configuration + + responses: + 200: + description: Get the server runtime configuration + content: + application/json: + schema: + type: object + properties: + disable_home_page: + type: boolean + description: Whether the homepage is disabled + """ + from marimo._cli.cli import GLOBAL_SETTINGS + app_state = AppState(request) + + # Get the user config and check for server config + user_config = app_state.config_manager.get_user_config() + server_config = user_config.get("server", {}) + + # Return runtime configuration combining user config and CLI flags + return JSONResponse( + content={ + "browser": server_config.get("browser", "default"), + "follow_symlink": server_config.get("follow_symlink", False), + "disable_home_page": GLOBAL_SETTINGS.DISABLE_HOME_PAGE, + } + ) From 1ce12dfbe36e533eeda14fe5be7889f84da211d7 Mon Sep 17 00:00:00 2001 From: Riya Sinha Date: Fri, 10 Oct 2025 18:06:54 -0500 Subject: [PATCH 3/7] add disable terminal option --- .../editor/chrome/wrapper/app-chrome.tsx | 6 +++++- .../editor/chrome/wrapper/footer.tsx | 20 +++++++++++-------- frontend/src/core/config/config-schema.ts | 1 + frontend/src/core/config/config.ts | 9 ++++++--- marimo/_cli/cli.py | 10 ++++++++++ marimo/_config/config.py | 4 ++++ marimo/_config/settings.py | 1 + marimo/_server/api/endpoints/config.py | 7 ++++++- 8 files changed, 45 insertions(+), 13 deletions(-) diff --git a/frontend/src/components/editor/chrome/wrapper/app-chrome.tsx b/frontend/src/components/editor/chrome/wrapper/app-chrome.tsx index d04ee35434c..26af669c0ab 100644 --- a/frontend/src/components/editor/chrome/wrapper/app-chrome.tsx +++ b/frontend/src/components/editor/chrome/wrapper/app-chrome.tsx @@ -19,6 +19,7 @@ import { XIcon } from "lucide-react"; import { Button } from "@/components/ui/button"; import { LazyMount } from "@/components/utils/lazy-mount"; import { IfCapability } from "@/core/config/if-capability"; +import { useServerConfig } from "@/core/config/config"; import { cn } from "@/utils/cn"; import { ErrorBoundary } from "../../boundary/ErrorBoundary"; import { ContextAwarePanel } from "../panels/context-aware-panel/context-aware-panel"; @@ -61,6 +62,7 @@ const LazyVariablePanel = React.lazy(() => import("../panels/variable-panel")); export const AppChrome: React.FC = ({ children }) => { const { isSidebarOpen, isTerminalOpen, selectedPanel } = useChromeState(); const { setIsSidebarOpen, setIsTerminalOpen } = useChromeActions(); + const serverConfig = useServerConfig(); const sidebarRef = React.useRef(null); const terminalRef = React.useRef(null); @@ -266,7 +268,9 @@ export const AppChrome: React.FC = ({ children }) => { {appBodyPanel} - {terminalPanel} + + {!serverConfig.disable_terminal && terminalPanel} + diff --git a/frontend/src/components/editor/chrome/wrapper/footer.tsx b/frontend/src/components/editor/chrome/wrapper/footer.tsx index 89d4f96ed1e..2f4e25c4537 100644 --- a/frontend/src/components/editor/chrome/wrapper/footer.tsx +++ b/frontend/src/components/editor/chrome/wrapper/footer.tsx @@ -6,6 +6,7 @@ import type React from "react"; import { Tooltip } from "@/components/ui/tooltip"; import { cellErrorCount } from "@/core/cells/cells"; import { IfCapability } from "@/core/config/if-capability"; +import { useServerConfig } from "@/core/config/config"; import { useHotkey } from "@/hooks/useHotkey"; import { cn } from "@/utils/cn"; import { invariant } from "@/utils/invariant"; @@ -25,6 +26,7 @@ export const Footer: React.FC = () => { const { selectedPanel, isTerminalOpen } = useChromeState(); const { toggleApplication, toggleTerminal } = useChromeActions(); const errorCount = useAtomValue(cellErrorCount); + const serverConfig = useServerConfig(); const renderIcon = ({ Icon }: PanelDescriptor, className?: string) => { return ; @@ -50,14 +52,16 @@ export const Footer: React.FC = () => { - toggleTerminal()} - data-testid="footer-terminal" - > - - + {!serverConfig.disable_terminal && ( + toggleTerminal()} + data-testid="footer-terminal" + > + + + )} diff --git a/frontend/src/core/config/config-schema.ts b/frontend/src/core/config/config-schema.ts index 4990989f45c..c9edacc92d9 100644 --- a/frontend/src/core/config/config-schema.ts +++ b/frontend/src/core/config/config-schema.ts @@ -185,6 +185,7 @@ export const UserConfigSchema = z server: z .looseObject({ disable_home_page: z.boolean().optional(), + disable_terminal: z.boolean().optional(), }) .prefault(() => ({})), sharing: z diff --git a/frontend/src/core/config/config.ts b/frontend/src/core/config/config.ts index bc7ced4d725..a0bb1038e71 100644 --- a/frontend/src/core/config/config.ts +++ b/frontend/src/core/config/config.ts @@ -52,11 +52,13 @@ export const aiAtom = atom((get) => { export const serverConfigAtom = atom(async () => { try { - const response = await API.get<{ disable_home_page: boolean }>( - "/kernel/server_config", - ); + const response = await API.get<{ + disable_home_page: boolean; + disable_terminal: boolean; + }>("/kernel/server_config"); return { disable_home_page: response?.disable_home_page ?? false, + disable_terminal: response?.disable_terminal ?? false, browser: "default", follow_symlink: false, }; @@ -64,6 +66,7 @@ export const serverConfigAtom = atom(async () => { Logger.warn("Failed to fetch server config:", error); return { disable_home_page: false, + disable_terminal: false, browser: "default", follow_symlink: false, }; diff --git a/marimo/_cli/cli.py b/marimo/_cli/cli.py index 0bd026c8948..fbf4254e0a2 100644 --- a/marimo/_cli/cli.py +++ b/marimo/_cli/cli.py @@ -483,6 +483,14 @@ def _get_stdin_contents() -> str | None: type=bool, help="Disable the home page, return 404 for root path when no file is specified.", ) +@click.option( + "--disable-terminal", + is_flag=True, + default=False, + show_default=True, + type=bool, + help="Disable terminal access in the UI and reject terminal websocket connections.", +) @click.option( "--timeout", required=False, @@ -518,6 +526,7 @@ def edit( server_startup_command: Optional[str], asset_url: Optional[str], disable_home_page: bool, + disable_terminal: bool, timeout: Optional[float], name: Optional[str], args: tuple[str, ...], @@ -590,6 +599,7 @@ def edit( GLOBAL_SETTINGS.PROFILE_DIR = profile_dir GLOBAL_SETTINGS.DISABLE_HOME_PAGE = disable_home_page + GLOBAL_SETTINGS.DISABLE_TERMINAL = disable_terminal if not skip_update_check and os.getenv("MARIMO_SKIP_UPDATE_CHECK") != "1": GLOBAL_SETTINGS.CHECK_STATUS_UPDATE = True # Check for version updates diff --git a/marimo/_config/config.py b/marimo/_config/config.py index 8e0bdfc6543..93aade4af2e 100644 --- a/marimo/_config/config.py +++ b/marimo/_config/config.py @@ -215,11 +215,14 @@ class ServerConfig(TypedDict): inside its static assets directory. - `disable_home_page`: if true, the server will return 404 for the root path when no file is specified, preventing access to the home page + - `disable_terminal`: if true, the server will disable terminal access + in the UI and reject terminal websocket connections """ browser: Union[Literal["default"], str] follow_symlink: bool disable_home_page: bool + disable_terminal: bool @dataclass @@ -655,6 +658,7 @@ class PartialMarimoConfig(TypedDict, total=False): "browser": "default", "follow_symlink": False, "disable_home_page": False, + "disable_terminal": False, }, "language_servers": { "pylsp": { diff --git a/marimo/_config/settings.py b/marimo/_config/settings.py index 433c26ef74c..f2d2712077d 100644 --- a/marimo/_config/settings.py +++ b/marimo/_config/settings.py @@ -22,6 +22,7 @@ class GlobalSettings: "MARIMO_IN_SECURE_ENVIRONMENT", "false" ) in ("true", "1") DISABLE_HOME_PAGE: bool = False + DISABLE_TERMINAL: bool = False GLOBAL_SETTINGS = GlobalSettings() diff --git a/marimo/_server/api/endpoints/config.py b/marimo/_server/api/endpoints/config.py index 10213346e3f..e1788a6d137 100644 --- a/marimo/_server/api/endpoints/config.py +++ b/marimo/_server/api/endpoints/config.py @@ -141,6 +141,9 @@ async def get_server_config(request: Request) -> JSONResponse: disable_home_page: type: boolean description: Whether the homepage is disabled + disable_terminal: + type: boolean + description: Whether terminal access is disabled """ from marimo._cli.cli import GLOBAL_SETTINGS app_state = AppState(request) @@ -150,10 +153,12 @@ async def get_server_config(request: Request) -> JSONResponse: server_config = user_config.get("server", {}) # Return runtime configuration combining user config and CLI flags + # CLI flags override config file settings return JSONResponse( content={ "browser": server_config.get("browser", "default"), "follow_symlink": server_config.get("follow_symlink", False), - "disable_home_page": GLOBAL_SETTINGS.DISABLE_HOME_PAGE, + "disable_home_page": server_config.get("disable_home_page", False) or GLOBAL_SETTINGS.DISABLE_HOME_PAGE, + "disable_terminal": server_config.get("disable_terminal", False) or GLOBAL_SETTINGS.DISABLE_TERMINAL, } ) From dd451a13ca47bf9b543d6d20a8666214eb9ca04a Mon Sep 17 00:00:00 2001 From: Riya Sinha Date: Fri, 10 Oct 2025 18:28:19 -0500 Subject: [PATCH 4/7] allow disabling side panels --- .../src/components/editor/actions/useNotebookActions.tsx | 2 +- frontend/src/components/editor/chrome/wrapper/sidebar.tsx | 7 ++++++- frontend/src/core/config/config.ts | 3 +++ marimo/_cli/cli.py | 8 ++++++++ marimo/_config/config.py | 6 ++++++ marimo/_config/settings.py | 3 ++- marimo/_server/api/endpoints/config.py | 1 + 7 files changed, 27 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/editor/actions/useNotebookActions.tsx b/frontend/src/components/editor/actions/useNotebookActions.tsx index b135e10d671..41e13581ef2 100644 --- a/frontend/src/components/editor/actions/useNotebookActions.tsx +++ b/frontend/src/components/editor/actions/useNotebookActions.tsx @@ -273,7 +273,7 @@ export function useNotebookActions() { label: "Helper panel", handle: NOOP_HANDLER, dropdown: PANELS.flatMap(({ type, Icon, hidden }) => { - if (hidden) { + if (hidden || serverConfig.disabled_panels.includes(type)) { return []; } return { diff --git a/frontend/src/components/editor/chrome/wrapper/sidebar.tsx b/frontend/src/components/editor/chrome/wrapper/sidebar.tsx index 15ba9a69fbb..bb5f2ded9dc 100644 --- a/frontend/src/components/editor/chrome/wrapper/sidebar.tsx +++ b/frontend/src/components/editor/chrome/wrapper/sidebar.tsx @@ -6,6 +6,7 @@ import type React from "react"; import type { PropsWithChildren } from "react"; import { Tooltip } from "@/components/ui/tooltip"; import { notebookQueuedOrRunningCountAtom } from "@/core/cells/cells"; +import { useServerConfig } from "@/core/config/config"; import { cn } from "@/utils/cn"; import { FeedbackButton } from "../components/feedback-button"; import { useChromeActions, useChromeState } from "../state"; @@ -14,13 +15,17 @@ import { PANELS, type PanelDescriptor } from "../types"; export const Sidebar: React.FC = () => { const { selectedPanel } = useChromeState(); const { toggleApplication } = useChromeActions(); + const serverConfig = useServerConfig(); const renderIcon = ({ Icon }: PanelDescriptor, className?: string) => { return ; }; const sidebarItems = PANELS.filter( - (p) => !p.hidden && p.position === "sidebar", + (p) => + !p.hidden && + p.position === "sidebar" && + !serverConfig.disabled_panels.includes(p.type), ); return ( diff --git a/frontend/src/core/config/config.ts b/frontend/src/core/config/config.ts index a0bb1038e71..ad767a47648 100644 --- a/frontend/src/core/config/config.ts +++ b/frontend/src/core/config/config.ts @@ -55,10 +55,12 @@ export const serverConfigAtom = atom(async () => { const response = await API.get<{ disable_home_page: boolean; disable_terminal: boolean; + disabled_panels: string[]; }>("/kernel/server_config"); return { disable_home_page: response?.disable_home_page ?? false, disable_terminal: response?.disable_terminal ?? false, + disabled_panels: response?.disabled_panels ?? [], browser: "default", follow_symlink: false, }; @@ -67,6 +69,7 @@ export const serverConfigAtom = atom(async () => { return { disable_home_page: false, disable_terminal: false, + disabled_panels: [], browser: "default", follow_symlink: false, }; diff --git a/marimo/_cli/cli.py b/marimo/_cli/cli.py index fbf4254e0a2..f597111730d 100644 --- a/marimo/_cli/cli.py +++ b/marimo/_cli/cli.py @@ -491,6 +491,12 @@ def _get_stdin_contents() -> str | None: type=bool, help="Disable terminal access in the UI and reject terminal websocket connections.", ) +@click.option( + "--disabled-panels", + default="", + type=str, + help="Comma-separated list of panel names to disable (e.g., 'files,packages,chat').", +) @click.option( "--timeout", required=False, @@ -527,6 +533,7 @@ def edit( asset_url: Optional[str], disable_home_page: bool, disable_terminal: bool, + disabled_panels: str, timeout: Optional[float], name: Optional[str], args: tuple[str, ...], @@ -600,6 +607,7 @@ def edit( GLOBAL_SETTINGS.PROFILE_DIR = profile_dir GLOBAL_SETTINGS.DISABLE_HOME_PAGE = disable_home_page GLOBAL_SETTINGS.DISABLE_TERMINAL = disable_terminal + GLOBAL_SETTINGS.DISABLED_PANELS = disabled_panels.split(",") if disabled_panels else [] if not skip_update_check and os.getenv("MARIMO_SKIP_UPDATE_CHECK") != "1": GLOBAL_SETTINGS.CHECK_STATUS_UPDATE = True # Check for version updates diff --git a/marimo/_config/config.py b/marimo/_config/config.py index 93aade4af2e..00179bfe04e 100644 --- a/marimo/_config/config.py +++ b/marimo/_config/config.py @@ -217,12 +217,17 @@ class ServerConfig(TypedDict): when no file is specified, preventing access to the home page - `disable_terminal`: if true, the server will disable terminal access in the UI and reject terminal websocket connections + - `disabled_panels`: list of panel names to disable in the UI. + Valid panel names: "files", "errors", "variables", "outline", + "dependencies", "tracing", "packages", "documentation", "snippets", + "datasources", "scratchpad", "chat", "agents", "secrets", "logs", "suggestions" """ browser: Union[Literal["default"], str] follow_symlink: bool disable_home_page: bool disable_terminal: bool + disabled_panels: list[str] @dataclass @@ -659,6 +664,7 @@ class PartialMarimoConfig(TypedDict, total=False): "follow_symlink": False, "disable_home_page": False, "disable_terminal": False, + "disabled_panels": [], }, "language_servers": { "pylsp": { diff --git a/marimo/_config/settings.py b/marimo/_config/settings.py index f2d2712077d..010b29c6a05 100644 --- a/marimo/_config/settings.py +++ b/marimo/_config/settings.py @@ -3,7 +3,7 @@ import logging import os -from dataclasses import dataclass +from dataclasses import dataclass, field @dataclass @@ -23,6 +23,7 @@ class GlobalSettings: ) in ("true", "1") DISABLE_HOME_PAGE: bool = False DISABLE_TERMINAL: bool = False + DISABLED_PANELS: list[str] = field(default_factory=list) GLOBAL_SETTINGS = GlobalSettings() diff --git a/marimo/_server/api/endpoints/config.py b/marimo/_server/api/endpoints/config.py index e1788a6d137..f230629279a 100644 --- a/marimo/_server/api/endpoints/config.py +++ b/marimo/_server/api/endpoints/config.py @@ -160,5 +160,6 @@ async def get_server_config(request: Request) -> JSONResponse: "follow_symlink": server_config.get("follow_symlink", False), "disable_home_page": server_config.get("disable_home_page", False) or GLOBAL_SETTINGS.DISABLE_HOME_PAGE, "disable_terminal": server_config.get("disable_terminal", False) or GLOBAL_SETTINGS.DISABLE_TERMINAL, + "disabled_panels": server_config.get("disabled_panels", []) + GLOBAL_SETTINGS.DISABLED_PANELS, } ) From 8332bd2438684cdcbba087152e7437bc363bca11 Mon Sep 17 00:00:00 2001 From: Riya Sinha Date: Fri, 10 Oct 2025 22:39:43 -0500 Subject: [PATCH 5/7] allow disabling package installation --- .../editor/chrome/panels/packages-panel.tsx | 21 +++++++++++++++---- .../src/components/editor/package-alert.tsx | 10 +++++++-- frontend/src/core/config/config.ts | 4 ++++ marimo/_cli/cli.py | 10 +++++++++ marimo/_config/config.py | 5 +++++ marimo/_config/settings.py | 1 + marimo/_server/api/endpoints/config.py | 1 + 7 files changed, 46 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/editor/chrome/panels/packages-panel.tsx b/frontend/src/components/editor/chrome/panels/packages-panel.tsx index 0e3a80b5673..70ccf839aa5 100644 --- a/frontend/src/components/editor/chrome/panels/packages-panel.tsx +++ b/frontend/src/components/editor/chrome/panels/packages-panel.tsx @@ -20,7 +20,7 @@ import { } from "@/components/ui/table"; import { Tooltip } from "@/components/ui/tooltip"; import { toast } from "@/components/ui/use-toast"; -import { useResolvedMarimoConfig } from "@/core/config/config"; +import { useResolvedMarimoConfig, useServerConfig } from "@/core/config/config"; import { useRequestClient } from "@/core/network/requests"; import type { DependencyTreeNode } from "@/core/network/types"; import { @@ -67,6 +67,7 @@ const PackageActionButton: React.FC<{ const PackagesPanel: React.FC = () => { const [config] = useResolvedMarimoConfig(); + const serverConfig = useServerConfig(); const packageManager = config.package_management.manager; const { getDependencyTree, getPackageList } = useRequestClient(); @@ -104,7 +105,12 @@ const PackagesPanel: React.FC = () => { return (
- + {!serverConfig.disable_package_installation && ( + + )} {isTreeSupported && (
@@ -352,9 +358,10 @@ const UpgradeButton: React.FC<{ }> = ({ packageName, onSuccess }) => { const [loading, setLoading] = React.useState(false); const { addPackage } = useRequestClient(); + const serverConfig = useServerConfig(); - // Hide upgrade button in WASM - if (isWasm()) { + // Hide upgrade button in WASM or if package installation is disabled + if (isWasm() || serverConfig.disable_package_installation) { return null; } @@ -389,6 +396,12 @@ const RemoveButton: React.FC<{ }> = ({ packageName, onSuccess }) => { const [loading, setLoading] = React.useState(false); const { removePackage } = useRequestClient(); + const serverConfig = useServerConfig(); + + // Hide remove button if package installation is disabled + if (serverConfig.disable_package_installation) { + return null; + } const handleRemovePackage = async () => { try { diff --git a/frontend/src/components/editor/package-alert.tsx b/frontend/src/components/editor/package-alert.tsx index bf681563dc7..32b12adbdec 100644 --- a/frontend/src/components/editor/package-alert.tsx +++ b/frontend/src/components/editor/package-alert.tsx @@ -29,7 +29,7 @@ import { useAlertActions, useAlerts, } from "@/core/alerts/state"; -import { useResolvedMarimoConfig } from "@/core/config/config"; +import { useResolvedMarimoConfig, useServerConfig } from "@/core/config/config"; import type { PackageInstallationStatus } from "@/core/kernel/messages"; import { useRequestClient } from "@/core/network/requests"; import { isWasm } from "@/core/wasm/utils"; @@ -79,6 +79,7 @@ export const PackageAlert: React.FC = () => { const { packageAlert, packageLogs } = useAlerts(); const { clearPackageAlert } = useAlertActions(); const [userConfig] = useResolvedMarimoConfig(); + const serverConfig = useServerConfig(); const [desiredPackageVersions, setDesiredPackageVersions] = useState< Record >({}); @@ -86,7 +87,12 @@ export const PackageAlert: React.FC = () => { Record >({}); - if (packageAlert === null) { + // Don't show package alerts if package installation is disabled + if ( + packageAlert === null || + (isMissingPackageAlert(packageAlert) && + serverConfig.disable_package_installation) + ) { return null; } diff --git a/frontend/src/core/config/config.ts b/frontend/src/core/config/config.ts index ad767a47648..da0a956d0f0 100644 --- a/frontend/src/core/config/config.ts +++ b/frontend/src/core/config/config.ts @@ -55,11 +55,14 @@ export const serverConfigAtom = atom(async () => { const response = await API.get<{ disable_home_page: boolean; disable_terminal: boolean; + disable_package_installation: boolean; disabled_panels: string[]; }>("/kernel/server_config"); return { disable_home_page: response?.disable_home_page ?? false, disable_terminal: response?.disable_terminal ?? false, + disable_package_installation: + response?.disable_package_installation ?? false, disabled_panels: response?.disabled_panels ?? [], browser: "default", follow_symlink: false, @@ -69,6 +72,7 @@ export const serverConfigAtom = atom(async () => { return { disable_home_page: false, disable_terminal: false, + disable_package_installation: false, disabled_panels: [], browser: "default", follow_symlink: false, diff --git a/marimo/_cli/cli.py b/marimo/_cli/cli.py index f597111730d..218d4ef3366 100644 --- a/marimo/_cli/cli.py +++ b/marimo/_cli/cli.py @@ -491,6 +491,14 @@ def _get_stdin_contents() -> str | None: type=bool, help="Disable terminal access in the UI and reject terminal websocket connections.", ) +@click.option( + "--disable-package-installation", + is_flag=True, + default=False, + show_default=True, + type=bool, + help="Disable package installation features including install input and missing package prompts.", +) @click.option( "--disabled-panels", default="", @@ -533,6 +541,7 @@ def edit( asset_url: Optional[str], disable_home_page: bool, disable_terminal: bool, + disable_package_installation: bool, disabled_panels: str, timeout: Optional[float], name: Optional[str], @@ -607,6 +616,7 @@ def edit( GLOBAL_SETTINGS.PROFILE_DIR = profile_dir GLOBAL_SETTINGS.DISABLE_HOME_PAGE = disable_home_page GLOBAL_SETTINGS.DISABLE_TERMINAL = disable_terminal + GLOBAL_SETTINGS.DISABLE_PACKAGE_INSTALLATION = disable_package_installation GLOBAL_SETTINGS.DISABLED_PANELS = disabled_panels.split(",") if disabled_panels else [] if not skip_update_check and os.getenv("MARIMO_SKIP_UPDATE_CHECK") != "1": GLOBAL_SETTINGS.CHECK_STATUS_UPDATE = True diff --git a/marimo/_config/config.py b/marimo/_config/config.py index 00179bfe04e..f2e142d1c4a 100644 --- a/marimo/_config/config.py +++ b/marimo/_config/config.py @@ -217,6 +217,9 @@ class ServerConfig(TypedDict): when no file is specified, preventing access to the home page - `disable_terminal`: if true, the server will disable terminal access in the UI and reject terminal websocket connections + - `disable_package_installation`: if true, the server will disable package + installation features including the install input in packages panel + and missing package installation prompts - `disabled_panels`: list of panel names to disable in the UI. Valid panel names: "files", "errors", "variables", "outline", "dependencies", "tracing", "packages", "documentation", "snippets", @@ -227,6 +230,7 @@ class ServerConfig(TypedDict): follow_symlink: bool disable_home_page: bool disable_terminal: bool + disable_package_installation: bool disabled_panels: list[str] @@ -664,6 +668,7 @@ class PartialMarimoConfig(TypedDict, total=False): "follow_symlink": False, "disable_home_page": False, "disable_terminal": False, + "disable_package_installation": False, "disabled_panels": [], }, "language_servers": { diff --git a/marimo/_config/settings.py b/marimo/_config/settings.py index 010b29c6a05..4a564d94a45 100644 --- a/marimo/_config/settings.py +++ b/marimo/_config/settings.py @@ -23,6 +23,7 @@ class GlobalSettings: ) in ("true", "1") DISABLE_HOME_PAGE: bool = False DISABLE_TERMINAL: bool = False + DISABLE_PACKAGE_INSTALLATION: bool = False DISABLED_PANELS: list[str] = field(default_factory=list) diff --git a/marimo/_server/api/endpoints/config.py b/marimo/_server/api/endpoints/config.py index f230629279a..1dd7149805a 100644 --- a/marimo/_server/api/endpoints/config.py +++ b/marimo/_server/api/endpoints/config.py @@ -160,6 +160,7 @@ async def get_server_config(request: Request) -> JSONResponse: "follow_symlink": server_config.get("follow_symlink", False), "disable_home_page": server_config.get("disable_home_page", False) or GLOBAL_SETTINGS.DISABLE_HOME_PAGE, "disable_terminal": server_config.get("disable_terminal", False) or GLOBAL_SETTINGS.DISABLE_TERMINAL, + "disable_package_installation": server_config.get("disable_package_installation", False) or GLOBAL_SETTINGS.DISABLE_PACKAGE_INSTALLATION, "disabled_panels": server_config.get("disabled_panels", []) + GLOBAL_SETTINGS.DISABLED_PANELS, } ) From bed29ce8478f8cdfd68be250817aba2a4a85ba24 Mon Sep 17 00:00:00 2001 From: Riya Sinha Date: Fri, 10 Oct 2025 22:44:12 -0500 Subject: [PATCH 6/7] allow disabling feedback button --- .../src/components/editor/chrome/wrapper/sidebar.tsx | 12 +++++++----- marimo/_config/config.py | 3 ++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/editor/chrome/wrapper/sidebar.tsx b/frontend/src/components/editor/chrome/wrapper/sidebar.tsx index bb5f2ded9dc..ceecd6e0d3e 100644 --- a/frontend/src/components/editor/chrome/wrapper/sidebar.tsx +++ b/frontend/src/components/editor/chrome/wrapper/sidebar.tsx @@ -40,11 +40,13 @@ export const Sidebar: React.FC = () => { {renderIcon(p)} ))} - - - - - + {!serverConfig.disabled_panels.includes("feedback") && ( + + + + + + )}
diff --git a/marimo/_config/config.py b/marimo/_config/config.py index f2e142d1c4a..1cc40080e2f 100644 --- a/marimo/_config/config.py +++ b/marimo/_config/config.py @@ -223,7 +223,8 @@ class ServerConfig(TypedDict): - `disabled_panels`: list of panel names to disable in the UI. Valid panel names: "files", "errors", "variables", "outline", "dependencies", "tracing", "packages", "documentation", "snippets", - "datasources", "scratchpad", "chat", "agents", "secrets", "logs", "suggestions" + "datasources", "scratchpad", "chat", "agents", "secrets", "logs", + "suggestions", "feedback" """ browser: Union[Literal["default"], str] From 10e7721be9fea1515d1b26566e1ef398c29a07d0 Mon Sep 17 00:00:00 2001 From: Riya Sinha Date: Sat, 11 Oct 2025 11:54:00 -0500 Subject: [PATCH 7/7] document ui capability modification features --- README.md | 41 +++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e8960ed4b23..5f99167688b 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,47 @@ This will render as: The suggestions are rendered in a new panel to the right of the agent cell. These are generated as a background task, so they can happen after the agent cell has returned its response. +## Other Fork Modifications 🔧 + +This fork includes additional server configuration options for enhanced security and control in shared environments: + +### UI Restrictions + +**Disable Panels**: Hide specific panels from the sidebar and navigation menus. +```toml +# In .marimo.toml +[server] +disabled_panels = ["chat", "secrets", "feedback", "files"] +``` +```bash +# Via CLI +marimo edit --disabled-panels "chat,secrets,feedback" +``` + +Available panels to disable: `files`, `errors`, `variables`, `outline`, `dependencies`, `tracing`, `packages`, `documentation`, `snippets`, `datasources`, `scratchpad`, `chat`, `agents`, `secrets`, `logs`, `suggestions`, `feedback`. + +**Disable Terminal**: Completely disable terminal access in the UI. +```toml +# In .marimo.toml +[server] +disable_terminal = true +``` +```bash +# Via CLI +marimo edit --disable-terminal +``` + +**Disable Package Installation**: Hide package installation features while keeping package viewing. +```toml +# In .marimo.toml +[server] +disable_package_installation = true +``` +```bash +# Via CLI +marimo edit --disable-package-installation +``` + --- # Original README diff --git a/pyproject.toml b/pyproject.toml index 454842809d9..3811c821b40 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "uv_build" [project] name = "marimo-agents" -version = "0.16.5.1" +version = "0.16.5.2" description = "A Marimo concept fork with some support for LLM execution as cells" # We try to keep dependencies to a minimum, to avoid conflicts with # user environments;we need a very compelling reason for each dependency added.