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
.pycode, 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,ioetc. 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-libfills most stdlib gaps. Modules likeargparse,pathlib,dataclasses,typing,unittestare available via micropython-lib and are declared withrequire("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
asynciois a subset of CPython's. Coroutines, tasks, queues, locks,gather,wait_forwork;asyncio.runwith policies, debug mode, theloop.add_signal_handlerinterface, 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
picoletCLI 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-13Intel,macos-14Apple 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
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
- Getting started — step-by-step tutorial
manifest.pyguide — declaring frozen modules +require()frommicropython-liband community packages- Architecture — design decisions
- Caveats — MicroPython compatibility reference
- Examples tour — what each example app demonstrates
- CLI reference — every
picoletsubcommand - SBOM — supply-chain documentation
- History — phase artefacts and version-specific specs/plans/audits
License
MIT throughout. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7af4876738ec31f38ae6959e34530dfe09ad1ae793a444d08ec1d7965833ea7d
|
|
| MD5 |
08fe2f19eb200b84e37f0ce38a23b032
|
|
| BLAKE2b-256 |
100accbd82af553ac9c33f5b40941f012f9c6f845aafd24d2873bc4180b25ccd
|
Provenance
The following attestation bundles were made for picolet-0.0.1.tar.gz:
Publisher:
pypi-publish.yml on andrewleech/picolet
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
picolet-0.0.1.tar.gz -
Subject digest:
7af4876738ec31f38ae6959e34530dfe09ad1ae793a444d08ec1d7965833ea7d - Sigstore transparency entry: 1703035761
- Sigstore integration time:
-
Permalink:
andrewleech/picolet@7aa671a804890d8488b26a0742b7c0ee6957a912 -
Branch / Tag:
refs/heads/dev - Owner: https://github.com/andrewleech
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@7aa671a804890d8488b26a0742b7c0ee6957a912 -
Trigger Event:
workflow_dispatch
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e1eeaa982bd4f36de7c8c313b390323d42dcab6a39c2b5959d06f724956fe67
|
|
| MD5 |
ca997c80dc1c83d649969b473a12a0f1
|
|
| BLAKE2b-256 |
33ce28f3b21d368240a7f4d0f07f0f141ac774fdd89c0ae5ce50b04190011c01
|
Provenance
The following attestation bundles were made for picolet-0.0.1-py3-none-any.whl:
Publisher:
pypi-publish.yml on andrewleech/picolet
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
picolet-0.0.1-py3-none-any.whl -
Subject digest:
6e1eeaa982bd4f36de7c8c313b390323d42dcab6a39c2b5959d06f724956fe67 - Sigstore transparency entry: 1703035845
- Sigstore integration time:
-
Permalink:
andrewleech/picolet@7aa671a804890d8488b26a0742b7c0ee6957a912 -
Branch / Tag:
refs/heads/dev - Owner: https://github.com/andrewleech
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@7aa671a804890d8488b26a0742b7c0ee6957a912 -
Trigger Event:
workflow_dispatch
-
Statement type: