Skip to main content

Compile Python programs to small self-contained native binaries via MicroPython

Project description

Picolet

Compile a Python program into a small self-contained native executable. Like PyInstaller, but the binary is hundreds of kilobytes rather than tens of megabytes, starts in milliseconds, and has no runtime Python dependency on the host.

The shape of it

A Picolet binary is one file. Inside:

  • A trimmed MicroPython interpreter (~410–650 KB depending on renderer).
  • Your application's .py code, compiled to bytecode and frozen into the binary.
  • Optional bundled assets (HTML, fonts, images, schemas) as a read-only ROM filesystem appended to the executable.
  • Optionally: a GUI renderer (system webview or native LVGL) for HTML/JS or native UIs.

The result runs on any matching-OS/arch machine without installing Python.

Three ways to use it

1. Bundle a single CLI script

The simplest case:

picolet build hello.py
./hello                # Linux  ≈ 647 KB
./hello.exe            # Windows ≈ 409 KB

hello.py becomes a self-contained executable. Sub-second startup. No python interpreter needed on the host machine. Roughly 20–50× smaller than the equivalent PyInstaller bundle, with no first-launch unpacking delay.

2. Manifest-driven build

For multi-module apps, drive the build from a MicroPython manifest.py:

# manifest.py
require("argparse")                   # frozen micropython-lib module
require("typing")
freeze("./src", "main.py")            # your entry
freeze("./src/lib", "utils.py")       # additional modules
freeze("./src/lib", "data_model.py")
picolet build --manifest manifest.py

The manifest is the canonical MicroPython mechanism for declaring what's frozen into a build. Picolet uses it directly — everything declared is included.

Medium-term: romfs contents (HTML, fonts, etc.) declared in the same manifest, per upstream evolution.

3. GUI application

Add a picolet.toml to pick a renderer and bundle UI assets:

[app]
name = "my-app"
entry = "src/main.py"

[ui]
renderer = "webview"            # or "lvgl" for native
root = "ui"

[window]
title = "My App"
size = [900, 600]

[romfs]
include = ["ui", "assets"]
picolet build

For Vue or other JS framework frontends:

[ui.frontend]
framework = "vue"               # builds Vite output into romfs automatically

The IPC bridge is set up automatically:

// JS side
await window.picolet.invoke('list_items', { filter: 'active' });
window.picolet.on('progress', e => bar.update(e.pct));
# Python side
@picolet.command
async def list_items(args):
    return [...]

Four worked examples under examples/ (pydfu, notes, config-editor, dashboard) demonstrate the patterns end-to-end, each with a distinct visual aesthetic.

Caveats

Read these before adopting.

  • MicroPython, not CPython. The standard library subset is smaller. Pure-Python code using os, sys, json, re, time, asyncio, struct, io etc. typically works. Code that depends on C extensions (numpy, pandas, Pillow, lxml, etc.) does not. Picolet cannot make a CPython library "just work" — it would have to be ported or replaced with a MicroPython equivalent.

  • micropython-lib fills most stdlib gaps. Modules like argparse, pathlib, dataclasses, typing, unittest are available via micropython-lib and are declared with require("name") in the manifest.

  • Custom C modules are straightforward. A Picolet binary is a MicroPython build under the hood, so any C module written against the standard MicroPython API works. Drop a directory under user_c_modules/ and reference it in the manifest. Once upstream PR #18229 lands in the fork, c_module("./path/to/mymodule") can declare it directly in the manifest.

  • Python C-API extensions (CPython .so/.pyd) do NOT work. MicroPython's runtime is binary-incompatible with CPython. Write a MicroPython C module instead.

  • Async semantics differ slightly. MicroPython's asyncio is a subset of CPython's. Coroutines, tasks, queues, locks, gather, wait_for work; asyncio.run with policies, debug mode, the loop.add_signal_handler interface, and some niche APIs don't. Most app code is unaffected.

  • First-class platform support is Linux x64 and Windows x64. macOS (Intel + Apple Silicon) is source-complete but requires GitHub Actions CI for native builds — local cross-compile from Linux is not supported. ARM Linux and mobile platforms are on the backlog.

See docs/caveats.md for a full catalogue.

Toolchain expectations

  • The picolet CLI runs on Linux, macOS, or Windows (host).
  • Building Windows binaries from Linux uses dockcross; Docker is required for that path.
  • Building macOS binaries uses GitHub Actions runners (macos-13 Intel, macos-14 Apple Silicon).
  • Node.js + npm are required only when building Vue/React frontends.

Getting started

Install the CLI. uv tool install is the recommended path (no separate package manager needed if you already use uv); pipx is the fallback for environments without uv. Plain pip install is deliberately not listed — most modern distros (PEP 668) block it system-wide.

uv tool install picolet-cli                       # recommended
# or:
pipx install picolet-cli                          # fallback

picolet init my-app --template hello-cli          # see --list-templates for the full set
cd my-app
picolet dev                                        # live rebuild on file changes
picolet build                                      # produce target/<os-arch>/my-app[.exe]

Templates: hello-cli, hello-webview, hello-lvgl, hello-vue, pydfu, notes, config-editor, dashboard.

Examples gallery

pydfu screenshot
pydfu
DFU firmware flasher (industrial control-panel aesthetic)
notes screenshot
notes
Markdown notes (editorial / refined)
config-editor screenshot
config-editor
Schema-driven TOML/YAML/JSON editor (brutalist terminal)
dashboard screenshot
dashboard
Live system metrics (data-dense)

See docs/examples.md for a longer tour of each.

Renderers

Renderer Backed by Use case Binary size (typical)
(none) CLI tool, no UI ~647 KB Linux / ~409 KB Windows
webview WebKitGTK 4.1 (Linux), WebView2 (Windows), WKWebView (macOS) HTML/CSS/JS frontend ~710 KB Linux / ~525 KB Windows
lvgl lv_binding_micropython + SDL2 Native widgets, zero system UI deps ~1.84 MB Linux / ~2.05 MB Windows

Repository layout

picolet/
├── packages/
│   ├── picolet-cli/         # picolet init|dev|build|run|test
│   ├── picolet-runtime/     # the MicroPython runtime + variants + user_c_modules
│   ├── picolet-bridge-js/   # JS shim: window.picolet.invoke(...)
│   ├── picolet-templates/   # `picolet init --template <name>` starter packs
│   └── picolet-testing/     # AppHarness for autonomous test/screenshot
├── examples/              # four worked example apps
├── tests/                 # per-phase test suites
└── docs/                  # architecture, caveats, examples, CLI reference

More

License

MIT throughout. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

picolet-0.0.1.tar.gz (1.6 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

picolet-0.0.1-py3-none-any.whl (1.7 MB view details)

Uploaded Python 3

File details

Details for the file picolet-0.0.1.tar.gz.

File metadata

  • Download URL: picolet-0.0.1.tar.gz
  • Upload date:
  • Size: 1.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for picolet-0.0.1.tar.gz
Algorithm Hash digest
SHA256 7af4876738ec31f38ae6959e34530dfe09ad1ae793a444d08ec1d7965833ea7d
MD5 08fe2f19eb200b84e37f0ce38a23b032
BLAKE2b-256 100accbd82af553ac9c33f5b40941f012f9c6f845aafd24d2873bc4180b25ccd

See more details on using hashes here.

Provenance

The following attestation bundles were made for picolet-0.0.1.tar.gz:

Publisher: pypi-publish.yml on andrewleech/picolet

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file picolet-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: picolet-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 1.7 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for picolet-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6e1eeaa982bd4f36de7c8c313b390323d42dcab6a39c2b5959d06f724956fe67
MD5 ca997c80dc1c83d649969b473a12a0f1
BLAKE2b-256 33ce28f3b21d368240a7f4d0f07f0f141ac774fdd89c0ae5ce50b04190011c01

See more details on using hashes here.

Provenance

The following attestation bundles were made for picolet-0.0.1-py3-none-any.whl:

Publisher: pypi-publish.yml on andrewleech/picolet

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page