Pets
VibeOS can show an animated pet — a small mascot sprite that reacts to what the agent is doing (idle, running a tool, thinking, finishing, failing) across the CLI, TUI, and desktop app. Pets come from the public petdex gallery.
Pets are purely cosmetic. They have no effect on prompt caching, tokens, or the agent's behavior — the sprite is a display concern only. The feature is off by default and stays dormant until you install and select a pet.
How it works
-
Pets are installed into your profile's
pets/directory (<VIBEOS_HOME>/pets/<slug>/), so each profile keeps its own set. -
Selecting a pet writes
display.pet.sluganddisplay.pet.enabledtoconfig.yaml— nothing is stored as a secret or env var. -
Each surface watches the activity it already tracks and maps it to one of six animation states. The mapping lives in one place so every surface behaves the same:
Agent activity Pet state A tool/turn just failed failedA plan finished (all todos done) jump(celebrate)A turn finished cleanly waveA tool is executing runThe model is thinking/reading reviewTurn in flight (unspecified) runBlocked on you (a clarify/approval prompt is open) waiting(falls back toidleon legacy 8-row sheets)Nothing happening idle
Rendering
In the terminal (CLI/TUI), VibeOS renders the sprite at full fidelity when your terminal supports a graphics protocol (kitty, Ghostty, WezTerm, iTerm2, or sixel). Otherwise it falls back automatically to a truecolor Unicode half-block rendering. Inside a pipe or redirect (no TTY), terminal rendering is disabled by design.
The desktop app draws the pet as a floating sprite on a canvas and toggles it from Settings → Appearance.
Quick start (CLI)
# Browse the gallery (filter by substring)
vibeos pets list
vibeos pets list cat
# Install a pet and make it active in one step
vibeos pets install boba --select
# Preview / animate it in your terminal (Ctrl+C to stop)
vibeos pets show
# Check your setup
vibeos pets doctor
vibeos pets commands
| Goal | Command |
|---|---|
| Browse the gallery | vibeos pets list [query] [--limit N] |
| List installed pets | vibeos pets list --installed |
| Install a pet | vibeos pets install <slug> [--select] [--force] |
| Set the active pet | vibeos pets select [slug] (omit slug for a picker) |
| Resize the pet everywhere | vibeos pets scale <factor> (e.g. 0.5, clamped 0.1–3.0) |
| Preview/animate | vibeos pets show [slug] [--state <s>] [--cycle] [--once] [--mode <m>] [--scale <f>] |
| Disable the pet | vibeos pets off |
| Remove an installed pet | vibeos pets remove <slug> |
| Diagnose setup | vibeos pets doctor |
vibeos pets show flags:
--state— play a single state (idle,wave,run,failed,review,jump).--cycle— cycle through every state.--once— play once instead of looping.--mode— override the render protocol (kitty,iterm,sixel,unicode,auto).--scale— override the on-screen scale (0= use config).
/pet slash command
Inside the CLI and TUI you can manage the pet without leaving the session:
/pet— toggle the pet on/off (adopts the first installed pet if none is active)./pet list— browse the gallery./pet scale <factor>— resize the pet everywhere (e.g./pet scale 0.5)./pet <slug>— adopt a specific pet./pet off— disable the pet.
In the TUI, /pet list opens an interactive picker overlay; in the desktop app
it opens the Cmd+K pet palette.
Desktop app
In the desktop app you can manage the pet two ways:
- Cmd+K → "Pets…" — browse, search, adopt, and toggle pets without leaving the keyboard (mirrors the theme picker).
- Settings → Appearance — the same gallery plus a size slider that resizes the floating mascot live as you drag.
Both adopt/toggle/resize the floating mascot in place — size changes apply instantly; adopting a new pet lights it up within a moment.
Pop-out overlay
Shift-click the floating pet to pop it out into its own transparent, always-on-top desktop window. Out there it stays visible while VibeOS is minimized (Codex-style), so a glance tells you what the agent is doing.
Gestures once it's popped out:
| Gesture | Action |
|---|---|
| Drag | Move the pet anywhere on screen, even outside the app. Its spot and in/out state persist across restarts. |
| Single-click | Open a mini composer to send a prompt to the most recent session — without surfacing the app. |
| Double-click | Toggle the app window: minimize it if it's up front, restore it if it's hidden. |
| Shift-click | Pop the pet back into the window. |
| Mail icon | Appears only when a turn finished while you were away; click to raise the app on the most recent thread (and mark it read). |
The popped-out pet shows a speech bubble with status lines (working…,
thinking…, your turn, …) and — after you message it from the mini composer —
a truncated preview of the assistant's text reply (full answer stays in the
chat transcript). In-window the pet stays quiet for status chatter, but the same
reply preview appears above the mascot once an answer lands.
Selecting a pet also creates a matching Avatar profile under
<VIBEOS_HOME>/avatars/ (id defaults to the pet slug). Avatars are the
conversational binding — full guide: Avatars (persona,
voice, soft memory, talking-head, /avatar commands).
Short summary: optional persona overlay + pet visual + TTS voice preset + soft
memory_scope (avatar:<id> by default; shared to opt out).
display.avatar.auto_speak gates TTS / talking-head while the pet is visible.
Quick switch
| Surface | How |
|---|---|
| Desktop Cmd+K | Avatars… — browse and select |
| Desktop / CLI / gateway | /avatar, /avatar list, /avatar <id>, /avatar none |
| Settings | Appearance → Pet — bind persona + voice + talking-head mode |
Create or patch from chat (same on desktop, CLI, and messaging):
/avatar create boba pet=boba personality=concise voice=edge:en-US-AriaNeural
/avatar update boba talking-head=skill memory=shared
/avatar boba
/avatar none
On messaging platforms, /avatar also updates the live session: soft
memory_scope on the running agent, ephemeral persona when the avatar has one,
and a one-shot note on the next turn (same cache-safe pattern as /model).
Classic CLI does the same for memory scope (and rebuilds the agent when the
persona overlay changes).
Fields: pet=, name=, personality=, voice=, memory= (shared or leave default),
talking-head= (off | wave | skill), portrait=.
From the popped-out pet, open the mini composer and use the mic to speak; completed replies are spoken back (using the avatar voice when set) while the overlay is active.
Talking-head render (optional)
display.avatar.talking_head controls the optional render layer (not a core
tool):
| Mode | Behavior |
|---|---|
wave (default) | Pet plays a celebrate/jump animation while avatar TTS speaks |
off | No extra render |
skill | Local talking-photo: TTS + ffmpeg still mux (avatar.talking_head.render); escalate to video_generate via the optional skill when you want motion |
In skill mode, leave the portrait path blank to auto-crop the pet's idle
frame into avatars/<id>-portrait.png. Set an explicit local image path when
you want a custom face. Settings → Pet also has Regenerate from pet
(avatar.portrait.regenerate) after you change the spritesheet.
Install the skill when you want clips:
vibeos skills install official/creative/talking-head
Vendor lip-sync SaaS (HeyGen, D-ID, …) stays out of the VibeOS core tree —
publish as a standalone plugin under ~/.vibeos/plugins/ if you need those
APIs. Scaffold:
bash scripts/scaffold-talking-head-vendor-plugin.sh
See the optional skill reference
optional-skills/creative/talking-head/references/standalone-vendor-plugin.md.
The overlay is a pure puppet of the in-app pet — it carries no separate gateway connection and never appears in the dock or app switcher.
Configuration
All settings live under display.pet in config.yaml:
display:
pet:
enabled: false # master on/off (true once you select a pet)
slug: "" # active pet; empty = first installed
render_mode: auto # auto | kitty | iterm | sixel | unicode | off
scale: 0.33 # master size knob (relative to native 192x208 frames)
unicode_cols: 0 # hard override for terminal width (0 = derive from scale)
scaleis the single master size knob. One number shrinks every surface: the desktop canvas scales its pixels by it, and the CLI/TUI derive their terminal column width from it. The half-block fallback clamps to a legibility floor — it can't shrink as far as true-pixel kitty/GUI rendering without turning to mush, so the samescalelooks crisp under kitty but is floored in half-blocks.render_mode: autodetects kitty/iTerm2/sixel and falls back to unicode half-blocks. Set it explicitly to force a protocol oroffto disable terminal rendering while keeping the pet on the desktop.unicode_colspins the terminal column width independently ofscale; leave it at0to derive width fromscale.
Troubleshooting
Run vibeos pets doctor — it reports:
- the pets directory and which pets are installed,
display.pet.enabled,display.pet.slug, and the resolved active pet,- the configured
render_mode, the detected terminal graphics protocol, and the effective mode for a TTY, - whether Pillow (used for sprite decoding) is importable.
It prints ✓ ready once a pet is installed, selected, enabled, and Pillow is
available.
Common gotchas:
- A pet only shows once one is installed AND selected (
enabled: true). - Inside a pipe/redirect (no TTY), terminal rendering is disabled by design.
- The petdex npm CLI installs to
~/.codex/pets; VibeOS uses its own profile-scoped<VIBEOS_HOME>/pets/instead — install throughvibeos pets.
See also
- The
petdexskill lets the agent install and switch pets for you on request.