Menu

Buddy navigation

Docs

Buddy Documentation

Buddy public docs are split into two tracks: one for users who want to get Buddy running, and one for hardware developers who want to build a Buddy-compatible device without access to the server or CLI source code.

Overview

User Docs

Use this track if you want to install the public CLI, connect Buddy to Codex, Claude, or Enter, pair one device, and confirm that status updates are reaching the device.

Device Developer Docs

Use this track if you are building firmware or client software for a Buddy-compatible device and need the public bootstrap, MQTT, and snapshot contracts.

Buddy is documented as a black-box product surface. External developers should depend on public commands, bootstrap responses, and snapshot payloads, not on Buddy internal implementation details.
For Users

Quick Start

This path is for users who want Buddy working end to end with one account and one bound device.

  • Sign in to the Buddy web app.
  • Generate a CLI key.
  • Bind one device in the same account.
  • Run buddy init --key buddy_xxx.
  • Use buddy codex for Codex, or run buddy install-claude-hooks before starting Claude or Enter.
  • Confirm updates with buddy status.
npm install -g hibuddy
buddy init --key buddy_xxx
buddy whoami
buddy install-claude-hooks
buddy codex
buddy status

Install And Init

Buddy users only need the public CLI package and a valid CLI key from the web app.

  • Runtime requirement: Node.js 20+.
  • Install package: npm install -g hibuddy.
  • Initialize Buddy: buddy init --key <cli-key>.
  • Verify the current local setup: buddy whoami.
buddy init --key buddy_xxx
buddy whoami
buddy status --json
Buddy supports two output modes. mqtt is the default and publishes snapshots to the bound device topic. local writes the same snapshot locally without MQTT publish.

Connect Codex / Claude / Enter

Buddy watches your AI session and continuously rebuilds one compact device-facing snapshot. Pick the integration that matches the agent you actually use.

Codex

Use Buddy as the wrapper when you want Codex activity to update the device.

buddy codex
buddy codex exec -- "Summarize this repository"

Claude / Enter

Both Claude and Enter read the same hook config in ~/.claude/settings.json. Install Buddy hooks once before starting a new session. Use buddy claude when you want Buddy to launch Claude for you; Enter runs the same way you normally launch it.

buddy install-claude-hooks
buddy claude    # or just launch Enter the way you usually do
If you ever want to fully detach Buddy, run buddy remove-claude-hooks. It strips only the Buddy entries from ~/.claude/settings.json and leaves the rest of the file alone.

Device Setup

Buddy V1 currently assumes one account and one bound device.

  • Bind the device in the Buddy web app first.
  • Generate the CLI key from the same account.
  • Run buddy init --key ... after the device is already bound.
  • Use buddy status or buddy status --json to verify fresh snapshot updates.
If buddy status --json updates locally but the hardware does not, the problem is usually the device side or MQTT transport rather than Codex, Claude, or Enter integration.

Download And Flash Firmware

The pet sprites and rendering live inside the firmware, not in the cloud. To get a Buddy device running, download the latest firmware build from GitHub and flash it onto an M5StickS3.

  • Open the firmware repo: github.com/guolin/HiBuddy.
  • Grab the latest firmware release or build from source.
  • Follow the flashing instructions in the repo README — it covers the toolchain, cable, and serial port steps.
Once flashed, power the device on and pair it from the web app. Pet appearance is fixed in firmware, so a new pet means a new firmware build.

Troubleshooting

buddy init fails

Check that the CLI key is valid, the account has a bound device, and the control plane is reachable.

The device does not update

Check buddy whoami, confirm the device is bound to the same account, and verify you are not in local mode.

Hooks did not take effect

Re-run buddy install-claude-hooks. Then restart your Claude or Enter session — hooks only attach at session start.

Clear local state

Run buddy reset to clear the local runtime state and device log.

For Device Developers

Integration Boundary

External hardware developers should treat Buddy as a black-box integration. The device consumes a compact public snapshot and should not depend on Buddy server source code, CLI source code, or upstream AI event formats.

The device should do

  • Request or refresh a pairing code when unpaired.
  • Fetch bootstrap state.
  • Connect to the assigned MQTT broker and topic.
  • Parse the latest retained snapshot.
  • Render the current UI or animation state.

The device should not do

  • Parse Codex payloads.
  • Parse Claude or Enter hook payloads.
  • Rebuild session priority from raw events.
  • Depend on Buddy internal runtime files.

Bootstrap

The device runtime should use the current bootstrap response as the source of truth for MQTT connectivity.

POST /functions/v1/device-bootstrap

Request body:

{
  "device_id": "demo-device-001",
  "device_token": "dev_xxx"
}

For a paired device, the key public fields are:

  • paired
  • mqtt.mqttBrokerUrl
  • mqtt.mqttUsername
  • mqtt.mqttToken
  • mqtt.mqttClientId
  • mqtt.mqttTopic
  • config
  • activePet
If paired is false, the device should stay in the pairing or bootstrap polling flow and should not connect to MQTT yet.

Pairing APIs

Buddy pairing has three public API surfaces: the device requests a pairing code, the user account binds the device, and either side may later unbind it.

Request Pairing Code

Use POST /functions/v1/device-pair-code when the device is unpaired. Response fields include deviceId, deviceToken, pairCode, pairUrl, and expiresAt.

{
  "device_id": "demo-device-001",
  "device_token": "dev_xxx"
}

Bind And Unbind

POST /functions/v1/bind-device requires a signed-in user session.

  • Use {"device_id":"123456"} to bind by 6-digit pairing code.
  • Use {"device_id":"demo-device-001","device_key":"optional-device-key"} to bind by explicit device id.
  • POST /functions/v1/unbind-device unbinds from the user side.
  • POST /functions/v1/device-unbind unbinds from the device side with device_id and device_token.

Snapshot Protocol

Buddy devices consume one compact retained JSON snapshot.

{
  "version": 1,
  "updated_at": 1776520000,
  "pet_state": 3,
  "session_states": [2, 0],
  "requires_user": true,
  "total_tokens": 120000,
  "today_tokens": 34000
}

Field meanings:

  • version: current protocol version, currently 1.
  • updated_at: Unix timestamp in seconds.
  • pet_state: top-level device state.
  • session_states: sorted active session states, highest priority first.
  • requires_user: whether the top active session needs user attention.
  • total_tokens: total tracked token count.
  • today_tokens: tracked token count for the current day.

pet_state

  • 0 idle
  • 1 thinking
  • 2 busy
  • 3 waiting
  • 4 error
  • 5 done
  • 6 sleep

session_states

  • 0 thinking
  • 2 waiting
  • 3 error

MQTT Contract

Buddy publishes the snapshot to the device-specific topic returned by bootstrap.

  • Payload: one JSON snapshot.
  • QoS: 1.
  • Retain: true.
  • Topic: use the topic returned by bootstrap.
The device should subscribe only to its assigned topic, replace its current rendered state when a newer snapshot arrives, and rely on the retained message after reconnect.

Minimum Device Behavior

  • Refresh the pairing code or poll bootstrap until the device is bound.
  • Connect to MQTT with the latest bootstrap credentials.
  • Parse and validate snapshot payloads.
  • Map pet_state and requires_user into UI or animation state.
  • Reconnect when MQTT disconnects.
Recommended fallback rules: retry bootstrap later if it fails, reconnect on MQTT loss, ignore bad payloads while keeping the last valid snapshot, and ignore unknown future fields instead of failing the whole payload.

Compatibility

Buddy devices should be conservative in what they depend on and permissive in what they accept.

  • Do not assume a fixed maximum length for session_states.
  • Ignore unknown future fields.
  • Branch on version before adding protocol-specific behavior.
  • Keep device presentation decisions local, but do not reinterpret the public field meanings.