# PROJECT KNOWLEDGE BASE **Generated:** 2026-06-26 **Repository:** `nexus-agent-embedded` ## OVERVIEW NexusGuard Embedded Agent: ESP32-based WireGuard client for IoT/edge devices. Runs on FreeRTOS + ESP-IDF, connects to NexusGuard Server Core via HTTP provisioning + heartbeat, manages WireGuard tunnel via lwIP stack. ## STRUCTURE ``` nexus-agent-embedded/ ├── main/ │ ├── main.c # Entry point, initialization │ ├── provision.c/.h # HTTP provisioning (POST /api/v1/provision) │ ├── heartbeat.c/.h # HTTP heartbeat loop (POST /api/v1/heartbeat) │ ├── tunnel.c/.h # WireGuard tunnel management via lwIP │ ├── crypto.c/.h # AES-256-GCM decrypt (mbedtls) │ ├── config.c/.h # NVS config storage │ └── wifi.c/.h # WiFi STA management ├── components/ │ └── wireguard-esp32/ # WireGuard library (lwIP-based) ├── docs/ │ ├── DESIGN.md # Technical design document │ ├── API_COMPAT.md # Server API compatibility │ └── HARDWARE.md # ESP32/LW840X hardware reference ├── CMakeLists.txt # ESP-IDF build system ├── sdkconfig.defaults # ESP-IDF configuration ├── AGENTS.md # This file └── README.md ``` ## API PROTOCOL (Shared with Server) ### Provisioning - **Endpoint**: `POST /api/v1/provision` - **Request**: `{ "token": "string", "hwid": "string" }` - **Response**: `{ "encrypted_config": "base64-bytes" }` - **ConfigPayload** (decrypted): device_id, private_key, preshared_key, internal_ip, server_pub, endpoint, dns, allowed_ips, server_wg_ip ### Heartbeat - **Endpoint**: `POST /api/v1/heartbeat` - **Request**: `{ "device_id": "UUID", "status": "connected|recovering|stopped", "tunnel_up": bool, "last_handshake": "ISO8601" }` - **Response**: Full config sync (same fields as ConfigPayload + forwards_hash) - **Interval**: 30 seconds ### Crypto - **Algorithm**: AES-256-GCM - **Key Derivation**: SHA256(hwid + salt) - **Format**: nonce (12 bytes) + ciphertext - **Implementation**: mbedtls (built-in ESP-IDF) ## HARDWARE PLATFORM ### Target: ESP32 (LW840X) - **MCU**: ESP32 Xtensa LX7 dual-core - **RAM**: 320KB SRAM - **Flash**: 4MB - **WiFi**: 802.11 b/g/n - **OS**: FreeRTOS via ESP-IDF - **Network Stack**: lwIP ### Build Toolchain - **ESP-IDF**: v5.2+ - **Compiler**: Xtensa GCC - **Build System**: CMake - **Debug**: JTAG + OpenOCD ## CONVENTIONS ### Code Style - C99 standard - Snake_case for functions and variables - UPPER_SNAKE_CASE for macros and constants - Doxygen-style comments for public API - Error handling: return esp_err_t or NULL on failure ### Memory Management - Use `heap_caps_malloc(MALLOC_CAP_SPIRAM)` for large buffers - Free all allocated memory in error paths - No static buffers > 1KB on stack ### Network - Use `esp_http_client` for HTTP requests - Timeout: 10s connect, 30s read - Retry: 3 attempts with exponential backoff - TLS: Skip verify for now (internal network only) ### Storage - NVS namespace: "nexusguard" - Keys: "device_id", "private_key", "preshared_key", "internal_ip", "server_pub", "endpoint", "dns", "allowed_ips" - Max key size: 15 chars (NVS limit) ## ANTI-PATTERNS - **NEVER** store WireGuard keys in plaintext on flash (always encrypted via NVS) - **NEVER** use `printf` for sensitive data (keys, tokens) - **NEVER** hardcode WiFi credentials (use menuconfig or provisioning) - **NEVER** block main task for > 100ms (use timers or tasks) - **NEVER** use `malloc()` in interrupt context ## COMMANDS ```bash # Build idf.py set-target esp32 idf.py build # Flash & Monitor idf.py -p /dev/ttyUSB0 flash monitor # Clean idf.py fullclean # Menuconfig idf.py menuconfig ``` ## DEPENDENCIES - **ESP-IDF**: v5.2+ (framework) - **mbedtls**: AES-256-GCM, SHA-256 (built-in) - **lwIP**: TCP/IP stack (built-in) - **FreeRTOS**: RTOS (built-in) - **wireguard-esp32**: WireGuard tunnel library (component) ## NOTES - ESP32 uses FreeRTOS, NOT Zephyr RTOS - lwIP is the network stack, NOT kernel networking - WireGuard runs in userspace via lwIP socket API - Config is stored in NVS (flash), not filesystem - No gRPC support (too heavy for ESP32) — HTTP only - No port forwarding (userspace agent only) - Agent version: 1.0.0 (initial release)