Repository navigation
feat: add spec.baseUrl to serve marimo under a path prefix - #21
Open
blarghmatey wants to merge 1 commit into
Open
blarghmatey wants to merge 1 commit into
blarghmatey wants to merge 1 commit into
Conversation
A reverse proxy that routes a sub-path of a shared host to a notebook (e.g. apps.example.com/<name>/) needs marimo started with --base-url, otherwise asset and websocket URLs resolve against the host root and the app fails to load. The operator builds the container args itself, so there was no way to set it short of replacing the args wholesale through podOverrides. spec.baseUrl is rendered as --base-url=<value> ahead of the notebook path. The CRD pattern mirrors marimo's own validator (leading slash, no trailing slash, not "/"), so a bad value is rejected at admission instead of crash-looping the pod. Unset, the args and pod spec hash are unchanged, so existing notebooks are not recreated on upgrade. Claude-Session: https://claude.ai/code/session_01Mznd5RYgzKGBShstpLnoFQ
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The API, generated schemas, pod construction, tests, and documentation are consistent and complete.
Review effort: Balanced
Findings: None
What changed in this PR
Adds spec.baseUrl so notebooks can be served behind path-prefixed reverse-proxy routes.
Changes:
- Adds validated CRD/API support for
baseUrl. - Passes the value to marimo as
--base-url. - Adds unit/controller tests and architecture documentation.
| File | Description |
|---|---|
api/v1alpha1/marimonotebook_types.go |
Defines the validated API field. |
config/crd/bases/marimo.io_marimos.yaml |
Updates the generated CRD schema. |
deploy/charts/marimo-operator/crds/marimo.io_marimos.yaml |
Updates the Helm CRD schema. |
pkg/resources/pod.go |
Adds the marimo CLI argument. |
pkg/resources/pod_test.go |
Tests set and unset behavior. |
internal/controller/marimonotebook_controller_test.go |
Tests reconciliation and admission validation. |
docs/ARCHITECTURE.md |
Documents the new field. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This branch has not been deployed
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
We want to serve several published notebooks from one host, each under its own path (e.g.
apps.example.com/<name>/), with the gateway routing each prefix to that notebook's Service. marimo supports this through--base-url. The operator builds the container args itself, though, so the only way to pass that flag today is to replace the marimo container's args wholesale throughpodOverrides, which means copying the operator's internal paths and auth flags into every CR.This adds
spec.baseUrl, rendered as--base-url=<value>ahead of the notebook path. The CRD pattern (^/.*[^/]$) mirrors marimo's own validator inmarimo/_cli/cli_validators.py(it must start with/, must not end with/, and must not be bare/), so a bad value is rejected at admission instead of crash-looping the pod. When the field is unset, the args are unchanged and so is the pod spec hash, so existing notebooks are not recreated after an operator upgrade.The kubectl plugin is untouched. It port-forwards to the pod directly, so it doesn't need a prefix.
Checklist
make lintandmake testpass locally (operator).uv run pytestanduv run ty check kubectl_marimopass locally (plugin). (Not applicable, the plugin is unchanged.)make manifestshas been run and generated files are committed.https://claude.ai/code/session_01Mznd5RYgzKGBShstpLnoFQ