Skip to content

fdrgsp/pyrunner

Repository files navigation

pyrunner icon
pyrunner

A standalone desktop launcher for Jupyter and marimo notebooks, and plain Python scripts. Double-click to run any .ipynb or .py file that has inline dependencies, no Python installation required.

Files must declare their dependencies using the PEP 723 inline script metadata format. The launcher uses juv + uv for .ipynb files, marimo + uv for .py files that declare marimo as a dependency, and plain uv run for other .py scripts.

Download

macOS Windows (Intel/AMD) Windows (ARM)
🚀 Download .app 🚀 Download .exe 🚀 Download .exe

How it works

  1. Download and unzip the file for your platform
  2. Double-click the executable (.app on macOS, .exe on Windows)
  3. A file picker appears — select a .ipynb or .py file
  4. The file opens in your browser (notebooks) or terminal (scripts)

First run only: uv and all packages are downloaded and cached automatically. Subsequent runs are fast.

Important

If uv is not already installed, the launcher will download and install it automatically on first run — no permission prompt will appear. On Windows, the launcher also silently sets the PowerShell execution policy to RemoteSigned for the current user to ensure the install script can run. On managed or enterprise machines where Group Policy enforces the execution policy, this may be blocked — in that case, an administrator will need to allow PowerShell scripts to run.

Platform notes

macOS Gatekeeper warning: on first launch macOS may show a popup with only "Delete" or "Done" as options and block the app from opening. If this happens:

  1. Open System Settings → Privacy & Security
  2. Scroll to the bottom of the page
  3. You will see a message about the app being blocked — click "Open Anyway"

Windows SmartScreen warning: on first launch Windows may show a warning that the app is from an unknown publisher. If this happens:

  1. Click "More info" on the warning dialog
  2. Click "Run anyway"

What users need

  • An internet connection on first run (to fetch uv and packages — cached locally after that)
  • Nothing else, no Python, no conda, no pip!

Preparing your files

Under the hood, pyrunner uses uv to run scripts in isolated environments. All files must declare their dependencies using PEP 723 inline script metadata. Since uv is the runner, you can use any feature it supports for scripts — including alternative indexes, reproducibility pinning, and the full [tool.uv] configuration block.

Jupyter notebooks (.ipynb)

The launcher runs .ipynb files using uvx juv run, which requires each notebook to declare its dependencies inline using PEP 723 script metadata.

Option 1: Use juv add (recommended)

Install uv, then add dependencies to your notebook:

uvx juv add my_notebook.ipynb numpy pandas matplotlib

This writes a hidden # /// script cell into the notebook. You can verify it works locally:

uvx juv run my_notebook.ipynb

Option 2: Add the metadata manually

Add a code cell at the top of your notebook with:

# /// script
# requires-python = ">=3.11"
# dependencies = [
#   "numpy>=1.26",
#   "pandas>=2.0",
#   "matplotlib>=3.8",
# ]
# ///

This cell tells juv which packages to install in the isolated environment.

Python scripts (.py)

The launcher inspects each .py file for PEP 723 inline script metadata and chooses the right runner automatically:

  • If marimo is listed as a dependency → opens in edit mode by default (or the mode fixed in the file)
  • Otherwise → runs with uv run

marimo notebooks

marimo must be listed as a dependency — this is how pyrunner detects that a .py file is a marimo notebook and opens it with marimo instead of uv run.

# /// script
# requires-python = ">=3.11"
# dependencies = [
#   "marimo",
#   "numpy>=1.26",
#   "pandas>=2.0",
# ]
# ///

You can verify it works locally:

uvx marimo edit my_notebook.py
# or in read-only mode:
uvx marimo run my_notebook.py

Fixing the open mode

By default marimo notebooks open in edit mode. To pin a notebook to a specific mode — for example a read-only notebook — add a [pyrunner] section inside the # /// script block:

# /// script
# requires-python = ">=3.11"
# dependencies = [
#   "marimo",
#   "numpy>=1.26",
# ]
#
# [pyrunner]
# marimo-mode = "run"  # or "edit" (default)
# ///

Accepted values:

Value Effect
"run" Opens in read-only app mode (marimo run)
"edit" Opens in full editor mode (marimo edit) — this is the default

uv ignores the [pyrunner] section when running the script — it only reads requires-python, dependencies, and [tool.uv].

Plain Python scripts

# /// script
# requires-python = ">=3.11"
# dependencies = [
#   "numpy>=1.26",
#   "pandas>=2.0",
# ]
# ///

You can verify it works locally:

uv run my_script.py

Using [tool.uv] in script metadata

Since pyrunner uses uv under the hood, you can use the [tool.uv] configuration block inside your script metadata for advanced features like alternative package indexes or reproducibility pinning:

# /// script
# requires-python = ">=3.11"
# dependencies = [
#   "numpy>=1.26",
#   "pandas>=2.0",
# ]
#
# [[tool.uv.index]]
# url = "https://example.com/simple"
#
# [tool.uv]
# exclude-newer = "2025-01-01T00:00:00Z"
# ///

See the uv scripts guide for all supported options.

About

Distribute Jupyter and marimo notebooks and python files as double-click desktop apps using uv + PEP723.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors