code-review-facilitator
Skill28 starsChanged 29 days agoMITView on GitHub
Automated code review for Arduino/ESP32/RP2040 projects focusing on best practices, memory safety, and common pitfalls. Use when user wants code feedback, says "review my code", needs help improving code quality, or before finalizing a project. Generates actionable checklists and specific improvement suggestions.
- Reads credentials
1 other project uses a version of this.
Adopted by
Most recently taken up by
- wedsamuel1230/arduino-skillsword for word, first seen Nov 1, 2026
Other versions1 project uses a version of this.
Word for word · 1
- wedsamuel1230/arduino-skills★ 28100% same
Edited · 0
None found.
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository48 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .cursor/rules/arduino-skills.mdcCursor rule
- cli-creatorSkill
- plugin-creatorSkill
- skill-creatorSkill
- arduino-cli-skillSkill
- arduino-code-generatorSkill
- arduino-project-builderSkill
- arduino-serial-monitorSkill
- arduino-workflow-routerSkill
- battery-selectorSkill
- board-selectionSkill
- board-supportSkill
- bom-generatorSkill
- boot-flash-recoverySkill
- bus-debuggingSkill
- circuit-debuggerSkill
- datasheet-interpreterSkill
- embedded-build-workflowSkill
- embedded-project-loopSkill
- enclosure-designerSkill
- error-message-explainerSkill
- fault-forensicsSkill
- field-power-and-connectivity-triagerSkill
- freertos-patternsSkill
- hardware-tddSkill
- i2c-bringup-diagnosticianSkill
- library-selectionSkill
- memory-budgetingSkill
- memory-timing-debuggingSkill
- mermaid-diagram-generatorSkill
- micropython-developmentSkill
- non-blocking-patternsSkill
- ota-deployment-guardianSkill
- pico-sdk-developmentSkill
- pin-assignmentSkill
- power-budget-calculatorSkill
- probe-debuggingSkill
- readme-generatorSkill
- realtime-control-designSkill
- sensor-calibration-workbenchSkill
- sensor-signal-filteringSkill
- stm32-developmentSkill
- usb-debuggingSkill
- wireless-telemetrySkill
- wiring-safety-checkSkill
- zephyr-developmentSkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 3 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 43
Before publishing to GitHub
- Distinctive: line 44
After completing a feature
- Distinctive: line 45
When code "works but feels wrong"
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Code Review Facilitator
Provides systematic code review for microcontroller projects.
Resources
This skill includes bundled tools:
- scripts/analyze_code.py - Static analyzer detecting 15+ common Arduino issues
Quick Start
Analyze a file:
uv run --no-project scripts/analyze_code.py sketch.inoAnalyze entire project:
uv run --no-project scripts/analyze_code.py --dir /path/to/projectInteractive mode (paste code):
uv run --no-project scripts/analyze_code.py --interactiveFilter by severity:
uv run --no-project scripts/analyze_code.py sketch.ino --severity warningWhen to Use
- "Review my code"
- "Is this code okay?"
- "How can I improve this?"
- Before publishing to GitHub
- After completing a feature
- When code "works but feels wrong"
Review Categories
1. 🏗️ Structure & Organization
Check For:
□ Single responsibility - each function does ONE thing
□ File organization - separate concerns (config, sensors, display, network)
□ Consistent naming convention (camelCase for variables, UPPER_CASE for constants)
□ Reasonable function length (< 50 lines ideally)
□ Header comments explaining purposeCommon Issues:
| Issue | Bad | Good |
| God function | 200-line loop() | Split into readSensors(), updateDisplay(), etc. |
| Mixed concerns | WiFi code in sensor file | Separate network.cpp/h |
| Unclear names | int x, temp1, val; | int sensorReading, temperatureC; |
Example Refactoring:
// ❌ Bad: Everything in loop()
void loop() {
// 50 lines of sensor reading
// 30 lines of display update
// 40 lines of network code
}
// ✅ Good: Organized functions
void loop() {
SensorData data = readAllSensors();
updateDisplay(data);
if (shouldTransmit()) {
sendToServer(data);
}
handleSleep();
}2. 💾 Memory Safety
Critical Checks:
□ No String class in time-critical code (use char arrays)
□ Buffer sizes declared as constants
□ Array bounds checking
□ No dynamic memory allocation in loop()
□ Static buffers for frequently used stringsMemory Issues Table:
| Issue | Problem | Solution |
| String fragmentation | Heap corruption over time | Use char arrays, snprintf() |
| Stack overflow | Large local arrays | Use static/global, reduce size |
| Buffer overflow | strcpy without bounds | Use strncpy, snprintf |
| Memory leak | malloc without free | Avoid dynamic allocation |
Safe String Handling:
// ❌ Dangerous: String class in loop
void loop() {
String msg = "Temp: " + String(temp) + "C"; // Fragments heap
Serial.println(msg);
}
// ✅ Safe: Static buffer with snprintf
void loop() {
static char msg[32];
snprintf(msg, sizeof(msg), "Temp: %.1fC", temp);
Serial.println(msg);
}
// ✅ Safe: F() macro for flash strings
Serial.println(F("This string is in flash, not RAM"));Memory Monitoring:
// Add to setup() for debugging
Serial.print(F("Free heap: "));
Serial.println(ESP.getFreeHeap());
// Periodic check in loop()
if (ESP.getFreeHeap() < 10000) {
Serial.println(F("WARNING: Low memory!"));
}3. 🔢 Magic Numbers & Constants
Check For:
□ No unexplained numbers in code
□ Pin assignments in config.h
□ Timing values named
□ Threshold values documentedExamples:
// ❌ Bad: Magic numbers everywhere
if (analogRead(A0) > 512) {
digitalWrite(4, HIGH);
delay(1500);
}
// ✅ Good: Named constants
// config.h
#define MOISTURE_SENSOR_PIN A0
#define PUMP_RELAY_PIN 4
#define MOISTURE_THRESHOLD 512 // ~50% soil moisture
#define PUMP_RUN_TIME_MS 1500 // 1.5 second watering
// main.ino
if (analogRead(MOISTURE_SENSOR_PIN) > MOISTURE_THRESHOLD) {
digitalWrite(PUMP_RELAY_PIN, HIGH);
delay(PUMP_RUN_TIME_MS);
}4. ⚠️ Error Handling
Check For:
□ Sensor initialization verified
□ Network connections have timeouts
□ File operations check return values
□ Graceful degradation when components fail
□ User feedback for errors (LED, serial, display)Error Handling Patterns:
// ❌ Bad: Assume everything works
void setup() {
bme.begin(0x76); // What if it fails?
}
// ✅ Good: Check and handle failures
void setup() {
Serial.begin(115200);
if (!bme.begin(0x76)) {
Serial.println(F("BME280 not found!"));
errorBlink(ERROR_SENSOR); // Visual feedback
// Either halt or continue without sensor
sensorAvailable = false;
}
// WiFi with timeout
WiFi.begin(SSID, PASSWORD);
unsigned long startAttempt = millis();
while (WiFi.status() != WL_CONNECTED) {
if (millis() - startAttempt > WIFI_TIMEOUT_MS) {
Serial.println(F("WiFi failed - continuing offline"));
wifiAvailable = false;
break;
}
delay(500);
}
}5. ⏱️ Timing & Delays
Check For:
□ No blocking delay() in main loop (except simple projects)
□ millis() overflow handled (after 49 days)
□ Debouncing for buttons/switches
□ Rate limiting for sensors/networkNon-Blocking Pattern:
// ❌ Bad: Blocking delays
void loop() {
readSensor();
delay(1000); // Blocks everything for 1 second
}
// ✅ Good: Non-blocking with millis()
unsigned long previousMillis = 0;
const unsigned long INTERVAL = 1000;
void loop() {
unsigned long currentMillis = millis();
// Handle button immediately (responsive)
checkButton();
// Sensor reading at interval
if (currentMillis - previousMillis >= INTERVAL) {
previousMillis = currentMillis;
readSensor();
}
}
// ✅ millis() overflow safe (works after 49 days)
// The subtraction handles overflow automatically with unsigned mathDebouncing:
// Button debouncing
const unsigned long DEBOUNCE_MS = 50;
unsigned long lastDebounce = 0;
int lastButtonState = HIGH;
int buttonState = HIGH;
void checkButton() {
int reading = digitalRead(BUTTON_PIN);
if (reading != lastButtonState) {
lastDebounce = millis();
}
if ((millis() - lastDebounce) > DEBOUNCE_MS) {
if (reading != buttonState) {
buttonState = reading;
if (buttonState == LOW) {
handleButtonPress();
}
}
}
lastButtonState = reading;
}6. 🔌 Hardware Interactions
Check For:
□ Pin modes set in setup()
□ Pull-up/pull-down resistors considered
□ Voltage levels compatible (3.3V vs 5V)
□ Current limits respected
□ Proper power sequencingPin Configuration:
// ❌ Bad: Missing or incorrect pin modes
digitalWrite(LED_PIN, HIGH); // Works by accident on some boards
// ✅ Good: Explicit configuration
void setup() {
// Outputs
pinMode(LED_PIN, OUTPUT);
pinMode(RELAY_PIN, OUTPUT);
// Inputs with pull-up (button connects to GND)
pinMode(BUTTON_PIN, INPUT_PULLUP);
// Analog input (no pinMode needed but document it)
// SENSOR_PIN is analog input - no pinMode required
// Set safe initial states
digitalWrite(RELAY_PIN, LOW); // Relay off at start
}7. 📡 Network & Communication
Check For:
□ Credentials not hardcoded (use config file)
□ Connection retry logic
□ Timeout handling
□ Secure connections (HTTPS where possible)
□ Data validationSecure Credential Handling:
// ❌ Bad: Credentials in main code
WiFi.begin("MyNetwork", "password123");
// ✅ Good: Separate config file (add to .gitignore)
// config.h
#ifndef CONFIG_H
#define CONFIG_H
#define WIFI_SSID "your-ssid"
#define WIFI_PASSWORD "your-password"
#define API_KEY "your-api-key"
#endif
// .gitignore
config.h8. 🔋 Power Efficiency
Check For:
□ Unused peripherals disabled
□ Appropriate sleep modes used
□ WiFi off when not needed
□ LED brightness reduced (PWM)
□ Sensor power controlledPower Optimization:
// ESP32 power management
void goToSleep(int seconds) {
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
btStop();
esp_sleep_enable_timer_wakeup(seconds * 1000000ULL);
esp_deep_sleep_start();
}
// Sensor power control
#define SENSOR_POWER_PIN 25
void readSensorWithPowerControl() {
digitalWrite(SENSOR_POWER_PIN, HIGH); // Power on
delay(100); // Stabilization time
int value = analogRead(SENSOR_PIN);
digitalWrite(SENSOR_POWER_PIN, LOW); // Power off
return value;
}Review Checklist Generator
Generate project-specific checklist:
## Code Review Checklist for [Project Name]
### Critical (Must Fix)
- [ ] Memory: No String in loop()
- [ ] Safety: All array accesses bounds-checked
- [ ] Error: Sensor init failures handled
### Important (Should Fix)
- [ ] No magic numbers
- [ ] Non-blocking delays where possible
- [ ] Timeouts on all network operations
### Nice to Have
- [ ] F() macro for string literals
- [ ] Consistent naming convention
- [ ] Comments for complex logic
### Platform-Specific (ESP32)
- [ ] WiFi reconnection logic
- [ ] Brownout detector consideration
- [ ] Deep sleep properly configuredCode Smell Detection
Automatic Red Flags
| Pattern | Severity | Action |
String + in loop() | 🔴 Critical | Replace with snprintf |
delay(>100) in loop() | 🟡 Warning | Consider millis() |
while(1) without yield() | 🔴 Critical | Add yield() or refactor |
| Hardcoded credentials | 🔴 Critical | Move to config.h |
malloc/new without free/delete | 🔴 Critical | Track allocations |
sprintf (not snprintf) | 🟡 Warning | Use snprintf for safety |
Global variables without volatile for ISR | 🔴 Critical | Add volatile keyword |
Review Response Template
## Code Review Summary
**Overall Assessment:** ⭐⭐⭐☆☆ (3/5)
### 🔴 Critical Issues (Fix Before Use)
1. **Memory leak in line 45** - String concatenation in loop()
- Current: `String msg = "Value: " + String(val);`
- Fix: Use `snprintf(buffer, sizeof(buffer), "Value: %d", val);`
### 🟡 Important Issues (Fix Soon)
1. **Missing error handling** - BME280 init not checked
2. **Magic number** - `delay(1500)` unexplained
### 🟢 Suggestions (Nice to Have)
1. Consider adding F() macro to Serial.print strings
2. Function `readAllSensors()` could be split
### ✅ Good Practices Found
- Clear variable naming
- Consistent formatting
- Good use of constants in config.h
### Recommended Next Steps
1. Fix critical memory issue first
2. Add sensor error handling
3. Run memory monitoring to verify fixQuick Reference Commands
// Memory debugging
Serial.printf("Free heap: %d bytes\n", ESP.getFreeHeap());
Serial.printf("Min free heap: %d bytes\n", ESP.getMinFreeHeap());
// Stack high water mark (FreeRTOS)
Serial.printf("Stack remaining: %d bytes\n", uxTaskGetStackHighWaterMark(NULL));
// Find I2C devices
void scanI2C() {
for (byte addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
if (Wire.endTransmission() == 0) {
Serial.printf("Found device at 0x%02X\n", addr);
}
}
}Shared Output Contract
See the shared Arduino skill contract.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

