embedagents-stm32 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. embedagents_stm32-0.3.0/CHANGELOG.md +198 -0
  2. embedagents_stm32-0.3.0/LICENSE +21 -0
  3. embedagents_stm32-0.3.0/MANIFEST.in +14 -0
  4. embedagents_stm32-0.3.0/PKG-INFO +315 -0
  5. embedagents_stm32-0.3.0/README.md +260 -0
  6. embedagents_stm32-0.3.0/pyproject.toml +84 -0
  7. embedagents_stm32-0.3.0/setup.cfg +4 -0
  8. embedagents_stm32-0.3.0/src/embedagents/stm32/__init__.py +15 -0
  9. embedagents_stm32-0.3.0/src/embedagents/stm32/_jsonc.py +141 -0
  10. embedagents_stm32-0.3.0/src/embedagents/stm32/cli/__init__.py +125 -0
  11. embedagents_stm32-0.3.0/src/embedagents/stm32/cli/_build.py +300 -0
  12. embedagents_stm32-0.3.0/src/embedagents/stm32/cli/_debug.py +525 -0
  13. embedagents_stm32-0.3.0/src/embedagents/stm32/cli/_mx.py +102 -0
  14. embedagents_stm32-0.3.0/src/embedagents/stm32/cli/_prog.py +664 -0
  15. embedagents_stm32-0.3.0/src/embedagents/stm32/cli/_serialize.py +108 -0
  16. embedagents_stm32-0.3.0/src/embedagents/stm32/cli/_vcp.py +193 -0
  17. embedagents_stm32-0.3.0/src/embedagents/stm32/context.py +647 -0
  18. embedagents_stm32-0.3.0/src/embedagents/stm32/cubeide/__init__.py +44 -0
  19. embedagents_stm32-0.3.0/src/embedagents/stm32/cubeide/client.py +1009 -0
  20. embedagents_stm32-0.3.0/src/embedagents/stm32/cubeide/cproject.py +634 -0
  21. embedagents_stm32-0.3.0/src/embedagents/stm32/cubeide/headless.py +161 -0
  22. embedagents_stm32-0.3.0/src/embedagents/stm32/cubeide/presets.py +124 -0
  23. embedagents_stm32-0.3.0/src/embedagents/stm32/cubeide/results.py +106 -0
  24. embedagents_stm32-0.3.0/src/embedagents/stm32/cubeide/workspace.py +220 -0
  25. embedagents_stm32-0.3.0/src/embedagents/stm32/cubemx/__init__.py +22 -0
  26. embedagents_stm32-0.3.0/src/embedagents/stm32/cubemx/client.py +253 -0
  27. embedagents_stm32-0.3.0/src/embedagents/stm32/cubemx/launcher.py +60 -0
  28. embedagents_stm32-0.3.0/src/embedagents/stm32/cubemx/results.py +51 -0
  29. embedagents_stm32-0.3.0/src/embedagents/stm32/cubemx/runner.py +350 -0
  30. embedagents_stm32-0.3.0/src/embedagents/stm32/cubeprogrammer/__init__.py +65 -0
  31. embedagents_stm32-0.3.0/src/embedagents/stm32/cubeprogrammer/client.py +1629 -0
  32. embedagents_stm32-0.3.0/src/embedagents/stm32/cubeprogrammer/codes.py +68 -0
  33. embedagents_stm32-0.3.0/src/embedagents/stm32/cubeprogrammer/diagnose.py +156 -0
  34. embedagents_stm32-0.3.0/src/embedagents/stm32/cubeprogrammer/external_loader.py +84 -0
  35. embedagents_stm32-0.3.0/src/embedagents/stm32/cubeprogrammer/parsers.py +897 -0
  36. embedagents_stm32-0.3.0/src/embedagents/stm32/cubeprogrammer/results.py +293 -0
  37. embedagents_stm32-0.3.0/src/embedagents/stm32/debug/__init__.py +72 -0
  38. embedagents_stm32-0.3.0/src/embedagents/stm32/debug/client.py +320 -0
  39. embedagents_stm32-0.3.0/src/embedagents/stm32/debug/gdb.py +432 -0
  40. embedagents_stm32-0.3.0/src/embedagents/stm32/debug/gdbserver.py +355 -0
  41. embedagents_stm32-0.3.0/src/embedagents/stm32/debug/parsers.py +571 -0
  42. embedagents_stm32-0.3.0/src/embedagents/stm32/debug/pipereader.py +76 -0
  43. embedagents_stm32-0.3.0/src/embedagents/stm32/debug/results.py +254 -0
  44. embedagents_stm32-0.3.0/src/embedagents/stm32/debug/session.py +641 -0
  45. embedagents_stm32-0.3.0/src/embedagents/stm32/debug/svd.py +670 -0
  46. embedagents_stm32-0.3.0/src/embedagents/stm32/errors.py +304 -0
  47. embedagents_stm32-0.3.0/src/embedagents/stm32/logging_setup.py +38 -0
  48. embedagents_stm32-0.3.0/src/embedagents/stm32/platform/__init__.py +43 -0
  49. embedagents_stm32-0.3.0/src/embedagents/stm32/platform/locking.py +172 -0
  50. embedagents_stm32-0.3.0/src/embedagents/stm32/platform/process.py +254 -0
  51. embedagents_stm32-0.3.0/src/embedagents/stm32/progress.py +34 -0
  52. embedagents_stm32-0.3.0/src/embedagents/stm32/py.typed +0 -0
  53. embedagents_stm32-0.3.0/src/embedagents/stm32/resolution.py +79 -0
  54. embedagents_stm32-0.3.0/src/embedagents/stm32/schemas/__init__.py +0 -0
  55. embedagents_stm32-0.3.0/src/embedagents/stm32/schemas/stm32-project.schema.json +189 -0
  56. embedagents_stm32-0.3.0/src/embedagents/stm32/schemas/stm32-runtime-defaults.schema.json +264 -0
  57. embedagents_stm32-0.3.0/src/embedagents/stm32/schemas/stm32-tools.local.schema.json +114 -0
  58. embedagents_stm32-0.3.0/src/embedagents/stm32/signing/__init__.py +23 -0
  59. embedagents_stm32-0.3.0/src/embedagents/stm32/signing/client.py +302 -0
  60. embedagents_stm32-0.3.0/src/embedagents/stm32/signing/results.py +33 -0
  61. embedagents_stm32-0.3.0/src/embedagents/stm32/subprocess_runner.py +229 -0
  62. embedagents_stm32-0.3.0/src/embedagents/stm32/vcp/__init__.py +40 -0
  63. embedagents_stm32-0.3.0/src/embedagents/stm32/vcp/client.py +451 -0
  64. embedagents_stm32-0.3.0/src/embedagents/stm32/vcp/discovery.py +84 -0
  65. embedagents_stm32-0.3.0/src/embedagents/stm32/vcp/reader.py +483 -0
  66. embedagents_stm32-0.3.0/src/embedagents/stm32/vcp/results.py +84 -0
  67. embedagents_stm32-0.3.0/src/embedagents_stm32.egg-info/PKG-INFO +315 -0
  68. embedagents_stm32-0.3.0/src/embedagents_stm32.egg-info/SOURCES.txt +70 -0
  69. embedagents_stm32-0.3.0/src/embedagents_stm32.egg-info/dependency_links.txt +1 -0
  70. embedagents_stm32-0.3.0/src/embedagents_stm32.egg-info/entry_points.txt +2 -0
  71. embedagents_stm32-0.3.0/src/embedagents_stm32.egg-info/requires.txt +9 -0
  72. embedagents_stm32-0.3.0/src/embedagents_stm32.egg-info/top_level.txt +1 -0
@@ -0,0 +1,198 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres
5
+ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.3.0] — 2026-06-12
8
+
9
+ Naming release: every identifier we publish is now brand-first — nothing
10
+ leads with ST's mark. **STM32 remains a registered trademark of
11
+ STMicroelectronics International N.V.; this project is independent and
12
+ community-driven** (see the README disclaimer). Functionally identical to
13
+ 0.2.0 — no behavior changes.
14
+
15
+ ### Changed
16
+
17
+ - **Distribution renamed `stm32-substrate` → `embedagents-stm32`**, and the
18
+ import package moved into a PEP 420 namespace:
19
+ `import stm32_substrate` → **`from embedagents import stm32`**. Future
20
+ sibling tools (e.g. `embedagents-esp32`) install into the same
21
+ `embedagents` namespace from their own distributions; `pip install
22
+ EmbedAgents` (the meta-package) pulls the whole family.
23
+ - **Claude-plugin renamed `stm32-substrate` → `embedagents-stm32`** and the
24
+ marketplace renamed `stm32` → `embedagents`: the install line is now
25
+ `/plugin install embedagents-stm32@embedagents`. **Upgrading from an
26
+ earlier install:** `/plugin uninstall stm32-substrate`, then reinstall —
27
+ and if you pip-installed the old package, `pip uninstall stm32-substrate`
28
+ first (both distributions own the `stm32` console script).
29
+ - **Unchanged on purpose:** the `stm32` CLI binary (every subcommand, flag,
30
+ and JSON contract), the five slash commands (`/stm32prog`, `/stm32build`,
31
+ `/stm32debug`, `/stm32project`, `/stm32agent`), the GitHub repo, the
32
+ project-descriptor format, and the `.stm32-substrate/` workspace
33
+ convention. How you *use* the tool is identical.
34
+ - Log-record prefixes follow the package: `stm32_substrate.*` →
35
+ `embedagents.stm32.*`.
36
+ - New `Release` workflow publishes to PyPI via Trusted Publishers (OIDC) on
37
+ GitHub Releases; CI and the release pipeline both assert the wheel ships
38
+ no `embedagents/__init__.py` (the namespace stays mergeable).
39
+
40
+ ## [0.2.0] — 2026-06-12
41
+
42
+ Hardening release. A comprehensive 10-dimension adversarial audit (129
43
+ independently-verified findings, 66 fixed this cycle) plus end-to-end
44
+ re-validation of the eval suite on `claude-fable-5` against real hardware —
45
+ 39 of 41 runnable scenarios green live on NUCLEO-L476RG + STM32N6570-DK,
46
+ including the full break→diagnose→fix→flash→verify loop on silicon.
47
+
48
+ ### Added
49
+
50
+ - **`stm32 prog svd`** — resolve the attached device's `.svd` file from a
51
+ fresh banner (D-008).
52
+ - **Keyless N6 signing**: `stm32 prog sign --no-key` and
53
+ `flash-pair --signed --sign-unsigned --no-key` — one-call sign+flash of an
54
+ unsigned boot/app pair, hardware-validated on the N6570-DK.
55
+ - `stm32 prog flash` now routes `.axf` / `.s19` / `.srec` like `.elf`
56
+ (address-embedded formats need no `--address`).
57
+ - `vcp tail --follow --timeout S` — an explicit wall-clock bound on follow
58
+ mode (bare `--follow` keeps its until-Ctrl-C contract); `vcp send
59
+ --terminator` decodes `"\r\n"`-style escapes.
60
+ - All nine `debug.*` runtime-default knobs in `stm32-runtime-defaults` are
61
+ now honored (timeouts, port walk, handshake budgets) — previously several
62
+ were silently dead.
63
+ - Every `Path`-typed public entry point accepts `str | Path`, and
64
+ descriptor-configured relative paths resolve against the project root, not
65
+ the process CWD.
66
+ - Test depth: an MI-record corpus of 23 real `arm-none-eabi-gdb` MI3 captures
67
+ with round-trip tests, and a hardware test reading sticky fault registers
68
+ (CFSR/HFSR) from a genuinely faulted target.
69
+
70
+ ### Changed
71
+
72
+ - **Debug read recipes attach without reset and halt in place** — sticky
73
+ fault registers and live peripheral state now survive into the dump. The
74
+ previous reset-first behavior wiped the very fault evidence
75
+ `decode-hardfault` exists to read.
76
+ - **ST-LINK gdbserver control vocabulary corrected**: `mi-async` is enabled
77
+ before target-select, halt/resume route through MI-level commands (the
78
+ gdbserver rejects OpenOCD-style `monitor reset halt`), `halt()` picks the
79
+ safe interrupt form for faulted cores, and `snapshot()` tolerates an
80
+ unwindable faulted stack. This latent cluster would have broken
81
+ `start_session(halt=True)` on all real hardware.
82
+ - **Compound flows are Claude-composed from atomics**: no dedicated compound
83
+ API ships; `/stm32agent` carries the composition contract (build→flash→
84
+ serial-verify, sign→flash, build-fix chains — live-validated on hardware).
85
+ - **`/stm32debug` rewritten lean** (8.7 KB → 3.3 KB), validated by a live
86
+ A/B on `claude-fable-5`: pass rates held with zero lean-attributable
87
+ failures, at lower cost per scenario.
88
+ - One-shot debug CLI timeouts are real deadlines — a silent gdbserver or a
89
+ never-hit breakpoint can no longer hang an invocation forever.
90
+ - gdb `^error` result records now raise a typed `GDBError("command-error")`
91
+ instead of being silently treated as success (a typo'd variable name used
92
+ to return an empty value with exit 0).
93
+ - Multi-probe benches: the `STM32_PROGRAMMER_DEFAULT_SN` pin idiom is
94
+ documented across the command surfaces (`prog`/`debug` one-shots do not
95
+ board-match the descriptor; the first-probe fallback is silent).
96
+ - Default eval model is `claude-fable-5`; 51 replay scenarios, with the four
97
+ T3 transcripts re-recorded against real problem states (a faulted target, a
98
+ broken build, a 4× baud mismatch).
99
+
100
+ ### Fixed
101
+
102
+ - CubeMX regeneration on a previously-generated project no longer reports
103
+ success on a nonzero exit, and the JVM doing the actual generation is
104
+ terminated with its launcher instead of being orphaned to keep writing the
105
+ output tree.
106
+ - Workspace safety: CubeIDE GUI-lock detection now actually works on both
107
+ OSes (it was dead on both, allowing cleanup to delete a live GUI's
108
+ `.metadata`); destructive workspace cleanup runs under the lock; the
109
+ Windows `.location` URI decode no longer spuriously purges project
110
+ metadata.
111
+ - gdb/MI robustness: spawn/attach failures tear down both processes (no more
112
+ leaked gdbserver holding the probe), truncated MI records raise a typed
113
+ `protocol-violation`, multi-block memory reads are stitched by declared
114
+ offset and truncated at unreadable holes, and user-supplied breakpoint
115
+ locations / expressions / monitor strings are MI-quoted (no command
116
+ injection via an embedded newline).
117
+ - VCP: streaming replies are bounded by wall clock (fast-printing firmware
118
+ could block `send` unboundedly), CLI `reconnect` polls enumeration up to
119
+ `--max-wait`, a dead drain thread flags the reader stale instead of
120
+ zombifying the port, `COM*` names no longer fail the POSIX path probe on
121
+ Windows, and follow-mode no longer drops lines that arrive during the
122
+ backlog snapshot.
123
+ - CubeProgrammer: vendor-CLI timeouts keep their diagnosis (was "exited with
124
+ code -1"), `tail_swo` merges stderr and raises on failure instead of
125
+ yielding a silent empty stream, and an RDP level-2 write no longer
126
+ read-backs the now-locked target and falsely reports the irreversible
127
+ operation as failed.
128
+ - Configuration: a set-but-broken tool-path env var or a typo'd explicit
129
+ config path raises a loud `ConfigurationError` instead of silently falling
130
+ through to PATH / built-in defaults.
131
+ - `callstack --full` returns populated frames; build-option values are
132
+ validated before being written into `.cproject` (invalid forms used to be
133
+ written verbatim and reported as success); plus ~25 further audit fixes
134
+ (full per-finding ledger in the development repo).
135
+
136
+ ### Security
137
+
138
+ - **Destructive verbs are never pre-authorized**: the slash commands'
139
+ `allowed-tools` no longer match `stm32 prog erase` / `write-ob` (they now
140
+ always raise a permission prompt — the human-in-the-loop gate), and
141
+ `/stm32debug` no longer pre-authorizes arbitrary `python`. All five
142
+ command files frame captured device/project output as untrusted data, not
143
+ instructions.
144
+ - CI: least-privilege `permissions:` block, actions pinned by commit SHA,
145
+ and a packaging job that builds sdist+wheel and asserts their contents;
146
+ the sdist no longer ships the test tree.
147
+
148
+ ## [0.1.0] — 2026-06-09
149
+
150
+ First public release. STM32 development by talking to Claude Code in plain
151
+ language, backed by ST's own toolchain.
152
+
153
+ ### Added
154
+
155
+ - **Python library** (`stm32_substrate`) wrapping six ST vendor CLIs —
156
+ STM32CubeProgrammer, STM32CubeIDE, STM32CubeMX, ST-LINK gdbserver,
157
+ arm-none-eabi-gdb, and STM32_SigningTool_CLI — plus a USB virtual COM port
158
+ reader. One class per tool, constructed from a dependency-injected
159
+ `SubstrateContext`; sync public surface; `@dataclass(frozen=True)` results;
160
+ a three-layer error hierarchy (`SubstrateError → ToolError → per-tool`).
161
+ - **`stm32` CLI** — subcommand groups for terminal use: `stm32 prog …`,
162
+ `stm32 build …`, `stm32 debug …`, `stm32 mx …`, `stm32 vcp …`. Every command
163
+ emits JSON; errors surface as a structured envelope, never a raw traceback.
164
+ Each subcommand takes its primary target positionally (`prog flash FILE`,
165
+ `build /path/to/proj`, `debug start [ELF]`, `mx generate [IOC]`), matching
166
+ how agents and humans naturally invoke CLI tools; `stm32 build` also accepts
167
+ the project via `--project PATH`.
168
+ - **Five Claude-Code slash commands** — `/stm32prog`, `/stm32build`,
169
+ `/stm32debug`, `/stm32project`, `/stm32agent` — routing natural-language
170
+ intent to the CLI. Each maps 1:1 to a library operation.
171
+ - **Flash / erase / read / verify / option-byte / signing** flows
172
+ (STM32CubeProgrammer + Signing Tool), with explicit confirmation gates on
173
+ every destructive operation (mass erase, inferred-address flash, option-byte
174
+ and RDP writes).
175
+ - **Headless build** (STM32CubeIDE) with preset and per-flag `.cproject` edits,
176
+ atomic edit/rollback, and a "Nothing to build" no-op guard. A build path with
177
+ no `.project` file (typically the repo root of an ST-example-shaped tree)
178
+ resolves through the descriptor: when `build.project_path` lands strictly
179
+ under the given path and is itself importable, that project is built (logged
180
+ at INFO); any other non-importable path raises a `ConfigurationError` whose
181
+ hint names the descriptor-resolved path, instead of handing Eclipse a
182
+ directory it fails on with `Project: file://… can't be found!`.
183
+ - **Project generation** (STM32CubeMX) from an IOC to a CubeIDE project, behind
184
+ a bounded sync facade.
185
+ - **Debug recipes** (ST-LINK gdbserver + arm-none-eabi-gdb) — one-shot register,
186
+ peripheral (SVD-decoded), memory, callstack, and snapshot reads; a
187
+ `decode-hardfault` recipe that composes the raw fault bundle for Claude to
188
+ classify (the substrate captures, it does not interpret).
189
+ - **USB VCP reader** for tailing / round-tripping serial output.
190
+ - **Device resolution** software-validated across the full installed Cube SVD
191
+ catalog (family→core mapping, SVD lookup, peripheral decode), not just
192
+ bench-tested boards.
193
+ - **Cross-platform**: Linux and Windows are first-class. macOS is not supported
194
+ in v1 (planned based on demand) — `SubstrateContext.from_environment()` fails
195
+ loud with a hint on macOS.
196
+ - Package-bundled JSON Schemas (2020-12) validated at config load.
197
+
198
+ [0.1.0]: https://github.com/EmbedAgents/stm32-substrate/releases/tag/v0.1.0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 EmbedAgents
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,14 @@
1
+ include LICENSE
2
+ include README.md
3
+ include CHANGELOG.md
4
+ recursive-include src/embedagents/stm32/schemas *.schema.json
5
+ include src/embedagents/stm32/py.typed
6
+
7
+ # sdist is package source + metadata only (SEC-08): no test tree, no
8
+ # repo plumbing — the wheel was always clean; this aligns the sdist.
9
+ prune tests
10
+ prune tools
11
+ prune docs
12
+ prune .claude
13
+ prune .claude-plugin
14
+ prune .github
@@ -0,0 +1,315 @@
1
+ Metadata-Version: 2.4
2
+ Name: embedagents-stm32
3
+ Version: 0.3.0
4
+ Summary: Deterministic Python wrapper around the six ST vendor CLIs (CubeProgrammer, CubeIDE, CubeMX, ST-LINK gdbserver, arm-none-eabi-gdb, STM32_SigningTool_CLI) plus a USB virtual COM port reader. Surfaces a Python library, a `stm32` CLI, and five Claude-Code slash commands.
5
+ Author-email: anup das <akd.jls@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 EmbedAgents
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/EmbedAgents/stm32-substrate
29
+ Project-URL: Repository, https://github.com/EmbedAgents/stm32-substrate
30
+ Project-URL: Issues, https://github.com/EmbedAgents/stm32-substrate/issues
31
+ Project-URL: Changelog, https://github.com/EmbedAgents/stm32-substrate/blob/main/CHANGELOG.md
32
+ Keywords: stm32,embedded,microcontroller,arm,cortex-m,claude,claude-code,stlink,cubeprogrammer,cubeide,gdb,firmware
33
+ Classifier: Development Status :: 4 - Beta
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Environment :: Console
37
+ Classifier: Programming Language :: Python :: 3
38
+ Classifier: Programming Language :: Python :: 3.11
39
+ Classifier: Programming Language :: Python :: 3.12
40
+ Classifier: Operating System :: POSIX :: Linux
41
+ Classifier: Operating System :: Microsoft :: Windows
42
+ Classifier: Topic :: Software Development :: Embedded Systems
43
+ Classifier: Topic :: Software Development :: Build Tools
44
+ Requires-Python: >=3.11
45
+ Description-Content-Type: text/markdown
46
+ License-File: LICENSE
47
+ Requires-Dist: jsonschema>=4.21
48
+ Requires-Dist: pyserial>=3.5
49
+ Provides-Extra: dev
50
+ Requires-Dist: pytest>=8.0; extra == "dev"
51
+ Requires-Dist: pytest-xdist>=3.5; extra == "dev"
52
+ Provides-Extra: eval
53
+ Requires-Dist: claude-agent-sdk>=0.0.20; extra == "eval"
54
+ Dynamic: license-file
55
+
56
+ # embedagents-stm32
57
+
58
+ **STM32 development, by talking to Claude.**
59
+
60
+ STM32 is one of the most widely used 32-bit microcontroller families in the
61
+ world. ST ships a strong, free toolchain for it — CubeMX to configure a chip,
62
+ CubeIDE to build and debug, CubeProgrammer to flash it, and a handful more. The
63
+ tools are capable, but they're a lot to learn, they don't talk to each other,
64
+ and none was built to be driven by an AI coding agent.
65
+
66
+ This plugin changes that. It lets you do STM32 development by talking to Claude
67
+ Code in plain language — *"build my project," "flash it to the board," "why is
68
+ it crashing?"* Claude calls ST's tools for you and reports back. You stop
69
+ juggling six separate applications and just describe what you want done.
70
+
71
+ **The promise: once it's installed, you don't have to remember anything about
72
+ it.** No flags to memorize, no syntax to keep in your head. The five slash
73
+ commands are there for when you'd rather point at a tool directly — but most of
74
+ the time you just talk.
75
+
76
+ ## Demo
77
+
78
+ ![Claude Code building and flashing an STM32 project from one plain-language request](docs/media/demo.gif)
79
+
80
+ *Real session, real hardware: a NUCLEO-L476RG (Cortex-M4), built and flashed
81
+ end-to-end from one sentence — first try.*
82
+
83
+ The same request in text, plus two more shapes of what a session looks like:
84
+
85
+ **Build & flash:**
86
+
87
+ > **You:** build my project and flash it to my nucleo
88
+ > **Claude:** *(runs `stm32 build ~/blinky-demo` — resolves the nested CubeIDE
89
+ > project, builds Debug)*
90
+ > Build: 0 errors, 0 warnings — `BLINKY.elf`, ~5.7 KB flash.
91
+ > *(runs `stm32 prog flash …/Debug/BLINKY.elf`)*
92
+ > Flashed in ~0.3 s, address taken from the ELF. The LED should be blinking now.
93
+
94
+ **Diagnose a crash:**
95
+
96
+ > **You:** my board keeps crashing — memory bug or interrupt problem?
97
+ > **Claude:** *(runs `stm32 debug read-peripheral SCB`, `read-peripheral NVIC`,
98
+ > `decode-hardfault`, `callstack`)*
99
+ > Neither — every fault register is zero (`CFSR=0`, `HFSR=0`) and no IRQs are
100
+ > enabled yet. You're looking at the *next* boot, not the crash: the MCU was
101
+ > reset mid-fault — most likely a watchdog, or an `NVIC_SystemReset()` inside a
102
+ > fault handler. Let's catch it live: I'll break in the fault handler before the
103
+ > reset fires.
104
+
105
+ **Read a register:**
106
+
107
+ > **You:** what's RCC->CR right now?
108
+ > **Claude:** *(runs `stm32 debug read-peripheral RCC` — gdbserver attach, SVD
109
+ > decode, detach)*
110
+ > `CR = 0x00000063`: `MSION=1, MSIRDY=1`, PLL off — the core is on the 4 MHz
111
+ > MSI reset default, which means your clock configuration never ran.
112
+
113
+ What just happened in all three: the substrate ran ST's own CLIs and captured
114
+ their output; Claude read it and decided the next step. No magic, no parsing of
115
+ vendor prose — the same tools you already trust, driven conversationally.
116
+
117
+ ## What Claude can do for you
118
+
119
+ **You ask, Claude does:**
120
+
121
+ - **Configure** a chip and generate project code (STM32CubeMX)
122
+ - **Build** firmware (STM32CubeIDE)
123
+ - **Flash, erase, read, and verify** device memory (STM32CubeProgrammer)
124
+ - **Sign** secure binaries for the chips that require it (STM32 Signing Tool)
125
+
126
+ **Claude reaches for these on its own:**
127
+
128
+ - **Read firmware state over the debugger** while diagnosing a crash or working
129
+ a fix (ST-LINK GDB server). For hands-on stepping you'll still want the
130
+ CubeIDE GUI — this path is built for Claude to *read* what your firmware is
131
+ doing, not to replace your debugger.
132
+ - **Read the serial port** when it needs to see what your firmware is printing,
133
+ or confirm a board is alive (USB virtual COM port).
134
+
135
+ The substrate is family-agnostic: if ST's tools support the chip, Claude can
136
+ drive them against it — from an 8 MHz low-power part up to the latest Cortex-M85
137
+ and NPU-equipped silicon.
138
+
139
+ ## Quick start
140
+
141
+ 1. **Install ST's tools** — the ones you need, from [st.com](https://www.st.com/en/development-tools/stm32-software-development-tools.html): CubeProgrammer, CubeIDE, CubeMX, the ST-LINK GDB server, `arm-none-eabi-gdb`, the Signing Tool. The substrate drives them; it doesn't bundle them.
142
+ 2. **Install the substrate** — the `stm32` CLI plus the Claude Code plugin, in one paste (see **Install** below).
143
+ 3. **Bring a project** — an existing CubeIDE project, a CubeMX `.ioc`, or just a `.bin`/`.elf` to flash. No project yet? Generate one with `/stm32project`.
144
+ 4. **Write `stm32-project.jsonc`** — point the substrate at that project (board, build, ELF, IOC). Claude can scaffold it for you (see **the one per-project step** below).
145
+ 5. **Attach your board** — an ST-LINK probe and a NUCLEO/DISCO for anything that flashes, debugs, or reads the serial port.
146
+ 6. **Talk** — *"build it and flash my Nucleo."* Claude runs the tools and reports back.
147
+
148
+ ## Install — 30 seconds
149
+
150
+ **Requirements:** [Claude Code](https://docs.claude.com/en/docs/claude-code), [Python 3.11+](https://www.python.org/downloads/), [Git](https://git-scm.com/), and [ST's STM32 tools](https://www.st.com/en/development-tools/stm32-software-development-tools.html) — install the ones you need; the substrate drives them, it doesn't bundle them. Linux or Windows (macOS isn't supported yet). An ST-LINK probe and a board for anything that touches hardware.
151
+
152
+ ### Step 1: Install on your machine
153
+
154
+ Open Claude Code and paste this. Claude does the rest.
155
+
156
+ > Install the STM32 substrate: run `pip install git+https://github.com/EmbedAgents/stm32-substrate.git` to get the `stm32` CLI, then register the plugin with `claude plugin marketplace add EmbedAgents/stm32-substrate` and `claude plugin install stm32-substrate@stm32`. Then ask me which ST tools I have installed (STM32CubeProgrammer, CubeIDE, CubeMX, the ST-LINK GDB server, arm-none-eabi-gdb, the Signing Tool) and write a `.claude/stm32-tools.local.jsonc` that points at them.
157
+
158
+ That installs the `stm32` CLI + `embedagents.stm32` library and registers the five `/stm32*` slash commands. Restart Claude Code if the commands don't show up right away.
159
+
160
+ Prefer to do the plugin half by hand? Run `/plugin marketplace add EmbedAgents/stm32-substrate` then `/plugin install embedagents-stm32@embedagents`. And once it's on PyPI, the package step is simply `pip install embedagents-stm32`.
161
+
162
+ ### Step 2: Point it at your ST tools
163
+
164
+ The substrate finds each tool by **environment variable → `.claude/stm32-tools.local.jsonc` → your `PATH`**, and fails loud — naming the exact key to set — if it can't. Claude can write that file for you in Step 1; the [schema](src/embedagents/stm32/schemas/stm32-tools.local.schema.json) lists every key. Set it once and you're done.
165
+
166
+ Then just talk:
167
+
168
+ > **You:** build my project and flash it to the Nucleo
169
+ > **Claude:** *(runs `stm32 build` then `stm32 prog flash …`, reports back)*
170
+
171
+ ## The one per-project step you can't skip
172
+
173
+ **Do this once per project — most commands have nothing to act on until you do.**
174
+ Drop a `stm32-project.jsonc` in your project folder; it tells the substrate your
175
+ board, build, workspace, ELF, and IOC, and every command reads it. Fill it once and
176
+ you stop repeating yourself. Only `version` is strictly required.
177
+
178
+ ```jsonc
179
+ {
180
+ "version": 1,
181
+ "project_name": "blinky",
182
+ "board": { "name": "NUCLEO-L476RG", "mcu": "STM32L476RG" },
183
+ "firmware": { "board": "nucleo-l476rg", "flash_address": "0x08000000" },
184
+ "build": {
185
+ "project_path": "STM32CubeIDE",
186
+ "workspace": ".stm32-substrate-workspace",
187
+ "default_configuration": "Debug",
188
+ "artifact": "Debug/blinky.elf"
189
+ },
190
+ "debug": { "elf_path": "STM32CubeIDE/Debug/blinky.elf" },
191
+ "cubemx": { "ioc_path": "blinky.ioc" }
192
+ }
193
+ ```
194
+
195
+ `build.workspace` is the Eclipse workspace CubeIDE uses for headless builds (defaults
196
+ to `<repo>/.stm32-substrate-workspace/` if omitted). Don't want to hand-write it? Ask
197
+ Claude to scaffold one, or run a command in the folder and it'll offer.
198
+
199
+ ### How you tell a command which project or file to use
200
+
201
+ 1. **You name it** — attach a file, or put a path in your request.
202
+ 2. **The folder's `stm32-project.jsonc`** — in the folder you name, or the one Claude
203
+ is running in.
204
+ 3. **Otherwise it stops and asks you**, with a template to fill — it never scans and
205
+ guesses (no "pick the only `.elf`").
206
+
207
+ A specific ELF or IOC follows the same order: **your explicit arg → the descriptor
208
+ field** (`debug.elf_path`, `cubemx.ioc_path`, `build.artifact`) **→ a loud error**.
209
+
210
+ *(Vendor-tool paths resolve separately — see Step 2. Device, board, and peripheral
211
+ names in your prompts are illustrative; ground truth is CubeMX's database and the SVD
212
+ files.)*
213
+
214
+ ## Usage
215
+
216
+ You mostly just talk, like in Step 1 — *"flash the build to my Nucleo and reset
217
+ it"* and Claude runs the tools. The five slash commands stay available when
218
+ you'd rather point at one directly:
219
+
220
+ | Command | What it does | ST tool behind it |
221
+ |---|---|---|
222
+ | `/stm32project` | Configure a chip and generate project code | STM32CubeMX |
223
+ | `/stm32build` | Build your firmware | STM32CubeIDE |
224
+ | `/stm32prog` | Flash, erase, read/verify memory, sign secure binaries | STM32CubeProgrammer + Signing Tool |
225
+ | `/stm32debug` | Read firmware state over the debugger during a fix | ST-LINK GDB server |
226
+ | `/stm32agent` | Read the serial port and run cross-tool flows | VCP reader |
227
+
228
+ Each surface — the library, the `stm32` CLI, and the slash commands — maps to
229
+ the same operations, so anything you can ask for in chat you can also script.
230
+
231
+ ### As a Python library
232
+
233
+ ```python
234
+ from embedagents.stm32.context import SubstrateContext
235
+ from embedagents.stm32.cubeprogrammer import CubeProgrammer
236
+
237
+ ctx = SubstrateContext.from_environment()
238
+ prog = CubeProgrammer(ctx)
239
+ banner = prog.connect()
240
+ print(banner.device_name, banner.flash_size_kb)
241
+ ```
242
+
243
+ ## Safety
244
+
245
+ Destructive operations are gated, not silent. Mass erase, flashing a `.bin` to
246
+ an inferred address, and option-byte / RDP writes all require an explicit
247
+ confirmation (`confirm_destructive=True` in the library, a `--confirm-…` flag on
248
+ the CLI). The substrate captures tool output and outcomes — it doesn't
249
+ second-guess them — and surfaces failures as structured errors with an
250
+ actionable hint rather than a raw traceback.
251
+
252
+ ## Uninstall
253
+
254
+ Remove the plugin and the package — nothing else is left behind.
255
+
256
+ ```bash
257
+ # Remove the Claude Code plugin + its marketplace entry
258
+ claude plugin uninstall embedagents-stm32
259
+ claude plugin marketplace remove stm32
260
+
261
+ # Uninstall the Python package / `stm32` CLI
262
+ pip uninstall embedagents-stm32
263
+ ```
264
+
265
+ If you created one, delete your `.claude/stm32-tools.local.jsonc`. The substrate
266
+ leaves nothing else on your machine — no caches, no dotfiles, no daemons.
267
+
268
+ ## Troubleshooting
269
+
270
+ - **`ConfigurationError: … not found`** — the substrate couldn't locate a tool.
271
+ The error names the exact env var / JSON key to set. Point it at the tool in
272
+ `.claude/stm32-tools.local.jsonc`, or export the named variable (e.g.
273
+ `STM32_PROGRAMMER_CLI`).
274
+ - **The `/stm32*` commands don't show up** — restart Claude Code, then check
275
+ `claude plugin list`. Re-run Step 1 if the plugin isn't listed.
276
+ - **`macOS is not supported`** — v1 runs on Linux and Windows only; macOS is
277
+ planned based on demand.
278
+ - **Probe not found / target-connect errors** — check the ST-LINK cable and board
279
+ power, and make sure nothing else holds the probe. Only one debug client can own
280
+ the SWD probe at a time, so close the CubeIDE GUI debugger or any other running
281
+ gdbserver first.
282
+ - **A destructive operation was refused** — that's the safety gate working. Re-run
283
+ with `confirm_destructive=True` (library) or the matching `--confirm-…` flag
284
+ (CLI).
285
+ - **Schema validation failed at startup** — fix the reported field in your config.
286
+ For a one-off debug bypass, set `STM32_SUBSTRATE_SKIP_SCHEMA_VALIDATION=1` (it
287
+ warns loudly).
288
+
289
+ ## Privacy & Telemetry
290
+
291
+ **Nothing is sent anywhere, ever.** The substrate has no telemetry, no analytics,
292
+ no crash reporting, no usage tracking, and no phone-home — none. It makes no
293
+ network calls at all.
294
+
295
+ It runs entirely on your machine: it shells out to ST's local vendor CLIs and
296
+ reads your serial port, and that's the whole story. No account and no API key are
297
+ needed to use it. Its only dependencies are `jsonschema` and `pyserial`, neither
298
+ of which contacts a server.
299
+
300
+ The only things that ever touch the network are tools you already run and control
301
+ — ST's own installers (when *you* download them) and Claude Code itself (your
302
+ conversation with Claude, under Anthropic's terms). The substrate adds zero
303
+ network surface of its own.
304
+
305
+ ## License
306
+
307
+ [MIT](LICENSE) © 2026 EmbedAgents
308
+
309
+ ## Disclaimer
310
+
311
+ This project is an independent, community-driven tool and is not an official
312
+ release by STMicroelectronics. STM32 is a registered trademark of
313
+ STMicroelectronics International N.V. This software is provided free of charge
314
+ for educational and development purposes, and its use of the trademark is
315
+ strictly descriptive to help developers identify hardware compatibility.