A configurable C++ linter based on simplified JSF AV C++ Coding Standards (Lockheed Martin, 2005), adapted for embedded AI and edge deployment contexts.
The linter consists of two files:
| File | Purpose |
|---|---|
jsf_lint.py |
Python linter engine (all rule checkers) |
linter_rules.yaml |
Configurable rule definitions (enable/disable, severity, thresholds) |
A CLAUDE.md file is included to instruct Claude Code on the active coding standards.
- Python 3.9+
- PyYAML (
pip install pyyaml)
# Lint a single file
python jsf_lint.py examples/sensor_filter.h
# Lint an entire project
python jsf_lint.py examples/
# JSON output for tooling
python jsf_lint.py src/ --format json
# GitHub Actions annotations
python jsf_lint.py src/ --format github --error-exitCopy CLAUDE.md and the linter files into your project root:
embedded-ai-book/
CLAUDE.md <-- Claude Code reads this automatically
jsf_lint.py
linter_rules.yaml
src/
chapter_03/
sensor_filter.h
sensor_filter.cpp
chapter_07/
pid_controller.h
pid_controller.cpp
Claude Code reads CLAUDE.md at the start of every session and will
apply the coding standards when writing or reviewing code.
Create a .claude/commands/lint.md file in your project:
---
description: Run JSF AV linter on project code
---
Run the JSF linter on the specified files or directories.
Use `python jsf_lint.py <target>` from the project root.
Report all violations grouped by severity.
For each error-level violation, suggest a concrete fix.Then invoke it in Claude Code with:
/lint src/chapter_03/
Add a .pre-commit-config.yaml entry or a git hook script:
#!/bin/bash
# .git/hooks/pre-commit
python jsf_lint.py src/ --error-exitAll rules live in linter_rules.yaml. The structure is:
category_name:
rule_name:
enabled: true # Toggle on/off
severity: error # error | warning | info
jsf_ref: "AV Rule N" # Traceability to original standard
description: "..." # Human-readable explanation
params: # Rule-specific thresholds
max_lines: 100
pattern: "\\bgoto\\b" # Regex for pattern-based rules
patterns: # Multiple regex patterns
- "\\bthrow\\b"
- "\\bcatch\\b"Relax function length for complex inference pipelines:
max_function_length:
params:
max_lines: 150Allow printf for debug builds (already disabled by default):
no_stdio:
enabled: falseTighten line length for book formatting:
max_line_length:
params:
max_chars: 80Add values to the magic number whitelist:
no_magic_numbers:
params:
allowed_values: [0, 1, 2, -1, 255, 1024]Suppress a specific rule on a single line by appending a comment:
int legacy_val = 42; // NOLINT(no_magic_numbers)The suppression marker is configurable in linter_rules.yaml under the
suppressions section.
The table below lists all implemented rules and their default state.
| Rule | JSF Ref | Default | Severity |
|---|---|---|---|
| max_function_length | AV Rule 1 | 100 lines | warning |
| max_function_args | AV Rule 110 | 6 args | warning |
| max_line_length | AV Rule 41 | 100 chars | info |
| Rule | JSF Ref | Default | Severity |
|---|---|---|---|
| no_goto | AV Rule 189 | enabled | error |
| no_continue | AV Rule 190 | enabled | error |
| no_exceptions | AV Rule 208 | enabled | error |
| no_unions | AV Rule 153 | enabled | error |
| no_errno | AV Rule 17 | enabled | warning |
| no_setjmp_longjmp | AV Rule 20 | enabled | error |
| no_signal_h | AV Rule 21 | enabled | error |
| no_stdio | AV Rule 22 | disabled | warning |
| no_atoi_atof | AV Rule 23 | enabled | warning |
| no_abort_exit | AV Rule 24 | enabled | error |
| no_register | AV Rule 140 | enabled | info |
| Rule | JSF Ref | Default | Severity |
|---|---|---|---|
| no_raw_int_types | AV Rule 209 | enabled | warning |
| no_c_style_casts | AV Rule 185 | enabled | error |
| no_octal_constants | AV Rule 149 | enabled | error |
| hex_uppercase | AV Rule 150 | enabled | info |
| literal_suffix_upper | AV Rule 14 | enabled | info |
| Rule | JSF Ref | Default | Severity |
|---|---|---|---|
| no_malloc_free | AV Rule 206 | enabled | error |
| no_raw_new_delete | AV Rule 206 | enabled | warning |
| volatile_for_hw_only | AV Rule 205 | enabled | warning |
| Rule | JSF Ref | Default | Severity |
|---|---|---|---|
| braces_required | AV Rule 59 | enabled | error |
| switch_default | AV Rule 194 | enabled | warning |
| no_float_loop_counter | AV Rule 197 | enabled | error |
| single_return | AV Rule 113 | disabled | info |
| Rule | JSF Ref | Default | Severity |
|---|---|---|---|
| no_tabs | AV Rule 43 | enabled | info |
| no_magic_numbers | AV Rule 151 | enabled | warning |
| one_decl_per_line | AV Rule 152 | enabled | warning |
| no_commented_out_code | AV Rule 127 | enabled | warning |
| include_guard | AV Rule 27 | enabled | error |
| cpp_comments_only | AV Rule 126 | enabled | info |
| Rule | JSF Ref | Default | Severity |
|---|---|---|---|
| virtual_destructor | AV Rule 78 | enabled | error |
| explicit_constructors | AV Rule 177 | enabled | warning |
| no_public_data_class | AV Rule 67 | enabled | warning |
| Rule | JSF Ref | Default | Severity |
|---|---|---|---|
| define_only_for_guards | AV Rule 29-31 | enabled | warning |
To add a new rule:
- Add the rule definition to
linter_rules.yamlunder the appropriate category. - If it is pattern-based, just add a
pattern:orpatterns:field. The existingPatternCheckerwill handle it. - If it requires custom logic, create a new
RuleCheckersubclass injsf_lint.pyand register it inJSFLinter.CHECKER_MAP. - Test with a sample file containing both violations and clean code.
The test suite uses Python's built-in unittest module and has no additional dependencies beyond PyYAML. From the repository root:
python tests/test_checkers.pyFor more detailed output with pytest (optional):
pip install pytest
python -m pytest tests/test_checkers.py -vThe suite contains 69 tests across eight areas:
| Test Class | What It Verifies |
|---|---|
TestCleanFixture |
A well-written file produces zero violations |
TestAllErrorsFixture |
Every rule fires the exact expected number of times |
TestSuppressionFixture |
NOLINT comments suppress their target rules |
TestSeverityClassification |
Error, warning, and info severity are assigned correctly |
TestOutputFormats |
Text, JSON, and GitHub annotation output all parse correctly |
TestErrorExitCode |
--error-exit returns code 1 on errors, 0 on clean files |
TestRuleToggle |
Disabling a rule in YAML stops it from firing |
TestPathExclusion |
Excluded directories produce no violations |
TestFalsePositiveImmunity |
Keywords in strings and comments do not trigger rules |
TestJSFTraceability |
Every violation carries a valid JSF AV Rule reference |
When adding or modifying rules, update the EXPECTED_COUNTS dictionary in TestAllErrorsFixture and the corresponding line in tests/fixtures/all_errors.cpp to keep the tests in sync.
This is a regex-based linter, not a full AST parser. It will not catch:
- Recursion (requires call graph analysis)
- Cross-file violations (single-file scope)
- Template instantiation issues
- Semantic type narrowing
The C-style cast checker intentionally exempts (void) casts, which are a standard idiom for suppressing unused-variable warnings in embedded C++.
For production safety-critical work, pair this linter with clang-tidy, MISRA checkers, or Polyspace. This tool is designed for rapid feedback during example development.
The JSF AV C++ Coding Standards document is approved for public release by Lockheed Martin (Distribution Statement A). This linter implementation is provided under the MIT License.