English | 简体中文
A physical security gateway & desktop mascot on ESP32-S3 for Claude Code, Gemini, Antigravity, Codex, and OpenCode. Supports direct importing and packaging of pet assets from Petdex & Codex-pets.
基于 ESP32-S3 触摸屏的多平台 AI 编程助手(Claude Code, Gemini, Antigravity, Codex, OpenCode)物理安全看门狗与电子宠物系统。支持从 Petdex 与 Codex-pets 平台一键导入宠物资产进行打包展示。
-
Physical Approval Gateway (Strict Guard Mode)
- Intercepts potentially risky shell commands or tool executions initiated by AI agents in real-time.
- Pushes command details, workspace paths, and AI thinking context to a physical ESP32-S3 touch screen.
- Requires physical confirmation (click "Approve") to proceed, or click "Reject" to halt and safely terminate agent execution.
-
Animated Desktop Mascot (Companion Mode)
- Renders animated 2D pixel-art pets that dynamically react to AI agent activity states:
- Idle: Looking around or blinking when AI is waiting for prompts.
- Review (Thinking): Pondering/inspecting files.
- Run: Running commands.
- Jump (Success): Celebrating approved/successful actions.
- Failed: Crying or showing disappointment on rejection or command errors.
- Renders animated 2D pixel-art pets that dynamically react to AI agent activity states:
-
Dynamic Client ID Configuration
- Automatically generates a unique Client ID on first run, displayed in the web dashboard header.
- Modifying the Client ID in the Web UI dynamically re-subscribes MQTT channels to prevent network conflicts.
-
Pet Store & Asset Packaging Tool
- Import mascot spritesheets directly from links of community galleries like Petdex and Codex-pets.
- Automatically slices and packages spritesheet assets into high-performance big-endian RGB565 binary payloads (
pet_assets.bin) to flash onto the ESP32.
sequenceDiagram
participant Agent as AI Coding Agent (Claude Code, etc.)
participant Hook as Interception Hook Script
participant Daemon as Local Daemon (Node.js)
participant ESP32 as ESP32-S3 Touch Screen (Mascot)
Agent->>Hook: Execute tool/command
Hook->>Daemon: Intercept request (/api/approve)
Daemon->>ESP32: Send approval message via MQTT
ESP32->>ESP32: Pop up dialog, display command, wait for confirmation
Note over ESP32: User taps Approve or Reject
ESP32->>Daemon: Send result back via MQTT
Daemon->>Hook: Send HTTP response
alt Approved
Hook->>Agent: Exit code 0 (Continue execution)
else Rejected
Hook->>Agent: Exit code 2 (Halt execution)
end
- Operating System: Linux (e.g. Ubuntu/Debian)
- Environments: Node.js (v18+), Python 3.8+ (for ESP32 firmware compilation)
- Hardware: ESP32-S3 board with a Touch LCD screen (default settings optimized for WaveShare 1.54" 240x240 ST7789 display)
You can choose to run directly on your host machine or use Docker Compose:
- Navigate to the
local-daemonfolder and install dependencies:cd local-daemon npm install - Start the daemon:
npm start
To keep your host environment clean, run this command in the project root:
docker-compose up -d💡 Critical Step: Once the daemon is running, open
http://localhost:4000in your browser. Copy the auto-generated Client ID from the header.
To prevent credentials leakage, we use environment variables for compilation. Follow these simple steps:
To flash code to /dev/ttyACM* devices, grant permissions to the current user:
sudo usermod -aG dialout $USER
# Note: You may need to re-login or restart the terminal session for this to take effect.
# For temporary quick access, you can also run:
sudo chmod 666 /dev/ttyACM*The project compiles code using PlatformIO Core CLI. If you do not have a virtual environment set up, run the following commands in the project root:
# 1. Create a virtual environment
python3 -m venv .venv
# 2. Activate the virtual environment
source .venv/bin/activate
# 3. Install PlatformIO Core dependencies
pip install -U platformioIn the project root, copy .env.example to .env:
cp .env.example .envOpen .env in a text editor and fill in your WiFi credentials and your Client ID:
WIFI_SSID="your_wifi_name"
WIFI_PASS="your_wifi_password"
CLIENT_ID="copied_client_id_from_web_ui"Connect your board via USB. Hold the BOOT button, press the RESET button, and release the BOOT button to enter download mode. In the activated virtual environment, run:
# Activate virtual environment if not already: source .venv/bin/activate
pio run -t uploadNote: PlatformIO automatically invokes the read_env.py pre-build script to compile the .env variables into C++ preprocessor macros. There is no need to manually modify src/main.cpp.
Go to the Hook Control Panel tab on the Web Dashboard (http://localhost:4000):
- Toggle your target AI agents (e.g. Claude Code, Antigravity) to
strict(Interception Approval) orcompanion(Mascot Only).
Now, when your AI agent attempts to run a shell command, it will hang and wait until you physically click "Approve" on the screen.
Reason: In strict mode, the hook script blocks until it receives a response from /api/approve on the local daemon. If the backend is down, the request blocks and locks your terminal command-line.
Fix: Copy and run this command in your terminal to instantly disable the interception hook:
curl -X POST http://localhost:4000/api/hooks/toggle -H "Content-Type: application/json" -d '{"platform":"claude-code","enabled":false}'Note: Antigravity terminal wrappers have a built-in safety whitelist (ls, ps are allowed by default) to prevent total deadlock.
- Verify your board is connected via the USB-CDC/UART data port (not the power-only port).
- Re-run the temporary authorization command:
sudo chmod 666 /dev/ttyACM*.
- WiFi Connection: Verify your WiFi credentials in
.envare correct, and your board has good signal coverage. - MQTT Connection: The daemon and board default to EMQX Broker (
broker-cn.emqx.io:1883). Ensure both your computer and board can connect to the internet. If you are in a firewalled environment, update the MQTT host inserver.jsandsrc/main.cppto use a local broker. - Force Sync: Click
Update Client IDin the Web UI to trigger a fresh MQTT state publication, then reset your development board.
