# Use Comma with marimo: Export the Notebook, Review It Like a Doc

Canonical: https://commareports.com/with/marimo

> marimo exports reactive Python notebooks to HTML — then leaves sharing to you. Publish the export to Comma for anchored comments, share roles, and revisions on a stable link.

# Use Comma with marimo

marimo fixed the notebook half of the problem: reactive execution, no
hidden state, notebooks stored as plain Python files that diff cleanly in
git. And it ships an honest export story — `marimo export html` snapshots
the notebook, outputs included, into an HTML file.

What it doesn't ship is the step after: the analysis is done, the export
exists, and now a PM, a data lead, and two engineers need to read it and
tell you what's wrong with it. Git diffs of the `.py` file review the
_code_. Nobody reviews the _findings_ in a diff.

Comma is that step. Publish the export, share one link, and feedback
arrives anchored to the exact output it's about.

## The pipeline

### 1. Export the notebook

```bash
marimo export html retention_analysis.py -o retention.html
```

This snapshots the notebook as it last ran — markdown, code, rendered
outputs — into a single HTML document. That's the right artifact for
review: the run you got, frozen, not a live re-execution that might
differ. (Skip the `html-wasm` export here; it builds a multi-file site
for static hosting, and Comma takes one document.)

### 2. Publish it to Comma

The create endpoint accepts JSON with a required `html` field and
optional `title` and `description`:

```bash
jq -Rs '{title: "Retention analysis — June", html: .}' retention.html |
  curl -s -X POST https://commareports.com/api/v1/reports \
    -H "Authorization: Bearer $COMMA_API_TOKEN" \
    -H "Content-Type: application/json" \
    --data-binary @-
```

The response carries the link to share:

```json
{
  "id": "b27e…",
  "title": "Retention analysis — June",
  "created_at": "2026-06-10T08:00:00Z",
  "edit_url": "/r/b27e…",
  "share_url": "/p/b27e…"
}
```

Reports default to public-with-link, view-only. Add
`"public_permission": "comment"` so anyone with the link can comment, or
`"visibility": "private"` to restrict it to people you invite. Tokens are
minted under **Settings → API tokens**, scoped and revocable. HTML up to
5 MB.

### 3. Review like a document

Reviewers open the link in a browser — no marimo install, no environment
setup, no repo access. They highlight a sentence in your markdown
commentary or a cell in a results table and pin a comment to it,
Google-Docs style. Threads, replies, resolution. Commenting is free on
every plan — unlimited commenters, no per-seat cost. You pay only for the
AI compute a routine uses.

### 4. Re-run, republish, same link

When the comments come back — "cell 4's join is dropping nulls," "rerun
with the May cohort included" — fix the notebook, export, and PATCH:

```bash
jq -Rs '{html: .}' retention.html |
  curl -s -X PATCH "https://commareports.com/api/v1/reports/$REPORT_ID" \
    -H "Authorization: Bearer $COMMA_API_TOKEN" \
    -H "Content-Type: application/json" \
    --data-binary @-
```

Comma appends a revision under the same share URL and keeps the comment
threads attached, so the conversation and the artifact stay in one
place across runs.

## What renders, honestly

Comma renders the export untouched in an opaque-origin sandbox — no
reformatting, no restyling. One deliberate exception: the API strips
`<script>` tags before storage, as defense-in-depth on an endpoint that
accepts arbitrary HTML. For a marimo export that means markdown, code,
tables, and static figures (matplotlib SVG/PNG, rendered DataFrames)
survive faithfully, while script-driven interactivity — altair/plotly
tooltips, marimo UI elements — renders statically or not at all.

For review that's usually the right trade: a comment can anchor to a
rendered chart; it can't anchor to a hover state. Keep the interactive
notebook for exploration and publish the snapshot for review.

## With an agent in the loop

If the notebook is run by Claude Code or Cursor, skip the curl. Comma's
MCP server exposes `create_report`, `update_report`, `list_comments`, and
`reply_to_comment` as typed tools under the same `comma_sk_…` token. The
agent exports the notebook, publishes the HTML, and — on its next run —
reads the anchored comments and addresses them before republishing. The
[Claude Code plugin](/mcp/claude-code) installs in one line.

To make the whole thing recur, either run the export + PATCH from your
own cron (works on Free), or use [Comma routines](/features/routines) —
hosted scheduling that re-runs a skill and republishes at any cadence on
every plan. You pay only for the AI compute (bring your own AWS Bedrock key
for free, or draw down prepaid credits).

## Try it

Export a notebook you've already run and publish it. The difference shows
up in the first comment: it lands on the row of the table it's about,
instead of in a Slack thread describing where to look.

**[Create your first report →](https://commareports.com/)**

### Related

- [Use Comma with Quarto](/with/quarto) — the document-renderer pipeline
- [Use Comma with Jupyter](/with/jupyter) — the classic-notebook pipeline via nbconvert
- [Datapane alternative](/alternatives/datapane-alternative) — the publish-and-share gap
- [Comment on HTML](/comment-on-html) — how anchored comments work
