AI code review for the physical world. Catches the embedded / IoT / robotics bugs that general-purpose code AI cannot see.
First instrument from PhyCyber. Local-first. No telemetry. v0.0.1 — alpha. Heuristic-only; tree-sitter and BYOK LLM reasoning land in v0.1.
Code Sentinel is useful only if it survives contact with real embedded code. If you work on FreeRTOS, STM32, ESP32, robotics firmware, IoT firmware, or driver code, the most valuable feedback is a run against one non-sensitive module.
pip install git+https://github.com/lonrun/code-sentinel
sentinel scan ./firmware --target=stm32 --rtos=freertos --format=html -o code-sentinel-report.htmlSend the report, false positives, or missed bug class to hello@phycyber.ai.
The v0.1 direction will be chosen from those reports: more rules, Zephyr / ROS
support, CI integration, editor integration, or an AI reasoning layer.
8 rules across two categories. Each rule fires on a real, named bug pattern that shows up in production firmware and that current AI coding tools confidently miss.
| ID | Severity | Rule |
|---|---|---|
CS-RTOS-001 |
high | Non-reentrant libc / allocator called from ISR (printf, malloc, strtok, …) |
CS-RTOS-002 |
critical | Task-context FreeRTOS API used inside ISR (xQueueSend instead of xQueueSendFromISR) |
CS-RTOS-003 |
critical | Mutex acquired from interrupt context (forbidden in FreeRTOS) |
CS-RTOS-004 |
critical | Blocking delay called from ISR (HAL_Delay, vTaskDelay) |
CS-RTOS-005 |
high | *FromISR API called from task context |
CS-MEM-001 |
high | Large stack-allocated buffer inside ISR (uint8_t buf[512]) |
CS-MEM-002 |
critical | malloc / pvPortMalloc inside ISR — heap is not interrupt-safe |
CS-MEM-003 |
high | Unbounded strcpy / sprintf into fixed-size local buffer |
ISR detection covers Cortex-M-style _IRQHandler / _Handler names, _isr /
_ISR suffixes, AVR-style ISR(VECTOR_NAME) macros, and explicit attribute
qualifiers (__interrupt, IRAM_ATTR, __weak, FAST_CODE).
pip install git+https://github.com/lonrun/code-sentinel
# or, from a local checkout
git clone https://github.com/lonrun/code-sentinel
cd code-sentinel
pip install -e .Zero runtime dependencies. Pure stdlib. Python 3.9+.
PyPI packaging is prepared but not published yet. Until the first tagged PyPI release lands, install directly from GitHub.
# Scan a directory
sentinel scan ./src --target=stm32 --rtos=freertos
# Scan a single file, write JSON for CI
sentinel scan firmware.c --format=json -o report.json
# Render a previous JSON as a self-contained HTML report
sentinel report report.json --format=html -o report.html
# List the installed rules
sentinel rules
# Run only specific rules
sentinel scan ./src --rule=CS-RTOS-002 --rule=CS-MEM-002
# CI exit code: non-zero if any issue at-or-above this severity (default: high)
sentinel scan ./src --fail-on=criticalgit clone https://github.com/lonrun/code-sentinel
cd code-sentinel
sentinel scan examples/freertos-demo --target=stm32 --rtos=freertosYou should see 13 findings across all 8 rules in sensor_task.c, and zero
findings in clean_task.c.
A pre-rendered HTML report ships at examples/freertos-demo-report.html.
The bugs Code Sentinel finds depend on interrupt context — information that lives in which function the call is inside, not in the call itself. A general-purpose lint or LLM looking at one line cannot see this. Code Sentinel walks function definitions, identifies ISRs from naming and attributes, and flags the call patterns that violate context contracts.
This is the philosophy laid out in the founding essay. We start with rules a domain expert recognizes on sight, and grow toward AI-assisted reasoning where the context is genuinely ambiguous — never the other way around.
# .github/workflows/code-sentinel.yml
name: Code Sentinel
on: [pull_request]
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.11" }
- run: pip install git+https://github.com/lonrun/code-sentinel
- run: sentinel scan ./firmware --target=stm32 --rtos=freertos --fail-on=criticalThe JSON output schema (schemaVersion: "1") is stable across patch releases.
terminal— colorized, dense; intended to be read by a human at the promptjson— stable schema for CI tools and editor integrationshtml— single-file report, no external assets; share by email or attach to a PR
code-sentinel/
├── src/code_sentinel/
│ ├── analyzer.py # orchestrator
│ ├── source.py # lightweight C/C++ tokenizer + scope/ISR detector
│ ├── issue.py # Issue + Severity model
│ ├── cli.py # `sentinel` entry point
│ ├── rules/
│ │ ├── rtos_concurrency.py
│ │ └── memory_safety.py
│ └── report/
│ ├── terminal.py
│ ├── json_report.py
│ └── html_report.py
├── examples/freertos-demo/ # bundled demo + pre-rendered HTML report
├── tests/ # 24 unit + e2e tests
├── run_tests.py # stdlib test runner (no pytest required)
├── pyproject.toml
└── README.md
# With pytest installed:
pytest
# Without pytest (stdlib only):
python3 run_tests.py- v0.0.1 (now): 8 rules, CLI, terminal/JSON/HTML reports, FreeRTOS demo
- v0.1: tree-sitter integration, ROS / Zephyr / Embedded Rust rule packs
- v0.2: BYOK LLM reasoning layer for the genuinely ambiguous cases (the user's API key, calls go directly to the model — code never lands on PhyCyber servers)
- v0.3: VS Code extension built on the same core, LSP exposed
- v1.0: Pro tier with team dashboard + GitHub PR comments
The full philosophy and 3-month delivery plan: see docs/plan.md.
Apache-2.0. PhyCyber Studio · hello@phycyber.ai