Metadata-Version: 2.3
Name: marimo-dev
Version: 0.3.7
Summary: Build and publish python packages from marimo notebooks
Author: Deufel
Author-email: Deufel <MDeufel13@gmail.com>
License: MIT
Classifier: Development Status :: 3 - Alpha
Requires-Dist: html-tags>=0.0.18
Requires-Python: >=3.12
Project-URL: PyPI, https://pypi.org/project/marimo-dev/
Project-URL: Repository, https://github.com/deufel/m-dev
Description-Content-Type: text/markdown

# marimo-dev
![PyPI version](https://img.shields.io/pypi/v/marimo-dev)


> [!WARNING]
> This project is under active development and is not an official marimo tool - Mar 2026


Build Python packages (and applications[in progress]) from Marimo notebooks.

## Why this exists

Marimo notebooks are excellent for development - they manage dependencies automatically, provide instant feedback, and let you import functions between notebooks without configuration. But publishing requires traditional Python packages with proper module structure and `__init__.py` files.

marimo-dev bridges this gap. It extracts decorated functions and classes from your notebooks and writes them to clean Python modules, leaving behind the exploratory code, UI elements, and notebook-specific logic.

## Limitations

Unlike [nbdev](https://nbdev.fast.ai/) (which this project was heavily inspired by) from we rely on the marimo DAG to identify the functions that will be exported into the final function. This means you really have to write things functionaly. For myself this constraint has helped out a lot. but because of this marimo has its own enforced naming limitations mainly `_foo()` stays local to the cell; cannot use `app()` and another few random reserved function names. The workaround currently is a bit ugly but it seems to be working. we allow the user to specify a dict of renameing conventions (these are replaced globaly so be weary of this but the regx should be safe that it does not match unintented tagets `internal_foo` WILL not match `internal_foobar`). Id the replacement is a "dunder" it is both prepended and appended to the stem.

```toml
[tool.marimo-dev]
  renames = {
    dunder_   = "__",   # __stem__
    internal_ = "_",    # _stem
    app_      = "app"   # exact substitution (empty stem)
  }
```

## Quick start

```bash
uv init --lib my-project
cd my-project
uv add marimo marimo-dev
mkdir notebooks
```

Create `notebooks/a_core.py`:

```python
import marimo
app = marimo.App()

@app.function
def greet(name:str="World"):
    "Return a greeting"
    return f"Hello, {name}!"
```

Build and publish:

```bash
md build
md publish --test
```

## Project structure

```
my-project/
├── pyproject.toml
├── notebooks/
│   ├── a_core.py      # letter prefix avoids collision with 'core' package
│   ├── b_utils.py     # avoids collision with 'utils' package
│   └── XX_draft.py    # XX_ prefix = ignored during build
├── src/               # generated by md build
│   └── my_project/
│       ├── __init__.py 
│       ├── core.py    # letter prefix stripped
│       └── utils.py
└── docs/              # generated by md build
    └── llms.txt       # API signatures for LLM consumption
```

## Module naming

Prefix notebooks with letters (`a_`, `b_`, `c_`) to avoid name collisions with common packages like `requests`, `utils`, or `core`. The prefix is stripped in the built package.

During development, import from other notebooks using their full names:

```python
from a_core import greet
```

marimo-dev rewrites these to relative imports in the built package:

```python
from .core import greet
```

## What gets exported

1. **Constants in setup cells** — any assignment in a setup cell becomes a constant
2. **Decorated functions and classes** — [self-contained functions and classes](https://docs.marimo.io/guides/reusing_functions/) with `@app.function` or `@app.class_definition`
3. **Export-named cells** — name a cell `export` (or `export_something`) to export arbitrary code as a blob:

```python
@app.cell
def export_main():
    if __name__ == "__main__":
        main()
    return
```

This is useful for code that isn't a function or class, like `if __name__ == "__main__"` blocks.

## Hash pipe directives

Control export and documentation behavior with `#|` directives on the line immediately after a decorator:

```python
@app.function
#| nodoc
def helper(): 
    pass  # exported but not in llms.txt

@app.function
#| internal
def private(): 
    pass  # not added to __all__

@app.function
#| nodoc internal
def helper(): 
    pass  # neither exported nor documented
```

## Documentation style

Use inline comments for parameter documentation:

```python
@app.function
def add(
    a:int, # first number
    b:int, # second number
)->int:    # sum of a and b
    "Add two numbers"
    return a + b
```

These comments appear in `llms.txt`, making your API documentation useful for LLM-assisted coding.

## Configuration

Add to `pyproject.toml` to override defaults:

```toml
[tool.marimo-dev]
nbs = "notebooks"           # notebook directory (default: "notebooks")
out = "src"                 # output directory (default: "src")
docs = "docs"               # docs directory (default: "docs")
decorators = ["app.function", "app.class_definition"]  # export markers
skip_prefixes = ["XX_", "test_"]  # ignore these files
```

## Commands

```bash
md build              # build package from notebooks and make docs
md bundle             # bundle into single file with PEP 723 dependencies
md bundle app.py      # bundle to specific filename at project root
md docs               # build the static docs (beta)
md publish --test     # publish to Test PyPI
md publish            # publish to PyPI
md tidy               # remove __pycache__ and cache files
md nuke               # remove all build artifacts (dist, docs, src, temp*)
```
*If you make a temp folder it will be explicitly removed when running `md nuke`*

## Single-file applications

Use `md bundle` to create a standalone Python file with [PEP 723](https://peps.python.org/pep-0723/) inline dependencies:

```bash
md bundle app.py
uv run app.py
```

The generated file includes a dependency header that `uv` reads automatically:

```python
# /// script
# dependencies = ["fasthtml", "uvicorn"]
# ///
```

This lets you deploy a single `.py` file — anyone with `uv` can run it without manual dependency installation.

## Dependencies

Marimo manages package dependencies automatically through its package tab. You do not need to manually maintain `pyproject.toml` dependencies during development.

When you build, ensure your `pyproject.toml` includes all packages your exported functions import.

## Requirements

- Python 3.12+
- marimo
- uv

## Tips

- Update `version` in `pyproject.toml` before publishing
- Use `uv sync --upgrade` to update dependencies
- Use `uv cache clean` if you encounter caching issues
- Rebuild takes ~18ms, so you can run `md build` frequently during development