A full-featured CLI and GUI tool for managing files on a Raspberry Pi Pico — or any MicroPython board — over a serial connection.
Features · Installation · Quick Start · CLI Reference · GUI Guide · Troubleshooting
Working with a Raspberry Pi Pico means constantly copying files back and forth over a serial connection. The official mpremote tool is powerful but low-level — every operation requires you to remember exact flags and syntax.
pico-sync wraps mpremote into a friendly, high-level interface:
- 🖥️ Two interfaces in one — a scriptable CLI for automation and a visual GUI for interactive development
- 🔁 Bidirectional sync — copy files and entire folder trees from PC → Pico or Pico → PC with one command
- 🔍 Smart skip — unchanged files are skipped by default, so only what changed gets transferred
- ⚡ Auto-detect — no need to remember serial port names; pico-sync finds your device automatically
- 🧑💻 Built-in editor — edit, deploy, and run
.pyfiles directly from the GUI without switching tools - 🔒 Hash verification — compare MD5/SHA-256 checksums between local and remote files to confirm transfers
| Feature | CLI | GUI |
|---|---|---|
| Auto-detect connected Pico devices | ✅ | ✅ |
| List files on the Pico | ✅ | ✅ |
| Copy file / folder PC → Pico (recursive) | ✅ | ✅ |
| Copy file / folder Pico → PC (recursive) | ✅ | ✅ |
| Remove files / directories (recursive) | ✅ | ✅ |
| Create directories on the Pico | ✅ | ✅ |
| Deploy with skip-unchanged / force overwrite | ✅ | ✅ |
| Soft-reset the Pico | ✅ | ✅ |
| Run a Python script on the Pico | ✅ | ✅ |
| Execute arbitrary code snippets | ✅ | ✅ |
| Open interactive REPL | ✅ | ✅ |
| Compare file hashes (local ↔ Pico) | ✅ | ✅ |
| Mount a local directory on the Pico | ✅ | — |
| Built-in code editor with syntax-highlighted output | — | ✅ |
| Deploy + Run in one click | — | ✅ |
| Transfer panel (browse files/folders, send/receive) | — | ✅ |
| Requirement | Details |
|---|---|
| Python | 3.8 or newer |
| mpremote | Official MicroPython remote tool — pip install mpremote |
| customtkinter | Modern Tkinter UI library (GUI only) — pip install customtkinter |
| Hardware | Raspberry Pi Pico or any MicroPython-compatible board connected via USB |
Clone the repository and install in editable mode so you always run the latest code:
git clone https://github.com/at0m-b0mb/pico-sync.git
cd pico-sync
pip install -e .Install dependencies only (useful if you just want to run the scripts directly):
pip install -r requirements.txtpico-sync --version # prints the installed version
pico-sync devices # lists any connected Pico devicesTip: All commands auto-detect your Pico's serial port. Plug in your device first.
pico-sync devicespico-sync ls /pico-sync copy main.py :main.pypico-sync copy ./lib :/lib/pico-sync pull /main.py ./backup/main.py # single file
pico-sync pull /lib ./backup/lib # entire folderpico-sync deploy ./project :/app/ --resetpico-sync-gui
# or equivalently
python -m pico_syncAll commands share a common --port / -p option to override the auto-detected serial port.
pico-sync [--port PORT] COMMAND [ARGS...]
pico-sync devicesScans all serial ports and lists any device running MicroPython.
pico-sync ls / # list root directory
pico-sync ls /lib # list a subdirectoryPATH defaults to / if omitted.
Copy a local file or folder to the Pico. Folders are copied recursively.
pico-sync copy main.py :main.py # copy a file
pico-sync copy ./project :/project/ # copy a folder recursively
pico-sync copy --force main.py :main.py # delete remote first, then copy
pico-sync copy --no-skip ./lib :/lib/ # copy all files, skip nothing| Option | Description |
|---|---|
--force |
Delete the remote file/folder first, then copy |
--no-skip |
Copy all files even if they haven't changed (by default unchanged files are skipped) |
-p PORT |
Override the serial port |
Copy a file or folder from the Pico to your local machine. Folders are copied recursively.
pico-sync pull /main.py ./main.py # download a single file
pico-sync pull /lib ./backup/lib # download an entire folder
pico-sync pull -p COM9 /data ./data # specify port explicitlyDeploy a local file or folder to the Pico. Identical to copy but adds a --reset flag to soft-reset after the transfer completes.
pico-sync deploy ./project # deploy to Pico root
pico-sync deploy ./project :/app/ --reset # deploy and reset afterwards
pico-sync deploy --force --reset main.py # force overwrite, then reset| Option | Description |
|---|---|
--reset |
Soft-reset the Pico after deployment |
--force |
Delete existing remote file/folder before copying |
--no-skip |
Don't skip unchanged files |
pico-sync mkdir /lib
pico-sync mkdir /data/logspico-sync rm /old_file.py # remove a file
pico-sync rm -r /lib # recursively remove a directory| Option | Description |
|---|---|
-r, --recursive |
Remove directory and all of its contents |
Copies and executes a local .py file on the Pico, streaming output live to your terminal.
pico-sync run blink.pyRun an arbitrary Python expression or statement directly on the Pico without creating a file.
pico-sync exec "import machine; print(machine.freq())"
pico-sync exec "import os; print(os.listdir('/'))"Drop into a live MicroPython REPL session on the Pico. Press Ctrl-X to exit.
pico-sync replpico-sync resetMount a local directory on the Pico for live development. While mounted, the Pico reads files directly from your PC over the serial connection — no upload required.
pico-sync mount ./srcPrint the hash of a local file. When a REMOTE_PATH is also provided, the Pico file is hashed too and a MATCH / DIFFER verdict is printed — useful to confirm a transfer completed correctly.
pico-sync hash main.py # local hash only
pico-sync hash main.py /main.py # compare local ↔ Pico
pico-sync hash -a sha256 main.py /main.py # use SHA-256 instead of MD5| Option | Description |
|---|---|
-a ALGO |
Hash algorithm: md5 (default) or sha256 |
pico-sync-gui
# or
python -m pico_syncThe GUI window is split into four areas:
┌──────────────────────────────────────────────────────┐
│ Top bar │ Device selector · Detect · Connect │
├───────────────────────────┬──────────────────────────┤
│ Left panel │ Right panel │
│ ┌─────────────────────┐ │ ┌────────────────────┐ │
│ │ Local file browser │ │ │ Output terminal │ │
│ └─────────────────────┘ │ └────────────────────┘ │
│ ┌─────────────────────┐ │ ┌────────────────────┐ │
│ │ Pico file browser │ │ │ Exec input box │ │
│ └─────────────────────┘ │ └────────────────────┘ │
│ ┌─────────────────────┐ │ │
│ │ Transfer panel │ │ │
│ └─────────────────────┘ │ │
├───────────────────────────┴──────────────────────────┤
│ Bottom panel │ Code editor · Run · Deploy · Reset │
└──────────────────────────────────────────────────────┘
- Click Detect — pico-sync scans all serial ports for MicroPython boards
- Select your device from the dropdown
- Click Connect — the Pico file browser refreshes automatically
Local Files (top half):
| Action | How |
|---|---|
| Select a file | Single-click |
| Select a folder | Single-click (highlighted in blue) |
| Navigate into a folder | Double-click |
| Go up one level | Up button |
| Pick a different root | Browse button |
| Upload to Pico | Copy to Pico or Deploy |
| Hash a file | Hash button |
Pico Files (bottom half):
| Action | How |
|---|---|
| Select a file or folder | Single-click |
| Download to local directory | Copy to Local |
| Open in built-in editor | Open in Editor |
| Delete (with confirmation) | Remove |
| Create a new directory | MkDir |
| Hash a file | Hash button |
The Transfer panel gives you full path control over send and receive operations:
| Control | Description |
|---|---|
| Local path | Browse or type the local file/folder path |
| Remote path | Pico destination path (e.g. / or /lib/) |
| Send to Pico → | Upload local file/folder to the Pico |
| ← Receive from Pico | Download remote file/folder locally |
| Compare Hashes | Compare MD5 checksums of the local and remote files |
The built-in editor lets you write, edit, and run MicroPython code without leaving pico-sync:
| Button | What it does |
|---|---|
| Open | Load a local .py file into the editor |
| Save | Save editor contents to disk |
| Run on Pico | Save the file, then execute it on the Pico (output streams live) |
| Exec Snippet | Execute only the selected text on the Pico |
| Deploy+Run | Copy the file to the Pico, then run it immediately |
| Reset Pico | Soft-reset the Pico |
| Open REPL | Open an interactive MicroPython REPL in a new terminal window |
The terminal displays all command output with color-coded lines:
- 🔵 Blue — command being run
- 🟢 Green — successful output
- 🔴 Red — errors or warnings
Additional controls:
| Control | Description |
|---|---|
| Exec input box | Type a Python one-liner and press Enter to run it immediately |
| Copy Log | Copy all terminal output to the clipboard |
| Save Log | Save terminal output to a .txt file |
| Stop | Terminate the currently running command |
pico-sync/
├── pico_sync/
│ ├── __init__.py # Package metadata and version
│ ├── __main__.py # python -m pico_sync entry point (launches GUI)
│ ├── cli.py # Click-based CLI commands
│ ├── commands.py # mpremote command wrappers (core logic)
│ ├── device.py # Serial device auto-detection
│ └── gui.py # CustomTkinter GUI application
├── pyproject.toml # Build config, dependencies, and entry points
├── requirements.txt # Runtime dependencies
├── CHANGELOG.md # Version history
├── LICENSE # MIT License
├── .gitignore # Git ignore rules
└── README.md # This file
pip install mpremote- Ensure your Pico is plugged in via USB and running MicroPython
- Linux: Add your user to the
dialoutgroup, then log out and back in:sudo usermod -a -G dialout $USER - macOS: The device appears as
/dev/tty.usbmodem*or/dev/cu.usbmodem* - Windows: Check Device Manager → Ports (COM & LPT) for the assigned COM port
Grant temporary access:
sudo chmod 666 /dev/ttyACM0Or grant permanent access (requires re-login):
sudo usermod -a -G dialout $USEREnsure both GUI dependencies are installed:
pip install customtkintertkinter is bundled with most Python distributions. If it's missing on Debian/Ubuntu:
sudo apt install python3-tkBy default, files that haven't changed are skipped. If you need to force a full re-transfer, use --force or --no-skip:
pico-sync copy --no-skip ./project :/project/Contributions are welcome! Here's how to get started:
- Fork the repository and create a feature branch
- Install the development dependencies:
pip install -e ".[dev]" - Make your changes and run the linter:
ruff check . - Open a pull request with a clear description of what changed and why
Please keep pull requests focused — one feature or fix per PR makes review much easier.
MIT License — see LICENSE for details.