A tiny desk-side inbox for AI coding agents.
AgentPing puts an animated 3D robot on a Waveshare ESP32-C6 Touch AMOLED 1.64 (280 × 456 portrait). A Windows USB worker connects it to Codex, Claude Code, and GitHub Copilot CLI. Agent notifications show a provider logo and message; CLI and MCP controls let you play animations, pose limbs, and display custom icons.
The physical robot uses the live3d_usb firmware. This path needs USB only: no Wi-Fi, .NET bridge, tray app, Node.js, or simulator is required.
- Get the Waveshare ESP32-C6 Touch AMOLED 1.64 display board. Here is the Amazon purchase link supplied for this project. Check that the selected listing variant matches this board; the firmware is configured for its 280 × 456 AMOLED display, not a bare ESP32 development board.
- Have a USB data cable ready. The same connection powers the board and carries commands; a charge-only cable will not expose a serial port.
- Install Git and Python 3.11 or newer (tested with 3.13), with their commands available on PATH. Open a new PowerShell terminal and check:
git --version
python --versionInstall and sign into your chosen agent CLIs separately. The USB Windows client
below is a background Python application controlled by robot.cmd; the optional
.NET tray application has separate instructions later in this guide.
git clone https://github.com/rwrife/AgentPing.git
cd AgentPing
.\companion\setup-robot.ps1Setup creates .venv-robot and installs the USB and MCP dependencies. Wait for
the Ready message, then check the launcher:
.\companion\robot.cmd --helpIf PowerShell blocks the setup script, perform the same installation directly:
python -m venv .venv-robot
.\.venv-robot\Scripts\python.exe -m pip install -r tools/requirements-robot.txtFor an existing checkout, preserve local work, then use git switch main and
git pull --ff-only. Run setup again when Python dependencies change. All commands
below run from the repository root; virtual environment activation is unnecessary.
Skip steps 3–4 if the board already has the current live3d_usb firmware.
Create a separate build environment, install the pinned dependencies, and compile:
python -m venv .venv-firmware
.\.venv-firmware\Scripts\python.exe -m pip install -r firmware/requirements-ci.txt
.\.venv-firmware\Scripts\pio.exe run -d firmware -e live3d_usbWait for [SUCCESS]. The first build downloads the ESP-IDF toolchain and can take
several minutes. The output is firmware/.pio/build/live3d_usb/firmware.bin.
Use -e live3d_usb explicitly; the default network firmware is a different
application. Model, textures, and animations are checked in, so FBX conversion,
Node.js, and the simulator are not needed. See live renderer details.
- Plug the board into the PC using the USB data cable.
- Find its serial port in Device Manager under Ports (COM & LPT), or run:
.\.venv-robot\Scripts\python.exe -m serial.tools.list_ports- Replace
COM5below with the reported port. Close serial monitors and stop an existing robot worker before flashing:
# Only needed if a worker is already running:
.\companion\robot.cmd stop
.\.venv-firmware\Scripts\pio.exe run -d firmware -e live3d_usb -t upload --upload-port COM5- Wait for the upload's
[SUCCESS]message and automatic reset. The robot should play its startup sequence and enter idle with the initial connection message. If no port appears, try another data cable/USB port before retrying.
.\companion\robot.cmd start
.\companion\robot.cmd statusA successful live response includes "ok": true and VIEW state=.... Wait a few seconds after plugging in or resetting the device before checking status. One background worker owns USB for both notifications and MCP.
.\companion\robot.cmd worker-status # Worker health and delivery counters
.\companion\robot.cmd reset # Return to idle
.\companion\robot.cmd stop # Release USB before flashingStart the worker again after restarting Windows; setup does not install an automatic startup service. The initial connection caption disappears after the first desktop signal.
Send the first message:
.\companion\robot.cmd message "Hello world!"Look for PAL STATE attention OK in the command response and a waving robot with
a message bubble on the device. The client runs in the background, so no app window
is expected. Continue with the terminal demo, then
wire up your CLI agents for automatic notices and MCP.
From the repository root, start the worker with .\companion\robot.cmd start.
Run the examples one at a time, leaving time to see each state. Sending the
next command replaces the current animation or message.
.\companion\robot.cmd state boot
.\companion\robot.cmd message "Consulting my rubber duck..." --state thinking
.\companion\robot.cmd message "Your approval is needed!"
.\companion\robot.cmd message "The changes are ready. Please review the pull request." --state attention
.\companion\robot.cmd resetThese demonstrate the error animation, close-up, and message bubble without causing an actual failure:
.\companion\robot.cmd message "Build failed: please check the terminal." --state error
.\companion\robot.cmd message "Tests failed. I need your help!" --state error
.\companion\robot.cmd message "Connection lost. Please check the USB cable." --state error
.\companion\robot.cmd reset.\companion\robot.cmd icon --file assets/icons/heart-48.bin --color "#ff8800" --message "Hello world!"
.\companion\robot.cmd icon --file assets/icons/teams-48.bin --color "#8b88ff" --message "Teams: Your meeting starts now"
.\companion\robot.cmd icon --file assets/icons/enghub.bin --color "#0078D4" --message "EngHub: Your review is needed"
# Error state overrides the requested green/purple and renders the icon red.
.\companion\robot.cmd icon --file assets/icons/heart-48.bin --color "#00ff00" --state error --message "Demo error: something needs fixing!"
.\companion\robot.cmd icon --file assets/icons/teams-48.bin --color "#8b88ff" --state error --message "Teams demo: unable to join the meeting."
.\companion\robot.cmd resetThe Teams icon is a demo graphic; these commands do not connect to Teams.
.\companion\robot.cmd dance chicken
.\companion\robot.cmd dance twist
.\companion\robot.cmd dance twist
.\companion\robot.cmd reset
.\companion\robot.cmd joint right_shoulder --z -90 --duration-ms 1000
.\companion\robot.cmd joint head --y 25 --duration-ms 800
.\companion\robot.cmd resetPaste this whole block to cycle through thinking, attention, and a red Teams-style error icon, with six seconds to view each notice, then finish in idle:
.\companion\robot.cmd start
.\companion\robot.cmd message "Thinking through the next step..." --state thinking
Start-Sleep -Seconds 6
.\companion\robot.cmd message "Ready for your review!" --state attention
Start-Sleep -Seconds 6
.\companion\robot.cmd icon --file assets/icons/teams-48.bin --color "#8b88ff" --state error --message "Demo error: please check the terminal."
Start-Sleep -Seconds 6
.\companion\robot.cmd resetMessages and custom icons dismiss after 30 seconds and return to idle. Error icons are always red, overriding the requested color. Manual joint poses hold until reset or another state; offsets are relative to the captured animation pose. These move the rendered skeleton. Full command and bitmap details: robot controls.
| Connection | Purpose | Setup |
|---|---|---|
| Notification hooks | Automatically show permission/input requests, completion, and supported errors | Install hooks below |
| MCP tools | Let an agent deliberately show messages, dance, move joints, or send icons | Register MCP in each client |
Both share the USB worker. MCP registration alone does not install notification hooks. Hooks notify you; they do not approve, deny, or resume agent tasks.
Automatic thinking notices are limited to once every two minutes across all agents. Repeats are dropped so the message can dismiss after 30 seconds and return to idle. Attention and error notices still get through immediately. Explicit CLI/MCP demo commands bypass this cooldown.
Preview the configuration paths, then install the additive hooks for all three providers:
.\.venv-robot\Scripts\python.exe tools/install_usb_hooks.py
.\.venv-robot\Scripts\python.exe tools/install_usb_hooks.py --apply
.\companion\robot.cmd startThe installer preserves unrelated handlers and backs up existing settings under %USERPROFILE%\.agentping\usb\backups.
| Agent | Configuration written | Events wired |
|---|---|---|
| Codex | %USERPROFILE%\.codex\hooks.json |
PermissionRequest, Stop |
| Claude Code | %USERPROFILE%\.claude\settings.json |
PermissionRequest, Notification, Stop, StopFailure |
| Copilot CLI | %USERPROFILE%\.copilot\hooks\agentping-usb.json |
userPromptSubmitted, permissionRequest, postToolUse, notification, awaitingUserInput, agentStop, errorOccurred |
Restart your CLI sessions after installation. In Codex, open /hooks and review/trust the AgentPing entries; untrusted hooks are skipped. Rerun the installer after moving the checkout, replacing its Python environment, or updating the hook implementation.
Run a normal task in each agent, then check robot.cmd worker-status for an incremented provider delivery counter and inspect the display. Claude and Copilot live completion hooks were verified during bring-up. Codex's injected permission event was verified, but live Codex hook delivery still requires review/activation and validation in your session. See notification details and tested versions.
For a synthetic pipeline test, not proof of a live agent event:
'{}' | .\.venv-robot\Scripts\python.exe tools/agentping_usb_notifications.py hook --provider codex --event PermissionRequest
Start-Sleep -Seconds 2
.\companion\robot.cmd worker-statusCopilot CLI on Windows: this repository includes .github/mcp.json.
After installing the desktop tools, launch Copilot from the repository root:
.\companion\robot.cmd start
copilot mcp list
copilotAccept the repository trust prompt, then use /mcp show agentping to inspect the
connection. The configuration uses the relative companion\robot.cmd launcher,
so start Copilot in the repository root. No user-level registration is needed
for this checkout. The USB worker must already be running. Use the registration
commands below if you want the robot available from other repositories too.
With the worker running, resolve the checkout paths in PowerShell:
$robotPython = (Resolve-Path .\.venv-robot\Scripts\python.exe).Path
$robotServer = (Resolve-Path .\tools\agentping_robot.py).PathRun the registration command for each installed client you want to use:
# Codex
codex mcp add agentping -- "$robotPython" "$robotServer" mcp
codex mcp list
# Claude Code: available across your projects
claude mcp add --transport stdio --scope user agentping -- "$robotPython" "$robotServer" mcp
claude mcp list
# GitHub Copilot CLI
copilot mcp add agentping -- "$robotPython" "$robotServer" mcp
copilot mcp listReconnect/restart the agent session and inspect its MCP tools. If an agentping entry exists, inspect/update it instead of registering a duplicate. For older Copilot CLI versions without copilot mcp add, use interactive /mcp add: local/stdio, the Python executable above, and the script path plus mcp as arguments.
Official references: Codex MCP, Claude Code MCP, and Copilot CLI MCP. Command syntax was also checked against the installed CLIs.
For another MCP client, configure a stdio server with the Python executable as its command and [absolute-script-path, "mcp"] as its two arguments. A complete JSON example is in robot-control.md. The client launches MCP; start the USB worker separately.
Available tools: robot_status, robot_message, robot_animation, robot_dance, robot_move_joint, robot_icon, and robot_reset.
Example demo prompts:
Use AgentPing to show "Hello world!", then do the chicken dance.
Reset the robot, turn its head 25 degrees on Y over 800 milliseconds, then reset it again.
Show "Waiting for your approval" on the robot in the attention state.
Use AgentPing's robot_message tool with state "error" to show "Build failed: please check the terminal." Leave it visible.
Read assets/icons/teams-48.bin as hexadecimal and use AgentPing's robot_icon tool with color "#8b88ff", state "error", and message "Teams demo: unable to join the meeting." The device should show the icon in red.
Use AgentPing's robot_reset tool to clear the demo and return to idle.
# Software checks; no board required
.\.venv-robot\Scripts\python.exe -m unittest discover -s tools/tests
# MCP-to-device smoke test; changes poses/messages and ends in idle
.\.venv-robot\Scripts\python.exe tools/check_robot_mcp.py- USB unavailable/no acknowledgment: check the data cable and USB port, close serial monitors, then run
robot.cmd stop. Reconnect or reset the board, wait for boot, and runrobot.cmd startfollowed byrobot.cmd status. The worker finds the board by USB VID/PID, so it does not matter which port it is plugged into. - MCP tools missing: check the registered absolute paths, reconnect the client, and confirm
.venv-robotexists. MCP speaks a machine protocol over stdio; it does not present a terminal UI. - MCP works but automatic notices do not: check hook installation and provider-session reload; review Codex
/hooks. Compare delivery counters before/after a real event. Identical provider events can be coalesced for three seconds. - Firmware upload fails: stop the worker and other serial clients, then flash
live3d_usbon the correct port.
USB rendering, CLI/MCP control, provider logos, red error icons, and timed return to idle have been tested on the physical device. Notifications replace the visible notice; there is no on-device queue or approval-response flow.
The Windows companion can send new notifications from selected apps to the USB robot, including the app's logo and message. Open Windows notifications in the packaged companion to grant access and select apps. Messages show for 30 seconds, then the robot returns to idle.
See Windows notification setup for the Windows 11 package build/install commands, permission setup, and testing steps. The USB host must be running; the network bridge is not required.
This is the separate .NET management UI for the network bridge. It does not start
or replace the USB robot worker above. For the USB demo, use robot.cmd.
- Install a stable .NET 10.0 SDK.
global.jsonselects the latest installed 10.0 feature band or patch (10.0.100 or newer). Confirm it appears indotnet --list-sdks. - From the repository root, restore the solution and publish the app and its companion bridge together:
dotnet restore AgentPing.sln --locked-mode
dotnet publish companion/AgentPing.Companion.Windows/AgentPing.Companion.Windows.csproj -c Release -r win-x64 --self-contained true --no-restore -o artifacts/win-x64/app
dotnet publish bridge/AgentPing.Bridge/AgentPing.Bridge.csproj -c Release -r win-x64 --self-contained true --no-restore -o artifacts/win-x64/app/bridge- Launch the published application:
Start-Process -FilePath .\artifacts\win-x64\app\AgentPing.Companion.exe -WindowStyle Normal- Use its management window/tray icon for bridge controls. For ARM64 Windows,
replace
win-x64withwin-arm64in all publish and launch paths. Keep the complete output folder, includingbridge/, together when moving it.
Publishing self-contained includes the .NET runtime. These local builds are unsigned. Network device pairing requires additional TLS/provisioning setup; see companion details and Windows troubleshooting.
- ASP.NET Core 10 executable with structured JSON console logging
- loopback-only default listener at
http://127.0.0.1:8742 GET /healthand non-secret protocol-v1GET /api/status- strict, 16 KiB-bounded
POST /api/eventsandPOST /api/attentionsingestion - deterministic session/attention state, contiguous ingress ordering, idempotency, bounded history, transactional atomic persistence, stale-session handling, and restart recovery
- digest-authenticated protocol-v1
/wscapability negotiation, heartbeat validation, reconnect replay, and live state fan-out - integration tests, process-level smoke coverage, and a reproducible Docker image build
- default-off, loopback-only adapters for Codex CLI, Claude Code, and Copilot CLI hooks, with bounded secret-redacted mapping, durable approve/deny outcomes, and synthetic fixtures
- Windows Forms tray controls and live bridge/device/adapter/attention status
- explicit private-interface TLS pairing, bounded discovery, token rotation/revocation, and redacted log export
- current-user DPAPI credential protection, opt-in startup, high-DPI/accessibility metadata, and
.resxlocalization extension points - signed-ready WiX packaging plus explicitly unsigned
win-x64andwin-arm64CI artifacts
- pinned PlatformIO 6.1.18 / ESP-IDF 5.5.0 ESP32-C6 project with locked managed components
- compile-tested CO5300 AMOLED, FT6146 touch, and LVGL initialization from pinned Waveshare schematic/BSP evidence
- accessible disconnected/idle/running/waiting/completed/error UI with burn-in movement plus touch approve/deny/cancel/acknowledge/reply controls and two-tap destructive confirmation
- strict host-tested protocol parser/action policy/state reducer, authenticated WSS capability/heartbeat/replay/action transport, persistent resume state, and bounded reconnect backoff
- USB-serial NVS provisioning and physical factory reset with no hardcoded network/provider credentials or secret-bearing logs
- JSON Schema Draft 2020-12 contract for all nine v1 message kinds
- bounded envelopes, revisioned/idempotent actions, version negotiation, and reconnect/resume rules
- LAN threat model and full-entropy token pairing/rotation/revocation design
- golden valid/fail-closed fixtures consumed by Python validation and bridge serialization tests
The network firmware described in this section has compile/host-test evidence; USB robot validation does not validate its Wi-Fi, touch actions, or network pairing. The bridge implements protected credential lifecycle and TLS-only enrollment; operators must separately configure the RFC1918 Kestrel HTTPS/WSS endpoint and certificate. Provider permission decisions were not exercised with live provider accounts.
bridge/ ASP.NET Core bridge and tests
firmware/ ESP32-C6 PlatformIO firmware, native logic tests, and bring-up guide
protocol/ shared machine-readable protocol schema, fixtures, and validator
hardware/ hardware scope and future editable KiCad sources
docs/ architecture and protocol status
integration/ process-level integration tooling
scripts/ canonical local verification command
Preview the imported Meshy FBX and dynamic face states locally at the device's
280 × 456 portrait resolution. Run npm ci then npm run dev from simulator/
and open http://127.0.0.1:5173. See simulator/README.md
for controls, validation, asset provenance, and the strategy for moving to hardware.
Requires the .NET 10 SDK.
dotnet restore AgentPing.sln --locked-mode
dotnet build AgentPing.sln --configuration Release --no-restore
dotnet test AgentPing.sln --configuration Release --no-build
./integration/smoke-bridge.shRun the service:
dotnet run --project bridge/AgentPing.Bridge
curl http://127.0.0.1:8742/health
curl http://127.0.0.1:8742/api/statusExpected health response: Healthy. The status JSON identifies agentping-bridge, reports status: ok, uses protocol apiVersion: 1.0, and exposes only non-secret session/attention/history counts plus the latest server sequence. See bridge/README.md for ingestion, authenticated WebSocket, persistence, and configuration details.
python3 -m venv .venv-platformio
. .venv-platformio/bin/activate
python3 -m pip install --requirement firmware/requirements-ci.txt
python3 -m pip install --requirement protocol/requirements-ci.txt
firmware/tests/run_host_tests.sh
python3 protocol/validate.py
platformio run -d firmwareThese commands build the network firmware. CI compilation does not validate physical Wi-Fi, touch, or pairing behavior. Use the explicit live3d_usb instructions above for the USB robot. See firmware/README.md.
docker build --file bridge/AgentPing.Bridge/Dockerfile --tag agentping-bridge:local .
docker run --rm -p 127.0.0.1:8742:8742 agentping-bridge:localThe container listens on 0.0.0.0:8742 inside its isolated network namespace so Docker can forward traffic; the documented host publish is explicitly restricted to 127.0.0.1.
The ESP32 remains a thin client; provider credentials stay on the PC. The bridge binds to loopback by default. LAN pairing requires a separately configured RFC1918 HTTPS/WSS endpoint and certificate; the default HTTP listener must never be exposed to the LAN.
docs/architecture.mddescribes current and planned boundaries.docs/protocol.mdspecifies protocol v1, secure pairing, compatibility, ordering, resume, and fail-closed action rules.docs/generated/protocol-v1-reference.mdis generated directly from the canonical schema.docs/provider-adapters.mddocuments default-off Codex CLI, Claude Code, Copilot CLI, and manual/test hook ingestion.docs/release/mvp-release-runbook.md,docs/release/security-privacy-review.md,docs/release/dependency-license-inventory.md, anddocs/release/rollback-recovery.mddefine MVP release gates and operations.hardware/README.mdstates the current hardware evidence and future KiCad scope.
See CONTRIBUTING.md for exact verification commands and SECURITY.md for private vulnerability reporting and trust-boundary requirements.
MIT. See LICENSE.
Use the USB CLI and MCP server to show custom messages, play animations and dances, and pose individual robot joints from the desktop.
