| name | openloomi-pet |
| description | OpenLoomi Pet sprite & state helper for Claude Code. Use when the user wants to change their Loomi Pet state, switch theme, drop in a custom character, override individual sprites, or ask Claude to mirror its lifecycle onto the pet. Triggers: pet state, /openloomi:pet, set pet, loomi pet, pet to happy, pet to working, pet to thinking, fox sprite, capybara sprite, custom pet theme, pet-custom, pet-config, override pet sprite. |
| allowed-tools | Bash(node ${CLAUDE_PLUGIN_ROOT}/scripts/loomi-bridge.mjs *) |
OpenLoomi Pet Sub-skill
The Loomi Pet has 9 universal state names. The plugin ships the fox
(loomi-*) sprite set for branding; the OpenLoomi runtime's
state-resolution watcher renders the matching sprite for whichever
theme you have active (fox or capybara, or any folder under
~/.openloomi/pet-custom/). State set:
| State | When to use |
|---|
happy | A task just completed successfully |
idle | Loomi is waiting for the next loop tick (watcher-only — do not set from Claude) |
juggling | Multiple sub-agents are running |
needsinput | Permission prompt / elicitation dialog visible |
presenting | Fresh decision requires the user's review (watcher-only — do not set from Claude) |
sleeping | Local hour outside 6–22 with no pending work (watcher-only — do not set from Claude) |
sweeping | User dismissed a card just now (watcher-only) |
thinking | Between steps, awaiting LLM response |
working | A tool call is in progress (PreToolUse hook fires this) |
Available commands
node ${CLAUDE_PLUGIN_ROOT}/scripts/loomi-bridge.mjs pet <state> — synchronous, returns JSON; use only when the user explicitly asks.
- Hooks call
state <name> automatically (fire-and-forget, 2s timeout).
Sprite set is hardcoded in the bridge — invalid state names are rejected
before any HTTP call. The endpoint POST /api/pet/state may not yet exist
in the target OpenLoomi runtime; the bridge falls back to "would have set
state to X — pending OpenLoomi endpoint" without raising an error.
Help the user customize their pet's appearance
The bridge only drives the state — sprite overrides and theme folders
are file-based and live outside the plugin. When the user asks to "change
the pet's look" or "add a custom character", walk them through the file
system. Do not try to write pet-config.json from the bridge; the
bridge has no such command and the runtime's file watcher does the work.
Decision tree
- "I just want the other built-in" → right-click Loomi →
Theme → Fox / Theme → Capybara. Persisted in ~/.openloomi/pet-config.json under activeTheme. Long-press (~600 ms) is the fallback if contextmenu is swallowed by the host.
- "I want my own character" → drop a folder at
~/.openloomi/pet-custom/<name>/ with PNGs named after the states. The watcher auto-discovers it within ~250 ms and the theme appears in the menu.
- "I want to change just one sprite" → edit
~/.openloomi/pet-config.json's overrides map. Wins over both built-ins and custom-theme sprites for the matching (theme, state) pair.
- "I want to make my theme the default" → set
activeTheme to the custom theme's folder name.
What the bridge can and can't do
| User intent | Bridge role |
|---|
Flip to happy mid-task | /openloomi:pet happy — yes |
| Switch fox ↔ capybara | No — that's a menu action or pet-config.json edit; do not try the bridge |
| Add a custom character | No — direct them to ~/.openloomi/pet-custom/<name>/ and the file watcher |
| Override a single sprite | No — direct them to ~/.openloomi/pet-config.json's overrides map |
| Diagnose "the pet isn't switching themes" | Direct them to the troubleshooting section in pet docs |
| Drive the pet from their own tool | Direct them to POST /api/pet/state — see Pet API |
Filename conventions to communicate
When guiding the user through a custom theme, surface these conventions up-front:
- PNG only.
.gif, .webp, .apng, .lottie are silently ignored.
- Bare or prefixed names both work.
idle.png, loomi-idle.png, capybara-thinking.png, my-pack-sweeping.png all normalize correctly (case-insensitive).
- One recognizable state PNG is enough. The folder is registered as a theme as soon as it has ≥1 normalized state stem; missing states fall through to the active theme's
idle sprite.
- Hidden / dot-prefixed folders are ignored.
.git, .DS_Store etc.
Override JSON shape to communicate
The overrides map is camelCase on the wire — activeTheme, customThemesDir. Snake_case keys silently no-op the assignment (a unit test in the runtime pins the contract). Use the exact shape:
{
"version": 1,
"activeTheme": "fox",
"customThemesDir": "~/.openloomi/pet-custom",
"overrides": {
"fox": {
"idle": "/absolute/path/to/my-fox-idle.png"
}
}
}
Absolute paths only — the runtime routes them through tauri::convertFileSrc, so relative paths and ~/ prefixes will not resolve.
Common pitfalls to surface
- The folder doesn't show up — usually a missing or mis-named state PNG. Run them through the filename convention table.
- Override doesn't apply — host log line
[loomi-pet/theme] failed to parse ~/.openloomi/pet-config.json means the JSON itself is malformed and defaults loaded. Host log line [loomi-pet/theme] failed to read <path>: <io error> means the path doesn't resolve.
- Theme menu tick is wrong / stuck — almost always a camelCase vs snake_case wire-format mismatch. The widget reads
activeTheme, not active_theme.
sleeping / sweeping rejected by /api/pet/state — those are watcher-only vocabulary; the runtime returns 400 invalid_state. Do not POST them from your tool.
What NOT to do from Claude
- Do not try to call
POST /api/pet/state with sleeping or sweeping. The API rejects them; the watcher owns them.
- Do not try to write
pet-config.json from the bridge. The bridge has no command for it; the file watcher owns updates.
- Do not invent new state names.
CAPYBARA_STATES rejects them before any HTTP call.
- Do not claim support for non-PNG sprite formats. The asset pipeline is static PNG only.
- Do not say "I'll set up your custom theme for you" if you can only walk them through the file system. The watcher does the work; you guide.
See also