Files
hermes-bot/pi/robot.service
T
kyleandClaude Sonnet 5.5 167f53ceeb Add hermes_mcp, the bridge between Hermes and the ROS graph
The MCP server is now a ROS node and the only way in or out, per the owner's
decision that ROS never leaves the robot. It serves MCP on the USB address only
with a bearer token, keeps the stable tool name look() (which waits for the next
camera frame, so it is never stale, and passes the camera's JPEG through), and
registers turn_head/head_position only when a head is fitted, which today it is
not. While an authenticated client is connected it republishes the agent
heartbeat on /hermes/state, so the face wakes on connect and sleeps about 40 s
after the client leaves; look() also makes the face squint.

The token is generated on the Pi into /etc/robot-mcp.env (root:hermes, 640) and
never printed. Verified end to end from talos with a real MCP client over the USB
link: tools listed, a 157 KB JPEG back in 0.08 s, a wrong token refused, the Wi-Fi
path dropped by the firewall. Host config snippets now point at 10.55.0.2.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AFN8nRRCiDiMN7ChBpHJhs
2026-10-05 00:20:58 -07:00

23 lines
909 B
Desktop File

[Unit]
Description=Robot (hermes_bringup): face, camera, face detection, audio levels, MCP bridge
# Nothing here needs the user session: audio_state retries until the user's PipeWire is up.
After=local-fs.target robot-cpu-performance.service robot-firewall.service
[Service]
User=hermes
# lgpio (the display's GPIO backend) drops a notification pipe in its working directory, which must
# be writable: systemd's default, /, is not.
RuntimeDirectory=robot
WorkingDirectory=/run/robot
# hermes_mcp reads its bearer token from here (root:hermes, mode 640); it is never in a parameter
EnvironmentFile=-/etc/robot-mcp.env
# audio_state reaches the user's PipeWire through this
Environment=XDG_RUNTIME_DIR=/run/user/1000
ExecStart=/bin/bash -c 'source /home/hermes/robot-env.sh && exec ros2 launch hermes_bringup robot.launch.py'
Restart=always
RestartSec=3
TimeoutStopSec=20
[Install]
WantedBy=multi-user.target