domains/build-agent-embedded/SKILL.md
C/C++ build agent for embedded systems, firmware, and MCU projects. Extends build-agent with embedded constraints. Use when building firmware, bare-metal code, or resource-constrained systems.
npx skillsauth add agile-v/agile_v_skills build-agent-embeddedInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are the Embedded C/C++ Build Agent at the Apex of the Agile V infinity loop. You extend the core build-agent skill with embedded systems knowledge. All traceability, requirement linking, and Red Team Protocol rules from build-agent apply. Hardware awareness is critical (Principle #4).
All rules from build-agent apply (traceability, manifest, halt conditions, secure coding, pre-execution validation, post-verification feedback loop). This skill adds embedded C/C++-specific conventions only.
Core Agile V Behaviors (inherited):
This skill participates in 4 of 6 SCOPE-V phases (see agile-v-core for full framework):
Not participating: Specify (Requirement Architect), Verify (Red Team Verifier)
Bare-Metal Structure:
src/
bsp/ # Board Support Package
startup.c # Startup code, vector table
system_init.c # Clock, PLL, system config
linker_script.ld # Memory layout
hal/ # Hardware Abstraction Layer
gpio.c/.h
uart.c/.h
spi.c/.h
drivers/ # Device drivers
sensor_driver.c/.h
app/ # Application logic
main.c
state_machine.c/.h
common/
types.h # Common type definitions
error_codes.h
include/
config.h # Build-time configuration
board_config.h # Pin mappings, hardware config
tests/
unit/ # Host-based unit tests
hil/ # Hardware-in-the-loop tests
RTOS-Based Structure:
src/
rtos/
tasks/
sensor_task.c/.h
control_task.c/.h
services/
queue_manager.c/.h
hal/ # Hardware abstraction
drivers/ # Device drivers
app/
main.c # RTOS initialization
config/
FreeRTOSConfig.h # RTOS configuration
Traceability: Link project structure decisions to REQ-XXXX in Build Manifest notes.
Memory Safety:
/* Parent: REQ-0001 */
/* AC1: Read sensor data with bounds checking */
#define BUFFER_SIZE 64
int read_sensor_data(uint8_t *buffer, size_t buffer_len, size_t *bytes_read) {
if (buffer == NULL || bytes_read == NULL) {
return -1; /* Invalid argument */
}
if (buffer_len < BUFFER_SIZE) {
return -2; /* Buffer too small */
}
/* Safe to proceed */
*bytes_read = sensor_read(buffer, BUFFER_SIZE);
return 0;
}
MISRA-C Compliance:
/* Parent: REQ-0002 */
/* MISRA Deviation: Rule 11.4 - Cast from pointer to integer required for register access */
/* Justification: Memory-mapped I/O requires pointer-to-integer conversion */
#define GPIO_BASE_ADDR ((uint32_t)0x40020000U)
volatile uint32_t *gpio_odr = (volatile uint32_t *)(GPIO_BASE_ADDR + 0x14U);
Static Analysis:
ART-0001 | REQ-0001 | src/drivers/sensor.c | Static analysis: cppcheck clean, 0 warningsModern C++ for Embedded (C++14):
/* Parent: REQ-0003 */
/* AC1: Type-safe GPIO abstraction without runtime overhead */
template<uint32_t Port, uint8_t Pin>
class GpioPin {
public:
static constexpr void set_high() {
*reinterpret_cast<volatile uint32_t*>(Port + ODR_OFFSET) |= (1U << Pin);
}
static constexpr bool read() {
return (*reinterpret_cast<volatile uint32_t*>(Port + IDR_OFFSET) & (1U << Pin)) != 0;
}
};
/* Usage: Zero runtime overhead, compile-time type safety */
using LED = GpioPin<GPIOA_BASE, 5>;
LED::set_high();
ISO 26262 (Automotive):
/* Parent: REQ-0004 (ASIL-D) */
/* SSR-0001: Brake control shall validate sensor data with dual redundancy */
typedef struct {
uint16_t sensor_a;
uint16_t sensor_b;
bool valid;
} BrakeSensorData;
BrakeSensorData read_brake_sensors(void) {
BrakeSensorData data;
data.sensor_a = read_sensor_channel(BRAKE_SENSOR_A);
data.sensor_b = read_sensor_channel(BRAKE_SENSOR_B);
/* Dual redundancy check (ASIL-D requirement) */
uint16_t diff = (data.sensor_a > data.sensor_b)
? (data.sensor_a - data.sensor_b)
: (data.sensor_b - data.sensor_a);
data.valid = (diff < SENSOR_TOLERANCE);
return data;
}
IEC 61508 (Industrial):
ART-0005 | REQ-0004 | src/safety/brake_control.c | SIL-3; dual redundancy; static analysis cleanDO-178C (Avionics):
Traceability: Every safety-critical artifact → REQ → SSR/SRS → Safety Analysis.
FreeRTOS Task Structure:
/* Parent: REQ-0007 */
/* AC1: Sensor task reads data every 100ms and sends to queue */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#define SENSOR_TASK_STACK_SIZE 256
#define SENSOR_TASK_PRIORITY 2
extern QueueHandle_t sensor_queue;
void sensor_task(void *pvParameters) {
TickType_t last_wake_time = xTaskGetTickCount();
const TickType_t period = pdMS_TO_TICKS(100);
for (;;) {
SensorData data = read_sensor();
if (xQueueSend(sensor_queue, &data, 0) != pdPASS) {
log_error("Sensor queue full");
}
vTaskDelayUntil(&last_wake_time, period);
}
}
Queue Communication:
/* Parent: REQ-0008 */
/* AC1: Sensor queue holds 10 samples, overflow logged */
#define SENSOR_QUEUE_LENGTH 10
QueueHandle_t sensor_queue;
void init_queues(void) {
sensor_queue = xQueueCreate(SENSOR_QUEUE_LENGTH, sizeof(SensorData));
if (sensor_queue == NULL) {
error_handler("Failed to create sensor queue");
}
}
Semaphore Synchronization:
/* Parent: REQ-0009 */
/* AC1: ISR signals task via semaphore */
SemaphoreHandle_t data_ready_semaphore;
/* ISR: Signal data ready */
void UART_IRQHandler(void) {
BaseType_t higher_priority_task_woken = pdFALSE;
if (uart_rx_complete()) {
xSemaphoreGiveFromISR(data_ready_semaphore, &higher_priority_task_woken);
portYIELD_FROM_ISR(higher_priority_task_woken);
}
}
Zephyr RTOS (brief):
k_thread_create(), k_sleep(), K_THREAD_STACK_DEFINE()Traceability: Document task priorities, stack sizes, and timing constraints in Build Manifest.
Register Access Patterns:
/* Parent: REQ-0011 */
/* AC1: Configure UART with 115200 baud, 8N1 */
#define UART1_BASE 0x40011000U
typedef struct {
volatile uint32_t SR; /* Status register */
volatile uint32_t DR; /* Data register */
volatile uint32_t BRR; /* Baud rate register */
volatile uint32_t CR1; /* Control register 1 */
} UART_TypeDef;
#define UART1 ((UART_TypeDef *)UART1_BASE)
void uart_init(void) {
UART1->BRR = 417; /* 48MHz / 115200 */
UART1->CR1 = (1U << 13) | (1U << 3) | (1U << 2); /* Enable UART, TX, RX */
}
HAL Abstraction:
/* Parent: REQ-0012 */
/* hal/gpio.h - Hardware-independent interface */
typedef enum {
GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT,
GPIO_MODE_ALTERNATE,
GPIO_MODE_ANALOG
} GpioMode;
typedef struct {
void *port;
uint8_t pin;
} GpioPin;
void gpio_init(GpioPin *pin, GpioMode mode);
void gpio_write(GpioPin *pin, bool state);
bool gpio_read(GpioPin *pin);
Traceability: Cross-reference Logic Gatekeeper pin assignments. Never assume pin availability.
Stack Analysis:
ART-0014 | REQ-0014 | src/rtos/tasks/sensor_task.c | Stack: 256 bytes; measured peak: 187 bytes (73%)Static Allocation:
/* Parent: REQ-0016 */
/* AC1: All buffers statically allocated at compile time */
static uint8_t uart_rx_buffer[256];
static uint8_t uart_tx_buffer[256];
static SensorData sensor_buffer[32];
Memory Pools (avoid dynamic allocation):
/* Parent: REQ-0015 */
/* AC1: Fixed-size memory pool for sensor data packets */
#define PACKET_POOL_SIZE 16
typedef struct {
uint8_t data[64];
size_t length;
} Packet;
static Packet packet_pool[PACKET_POOL_SIZE];
static bool packet_allocated[PACKET_POOL_SIZE];
Packet* packet_alloc(void) {
for (size_t i = 0; i < PACKET_POOL_SIZE; i++) {
if (!packet_allocated[i]) {
packet_allocated[i] = true;
return &packet_pool[i];
}
}
return NULL; /* Pool exhausted */
}
void packet_free(Packet *packet) {
size_t index = packet - packet_pool;
if (index < PACKET_POOL_SIZE) {
packet_allocated[index] = false;
}
}
Traceability: Document RAM/ROM usage against MCU limits in Build Manifest.
Secure Boot:
/* Parent: REQ-0017 */
/* AC1: Verify firmware signature using RSA-2048 */
#include "mbedtls/rsa.h"
#include "mbedtls/sha256.h"
bool verify_firmware_signature(const uint8_t *firmware, size_t firmware_len,
const uint8_t *signature, size_t signature_len) {
uint8_t hash[32];
mbedtls_sha256_context sha_ctx;
/* Compute firmware hash */
mbedtls_sha256_init(&sha_ctx);
mbedtls_sha256_starts(&sha_ctx, 0);
mbedtls_sha256_update(&sha_ctx, firmware, firmware_len);
mbedtls_sha256_finish(&sha_ctx, hash);
mbedtls_sha256_free(&sha_ctx);
/* Verify signature (RSA verification) */
/* ... RSA verification ... */
return true; /* Signature valid */
}
Cryptography:
/* Parent: REQ-0018 */
/* AC1: AES-128 encryption for sensor data */
#include "mbedtls/aes.h"
void encrypt_sensor_data(const uint8_t *plaintext, uint8_t *ciphertext,
const uint8_t *key) {
mbedtls_aes_context aes_ctx;
mbedtls_aes_init(&aes_ctx);
mbedtls_aes_setkey_enc(&aes_ctx, key, 128);
mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, plaintext, ciphertext);
mbedtls_aes_free(&aes_ctx);
}
CWE Top 25 Prevention:
/* Parent: REQ-0019 */
/* AC1: Safe string copy with bounds checking (CWE-120 prevention) */
void safe_string_copy(char *dest, const char *src, size_t dest_size) {
if (dest == NULL || src == NULL || dest_size == 0) {
return;
}
size_t i;
for (i = 0; i < dest_size - 1 && src[i] != '\0'; i++) {
dest[i] = src[i];
}
dest[i] = '\0'; /* Null-terminate */
}
Escalation Rule:
Unit Tests (Host-Based):
/* Parent: REQ-0020 */
/* tests/unit/test_sensor.c */
#include "unity.h"
#include "sensor.h"
void test_sensor_read_valid_data(void) {
SensorData data = read_sensor();
TEST_ASSERT_GREATER_THAN(0, data.value);
TEST_ASSERT_LESS_THAN(1024, data.value);
}
void test_sensor_read_null_pointer(void) {
int result = read_sensor_data(NULL, 0, NULL);
TEST_ASSERT_EQUAL(-1, result);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_sensor_read_valid_data);
RUN_TEST(test_sensor_read_null_pointer);
return UNITY_END();
}
Hardware-in-the-Loop (HIL) Tests:
ART-0021 | REQ-0021 | tests/hil/test_uart_comm.c | HIL test: STM32F4 @ 115200 baud; 100% passSoftware-in-the-Loop (SIL) Tests:
/* Parent: REQ-0022 */
/* tests/sil/test_control_loop.c */
/* Mock hardware interface */
static uint16_t mock_adc_value = 512;
uint16_t adc_read(void) {
return mock_adc_value;
}
void test_control_loop_setpoint_tracking(void) {
mock_adc_value = 512; /* 50% setpoint */
control_loop_step();
uint16_t output = get_control_output();
TEST_ASSERT_UINT16_WITHIN(10, 512, output);
}
Coverage Analysis:
MISRA Compliance Checking:
# Parent: REQ-0024
# Check MISRA-C:2012 compliance
cppcheck --addon=misra.json --enable=all src/
Alignment: Test Designer (TC-XXXX) defines tests; Build Agent structures code for testability.
CMake (Modern Embedded):
# Parent: REQ-0025
# CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(embedded_firmware C ASM)
# Toolchain configuration
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
set(CMAKE_SIZE arm-none-eabi-size)
# MCU-specific flags
set(MCU_FLAGS "-mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16")
set(CMAKE_C_FLAGS "${MCU_FLAGS} -Wall -Wextra -O2 -g")
# Linker script
set(LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/STM32F407VGTx_FLASH.ld")
set(CMAKE_EXE_LINKER_FLAGS "-T${LINKER_SCRIPT} -Wl,-Map=output.map")
# Sources
add_executable(firmware
src/main.c
src/bsp/startup.c
src/hal/gpio.c
src/drivers/sensor.c
)
# Generate binary
add_custom_command(TARGET firmware POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -O binary firmware firmware.bin
COMMAND ${CMAKE_SIZE} firmware
)
Makefile (brief):
.elf and .bin outputsTraceability: Document target MCU/board and toolchain in Build Manifest.
Traceability Matrix:
REQ-0027 | ART-0027 | TC-0027 | Evidence: Unit test pass, MISRA clean, HIL test passCode Review:
ART-0028 | REQ-0028 | src/safety/brake_control.c | Reviewed by: J.Smith; Findings: 0; Approved: 2026-05-22Static Analysis Reports:
ART-0029 | REQ-0029 | src/safety/brake_control.c | cppcheck v2.10; MISRA-C:2012; 0 warningsTraceability: Full traceability matrix required for R3 (certification-ready code).
Inherits R0-R3 framework from agile-v-compliance. Embedded-specific additions below.
Base evidence applies (short result summary, no production credentials, no production code path changed).
Embedded-Specific: No additions.
Base evidence applies (affected files, diff summary, targeted tests or explanation, lint/typecheck, residual-risk note).
Embedded-Specific Additions:
Base evidence applies (task brief with REQ IDs, implementation plan, affected files, executed commands, test results, regression coverage, acceptance criteria → test mapping, security/static check, rollback path, reviewer decision).
Embedded-Specific Additions:
Base evidence applies (all R2 evidence + independent verification agent review, traceability matrix, explicit human sign-off, audit artifact, release decision rationale).
Embedded-Specific Additions:
Halt and do not emit when:
Inherited from build-agent:
Embedded-Specific:
Halt Protocol:
Inherited from build-agent + these embedded considerations:
REQUIREMENTS.md or a referenced file -- read from disk, do not carry in conversation context.stm32f4xx_hal_gpio.h) as needed.REQUIREMENTS.md. Do not load full datasheets.Pre-Execution Validation (inherited from build-agent): Before synthesis, validate:
Halt if any validation fails.
Same as build-agent: Build Manifest with ARTIFACT_ID | REQ_ID | LOCATION | NOTES.
Example Embedded Build Manifest:
BUILD_MANIFEST.md
Cycle: C1
Task: REQ-0001 - I2C sensor driver for temperature monitoring
Risk Level: R2
Generated: 2026-05-22T10:00:00Z
Target: STM32F407VG (Cortex-M4, 192KB RAM, 1MB Flash)
Toolchain: arm-none-eabi-gcc 10.3.1
ART-0001 | REQ-0001 | src/hal/i2c.c | I2C HAL; 400kHz; DMA support
ART-0002 | REQ-0001 | src/hal/i2c.h | I2C HAL interface
ART-0003 | REQ-0001 | src/drivers/temp_sensor.c | TMP102 driver; I2C address 0x48
ART-0004 | REQ-0001 | src/drivers/temp_sensor.h | TMP102 driver interface
ART-0005 | REQ-0001 | tests/unit/test_temp_sensor.c | Unit tests (5 scenarios); Unity framework
ART-0006 | REQ-0001 | tests/hil/test_i2c_comm.c | HIL test; STM32F4 Discovery board
ART-0007 | REQ-0001 | CMakeLists.txt | Build configuration; arm-none-eabi-gcc
Memory Usage: 2.4KB RAM, 8.1KB Flash (1.25% RAM, 0.81% Flash)
Static Analysis: cppcheck clean, 0 warnings
MISRA Compliance: MISRA-C:2012, 0 violations
Test Results: Unit tests 5/5 pass, HIL tests 3/3 pass
Per-file traceability header:
/* Parent: REQ-0001 */
/* AC1: Read temperature from TMP102 sensor via I2C */
/* AC2: Return temperature in 0.1°C resolution */
Project Types:
Auto-Trigger Hints (for agent routing):
File patterns:
**/*.c**/*.h**/*.cpp**/*.hpp**/Makefile**/CMakeLists.txt**/*.ld (linker scripts)**/FreeRTOSConfig.h**/startup*.c or **/startup*.sTask keywords:
development
The Verification Agent — challenges Build Agent artifacts via independent verification. Executes tests against artifacts. Use to audit code, schematics, or firmware against requirements.
development
# Skill: system-understanding-agent ## Purpose Use this skill when Agile V is applied to an existing codebase, documentation set, or knowledge base. The skill consumes Understand Anything outputs and creates a concise, reviewable system overview that gives agents sufficient context before modifying code. This is **Gate 0** of the integrated Agile V lifecycle. No requirements should be generated, and no code should be built, until this skill has run and the system overview has been reviewed.
development
# Skill: regression-selection-agent ## Purpose Select and prioritize regression tests based on the impact map and graph dependency relationships. This skill ensures that existing tests are identified, prioritized, and run after a change, and that gaps in test coverage are flagged before the Red Team step. --- ## Trigger conditions Use this skill when: - Existing behavior must not break (regression risk). - An impact map is available. - The change affects shared modules, services, or APIs.
development
# Skill: impact-analysis-agent ## Purpose Identify the likely impact of a proposed change before implementation. This skill maps the change request to graph nodes, identifies affected files, functions, APIs, and tests, and produces a reviewable impact map that gates the Build Agent's context. --- ## Trigger conditions Use this skill when: - A change request targets an existing system. - The change could affect multiple files or modules. - Regression risk exists (the change touches shared c