Agent skill
power-of-10
NASA/JPL Power of 10 coding rules for safety-critical C code. Use when writing embedded C firmware, safety-critical systems, aerospace code, or any project requiring high reliability. Enforces static analysis, bounded loops, no dynamic memory.
Install this agent skill to your Project
npx add-skill https://github.com/mojoatomic/triton/tree/main/.claude/skills/power-of-10
SKILL.md
Power of 10 Coding Standards
Rules derived from NASA/JPL's "Power of 10" by Gerard Holzmann. These rules enable static analysis and prove code correctness for safety-critical systems.
The Ten Rules
Rule 1: Simple Control Flow
No goto, setjmp, longjmp, or direct/indirect recursion.
// FORBIDDEN
void bad_recursive(int n) {
if (n > 0) bad_recursive(n - 1); // Recursion
}
void bad_goto(void) {
goto cleanup; // goto
cleanup:
return;
}
// ALLOWED - use iteration
void good_iterative(int n) {
for (int i = n; i > 0; i--) {
do_work(i);
}
}
Rule 2: Fixed Loop Bounds
All loops must have statically provable upper bounds. No unbounded while(1) except in main loop with watchdog.
// FORBIDDEN
while (condition) { // Unknown iterations
do_work();
}
// ALLOWED
#define MAX_RETRIES 10
for (uint32_t i = 0; i < MAX_RETRIES; i++) {
if (try_operation()) break;
}
// ALLOWED - main loop with watchdog
while (1) {
watchdog_update();
safety_monitor_run();
}
Rule 3: No Dynamic Memory After Init
No malloc, free, calloc, realloc in runtime code. Static allocation only.
// FORBIDDEN
void bad_dynamic(void) {
char* buf = malloc(1024); // Dynamic allocation
// ...
free(buf);
}
// ALLOWED - static allocation
static char s_buffer[1024];
void good_static(void) {
memset(s_buffer, 0, sizeof(s_buffer));
// Use s_buffer
}
Rule 4: Short Functions
Maximum 60 lines per function (excluding comments and blank lines). One screen of code.
// If function exceeds 60 lines, split it:
static void process_phase_one(Context_t* ctx);
static void process_phase_two(Context_t* ctx);
static void process_phase_three(Context_t* ctx);
void process_all(Context_t* ctx) {
process_phase_one(ctx);
process_phase_two(ctx);
process_phase_three(ctx);
}
Rule 5: Assertions
Minimum 2 assertions per function. Assert preconditions, invariants, and postconditions.
#define P10_ASSERT(cond) do { \
if (!(cond)) { \
p10_assert_fail(__FILE__, __LINE__, #cond); \
} \
} while(0)
error_t read_sensor(int channel, uint16_t* value) {
P10_ASSERT(channel >= 0);
P10_ASSERT(channel < MAX_CHANNELS);
P10_ASSERT(value != NULL);
// Implementation...
P10_ASSERT(*value <= MAX_SENSOR_VALUE);
return ERR_NONE;
}
Rule 6: Minimal Variable Scope
Declare variables at the innermost scope possible. Initialize at declaration.
// FORBIDDEN
int i;
int result;
// ... 50 lines later
for (i = 0; i < 10; i++) {
result = compute(i);
}
// ALLOWED
for (int i = 0; i < 10; i++) {
int result = compute(i);
process(result);
}
Rule 7: Check All Return Values
Every function return must be checked. Use MUST_CHECK attribute.
#define MUST_CHECK __attribute__((warn_unused_result))
MUST_CHECK error_t do_operation(void);
// FORBIDDEN
do_operation(); // Ignoring return value
// ALLOWED
error_t err = do_operation();
if (err != ERR_NONE) {
handle_error(err);
return err;
}
Rule 8: Limited Preprocessor
Use preprocessor only for:
- Include guards
- Compile-time constants
- Conditional compilation (sparingly)
// ALLOWED
#ifndef MODULE_H
#define MODULE_H
#define MAX_SIZE 256
#ifdef DEBUG
#define LOG(msg) printf(msg)
#else
#define LOG(msg)
#endif
#endif
// FORBIDDEN - complex macro logic
#define COMPUTE(x, y) ((x) > (y) ? (x) * 2 : (y) / 2)
Rule 9: Limited Pointer Dereferencing
Maximum 2 levels of dereferencing. No ***ptr.
// FORBIDDEN
void bad_pointers(int*** ppp) {
***ppp = 42; // Three levels
}
// ALLOWED
void good_pointers(int** pp) {
**pp = 42; // Two levels maximum
}
// Better - avoid deep nesting
typedef struct {
int* data;
} Container_t;
void best_approach(Container_t* container) {
*(container->data) = 42; // Clear, single logical dereference
}
Rule 10: Compile Clean
Code must compile with maximum warnings enabled and zero warnings.
# Required compiler flags
CFLAGS = -Wall -Wextra -Werror -Wpedantic \
-Wconversion -Wshadow -Wstrict-prototypes \
-Wmissing-prototypes -Wold-style-definition
Error Handling Pattern
typedef enum {
ERR_NONE = 0,
ERR_INVALID_PARAM,
ERR_TIMEOUT,
ERR_I2C,
ERR_OVERFLOW
} error_t;
#define RETURN_IF_ERROR(expr) do { \
error_t _err = (expr); \
if (_err != ERR_NONE) return _err; \
} while(0)
error_t complex_operation(void) {
P10_ASSERT(initialized);
RETURN_IF_ERROR(step_one());
RETURN_IF_ERROR(step_two());
RETURN_IF_ERROR(step_three());
return ERR_NONE;
}
Static Analysis Requirements
Run before every commit:
# cppcheck
cppcheck --enable=all --error-exitcode=1 src/
# Custom P10 checker (if available)
python3 ci/p10_check.py src/
# Compiler warnings as errors
make CFLAGS="-Wall -Werror"
Documented Exceptions
When a rule must be violated, document explicitly:
// P10 EXCEPTION: Rule 2 (bounded loops)
// Justification: Main safety loop must run indefinitely.
// Mitigation: Hardware watchdog ensures termination on fault.
// Reviewed: 2026-01-05
while (1) {
watchdog_update();
safety_monitor_run();
}
File Header Template
/**
* [Module Name]
* [filename] - [brief description]
*
* Power of 10 compliant
*
* Exceptions: [List any P10 exceptions or "None"]
*/
Summary
These rules exist to enable static verification of code correctness. Every rule has a purpose: enabling tools to prove your code terminates, doesn't leak memory, handles all errors, and behaves predictably. Do not circumvent them without documented justification and review.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
documentation-standards
Apply professional documentation standards. Use when writing README files, commit messages, code comments, technical docs, or any user-facing text. Enforces evidence-based claims, no marketing language.
github-hygiene
Enforces strict GitHub workflow hygiene and best practices. Use this skill for ALL git and GitHub operations including commits, branches, pull requests, and repository management. Core rules - NEVER commit directly to main/master, ALWAYS work on feature branches, use GitHub MCP for all GitHub API operations (issues, PRs, reviews), require PRs for all merges. Triggers on any git command, GitHub operation, or when starting new feature work.
safety-critical-embedded
Safety-critical embedded system design patterns. Use when building dual-core safety monitors, failsafe systems, watchdog implementations, or any system where failure could cause harm. Covers isolation, fault detection, and emergency procedures.
handoff
Compact the current conversation into a handoff document for another agent to pick up.
setup-pre-commit
Set up Husky pre-commit hooks with lint-staged (Prettier), type checking, and tests in the current repo. Use when user wants to add pre-commit hooks, set up Husky, configure lint-staged, or add commit-time formatting/typechecking/testing.
obsidian-vault
Search, create, and manage notes in the Obsidian vault with wikilinks and index notes. Use when user wants to find, create, or organize notes in Obsidian.
Didn't find tool you were looking for?