Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/SchemaStore/schemastore/refs/heads/master/src/schemas/json/github-issue-forms.json
name: "🐞 Bug report"
description: Report an issue with the marimo-operator or kubectl-marimo plugin
labels: [bug]
body:
- type: markdown
attributes:
value: |
Thank you for filing this bug report!

**Tip:** You can check the operator version and logs quickly with:
```bash
kubectl logs -n marimo-operator-system -l control-plane=controller-manager --tail=50
kubectl describe marimo <name>
```

- type: textarea
id: bug-description
attributes:
label: Describe the bug
description: What went wrong? Include any error messages or stack traces.
placeholder: |
Running `kubectl marimo edit notebook.py` fails with:
...
validations:
required: true

- type: textarea
id: reproduction
attributes:
label: Steps to reproduce
description: The smallest set of steps or YAML that triggers the bug.
placeholder: |
1. Apply this MarimoNotebook CR:
```yaml
apiVersion: marimo.io/v1alpha1
kind: MarimoNotebook
...
```
2. Run `kubectl get marimos`
3. See error...
validations:
required: false

- type: textarea
id: env
attributes:
label: Environment
value: |
- **operator version** (image tag or `kubectl get deployment -n marimo-operator-system`):
- **kubectl-marimo version** (`kubectl-marimo --version`):
- **Kubernetes version** (`kubectl version --short`):
- **Cloud / cluster type** (e.g. CKS, GKE, kind):
- **OS**:
validations:
required: true

- type: checkboxes
id: will-submit-pr
attributes:
label: Will you submit a PR?
options:
- label: "Yes, I'd like to fix this"
8 changes: 8 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
blank_issues_enabled: true
contact_links:
- name: Discord Chat
url: https://marimo.io/discord?ref=issues
about: Ask questions and chat with the marimo community.
- name: GitHub Discussions
url: https://github.com/marimo-team/marimo-operator/discussions
about: Use Discussions for questions, ideas, and general conversation.
46 changes: 46 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/SchemaStore/schemastore/refs/heads/master/src/schemas/json/github-issue-forms.json
name: "🚀 Feature request"
description: Propose a new feature or improvement for the marimo-operator
labels: [enhancement]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to propose a new feature!

- type: textarea
id: problem
attributes:
label: Problem / motivation
description: What are you trying to do that is currently difficult or impossible?
placeholder: I'm trying to ... but I can't because ...
validations:
required: true

- type: textarea
id: solution
attributes:
label: Proposed solution
description: Describe the feature or behavior you'd like to see. Include example YAML or CLI usage if applicable.
validations:
required: true

- type: textarea
id: alternatives
attributes:
label: Alternatives considered
description: Any workarounds or alternative approaches you've tried?

- type: textarea
id: context
attributes:
label: Additional context
description: Screenshots, links, prior art, or anything else that helps explain the request.

- type: checkboxes
id: will-submit-pr
attributes:
label: Are you willing to submit a PR?
description: Please confirm with the team before starting work on a large feature.
options:
- label: "Yes, I'd like to implement this"
17 changes: 17 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## Summary

<!--
If this closes an issue, link it here (e.g. Closes #123).
Describe what changed and why.
-->

Closes #

## Checklist

- [ ] Any AI-generated code has been reviewed line-by-line by the human PR author.
- [ ] Tests have been added or updated for the changes (where applicable).
- [ ] `make lint` and `make test` pass locally (operator).
- [ ] `uv run pytest` and `uv run ty check kubectl_marimo` pass locally (plugin).
- [ ] If CRD fields changed, `make manifests` has been run and generated files are committed.
- [ ] Documentation updated where relevant.
23 changes: 23 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-merge-conflict

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.6
hooks:
- id: ruff
args: [--fix]
files: ^plugin/
- id: ruff-format
files: ^plugin/

- repo: https://github.com/dnephin/pre-commit-golang
rev: v0.5.1
hooks:
- id: go-fmt
- id: go-vet
145 changes: 145 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Build & Test Commands

### Operator (Go)

```bash
make test # Unit tests with coverage
make test-e2e # E2E tests on Kind cluster (creates cluster automatically)
make fmt # go fmt
make vet # go vet
make lint # golangci-lint
make lint-fix # Auto-fix lint issues
make build # Build manager binary to bin/manager
make manifests # Regenerate CRD YAML and RBAC from types
make generate # Regenerate DeepCopy methods
make build-installer # Regenerate deploy/install.yaml
```

### Plugin (Python)

```bash
cd plugin
uv sync --dev # Install dev dependencies
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

plugin/pyproject.toml exposes dev dependencies as an optional extra ([project.optional-dependencies].dev), and CI uses uv sync --extra dev. Using uv sync --dev here may not install the extra, causing pytest/ty to be missing. Update this command to match the project/CI install method.

Suggested change
uv sync --dev # Install dev dependencies
uv sync --extra dev # Install dev dependencies

Copilot uses AI. Check for mistakes.
uv run pytest tests -v # Run all tests
uv run pytest tests/test_deploy.py # Run single test file
uv run ty check kubectl_marimo # Static type checking
```

## Architecture

marimo-operator is a Kubernetes operator (Go, controller-runtime) that manages `MarimoNotebook` custom resources, plus a Python kubectl plugin (`kubectl-marimo`) for deploying individual local notebooks.

### Operator (Go)

For each `MarimoNotebook` CR the controller creates:
- **PVC** — persistent storage, **intentionally has no owner reference** (not GC'd on CR delete; requires explicit `--delete-pvc`)
- **Pod** — init container clones `spec.source` git repo into `/data`, then marimo container serves from there; sidecars share the same PVC volume
- **Service** — exposes marimo port (default 2718) and any sidecar `exposePort`s

Pod updates use a **recreate** strategy (delete + recreate); init container skips clone if `/data` already has content, preserving edits across restarts.

Key files:
- `api/v1alpha1/marimonotebook_types.go` — CRD schema (all spec fields with defaults)
- `internal/controller/marimonotebook_controller.go` — reconciliation loop
- `pkg/resources/pod.go` — Pod construction (init container, sidecars, mounts)
- `pkg/config/images.go` — configurable default images via env vars

Configurable default images (set as env vars on the operator deployment):

| Env Var | Default | Purpose |
|---------|---------|---------|
| `DEFAULT_INIT_IMAGE` | `busybox:1.36` | copy-content init container |
| `GIT_IMAGE` | `alpine/git:latest` | git clone |
| `ALPINE_IMAGE` | `alpine:latest` | sshfs/rsync sidecars |
| `S3FS_IMAGE` | `ghcr.io/marimo-team/marimo-operator/s3fs:latest` | cw:// mounts |
| `S3_ENDPOINT` | `https://cwobject.com` | CoreWeave S3 endpoint |

### Plugin (Python)

`kubectl-marimo` reads local `.py`/`.md` notebooks, uploads content to a ConfigMap, creates the `MarimoNotebook` CR, then port-forwards for interactive access. State is tracked in swap files (`.notebook.py.marimo`).

Key files:
- `plugin/kubectl_marimo/deploy.py` — orchestrates edit/run flows
- `plugin/kubectl_marimo/resources.py` — builds MarimoNotebook CR from frontmatter
- `plugin/kubectl_marimo/formats/` — parsers for `.py` (inline TOML) and `.md` (YAML frontmatter)
- `plugin/kubectl_marimo/swap.py` — tracks deployed notebooks for sync/delete

Notebook configuration is embedded in frontmatter:

```python
# /// script
# dependencies = ["marimo", "torch"]
#
# [tool.marimo.k8s]
# storage = "5Gi"
#
# [tool.marimo.k8s.resources]
# limits."nvidia.com/gpu" = 1
# ///
```

## CoreWeave (CKS) Specifics

### GPU Workloads

Use `podOverrides.nodeSelector` to target GPU node pools:

```yaml
spec:
resources:
limits:
nvidia.com/gpu: 2
podOverrides:
nodeSelector:
compute.coreweave.com/node-pool: gpu-node-pool
```

Or via notebook frontmatter:
```python
# [tool.marimo.k8s.resources]
# limits."nvidia.com/gpu" = 2
```

See `plugin/nccl-all-reduce.yaml` for a multi-GPU NCCL all-reduce benchmark example.

### CoreWeave Object Storage (`cw://`)

`cw://` mounts attach CoreWeave S3 buckets via an s3fs sidecar (FUSE). The plugin auto-creates the `cw-credentials` secret from `~/.s3cfg`.

**Setup:**
```bash
# 1. Create access policy, bucket, and token via cwic
cwic cwobject policy create -f cw-policy.json
cwic cwobject mb my-bucket
cwic cwobject token create --name marimo-s3 --duration Permanent

# 2. Configure ~/.s3cfg
cat > ~/.s3cfg << EOF
[default]
access_key = CWXXXXXXXXXX
secret_key = cwXXXXXXXXXXXX
host_base = cwobject.com
host_bucket = %(bucket)s.cwobject.com
use_https = True
EOF

# 3. Deploy with mount (auto-creates cw-credentials secret)
kubectl marimo edit --source=cw://my-bucket notebook.py
```

Credentials are read from `~/.s3cfg` sections in priority order: `[namespace]` > `[marimo]` > `[default]`. This allows per-namespace credentials in multi-tenant clusters.

For LOTA-optimized access from GPU nodes, override the S3 endpoint:
```bash
kubectl set env deployment/marimo-operator-controller-manager \
-n marimo-operator-system \
S3_ENDPOINT=http://cwlota.com
```

Mounted buckets are accessible at `/home/marimo/notebooks/mounts/cw-0/` (cw-1/, cw-2/ for additional mounts).

See `plugin/docs/cw-mounts.md` for full setup, multi-tenancy, and troubleshooting.
Loading
Loading