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.
- embedagents_stm32-0.3.0/CHANGELOG.md +198 -0
- embedagents_stm32-0.3.0/LICENSE +21 -0
- embedagents_stm32-0.3.0/MANIFEST.in +14 -0
- embedagents_stm32-0.3.0/PKG-INFO +315 -0
- embedagents_stm32-0.3.0/README.md +260 -0
- embedagents_stm32-0.3.0/pyproject.toml +84 -0
- embedagents_stm32-0.3.0/setup.cfg +4 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/__init__.py +15 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/_jsonc.py +141 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cli/__init__.py +125 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cli/_build.py +300 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cli/_debug.py +525 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cli/_mx.py +102 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cli/_prog.py +664 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cli/_serialize.py +108 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cli/_vcp.py +193 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/context.py +647 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubeide/__init__.py +44 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubeide/client.py +1009 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubeide/cproject.py +634 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubeide/headless.py +161 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubeide/presets.py +124 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubeide/results.py +106 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubeide/workspace.py +220 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubemx/__init__.py +22 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubemx/client.py +253 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubemx/launcher.py +60 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubemx/results.py +51 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubemx/runner.py +350 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubeprogrammer/__init__.py +65 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubeprogrammer/client.py +1629 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubeprogrammer/codes.py +68 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubeprogrammer/diagnose.py +156 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubeprogrammer/external_loader.py +84 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubeprogrammer/parsers.py +897 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/cubeprogrammer/results.py +293 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/debug/__init__.py +72 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/debug/client.py +320 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/debug/gdb.py +432 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/debug/gdbserver.py +355 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/debug/parsers.py +571 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/debug/pipereader.py +76 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/debug/results.py +254 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/debug/session.py +641 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/debug/svd.py +670 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/errors.py +304 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/logging_setup.py +38 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/platform/__init__.py +43 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/platform/locking.py +172 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/platform/process.py +254 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/progress.py +34 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/py.typed +0 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/resolution.py +79 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/schemas/__init__.py +0 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/schemas/stm32-project.schema.json +189 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/schemas/stm32-runtime-defaults.schema.json +264 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/schemas/stm32-tools.local.schema.json +114 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/signing/__init__.py +23 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/signing/client.py +302 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/signing/results.py +33 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/subprocess_runner.py +229 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/vcp/__init__.py +40 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/vcp/client.py +451 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/vcp/discovery.py +84 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/vcp/reader.py +483 -0
- embedagents_stm32-0.3.0/src/embedagents/stm32/vcp/results.py +84 -0
- embedagents_stm32-0.3.0/src/embedagents_stm32.egg-info/PKG-INFO +315 -0
- embedagents_stm32-0.3.0/src/embedagents_stm32.egg-info/SOURCES.txt +70 -0
- embedagents_stm32-0.3.0/src/embedagents_stm32.egg-info/dependency_links.txt +1 -0
- embedagents_stm32-0.3.0/src/embedagents_stm32.egg-info/entry_points.txt +2 -0
- embedagents_stm32-0.3.0/src/embedagents_stm32.egg-info/requires.txt +9 -0
- 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
|
+

|
|
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.
|