Skip to main content

chumicro-deploy

Push code onto a CircuitPython or MicroPython board, probe its identity, and flash firmware, all from your laptop.

Ship a host directory, a file map you built in memory, or only the modules your entrypoint actually imports. Run the payload from RAM while you iterate, or write it to flash when the code has to survive a reboot. When a deploy fails you get the reason (another app is holding the serial port, the CIRCUITPY drive ejected, the raw REPL is stuck, macOS wedged its FSKit filesystem extension) and the steps that clear it, instead of a raw traceback. Available as a Python API and as a chumicro-deploy CLI.


Part of the ChuMicro family: small, focused Python libraries for microcontrollers and laptops. Browse all workbench tools. This is a workbench tool: it runs on your laptop, not on the board.

Install

pip install chumicro-deploy-experimental

pyserial (CircuitPython transport) and mpremote (MicroPython transport) come along as dependencies. On macOS and Linux you'll also need rsync available on $PATH for flash-mode deploys to the CIRCUITPY USB drive. Install it via brew install rsync (macOS Homebrew if not already shipped), apt-get install rsync (Debian/Ubuntu), dnf install rsync (Fedora), pacman -S rsync (Arch), apk add rsync (Alpine), or zypper install rsync (openSUSE). Native Windows isn't currently supported (raises WindowsNotSupportedError on import); WSL2 works.

Experimental (pre-release) versions and channel switching

Pre-release builds are published automatically when the package version is bumped.

pip install chumicro-deploy-experimental

Quick example

Deploy a one-liner to a connected MicroPython board and read its output back:

from chumicro_deploy import Device, Deployer, FileMapSource

device = Device(
    transport="micropython",
    address="/dev/cu.usbmodem14101",  # see `chumicro-deploy probe --address ...` to identify
    deploy_mode="ram",                # no flash wear, no CIRCUITPY drive needed
)
source = FileMapSource(
    {"/main.py": "import sys\nprint(f'hello from {sys.implementation.name}')"},
    entrypoint="/main.py",
)

result = Deployer(device).deploy_diff(source)
print(result.execute_output)  # → "hello from micropython"

For a workspace project that already has a devices.yml, swap the Device(...) constructor for chumicro_deploy.config.default.load_devices_yml("devices.yml", device_id="my-board").

What's included

Programmatic API

Symbol Description
Device(transport, address, deploy_mode, ...) Configure a target board. Build explicitly or via Device.from_dict(...); or load a registry via load_devices_yml(...) / load_device_registry(...)
Deployer(device) Deploy orchestrator for one board. deploy_diff is its one deploy method
Deployer.deploy_diff(source, *, clean=True, wipe=False, ...) Push a FileSource, run the entrypoint, and delete the on-device files that aren't in the new payload. Returns a DeployResult with success / output / traceback. Clean-slate by default; clean=False reconciles only the entrypoint, state files, and /lib; wipe=True erases the filesystem first
RecoveringDeployer(deployer, *, prompt=None, max_attempts=3) Wraps Deployer with failure classification and a RecoveryPlan. Pass prompt=input for an interactive retry loop; default prompt=None reports once and re-raises. Both CLIs use the interactive form by default (--non-interactive to opt out)
FileMapSource(files, entrypoint) In-memory dict[device_path, bytes] source, for generated payloads or one-off scripts
DirectorySource(directory, entrypoint, resource_prefix) Walk a host directory and ship every file under it
ImportGraphSource(entrypoint, search_paths, device_entrypoint) AST-walk the entrypoint and ship only transitively-imported modules
probe_device(device) → DeviceInfo Identify a connected board (runtime, version, machine string, CPU UID)
flash_firmware(url, device, reflash_method, ...) Download + apply firmware via UF2 (Pi Pico family) or esptool (ESP32 family)
resolve_firmware_url(board_id, runtime, version) Build the canonical Adafruit / micropython.org download URL
classify_deploy_failure(error) → DeployFailureKind Standalone classifier for building your own failure-handling on top of Deployer
detect_fskit_wedge() → bool macOS-only probe for the FSKit / DiskArbitration wedge that can leave CIRCUITPY drives unmountable

devices.yml writer surface

chumicro_deploy.config.devices_yaml (separate submodule) reads and writes the device registry round-trip, preserving comments and key order, and classifies every field into one of three zones (user-owned / hardware-once / probed-always). This is what chumicro-workspace add-device and friends sit on; consumers building their own onboarding flow against devices.yml use this surface directly.

Symbol What it does
read_devices_yml_template() → str The empty-registry devices.yml text, for writing a fresh file before the first device is registered
load_devices(path) → CommentedMap Parse with comments + key order preserved (returns ruamel CommentedMap, distinct from the typed reader at chumicro_deploy.config.default.load_devices)
dump_devices(data, path) Atomic write back via tempfile + rename
find_device(data, device_id) / list_device_ids(data) Read-only lookups against the loaded document
add_device(data, *, device_id, runtime, address, hardware, ...) Append a new entry; raises DeviceAlreadyExistsError on id collision
remove_device(data, device_id) → CommentedMap Drop an entry and null any defaults: key that pointed at it. Returns the removed entry, so the same id can be re-registered. Raises DeviceNotFoundError when there's no match
update_device_address(data, device_id, new_address) Silent refresh; address is in the probed-always zone
update_device_firmware_version(data, device_id, new_version) Silent refresh of the cached firmware_version
update_device_hardware(data, device_id, *, force=False, **fields) Hardware-once zone. Raises HardwareOverwriteError on a value change unless force=True
rename_device(data, old_id, new_id) / set_runtime_default(data, runtime, device_id) Higher-level mutations
USER_OWNED_FIELDS / PROBED_ALWAYS_FIELDS / HARDWARE_ONCE_FIELDS / HARDWARE_BLOCK_ZONES The canonical zone classification, the single source of truth that the typed reader's _KNOWN_KEYS derives from

CLI subcommands

python -m chumicro_deploy <subcommand> (or just chumicro-deploy-experimental <subcommand> after pip install). The three board-facing subcommands accept --devices-file devices.yml --device <id> instead of --transport + --address for workspace-style invocations.

Subcommand What it does
probe Identify a board's runtime / version / machine / UID. --json for machine-readable output
deploy Push a --directory or --file-map to the board and run the --entrypoint. Interactive coaching by default; --non-interactive for CI
flash-firmware Download and apply firmware. --method uf2 or --method esptool, inferred from the URL extension when omitted. On the esptool path the flash is erased first, wiping the CIRCUITPY drive, NVS, and stored WiFi credentials; pass --no-erase to keep user data on an in-place upgrade. --non-interactive fails instead of prompting on bootloader entry
resolve-firmware-url Print the CircuitPython firmware URL for a --board-id + --runtime + --version (no board needed)

Testing fakes

Symbol What it does
FakeTransport Implements TransportProtocol + ExtendedTransportProtocol for unit-testing Deployer orchestration without real hardware
FakeSerialPort Scriptable pyserial substitute for CircuitpythonTransport tests
FakeTime Deterministic clock for Deployer / transport / flash_firmware tests

Where this fits

Leaf: no upstream ChuMicro deps (uses third-party pyserial and mpremote for transport). Sister of chumicro-repl, substrate for chumicro-workspace and chumicro-pytest-device.

Companion: chumicro-repl

chumicro-repl is the sister workbench tool for opening interactive serial sessions and tailing the friendly REPL after a deploy. Both packages consume the same devices.yml schema (owned here in chumicro_deploy.config.default), so a single workspace file points both at the same boards. Use chumicro_repl.tail(device, seconds) to follow a deploy and fail-fast on a traceback; use chumicro_repl.ReplSession(device) for headless test fixtures over raw REPL.

Examples

Example What it shows
programmatic_deploy.py Minimal Deployer + DirectorySource walkthrough
file_map_deploy.py Multi-file payload built in memory via FileMapSource
import_graph_deploy.py ImportGraphSource AST-walk that ships only the modules the entrypoint actually imports
demo_recovery_hand_holding.py Interactive walk through every DeployFailureKind recovery scenario against real hardware

Contributing

Issues, bug reports, and pull requests are welcome, and so is "I ran it on this board and here's what happened", some of the most useful feedback a hardware project can get. Development happens in the ChuMicro repository, whose contributing guide covers setup and the test workflow.

Docs

📖 Stable docs · Experimental docs

Find this library

License

MIT

Metadata

Release files for chumicro-deploy-experimental 0.39.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for chumicro-deploy-experimental 0.39.0
File Size Uploaded
chumicro_deploy_experimental-0.39.0.tar.gz 168.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for chumicro-deploy-experimental 0.39.0
File Interpreter ABI Platform
chumicro_deploy_experimental-0.39.0-py3-none-any.whl Python 3 none any Details

Total release size: 360.8 kB

Release files / chumicro_deploy_experimental-0.39.0.tar.gz

Download URL chumicro_deploy_experimental-0.39.0.tar.gz
Size 168.4 kB
Tags Source
SHA-256 checksum
How to use checksums
fbd23150ac3b017fce9f66959ff541c9bf73724713c53df7a0becf5b1366cdd0
BLAKE2b-256 checksum
How to use checksums
1b475b79071a41bfb3be9a27633ea822fa4485ef677e9f971c58cf6e3f86c304
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 8, 2026.

Transparency log

Release files / chumicro_deploy_experimental-0.39.0-py3-none-any.whl

Download URL chumicro_deploy_experimental-0.39.0-py3-none-any.whl
Size 192.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c334e52e5c16dcb42cf6d71c7185657ac05be275652ca5571f21fc8266f32283
BLAKE2b-256 checksum
How to use checksums
8156c9773a2f6b9b42301efd16909ee34ad9e81531c420ff29758592a16b6c1b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 8, 2026.

Transparency log

Release history Release notifications | RSS feed

0.39.4

2 release files

This release

0.39.0 This release

2 release files

0.38.0

2 release files

0.37.2

2 release files

0.37.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page