Installation
VibeMon App (Recommended)
Install the desktop app, then let it configure everything else for you — no separate script needed.
brew tap opspresso/tap
brew install opspresso/tap/vibemon
Or via npm: npx vibemon@latest
Open the app, go to Settings > AI Tools, and click Install for Claude Code, Codex CLI, Kiro IDE, or OpenClaw.
Non-interactive Install (AI agents, CI)
For headless setups where a GUI app isn't available:
# Choose exactly one platform + your token
curl -fsSL https://docs.vibemon.io/install.py | python3 - --claude --token my_token
# --codex / --kiro / --openclaw for other tools, --all for every detected tool
Interactive prompt version:
curl -fsSL https://docs.vibemon.io/install.py | python3
Or point your AI agent at docs/setup.md (https://docs.vibemon.io/setup.md) and have it follow the instructions directly.
Local Install
git clone https://github.com/opspresso/vibemon-docs.git
cd vibemon-docs
python3 docs/install.py
Configuration
After installation, edit ~/.vibemon/config.json to configure your targets:
{
"debug": false,
"cache_path": "~/.vibemon/cache/projects.json",
"auto_launch": true,
"http_urls": [],
"serial_port": null,
"vibemon_token": "",
"vibemon_url": "https://vibemon.io"
}
| Field | Description | Example |
|---|---|---|
debug | Enable debug logging | true |
cache_path | Cache file path for project metadata | ~/.vibemon/cache/projects.json |
auto_launch | Auto-launch Desktop App on session start | true |
http_urls | HTTP targets (Desktop App, ESP32 WiFi) | ["http://127.0.0.1:19280"] |
serial_port | ESP32 USB serial port (wildcard supported) | /dev/cu.usbmodem* |
vibemon_url | VibeMon cloud API URL | https://vibemon.io |
vibemon_token | VibeMon API access token (from dashboard) |
Claude Code's statusline reads a separate ~/.vibemon/statusline.json for display toggles (e.g. show_cost, show_git, show_model, show_tokens) and the fallback token_reset_hours setting — see statusline.example.json for the full set of defaults. This file is optional; statusline.py falls back to sensible defaults (and to any matching keys still in config.json) when it's absent.
The Claude Code installer also places a standalone refresher at ~/.vibemon/usage.py. For Claude, it fetches plan usage directly from Anthropic's OAuth usage API using the local Claude Code login token (no active session required), falling back to a claude -p "/usage" subprocess when a token isn't available or the API call fails. For Codex, it queries the same account-level usage API Codex CLI's own /status polls using the local Codex login token, falling back to the newest local session log. Either way it writes the shared ~/.vibemon/cache/usage.json, so the Desktop app can run it (python3 ~/.vibemon/usage.py --max-age 600) on startup or on a schedule to keep usage data fresh even when no Claude Code or Codex session is active. Since the claude -p "/usage" fallback is itself a real Claude Code session, the Desktop app sets VIBEMON_SUPPRESS_HOOKS=1 in its environment so the spawned session's own hooks don't report status back. Independently of that env var, the hooks also skip any session whose cwd is ~/.vibemon itself, so spawners that don't set the variable (older Desktop app versions, manual usage.py runs) can't surface a phantom .vibemon project either.
The reset-countdown fields the hooks attach (usage5hResetsIn/usageWeekResetsIn) are populated whenever the cache was refreshed via a resets_at epoch — either an active Claude Code session's statusline (the official rate_limits path), usage.py's direct Anthropic/Codex API queries, or a Codex session log. Only the last-resort claude -p "/usage" text fallback lacks a machine-parseable reset time, so the reset countdown is omitted in that case while the usage percentages still update.
Note that the plan-usage fields (usage5h/usageWeek and their reset countdowns) are sent by the Claude Code and Codex hooks, since they both read from the same usage.py-refreshed cache (under separate claude/codex cache keys). The Kiro hook doesn't report usage, and OpenClaw reports context-window usage as memory instead.
Codex Configuration
Codex uses the same ~/.vibemon/config.json as Claude Code and Kiro. Enable Codex hooks in ~/.codex/config.toml:
[features]
hooks = true
Then merge codex/hooks.json into your existing ~/.codex/hooks.json (do not overwrite). Codex hooks are experimental, and Codex CLI's own hooks documentation currently lists Windows as unsupported.
OpenClaw Configuration
The OpenClaw plugin reads transmission settings (http_urls, serial_port, vibemon_url, vibemon_token) from the same ~/.vibemon/config.json as the other tools. It only needs to be registered and enabled in ~/.openclaw/openclaw.json — OpenClaw doesn't auto-discover extension directories, so the plugin path must also be registered under plugins.load.paths or the manifest/entries config alone won't load it:
{
"plugins": {
"load": {
"paths": ["~/.openclaw/extensions/vibemon-bridge"]
},
"entries": {
"vibemon-bridge": {
"enabled": true,
"hooks": { "allowConversationAccess": true }
}
}
}
}
To override the shared settings for OpenClaw only, add a config object to the entry (projectName, character, httpEnabled, httpUrls, serialEnabled, vibemonUrl, vibemonToken, autoLaunch, debug) — plugin config always wins over ~/.vibemon/config.json.
After installing or updating the plugin, rebuild OpenClaw's persisted plugin registry and restart the gateway (openclaw plugins registry --refresh && openclaw gateway restart) — the gateway boots from a registry snapshot and won't pick up the plugin's hooks otherwise. The installer runs the refresh automatically when the openclaw CLI is available.
CLI Commands
The hook script supports these commands:
# Lock monitor to current project
python3 ~/.claude/hooks/vibemon.py --lock [project_name]
# Unlock monitor
python3 ~/.claude/hooks/vibemon.py --unlock
# Get current status
python3 ~/.claude/hooks/vibemon.py --status
# Get/set lock mode (first-project, on-thinking)
python3 ~/.claude/hooks/vibemon.py --lock-mode [mode]
# Reboot ESP32 device
python3 ~/.claude/hooks/vibemon.py --reboot
Apps
Desktop App
Electron app with system tray for macOS, Windows, Linux. See Installation above to install.
Token can be configured via the system tray menu.
It shows a single character window with a speech bubble that follows it. The window retargets to whichever project is currently active instead of opening one window per project.
Features: frameless floating window, always on top, system tray integration, snap to screen corners, click to focus terminal (macOS).
ESP32 Hardware
Dedicated LCD display (172×320, ST7789V2). Hardware: ESP32-C6-LCD-1.47 board, USB-C cable.
Required libraries: LovyanGFX (lovyan03), ArduinoJson (Benoit Blanchon), WebSockets (Markus Sattler, for WebSocket mode).
Arduino IDE setup: add the ESP32 Board Manager URL below, install the ESP32 board and required libraries, select the ESP32C6 Dev Module, then upload.
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
WiFi configuration (credentials.h):
#define USE_WIFI
#define WIFI_SSID "YOUR_SSID"
#define WIFI_PASSWORD "YOUR_PASSWORD"
Optional WebSocket mode:
#define USE_WEBSOCKET
#define WS_HOST "ws.vibemon.io"
#define WS_PORT 443
#define WS_PATH "/"
#define WS_USE_SSL true
#define WS_TOKEN "your-access-token"
For SSL, change the Partition Scheme to "Huge APP (3MB No OTA/1MB SPIFFS)".
Testing via serial:
# macOS
echo '{"state":"working","tool":"Bash","project":"my-project"}' > /dev/cu.usbmodem1101
# Linux (set baud rate first)
stty -F /dev/ttyACM0 115200
echo '{"state":"working","tool":"Bash","project":"my-project"}' > /dev/ttyACM0
API
WebSocket
wss://ws.vibemon.io?token=your-access-token
Message types:
// Status update
{
"type": "status",
"data": {
"state": "working",
"tool": "Bash",
"project": "my-project",
"model": "opus",
"memory": 45,
"character": "clawd",
"usage5h": 36,
"usageWeek": 37,
"usage5hResetsIn": 154,
"usageWeekResetsIn": 4381,
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-01-01T00:00:00.000Z"
}
}
// Project deleted
{
"type": "delete",
"data": { "project": "my-project" }
}
HTTP API
curl -X POST https://vibemon.io/api/status \
-H "Authorization: Bearer your-token" \
-H "Content-Type: application/json" \
-d '{
"state": "working",
"project": "my-project",
"character": "clawd",
"tool": "Bash",
"model": "opus",
"memory": 45
}'
| Field | Type | Description |
|---|---|---|
state | string | start, idle, thinking, planning, working, packing, notification, done, sleep, alert (required) |
project | string | Project name (required) |
character | string | vibemon, clawd, codex, kiro, claw, or daangni (required; an unrecognized value falls back to vibemon rather than being rejected). daangni is manual selection only (no tool maps to it) |
tool | string | Tool name (Bash, Read, Edit, etc.) (optional) |
model | string | Model name (opus, sonnet, etc.) (optional) |
memory | number | Context window usage 0-100 (optional) |
usage5h / usageWeek | number | Plan-usage percentage 0-100 (optional; Claude Code and Codex hooks only — see above) |
usage5hResetsIn / usageWeekResetsIn | number | Minutes until the usage window resets (optional; see above) |
usageWeekModel | number | Model-scoped weekly plan-usage percentage 0-100, e.g. the Fable weekly limit (optional) |
usageWeekModelResetsIn | number | Minutes until the model-scoped weekly window resets (optional) |
usageWeekModelLabel | string | Display label of the scoped model, e.g. "Fable" (optional) |
# Delete agent status
curl -X DELETE "https://vibemon.io/api/status?project=my-project" \
-H "Authorization: Bearer your-token"
# Aggregated metrics
curl "https://vibemon.io/api/metrics?granularity=HOUR&range=24h" \
-H "Authorization: Bearer your-token"
Token format: a-z, 0-9, _, -, 8-64 characters (e.g. my_token_123).
State Mapping
Claude Code
| Event | State |
|---|---|
SessionStart | start |
UserPromptSubmit | thinking |
PreToolUse | working |
SubagentStart | working |
PreCompact | packing |
Notification | notification |
PermissionRequest | notification |
SessionEnd | done |
Stop | done |
Plan Mode: when Claude Code is in plan mode, thinking and working states automatically become planning.
Codex CLI
| Event | State |
|---|---|
SessionStart | start |
UserPromptSubmit | thinking |
PreToolUse (Bash only) | working |
SubagentStart | working |
PermissionRequest (Bash only) | notification |
PostToolUse (Bash only) | thinking |
SubagentStop | thinking |
PreCompact | packing |
PostCompact | thinking |
Stop | done |
PreToolUse, PermissionRequest, and PostToolUse are registered with a Bash-only matcher (see docs/codex/hooks.json), so non-Bash tool calls (Read, Edit, etc.) don't trigger a state change.
Codex hooks are experimental, and Codex CLI's own hooks documentation currently lists Windows as unsupported.
Kiro IDE
| Event | State |
|---|---|
agentSpawn | start |
promptSubmit / userPromptSubmit | thinking |
fileCreated / fileEdited / fileDeleted | working |
preToolUse | working |
postToolUse | thinking |
agentStop / stop | done |
OpenClaw
| Event | State |
|---|---|
gateway_start | start |
before_agent_start | thinking |
before_tool_call | working |
after_tool_call | thinking |
message_sent / agent_end | done (3s delay) |
session_end / gateway_stop | done |