Migrate a Tool to esp-pylib
Using this skill
- Bundle: use the whole
migrate-to-esp-pylib/ directory (SKILL.md plus references/workflow.md), not SKILL.md alone — symlink, copy, submodule, or fetch that folder from GitHub.
- Target repo: run the migration in the consumer Python tool you are updating, not in the esp-pylib repository.
- Dependency: add
esp-pylib on PyPI to the consumer's pyproject.toml or setup.py (see Step 2); look up the current release on PyPI and pin >= that version — do not leave the X.Y.Z placeholder from the workflow examples.
esp-pylib ships incrementally. The module status table below shows what is implemented today; skip steps marked [Planned] until they flip to [Available]. For per-parameter semantics, platform quirks, and edge cases, read the relevant module's docstrings (installed package or Source links below) rather than relying on this skill — it intentionally stays at the workflow level.
Module status
| Module |
Status |
Replaces |
esp_pylib.constants |
Available |
Duplicated VID/PID, baud, port name patterns, macOS exclude list, hardware-flow-control adapter list |
esp_pylib.errors |
Available |
Duplicated FatalError classes, plus the recoverable PortVidPidNotFoundError |
esp_pylib.logger |
Available |
Raw ANSI helpers, local log.py modules, Python logging usage, ad-hoc progress-bar printers |
esp_pylib.ws |
Available |
Tool-local WebSocket clients + structured diagnostics |
esp_pylib.excepthook |
Available |
Uncaught-exception reporting (no prior equivalent) |
esp_pylib.config |
Available |
Duplicated INI config file loaders |
esp_pylib.serial_ports |
Available |
Duplicated port discovery / filtering / sorting + USB VID/PID lookup for a device path |
esp_pylib.serial_reset |
Available |
Duplicated DTR/RTS primitives, named reset sequences, hardware-flow-control reset paths, custom-sequence parser |
esp_pylib.cli_types |
Available |
SerialPortType, AnyIntType, AutoSizeType, BaudRateType, arg_auto_int() |
esp_pylib.cli_options |
Available |
EspRichGroup, MutuallyExclusiveOption, OptionEatAll |
esp_pylib.rom |
Available |
Duplicated ROM ELF resolution |
esp_pylib.serial_reset ships the low-level pin primitives, the four named reset sequences shared between esptool and esp-idf-monitor (each with an opt-in flow_control=True mode for hardware-flow-control adapters), and the custom-sequence parser/executor. The strategy-selection layer above the sequences (which sequence to run for a given chip + connection mode, retry orchestration, --before / --after plumbing) stays in each tool — see Step 10.
Migration workflow
One PR per consumer repo. Skip [Planned] steps.
Copy this checklist and track progress. After Step 1, open references/workflow.md (or the GitHub copy if the skill folder is not on disk) and follow only the sections for steps marked [Available] above.
Task Progress:
- [ ] Step 1: Audit — identify what to migrate
- [ ] Step 2: Add esp-pylib dependency
- [ ] Step 3: Replace constants [Available]
- [ ] Step 4: Replace error classes [Available]
- [ ] Step 5: Replace logging / output (incl. progress) [Available]
- [ ] Step 6: Wire up IDE WebSocket + exception hooks [Available]
- [ ] Step 7: Replace config loader [Available]
- [ ] Step 8: Replace ROM ELF resolution [Available]
- [ ] Step 9: Replace serial port logic [Available]
- [ ] Step 10: Replace reset primitives + sequences [Available]
- [ ] Step 11: Replace local WebSocket client [Available]
- [ ] Step 12: Convert CLI to rich-click [Available]
- [ ] Step 13: Migrate sys.exit calls
- [ ] Step 14: Delete redundant files
- [ ] Step 15: Run tests and verify
- [ ] Step 16: Write a migration report for the reviewer
| Step |
Detail |
| 1 |
Audit |
| 2 |
Add dependency |
| 3 |
Constants |
| 4 |
Errors |
| 5 |
Logging / output |
| 6 |
IDE WebSocket + excepthook |
| 7 |
Config loader |
| 8 |
ROM ELF |
| 9 |
Serial ports |
| 10 |
Reset sequences |
| 11 |
WebSocket client |
| 12 |
CLI |
| 13 |
sys.exit |
| 14 |
Delete redundant files |
| 15 |
Tests and verify |
| 16 |
Migration report |
Also in workflow.md: what stays local, common pitfalls, backward-compatibility patterns.
Critical rules
- No breaking changes to public APIs — preserve Python callables consumers import, CLI flag names/defaults/semantics, return types, exception types external code catches, and exit codes. Unified log wording and styling for cross-tool consistency (e.g.
Notice → NOTE:, bold WARNING:) are not breaking — see Common pitfalls and Backward-compatibility patterns.
- Tool-specific code stays local — chip/protocol definitions, reset strategy selection and
--before/--after plumbing, byte-level serial ANSI coloring, and tool-specific env vars/timings stay in the consumer; see what stays local.
esp-pylib never imports consumer tools — the dependency graph flows one way.
- Skip [Planned] steps — never invent imports for unshipped modules.
- Read module docstrings during migration — use installed-package docstrings or the Source column above; this skill intentionally omits per-parameter semantics, platform quirks, and edge cases that live in the source.
See also
README.md (repo root) — public-facing usage doc; keep aligned with this skill.
references/workflow.md — detailed step instructions, code examples, and compatibility wrappers (GitHub when the skill folder is not on disk).
1---2name: migrate-to-esp-pylib3description: Migrates Espressif Python tools to the shared esp-pylib library. Use when the user explicitly asks to migrate to esp-pylib, replace duplicated code (FatalError, logging, console output options via set_console_options, set_info_stream, progress bars, collapsible log stages, byte progress or unbounded counters, IDE WebSocket, INI config, ROM ELF resolution, serial port discovery, DTR/RTS reset primitives, named reset sequences, Click ParamTypes and Click option classes), convert argparse CLIs to rich-click, remove dependencies superseded by an esp_pylib.* module, or troubleshoot common migration pitfalls (pinned stdout file vs TTY progress, soft_wrap defaults, terminal width in tests, logger prefix assertions in tests, leftover argparse imports after rich-click, breaking vs cosmetic API changes).4---56# Migrate a Tool to esp-pylib78## Using this skill910- **Bundle:** use the whole [`migrate-to-esp-pylib/`](https://github.com/espressif/esp-pylib/tree/master/migrate-to-esp-pylib) directory (`SKILL.md` plus `references/workflow.md`), not `SKILL.md` alone — symlink, copy, submodule, or fetch that folder from GitHub.11- **Target repo:** run the migration in the **consumer** Python tool you are updating, not in the esp-pylib repository.12- **Dependency:** add [`esp-pylib` on PyPI](https://pypi.org/project/esp-pylib/) to the consumer's `pyproject.toml` or `setup.py` (see [Step 2](references/workflow.md#step-2-add-dependency)); look up the current release on PyPI and pin `>=` that version — do not leave the `X.Y.Z` placeholder from the workflow examples.1314`esp-pylib` ships incrementally. The module status table below shows what is implemented today; skip steps marked `[Planned]` until they flip to `[Available]`. For per-parameter semantics, platform quirks, and edge cases, **read the relevant module's docstrings** (installed package or **Source** links below) rather than relying on this skill — it intentionally stays at the workflow level.1516## Module status1718| Module | Status | Replaces |19|--------------------------|-----------|-----------------------------------------------------------------------------------------------------------------|20| `esp_pylib.constants` | Available | Duplicated VID/PID, baud, port name patterns, macOS exclude list, hardware-flow-control adapter list |21| `esp_pylib.errors` | Available | Duplicated `FatalError` classes, plus the recoverable `PortVidPidNotFoundError` |22| `esp_pylib.logger` | Available | Raw ANSI helpers, local `log.py` modules, Python `logging` usage, ad-hoc progress-bar printers |23| `esp_pylib.ws` | Available | Tool-local WebSocket clients + structured diagnostics |24| `esp_pylib.excepthook` | Available | Uncaught-exception reporting (no prior equivalent) |25| `esp_pylib.config` | Available | Duplicated INI config file loaders |26| `esp_pylib.serial_ports` | Available | Duplicated port discovery / filtering / sorting + USB VID/PID lookup for a device path |27| `esp_pylib.serial_reset` | Available | Duplicated DTR/RTS primitives, named reset sequences, hardware-flow-control reset paths, custom-sequence parser |28| `esp_pylib.cli_types` | Available | `SerialPortType`, `AnyIntType`, `AutoSizeType`, `BaudRateType`, `arg_auto_int()` |29| `esp_pylib.cli_options` | Available | `EspRichGroup`, `MutuallyExclusiveOption`, `OptionEatAll` |30| `esp_pylib.rom` | Available | Duplicated ROM ELF resolution |3132`esp_pylib.serial_reset` ships the low-level pin primitives, the four named reset sequences shared between `esptool` and `esp-idf-monitor` (each with an opt-in `flow_control=True` mode for hardware-flow-control adapters), and the custom-sequence parser/executor. The *strategy-selection* layer above the sequences (which sequence to run for a given chip + connection mode, retry orchestration, `--before` / `--after` plumbing) stays in each tool — see [Step 10](references/workflow.md#step-10-replace-reset-primitives--sequences).3334## Migration workflow3536One PR per consumer repo. Skip `[Planned]` steps.3738Copy this checklist and track progress. After Step 1, open **[references/workflow.md](references/workflow.md)** (or the [GitHub copy](https://github.com/espressif/esp-pylib/blob/master/migrate-to-esp-pylib/references/workflow.md) if the skill folder is not on disk) and follow only the sections for steps marked `[Available]` above.3940```text41Task Progress:42- [ ] Step 1: Audit — identify what to migrate43- [ ] Step 2: Add esp-pylib dependency44- [ ] Step 3: Replace constants [Available]45- [ ] Step 4: Replace error classes [Available]46- [ ] Step 5: Replace logging / output (incl. progress) [Available]47- [ ] Step 6: Wire up IDE WebSocket + exception hooks [Available]48- [ ] Step 7: Replace config loader [Available]49- [ ] Step 8: Replace ROM ELF resolution [Available]50- [ ] Step 9: Replace serial port logic [Available]51- [ ] Step 10: Replace reset primitives + sequences [Available]52- [ ] Step 11: Replace local WebSocket client [Available]53- [ ] Step 12: Convert CLI to rich-click [Available]54- [ ] Step 13: Migrate sys.exit calls55- [ ] Step 14: Delete redundant files56- [ ] Step 15: Run tests and verify57- [ ] Step 16: Write a migration report for the reviewer58```5960| Step | Detail |61|------|--------|62| 1 | [Audit](references/workflow.md#step-1-audit) |63| 2 | [Add dependency](references/workflow.md#step-2-add-dependency) |64| 3 | [Constants](references/workflow.md#step-3-replace-constants) |65| 4 | [Errors](references/workflow.md#step-4-replace-error-classes) |66| 5 | [Logging / output](references/workflow.md#step-5-replace-logging--output) |67| 6 | [IDE WebSocket + excepthook](references/workflow.md#step-6-wire-up-ide-websocket--exception-hooks) |68| 7 | [Config loader](references/workflow.md#step-7-replace-config-loader) |69| 8 | [ROM ELF](references/workflow.md#step-8-replace-rom-elf-resolution) |70| 9 | [Serial ports](references/workflow.md#step-9-replace-serial-port-logic) |71| 10 | [Reset sequences](references/workflow.md#step-10-replace-reset-primitives--sequences) |72| 11 | [WebSocket client](references/workflow.md#step-11-replace-local-websocket-client) |73| 12 | [CLI](references/workflow.md#step-12-convert-cli-to-rich-click) |74| 13 | [sys.exit](references/workflow.md#step-13-migrate-sysexit-calls) |75| 14 | [Delete redundant files](references/workflow.md#step-14-delete-redundant-files) |76| 15 | [Tests and verify](references/workflow.md#step-15-run-tests-and-verify) |77| 16 | [Migration report](references/workflow.md#step-16-write-a-migration-report-for-the-reviewer) |7879Also in [workflow.md](references/workflow.md): [what stays local](references/workflow.md#what-stays-local), [common pitfalls](references/workflow.md#common-pitfalls), [backward-compatibility patterns](references/workflow.md#backward-compatibility-patterns).8081## Critical rules82831. **No breaking changes to public APIs** — preserve Python callables consumers import, CLI flag names/defaults/semantics, return types, exception types external code catches, and exit codes. Unified log *wording* and styling for cross-tool consistency (e.g. `Notice` → `NOTE:`, bold `WARNING:`) are **not** breaking — see [Common pitfalls](references/workflow.md#common-pitfalls) and [Backward-compatibility patterns](references/workflow.md#backward-compatibility-patterns).842. **Tool-specific code stays local** — chip/protocol definitions, reset *strategy* selection and `--before`/`--after` plumbing, byte-level serial ANSI coloring, and tool-specific env vars/timings stay in the consumer; see [what stays local](references/workflow.md#what-stays-local).853. **`esp-pylib` never imports consumer tools** — the dependency graph flows one way.864. **Skip [Planned] steps** — never invent imports for unshipped modules.875. **Read module docstrings during migration** — use installed-package docstrings or the **Source** column above; this skill intentionally omits per-parameter semantics, platform quirks, and edge cases that live in the source.8889## See also9091- [`README.md`](https://github.com/espressif/esp-pylib/blob/master/README.md) (repo root) — public-facing usage doc; keep aligned with this skill.92- [`references/workflow.md`](references/workflow.md) — detailed step instructions, code examples, and compatibility wrappers ([GitHub](https://github.com/espressif/esp-pylib/blob/master/migrate-to-esp-pylib/references/workflow.md) when the skill folder is not on disk).