From mcu-go
Implement, build, verify, or flash a complete embedded application on top of an STM32CubeMX-generated framework by using the generated requirement document, software design document, CubeMX setup guide, and project skeleton. Use when Codex needs to work in a CubeMX project, including CMake/Ninja projects with `CMakePresets.json`, `cmake/gcc-arm-none-eabi.cmake`, OpenOCD flashing, adding `Common`, `app` or `APP`, `Module`, `Board`, and `Config` implementation code without breaking CubeMX-generated directory structure, parallelizing unrelated module-driver work with subagents, and keeping business logic and HMI code in the main agent for user-facing clarification.
How this skill is triggered — by the user, by Claude, or both
Slash command
/mcu-go:cubemx-code-implementationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Use this skill to turn project documents plus an STM32CubeMX-generated project skeleton into working embedded code.
agents/openai.yamlreferences/automated-review-checks.mdreferences/cmake-build-and-openocd-flash.mdreferences/config-parameter-management.mdreferences/embedded-development-rules.mdreferences/freertos-development-rules.mdreferences/object-oriented-c-module-architecture.mdreferences/peripheral-callback-rules.mdreferences/subagent-implementation-and-review.mdreferences/watchdog-safe-startup-rules.mdscripts/check_layer_dependencies.pyUse this skill to turn project documents plus an STM32CubeMX-generated project skeleton into working embedded code.
Read project documents directly from the active release under docs/releases/<version>:
docs/releases/<version>/requirements.mddocs/releases/<version>/software_design.mddocs/releases/<version>/cubemx_build.mddocs/releases/<version>/notes.mddocs/modulesTreat these docs artifacts as the implementation basis. Do not depend on re-reading upstream skill definitions when the needed project information is already present in docs.
If the user names a release version, use that version exactly after sanitizing it to a directory-safe name such as v1.0. If the user does not name a version, use the newest semantic version under docs/releases. If no release exists, report that the required release documents are missing instead of guessing project inputs.
When implementing or reviewing a module driver, locate its manual under docs/modules/<module-name>, where <module-name> should match the module being implemented as closely as the repository naming allows.
Inside the module-named folder, prefer markdown files first. The markdown manual is a converted and merged version of the module's source manual files, so read it before PDFs, images, or other original source artifacts. If multiple markdown files exist, start with the broadest manual-style file such as manual.md, README.md, or the file whose name matches the module folder, then read narrower markdown supplements only when needed.
Use PDFs or other original artifacts only when the relevant detail is missing, ambiguous, or contradicted in the markdown manual. If the module-named folder or merged markdown manual is missing, report that as a documentation gap before treating the driver behavior as fully specified.
Load these references only when their condition applies:
references/embedded-development-rules.md: read before writing or reviewing capability interface files, concrete drivers, board binding files, business application code, or CubeMX user-code blocks.references/config-parameter-management.md: read when adding, injecting, centralizing, or reviewing timeouts, thresholds, retry counts, calibration values, queue depths, stack sizes, task periods, or feature switches.references/peripheral-callback-rules.md: read when using interrupts, HAL callbacks, DMA, polling loops, shared buffers, or ISR-to-main/task handoff.references/freertos-development-rules.md: read when the CubeMX project includes FreeRTOS middleware or RTOS-generated source files.references/watchdog-safe-startup-rules.md: read when requirements, software design, CubeMX configuration, or generated code includes IWDG, WWDG, reset-cause handling, startup self-checks, or safe-startup behavior.references/object-oriented-c-module-architecture.md: read when designing, implementing, or reviewing module interfaces, concrete drivers, board binding, or business-layer dependencies.references/subagent-implementation-and-review.md: read before dispatching or reviewing subagents for independent module-driver work.references/automated-review-checks.md: read before reviewing completed implementation work, subagent output, or suspected style violations; run scripts/check_layer_dependencies.py before final manual review when practical, and use the documented rg checks as fallback or follow-up detail.references/cmake-build-and-openocd-flash.md: read when the CubeMX project is a CMake/Ninja project, has CMakePresets.json, uses cmake/gcc-arm-none-eabi.cmake, or the user asks to build, verify, or flash firmware with CMake, Ninja, ARM GCC, or OpenOCD.When dispatching a subagent, explicitly name the reference files it must read. Do not assume the subagent will infer these rules from this skill.
docs/releases/<version>/requirements.mddocs/releases/<version>/software_design.mddocs/releases/<version>/cubemx_build.md*.iocCoreDriversIf multiple candidate projects exist, match by shared project stem first and then prefer the newest date.
Generate the full project code required by the requirement document and software design document on top of the existing CubeMX framework.
Implement under the CubeMX project rather than as a standalone rewrite. Keep the CubeMX-generated directory structure intact and add implementation code through the top-level Common, app or APP, Module, Board or board, and Config or config folders as needed.
When designing or implementing a module, use object-oriented C design unless the existing project already has a stronger local convention. The CubeMX-generated project remains the base framework; object boundaries are added on top of it and must not require reorganizing CubeMX output.
The main architecture rule is: upper layers depend on capability interfaces, not on a specific hardware implementation. For example, an MPU6050 driver depends on an I2C register-access interface, not directly on hi2c1, GPIOB, HAL_I2C_Mem_Read, or an i2c_hal concrete driver.
Read artifacts in this order:
*.ioc, Core/Inc, Core/Src, Drivers, middleware folders, and build files to determine actual integration points.docs/modules: read only the module-named folders relevant to modules being implemented, following the Module Manual Lookup Rules and preferring the converted merged markdown manual before PDFs or original source artifacts.Core, Drivers, startup files, linker scripts, or project files.Common for cross-module capability interfaces, shared status values, and platform-neutral utilitiesapp for business logic, state machines, HMI flow, orchestration, and project-level servicesModule for reusable external-device drivers or hardware abstractionsBoard or board for object creation, CubeMX resource binding, concrete-driver initialization, and abstract accessorsConfig or config for centralized project-tunable parameters/* USER CODE BEGIN ... */ and /* USER CODE END ... */ blockshi2c*, huart*, htim*, DMA links, IWDG/WWDG handles, and generated init paths instead of duplicating peripheral initialization.main.c user blocks or a dedicated app init callUse the Common / Module / APP or app / Board layering model. The goal is not to create extra folders for their own sake; it is to keep changes localized when pins, bus implementations, device models, boards, or business policies change.
Common owns capability interfaces and platform-neutral shared code: status.h, error.h, i2c_if.h, spi_if.h, uart_if.h, display_if.h, led_if.h, ring buffers, CRC helpers, and similar utilities.Common must not contain current-board pin configuration, CubeMX handles such as hi2c1 or huart1, HAL calls, register access, concrete driver headers, board headers, or app business types.Module owns hardware capabilities and reusable modules:
Module/bus implements bus or MCU peripheral behavior such as HAL I2C, GPIO I2C, SPI, UART, PWM, ADC, or timers; it may depend on HAL/CubeMX because it is the concrete platform adapter.Module/device owns a concrete external device or chip protocol such as MPU6050, SSD1306, or W25Q64; it may know registers and data formats, but must not know product business states or which concrete bus implementation is used.Module/component combines abstract interfaces into a higher-level reusable feature such as display, status LED, button manager, storage, or sensor fusion; it should prefer Common/*_if.h interfaces over concrete device headers.APP or app owns product behavior: state machines, events, control policy, HMI flow, inter-module coordination, scheduling, and system-level health decisions.APP or app must not own low-level operations such as GPIO toggling, I2C/SPI/UART register transfers, OLED controller command details, sensor register parsing, CubeMX handle selection, or board pin mapping.Board or board is the only layer that knows which device is wired to which pins, bus handles, DMA channels, timer channels, addresses, chip-select lines, and concrete implementations.Board or board creates concrete objects, injects CubeMX resources, selects implementations such as hardware I2C versus GPIO-simulated I2C, calls concrete init functions, and exposes only abstract capability pointers or narrow board-level services upward.Board or board, at the same level as Common, app, and Module; do not place board binding inside concrete driver folders and do not mix it into the business app directory.Common/*_if.h defines stable capability interfaces only.Module/device and Module/component use Common/*_if.h interfaces instead of concrete hardware implementations.Module/bus and concrete drivers implement capability interfaces using HAL/CubeMX or low-level hardware libraries.Board or board binds concrete implementations and CubeMX resources, then hands abstract pointers to app.APP or app uses abstract interfaces and project-level services only.Module, keep the local convention, but enforce the same boundary as Common: no HAL, CubeMX, board, GPIO, PWM, I2C, SPI, UART, DMA, timer, register, concrete-driver, or business dependency leaks.app unless the software design explicitly requires that exposure.Config/project_config.h pattern plus config structs, init arguments, or explicit narrow mapping in board binding as described in references/config-parameter-management.md.construct from init when the module owns persistent objects: construct binds function pointers and dependency references; init performs hardware communication, register configuration, buffer clearing, sampling start, display start, or other actions that may need retry or deinit/reinit.Typical dependency chain:
APP/app
-> Module/component or Module/device through abstract APIs
-> Common/*_if.h capability interfaces
<- Module/bus or concrete device implementations
<- Board selects concrete implementations and injects CubeMX resources
These are automatic violations unless the design explicitly names a controlled exception:
HAL headers, generated hardware headers, GPIO ports/pins, timer handles,
DMA handles, hi2c/huart/hspi/htim handles, concrete driver headers,
SSD1306 page-address commands, MPU6050 register-transfer details, or
HAL_GPIO_WritePin/HAL_I2C_Mem_Read calls in APP/app code.
Read references/object-oriented-c-module-architecture.md for the full pattern, examples, and review checklist when practical. If that reference is not loaded, still follow these minimum rules:
Common/*_if.h or the project's established capability-interface location: base struct, ops table, status enum, capability flags when needed, and wrapper functionsxxx_gpio.h/.c, xxx_pwm.h/.c, or xxx_i2c.h/.cstatic const xxx_ops_t table during init, and call behavior through wrapper functionsapp code on abstract pointers such as xxx_base_t *; do not cast to concrete types or branch on concrete driver kindBoard or board create concrete objects, inject CubeMX resources, call concrete init functions, and pass only abstract base pointers to appCommon, app or APP, Module, Board or board, and Config or config folders as required by the implementation if they do not already exist.Module.app.scripts/check_layer_dependencies.py against the CubeMX project root when practical, then build or run other available checks.Use subagents only for independent module-driver tasks.
Good subagent candidates:
Module/<sensor-name>Module/<radio-name>Module/<power-monitor-name>Do not delegate tasks involving:
These stay in the main agent so clarification and product behavior decisions remain centralized.
Read references/subagent-implementation-and-review.md before dispatching implementation subagents. At minimum, each subagent task must define a narrow owned module area, state that the subagent must not revert others' changes, require the relevant docs and references, keep board binding out of Module, and prohibit changes to business logic, HMI flow, shared startup, unrelated callbacks, or unrelated framework files.
Read references/subagent-implementation-and-review.md before reviewing subagent output. At minimum, run scripts/check_layer_dependencies.py when practical, explicitly judge every hit, verify ownership boundaries, confirm board binding is in a dedicated top-level Board or board directory, confirm capability interfaces are platform-neutral, and require rewrite for confirmed violations before integration.
The main agent owns:
When requirement or design artifacts leave business behavior uncertain, stop at the uncertainty, name it concretely, and ask the user instead of guessing.
Before claiming completion, verify as many of these as practical:
Common, app or APP, Module, Board or board, and Config or config integration points are connected to the CubeMX frameworkscripts/check_layer_dependencies.py has been run for completed implementation or subagent output when practical, and all hits are explained or correctedWhen the project uses an STM32CubeIDE .cproject and new source folders or module subfolders were added, treat this as the default verification flow:
.cprojectCommon or Module/<module-name>, concrete driver directories when their headers are used by board binding, dedicated board binding directories such as Board, project configuration directories such as Config, and app directories that expose business application headersCommon, app, Board, Module, or specific module subfolders to each relevant <sourceEntries> group; add Config include paths when it contains headersCore and Drivers.cproject for unrelated toolchain or optimization churnarm-none-eabi-gcc is available:
Core/Inc, capability interface headers, concrete driver headers needed by board binding, Board headers, Config headers, app headers, HAL driver headers, CMSIS device headers, and CMSIS core headersUSE_HAL_DRIVER and the exact device macro such as STM32F407xx-fsyntax-only first, grouped as capability interface wrappers, concrete drivers, board binding, and business application filesCore/Src, and the required Drivers/STM32F4xx_HAL_Driver/Src C files into temporary object files under a local build-verification directory such as build_verifyCore/Startup/startup_<device>.s, with -x assembler-with-cpp-T./STM32F407VETX_FLASH.ld-Wl,... arguments when using PowerShell, for example '-Wl,--gc-sections' and '-Wl,-Map=build_verify/<project>.map'arm-none-eabi-size on itapp often indicate business-layer dependency on concrete drivers or hardware headers; correct the architecture rather than hiding the issue with broader includesarm-none-eabi-gcc or the linker script is unavailable, say so explicitly and report the remaining build riskIf build or test execution is unavailable, say so explicitly and report the remaining risk.
When the project contains CMakePresets.json or a cmake/gcc-arm-none-eabi.cmake toolchain file, prefer the CMake flow in references/cmake-build-and-openocd-flash.md over CubeIDE managed-build assumptions.
Use that reference for:
cmake, ninja, arm-none-eabi-gcc, and openocdcmake, ninja, arm-none-eabi-gcc, or openocd cannot be found from the current command environment.elfSummarize:
app and which concrete drivers were bound behind them--include-core, --strict-review, or --allow exceptions were usedKeep the final response implementation-focused. Do not describe the result as complete if business behavior or HMI logic is still ambiguous.
Provides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
npx claudepluginhub aregues/mcu-go --plugin mcu-go