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.
| macOS | Windows (Intel/AMD) | Windows (ARM) |
|---|---|---|
| 🚀 Download .app | 🚀 Download .exe | 🚀 Download .exe |
- Download and unzip the file for your platform
- Double-click the executable (
.appon macOS,.exeon Windows) - A file picker appears — select a
.ipynbor.pyfile - 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.
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:
- Open System Settings → Privacy & Security
- Scroll to the bottom of the page
- 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:
- Click "More info" on the warning dialog
- Click "Run anyway"
- An internet connection on first run (to fetch
uvand packages — cached locally after that) - Nothing else, no Python, no conda, no pip!
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.
The launcher runs .ipynb files using uvx juv run, which requires each notebook to declare its dependencies inline using PEP 723 script metadata.
Install uv, then add dependencies to your notebook:
uvx juv add my_notebook.ipynb numpy pandas matplotlibThis writes a hidden # /// script cell into the notebook. You can verify it works locally:
uvx juv run my_notebook.ipynbAdd 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.
The launcher inspects each .py file for PEP 723 inline script metadata and chooses the right runner automatically:
- If
marimois listed as a dependency → opens in edit mode by default (or the mode fixed in the file) - Otherwise → runs with
uv run
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.pyBy 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].
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "numpy>=1.26",
# "pandas>=2.0",
# ]
# ///You can verify it works locally:
uv run my_script.pySince 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.