vibemon-app

Features

Cloud resources and coding accounts

Select Dashboard from the tray menu to open the workspace and select custom resources, host/cluster presets, and multiple accounts per provider. The App polls summaries with an OS-encrypted read token. Web resource edits control labels, display ranges, and metric order; local hook activity still works independently. See cloud monitoring for setup, selection, trends, and failure states.

The tray’s orange-red dot shows that something needs you. The same dot marks where to resolve it:

Issue Tray menu item Workspace mark
A selected agent or resource needs attention Dashboard Agents or Resources in the sidebar
The read connection failed Settings… (opens Connections) Settings and the Connections tab
An integration needs repair or an update, local delivery settings are invalid, or the cloud delivery check failed Integrations… Settings and the Integrations tab
An app update is available or ready to install About VibeMon Settings and the About tab

A marked menu item shows the cause below its name on macOS and after its name on Windows and Linux. The icon tooltip lists every cause. In the workspace, hover over a dot to read its cause; screen readers announce it. Need attention in Overview counts the affected resources and accounts. Sources on Standby do not turn on a dot. src/shared/attention.cjs assigns each issue to its location for the tray and the workspace.

Languages

The App shows English, Korean, and Japanese. At startup it uses the first of these languages in the macOS, Windows, or Linux language list. Any other language shows English. The tray, menus, dialogs, workspace, speech bubble, and macOS widgets use that language. To change it, change the OS language order and restart the App. Character, provider, and product names are not translated, and installer and hook output stays in English.

To add or change text:

  1. Add the message to src/shared/i18n/desktop.json in en, ko, and ja. Messages that Web and iPhone also show belong in src/shared/i18n/shared.json; use its terms in Desktop text too. Every locale needs the same keys and {placeholder} names. A count message can have { "one": …, "other": … } forms.
  2. In main-process code, call t(key, params) from src/shared/i18n/locale.cjs. In the workspace, call t from src/workspace/i18n.js, or add data-i18n="key" or data-i18n-attr="aria-label:key" to index.html and keep the English text there.
  3. For the macOS widgets’ own words, edit native/macos/Widgets/Localizable.xcstrings. A widget string with the English of a shared.json message must use its translations.
  4. Run node scripts/generate-monitoring.mjs --write after a shared.json change, then pnpm test:design. The generator checks both catalogs.

VIBEMON_LOCALE=ko pnpm preview:workspace and VIBEMON_LOCALE=ja pnpm preview:widgets preview a translation.

Agent Support

VibeMon normalizes multiple agent ecosystems into one display model. The rendering layer is shared, but the integration path is not.

Agent Integration path Best signal source Observability quality Important limitation
Claude Code Native hooks Session, turn, and tool hooks High None significant for basic monitoring
Codex Native hooks and non-interactive JSON output Interactive lifecycle and local tool hooks, codex exec --json for automation High Hosted tools such as WebSearch do not pass through local tool hooks
Kiro Native hooks Prompt, tool, and stop hooks Medium to high A cancelled CLI V3 turn runs no Stop hook. The watcher reads turn_end from the V3 session record and reports done; SessionEnd reports done when the session ends. The default CLI 2.x V2 engine runs no global hooks; with a custom agent, its cancellation record also ends the turn
OpenClaw Plugin bridge Plugin SDK hooks Medium to high Internal hooks are not enough by themselves for full tool-loop visibility
OpenCode Plugin + Python adapter Session, chat, tool, permission, and compaction events High No context or plan-usage metrics; uses the default character until registered in this repository

Bridge Types

Agent-Specific Notes

OpenCode Setup

OpenCode 1.18.29 or later is required. One plugin file serves OpenCode 1.x and 2.x. In Settings → Integrations, click Install integration for OpenCode, then restart OpenCode. OpenCode discovers local plugins in plugins/ at startup; no opencode.jsonc registration is required.

The installer places plugins/vibemon.js and hooks/vibemon.py under OPENCODE_CONFIG_DIR, or $XDG_CONFIG_HOME/opencode (default ~/.config/opencode). Both files must be present for the app to report the integration as installed. Transmission settings come from the shared ~/.vibemon/config.json.

On Windows, the installer pins the Python interpreter in the plugin; custom config directories also receive an absolute adapter path. The app normalizes these known path adaptations when checking the published plugin checksum, so updates remain detectable. A missing pinned interpreter or stale adapter reference is shown as Needs repair; use Repair installation, then restart OpenCode. Missing installation files restore the Install integration action.

Characters

Character Color Description Auto-selected for
vibemon Purple Rounded V companion with two watchful eyes Any bridge without its own character
clawd Orange Four-legged friend Claude Code
codex Navy Cloud character with light eyes on a dark screen Codex CLI
kiro White Ghost character Kiro
claw Red Antenna character OpenClaw
daangni Peach/teal Round face, fluffy top Manual only (Character Lock)

OpenCode reports character: "opencode", which currently falls back to vibemon because the canonical registry does not contain that name. Its states, project, tool, and model remain visible. Add a dedicated character to this repository’s registry and export map before it can be bundled or offered in Character Lock.

In 2D (default) all characters use image-based rendering: a square PNG of 128, 256, or 512 pixels (CHARACTER_IMAGE_SIZES). Registry coordinates stay in 128-unit canvas space at every image size, so a larger image only adds sharpness. Images bundled in src/assets/characters/ load without network requests. Only new, versioned images from a refreshed registry are downloaded from vibemon.io/static; downloads are bounded to 64 KiB and must declare one of those square PNG dimensions. Character is auto-selected by bridge, not by the core display runtime. You can also force one with Character Lock.

Characters are defined in src/shared/data/characters.json: display name, accent color, PNG, eye/effect coordinates, and 3D theme. App owns these sources; Web serves the pinned public snapshot at vibemon.io/static/data/characters.json. Rendering, tray menus, and validation derive from the same registry. Add the image and registry entry here, update web-distribution.json, and run pnpm check:registry plus pnpm check:distribution.

Render Mode

Settings → Companion → Render style switches the character window between the two engines; the choice persists and the open window reloads into it.

Settings → Companion → Size offers 100% through 30% in 10-point steps. The choice applies to both render modes and persists across restarts. The 3D canvas uses the largest uniform scale that fits each pose about the camera center, leaving a 2px margin. It recalculates before rendering each frame, including state transitions, and uses higher WebGL resolution for sharp enlargement. The 2D presentation is unchanged.

Adaptive 3D character framing

Both engines are maintained here (src/engine/); three.js ships locally in src/vendor/ because the renderer CSP forbids runtime CDN imports.

Desktop 3D hit testing reads the preserved WebGL frame and reuses the alpha result for an unchanged pixel and frame. Pointer checks never render the scene, so they respect the animation frame limit and reduced-motion setting. Web rendering keeps the default unpreserved buffer. Run pnpm test:hit-testing to verify transparent pixels, transformed coordinates, and stopped frames in Electron.

Character Lock

Forces the character window to always show one character, ignoring whatever character each project’s status reports.

States

The state drives the character’s eyes/effects on the sprite, the speech bubble’s background color, and the tray icon’s background color. States are defined in a single registry (src/shared/data/states.json): bubble color/text, focus and loading behavior, and eye/effect type all live in one entry per state.

State Color Eyes + effect Bubble text Trigger
start Cyan sprite eyes + sparkle Hello! Session begins
idle Green sprite eyes, periodic blink Ready start or done aged 1 minute
thinking Purple sprite eyes + thought bubble Thinking Prompt submitted, or a tool ended
planning Teal sprite eyes + thought bubble Planning thinking or working in plan mode
working Blue glasses + sparkle (tool-based) Tool running
packing Gray sprite eyes + thought bubble Compacting Context compacting
notification Yellow sprite eyes + question mark Input? User answer or approval needed
done Green happy eyes Done! Turn ended (stop, interrupt, or session end)
sleep Navy closed eyes + Z Zzz… idle aged 5 minutes
alert Red sprite eyes + exclamation Alert Critical error or failure

Working State Text

The working state’s speech bubble shows fixed text based on the active tool:

Tool Text
Bash Running
Read Reading
Edit Editing
Write Writing
Grep / WebSearch Searching
Glob Scanning
WebFetch Fetching
Task Tasking
Default Working

State Timeout

From State Timeout To State
start, done 1 minute idle
planning, thinking, working, packing, notification, alert 5 minutes idle
idle 5 minutes sleep

The timeout counts from the last report. While an agent turn runs, hooks repeat its state every 60 seconds (see turn lifecycle), so a long tool call or response stays active until the turn ends. An active state reaches idle only when its reports stop, for example when the hooks cannot identify the agent process.

After 10 minutes in sleep state, the window automatically closes. It reappears on the next status update — or on demand via the tray menu’s Show companion action, which reopens the character (and its speech bubble) immediately.

Show or hide the companion

Select Hide companion in the tray menu or the Workspace menu, or turn off Settings → Companion → Show companion. The character and its speech bubble close and stay closed, also after a restart. Status updates continue: the tray icon, the dashboard, and the widgets still show them. Select Show companion to bring the character back at once. It shows the project that has focus now.

Animations

Character Window

The app shows exactly one character window plus its following speech bubble:

Desktop App Features

Always on Top Modes

Mode Description
all The window stays on top regardless of state - Default
active-only Only active states (thinking, planning, working, packing, notification, alert) stay on top
disabled The window never stays on top

When active-only is selected:

Choose Settings → Companion → Stay on top.

Click to Focus Terminal (macOS)

Clicking the character selects the iTerm2 tab reported by its coding task. For Ghostty, it activates the application; choose the tab yourself.

Supported Terminals:

Requirements:

Speech Bubble

A small, transparent window with input only on its visible body and tail that displays selected info fields (status, project name, model, memory, 5h usage, weekly usage, model-scoped weekly usage — e.g. “Fable 12% · 4d11h”) next to the character. Each plan-usage row shows its own reset countdown when available. Positioned automatically so it never overlaps the character window and stays on-screen, with an animated slide when it needs to move.

Workspace and settings

The tray icon opens a menu. Its first line shows the installed version, for example VibeMon 3.8.5. Below it are Dashboard and Show companion or Hide companion, then Settings… and Integrations…, then About VibeMon and Quit VibeMon. Select Dashboard to open the workspace with Overview, Agents, Resources, and Settings. Connections, Companion, Integrations, and About share its navigation and connection state. Preference changes apply immediately; connection and display-selection forms require Save. Search fields and unsaved choices survive automatic polling.

The tray menu provides Dashboard, Settings, Show companion or Hide companion, Integrations, About VibeMon, and Quit VibeMon. Usage and preference controls live in the workspace instead of submenus. Show companion appears while the character is off the desktop. It restores the character and speech bubble without waiting for another status event. Hide companion appears while the character is on the desktop; see Show or hide the companion.

See the desktop workspace guide for navigation, connection, settings, and recovery.

Rendering Engine

The character is rendered by a bundled engine (src/engine/vibemon-engine.js): a 128-unit canvas with at least 2x backing pixels, drawing the character PNG with smooth scaling, state-driven pixel-art eyes/effects, and the floating animation, over a fully transparent background. Bundled character images load locally, so starting or reopening the companion does not wait for the CDN. New registry artwork uses bounded downloads; keep versioned filenames when changing artwork.

Hook installation and updates

Two trust levels apply:

install.py re-checks every file it downloads against the manifest before writing it, so install.py and manifest.json have to go out in the same deploy. Custom installer deployments can pin a specific hash via VIBEMON_INSTALLER_SHA256 together with VIBEMON_DOCS_URL; for installs that you start, the pin takes precedence over the manifest. VIBEMON_DOCS_URL selects the source for the installer, manifest, and all installed files. The App passes the same source to the Python child. Use VIBEMON_URL separately for the API origin; see self-hosted installation.

Installs run unattended but not force-approved: the app passes a platform flag and never --yes. VibeMon’s own hook scripts are upgraded in place, while settings you own — most visibly an existing Claude Code statusLine — are left as they are. Run install.py yourself with --yes to have those replaced too. The periodic hook check (shortly after launch, then every 30 minutes) compares installed integrations with the manifest and runs this installer for every one that drifted, under the unattended trust rule above. Broken registrations are only reported; fix them from Settings → Integrations. When a run fails, the installer’s own reason (a failed integrity check, a file it couldn’t write) is shown with the exit code instead of the bare code.

Detection and hook paths honor CLAUDE_CONFIG_DIR, CODEX_HOME, KIRO_HOME, and OPENCODE_CONFIG_DIR (with the OpenCode XDG fallback described above). These variables must reach the Desktop App process. Kiro is detected through either kiro or kiro-cli.

Registration checks inspect the command used on the current OS, including Codex’s Windows override and the installer’s quoted POSIX paths. OpenClaw requires its script, manifest, and enabled vibemon-bridge entry. The installer records plugins.load.paths, and existing installations in the global extensions directory are also recognized without that entry. Global disable, deny entries, and a non-empty allowlist that excludes VibeMon prevent an installed status, matching OpenClaw’s plugin policy. After an OpenClaw update, refresh its persisted plugin registry and restart the gateway as described in the hook reference. The docs installer currently skips OpenClaw on Windows.

See build and release for packaging commands.