Claude Code Plugin

Run OpenLoomi from inside Claude Code. OpenLoomi is a local-first desktop app that holds your memory, runs background tasks, and talks to your connected apps (Gmail, Slack, GitHub, Calendar, Linear, …). This plugin turns Claude Code into a front-end for that local runtime — Claude Code stays your coding surface, OpenLoomi does the long-running and cross-app work in the background.

You keep using Claude Code the way you already do. OpenLoomi runs next to it, on your machine.

What you can do with it

  • Run first-use setup in one command. /openloomi:setup discovers your OpenLoomi install, downloads it if missing, launches the desktop app, waits for the local API, and mints a guest session token. Nothing GUI is required.
  • Drive the Loomi Pet. /openloomi:pet happy flips the pet sprite from your terminal — useful as a heartbeat signal while Claude Code is grinding on a long task.
  • See today's LLM cost. /openloomi:usage summarizes token usage and spend without leaving the session.
  • Mirror Claude Code's lifecycle onto OpenLoomi (opt-in). With hooks installed, every Claude Code turn gets archived into OpenLoomi's memory, and every lifecycle event flips the pet sprite accordingly. You keep full control — install/uninstall with one command, and ~/.claude/settings.json is never modified unless you ask.

OpenLoomi still owns the heavy lifting: local memory storage, connector credentials, scheduled tasks, the desktop UI, secrets. Claude Code just gets a doorway into all of it.

Runtime implementation details (how OpenLoomi drives a Claude subprocess internally) live in Claude Agent Runtime. This page is about the external integration — how a Claude Code user drives OpenLoomi.


Install

Three paths:

  • Marketplace:
    /plugin marketplace add melandlabs/plugins
    /plugin install openloomi
    Run each line separately in a Claude Code session — slash commands can't be chained with &&. The first line adds the slim melandlabs/plugins marketplace (only the plugin payloads); the second installs the openloomi plugin from it. Then restart Claude Code and run /openloomi:setup.
  • From source, pointing Claude Code at the plugin directory:
    git clone https://github.com/melandlabs/openloomi.git
    cd openloomi
    claude --plugin-dir plugins/claude
  • Local marketplace checkout as an alternative before the marketplace listing goes live.

First-run wizard

Run /openloomi:setup once. It auto-chains the whole setup and stops early only when it needs you:

install OpenLoomi.app
   → launch the desktop app
   → wait for the local HTTP API
   → mint a guest bearer token (→ ~/.openloomi/token)
   → { setup: "ready" }

A user who has already run claude auth login on the host lands in the ready state with no per-user key and no env-var step — the runtime detects the host claude CLI on its own.

The setup result reports one of: ready, install_attempted, install_failed, launch_failed, api_not_ready, guest_login_failed, awaiting_user_action, or step_limit_reached. Default API wait is 30 s (--max-wait).


Walkthrough

The screenshots below are from a real end-to-end run. Follow them in order — every step is one Claude Code turn or one desktop app interaction.

1. Install the plugin from a fresh Claude Code session

Ask Claude Code to install the plugin from the GitHub URL — no copy-pasting commands needed.

Install the plugin and setup https://github.com/melandlabs/plugins/tree/main/openloomi/claude

Step 1 — User asks Claude Code to install the plugin

2. Add the marketplace

For the long-lived install path, add the marketplace once. Claude Code prompts for the source; enter melandlabs/plugins.

> /plugin marketplace add melandlabs/plugins

Step 2 — Add the OpenLoomi marketplace

3. Or launch Claude Code pointing at a local checkout

If you're hacking on the plugin (or running from source), point Claude Code at the directory and your edits are picked up live.

git clone https://github.com/melandlabs/openloomi.git
cd openloomi
claude --plugin-dir plugins/claude

Step 3 — Launch Claude Code with the local plugin directory

4. Discover the slash commands

Type /openloomi: — the autocomplete lists everything the plugin ships with.

Step 4 — /openloomi: autocomplete lists every available command

5. Run /openloomi:setup — readiness table lands in READY and the Loomi Pet appears

The wizard auto-chains install → launch → wait API → guest login. When it finishes, the bridge prints a small readiness table on the left and the Loomi Pet pops onto your desktop on the right with a Loomi is on watch badge. The screenshot below shows the kawaii cat pack as the active sprite (a custom theme loaded via ~/.openloomi/pet-custom/kawaii/, see step 7c) — the built-in default is the Fox theme, which the right-click context menu lists as THEME: Fox ✓, Capybara (step 6). The pet is the file-watcher-driven widget — it doesn't talk to the bridge; it watches ~/.openloomi/pet-config.json and the assets/{fox,capybara,~/.openloomi/pet-custom/<name>}/ folders.

ItemStatus
Guest loginSuccessful
Runtime modepackaged
Version0.8.5
Local APIReachable
AI providerConfigured
Execution providerReady
Desktop processRunning
Final statusREADY

Step 5 — Setup completes; readiness table is READY and the fox Pet appears on the desktop with the Loomi is on watch badge

6. Right-click the Pet to open the context menu

The pet's context menu exposes Open Loomi / Settings / THEME (Fox ✓, Capybara) / Quit. The theme switch is hot-reload — the file watcher picks up activeTheme in pet-config.json within ~250 ms, and the bridge never writes these files.

Step 6 — Right-click the Pet to open the context menu (Fox is currently active)

7. Pick Capybara — the theme hot-reloads in place

The pet re-skins immediately. Same 9-state vocabulary (happy / idle / juggling / needsinput / presenting / sleeping / sweeping / thinking / working) — only the artwork changes. The readiness table on the left is unchanged.

Step 7 — Capybara theme is hot-reloaded in place; readiness table unchanged

7b. Manually override the Pet state with /openloomi:pet

The hot-reload pet also accepts manual overrides from Claude Code. Type /openloomi:pet <state> and the bridge writes the new state to ~/.openloomi/pet/runtime_state.json; the file watcher picks it up and the sprite swaps within ~250 ms. Useful for "task done" beats where you want the pet to flip to happy between turns.

Step 7b — /openloomi:pet happy overrides the sprite; runtime state persisted to ~/.openloomi/pet/runtime_state.json

7c. Drop in your own theme — kawaii cat via pet-custom/

The built-in themes are Fox and Capybara, but the pet watcher also auto-discovers any folder under ~/.openloomi/pet-custom/<name>/ with PNG state sprites. Drop a folder in, and the theme appears in the right-click menu within ~250 ms — no bridge call, no restart. Below, a kawaii cat pack is installed and active: the small sprite in the top-left of the desktop app swaps to the kawaii cat, and the inline chat pet (shown thinking with a thought bubble while a tool call is in flight) renders from the same pack.

Step 7c — Custom kawaii theme via ~/.openloomi/pet-custom/kawaii/; desktop sprite + inline chat pet both render from the pack

8. /openloomi:status returns the canonical JSON

For any triage or bug report, paste the JSON output verbatim. The shape never changes: mode / installed / version / tokenPresent / aiProviderConfigured / nativeRuntime / apiReachable / hooksInstalled / ready / nextAction / reason / source.

Step 8 — /openloomi:status prints stable readiness JSON

9. Opt into the Pet mirror + Stop archive with /openloomi:hooks

The command walks you through install | uninstall | status. After install, the bridge writes a marked block (_openloomi_plugin, keyed __openloomi_claude_plugin_hooks__) into ~/.claude/settings.json — merge-no-overwrite, atomic, idempotent.

Step 9 — /openloomi:hooks walks you through install / uninstall / status

10. Confirm the hooks are installed

/openloomi:hooks status reports installed: true, the settings path, the marker, the schema, and the legacy block key — so you can verify nothing else was overwritten. The Stop hook now reads your session transcript (last 6 turns, ≤6 KB) and POSTs a note to /api/insights under the claude-code group. It always exits 0.

Step 10 — Hooks report shows installed: true, marker and schema confirmed

11. Connect your apps with /openloomi:connect

The wizard walks you through three independent y/N choices: install the composio skill, enable Screen Memory (Preferences → Chronicle → Screen Memory in the desktop app), and connect a messaging connector (native 7 platforms via openloomi-connectors, or 1000+ via composio).

Step 11 — /openloomi:connect wizard — Step 3 "Connect a messaging connector"

12. After Composio connects — 6 active apps in your workspace

The next Claude Code turn can list what you're wired up to. In this run: Gmail, Google Calendar, Google Drive, GitHub, Linear, Slack — all through Composio, with the workspace org and test user echoed back.

Step 12 — After Composio connects, 6 active apps listed in Claude Code

Connected via Composio (6 active): Gmail, Google Calendar, Google Drive, GitHub, Linear, Slack
Org: timi_workspace · Test user: pg-test-…

13. /openloomi:memory — see what's already in your local memory

> /openloomi:memory

The command searches the local memory + knowledge base + insights and returns a digest of what OpenLoomi already knows. In this run, the digest includes a "From Loomi" callout ("Sarah's signature says 'Head of Product' — memory still says PM" — the same drift the Loop is about to surface as a CONTACT_UPDATE card), a "Last 7 days (50 insights total)" table with # / Time (UTC) / Type / Importance / Title columns (auto-captured Claude Code session snapshots, Screen Memory captures, occasional archive notes), and Notes at the bottom explaining the mix.

This is the read-only doorway into OpenLoomi's local memory. For a deeper search, pass a query: /openloomi:memory <query>.

Step 13 — /openloomi:memory returns the recent-insights table + From Loomi callout

13b. Write to memory from Claude Code with add-memory

Reading is half the story — you can also write. From any Claude Code turn, invoke openloomi-memory add-memory "<text>" --file=<path> and the entry lands in ~/.openloomi/data/memory/<path>. Below, "My boss is Tom." is saved to people/boss.md and immediately searchable via search-memory "boss" or search-all "boss tom".

Step 13b — openloomi-memory add-memory saves "My boss is Tom." to people/boss.md and is searchable right after

14. /openloomi:loop — see the Loop dashboard snapshot

> /openloomi:loop

The command hits GET /api/loop/state and returns the Loop dashboard: enabled status + last tick, counts (pending decisions / done / dismissed / signals seen), per-connector health (needs_setup / local-only / linked), prefs in effect (tick frequency, brief time, quiet-when-empty, desktop notifications, …), and actionable notes (e.g. "all 5 Composio-backed connectors share one failure: the local Composio surface isn't reachable — Loop can't pull signals until /openloomi:connect walks the Composio install").

This is purely a dashboard snapshot — the Loop never takes destructive actions from this command. For actions, the Loop pops cards in the desktop app (step 15) and you decide there.

Step 14 — /openloomi:loop prints the dashboard: counts, connector health, prefs, notes

15. The Loop starts surfacing decision cards in the desktop app

This is what the system looks like once it's humming. OpenLoomi's Loop is the proactive execution brain: it watches your connected signals, classifies them into decision types, and pops a card into the desktop app with the reasoning trace and the actions you can hit.

Every card has the same shape: Signal + Type + Received + Confidence at the top, the From Loomi explanation, the Reason 1 / Reason 2 evidence, and the action buttons at the bottom.

The Loop ships with these decision types out of the box:

Decision typeWhat it doesExample
RSVPReply Yes / No to a calendar invitation"Reverb Q3 review — Wed 10:00 PT, organizer Sarah, conflicts with standup"
IM_REPLYDraft a reply to a known contact"Alice is bumping the Q3 deck timeline — Thursday is close"
EMAIL_REPLYPre-draft an outbound email"Sarah needs the Q3 OKR draft status by Friday"
LINEAR_REVIEWTriage a Linear issue assigned to you"LIN-1234 (pet bubble drag-and-drop) is in In Review with you assigned"
REQUIREMENT_SYNTHESISCluster PRs/issues into a requirements doc"14 PRs/issues tagged loop/v0.9 — needs a single requirements doc"
RELEASE_PLANDraft a release plan from merged PRs"12 PRs merged since v0.8.5 — time to draft the v0.8.5 release plan"
CONTACT_UPDATEUpdate a contact record when memory drifts"Sarah's signature says 'Head of Product' — memory still says PM"
DOC_UPDATERefresh a stale doc for the next version"docs/getting-started.md is stale (42 days, pre-v0.8.5)"
REVIEW_PRSurface a PR waiting on your review"PR #220 (lifestyle image prompts) is waiting on your review"
DEADLINE_REMINDERSurface an upcoming due date"v0.8.5 release plan due Friday — 3 PRs blocking the cut"
TODOAdd a follow-up to your todo list"Bug: historical self-owned calendar events surface as fake RSVP decisions"
DIGEST (QUIET)Consolidate a flood of low-priority signals"8 GitHub notifications — none urgent individually, but here's the consolidated view"

A few examples in detail:

Loop card — IM_REPLY for an Alice follow-up

Loop card — IM_REPLY expanded into a full reply composer

Loop card — LINEAR_REVIEW for LIN-1234 "pet bubble drag-and-drop"

Loop card — REQUIREMENT_SYNTHESIS for 14 PRs/issues tagged loop/v0.9

Loop card — RELEASE_PLAN for v0.8.5 "classifier-rules UX + custom channels"

Loop card — CONTACT_UPDATE for Sarah Chen's new "Head of Product" role

Loop card — DOC_UPDATE for docs/getting-started.md (42 days stale)

Loop card — DRAFT_REPLY for the Q3 OKR status email

Loop card — DRAFT_REPLY expanded with Subject and Body reply editor

Loop card — REVIEW_PR for PR #220 "compose lifestyle image prompts"

Loop card — TODO for issue #382 "historical RSVPs misclassified"

Loop card — DIGEST (QUIET) consolidating 8 GitHub notifications

15b. From the card — Dry run / Edit / Run / Dismiss

The action row at the bottom of every card turns a recommendation into a real outcome. The exact buttons depend on the card type:

  • RSVP (calendar invitation): Attend (primary) · Decline (outline) · View original (ghost). Tap Attend or Decline and OpenLoomi fires your Yes / No straight back through the connected Google Calendar as a calendar_rsvp action — no opening the event yourself to click the RSVP buttons.
  • Reply / update cards (IM_REPLY, EMAIL_REPLY, REVIEW_PR, LINEAR_REVIEW, REQUIREMENT_SYNTHESIS, RELEASE_PLAN, CONTACT_UPDATE, DOC_UPDATE, DEADLINE_REMINDER, TODO): Dry run (outline) · Edit · Run (primary when ready) · Dismiss (ghost). Dry run previews the exact draft or plan without firing; Run schedules the action through the right connector — email_reply via Gmail, im_reply via Slack / iMessage, github_review via the GitHub Reviews API, linear_review via Linear, requirement_synthesis / release_plan / doc_update into the local knowledge base, contact_update into memory, todo into the local todo store.
  • Quiet digests (DIGEST / QUIET_DIGEST / github_notification): Mark as read only — read-only aggregations, nothing to execute.

Two affordances live outside the action row so they never collide with the decision itself:

  • Card-level Dismiss sits in the header kebab (three-dot menu). Dismissing a card never accidentally declines a meeting. A mute rule is created for that signal scope, so the same hint won't resurface today.
  • Cancel scheduled action appears for ~30 s after you tap Run / Attend / Decline. The action is queued as a cron job before it actually fires — Cancel stops it. A per-card audit history (under the technical details) records every attempt with its terminal state (completed / skipped / blocked / failed / cancelled / superseded), so contradictory responses (e.g. RSVP "No" then "Yes") appear side-by-side instead of overwriting each other.

If the underlying connector refuses (the runner returns blocked or failed), the action row stays open with a one-tap retry — the card never silently flips to done when nothing actually happened.

16. Register your own decision types

The Loop is extensible. Drop a PUT /api/loop/types against the local runtime and your custom card joins the queue.

TOKEN=$(cat ~/.openloomi/token | base64 -d)
curl -s -X PUT -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  http://localhost:3414/api/loop/types \
  -d '{
    "id": "mom_imessage_alert",
    "label": "Mom iMessage",
    "icon": "👩",
    "actionKind": "todo",
    "description": "Triggers when mom sends an iMessage — surfaces as a high-priority todo so you never miss her"
  }'

Step 16 — Register a custom decision type via PUT /api/loop/types

17. The custom type fires on the next signal

The next iMessage from mom surfaces the new card with your icon, label, and a high-priority todo action.

Step 17 — MOM_IMESSAGE_ALERT custom type fires and surfaces a high-priority todo card


Slash commands

CommandDoesNotable failures
/openloomi:setupOne-time end-to-end setup wizard (above)awaiting_user_action, api_not_ready
/openloomi:statusPrints stable readiness JSON (see below)read-only; never fails destructively
/openloomi:usageToday's LLM usage summaryAPI_UNREACHABLE
/openloomi:petSet the Pet to a state (happy, thinking, …)INVALID_STATE, ENDPOINT_MISSING
/openloomi:hooksinstall / uninstall / status for the Pet + archive hooksnever auto-installs
/openloomi:connectOpt-in: install composio skill, enable screen memory, connect a connectornever echoes tokens
/openloomi:helpLists all commands

The valid Pet states are: happy, idle, juggling, needsinput, presenting, sleeping, sweeping, thinking, working.


Pet mirror + Stop archive

Hooks are opt-in — run /openloomi:hooks install to write a marked block into ~/.claude/settings.json (merge-no-overwrite, atomic; keyed so it can be cleanly removed). Once installed, Claude Code lifecycle events mirror onto the Pet:

Claude Code eventPet state
SessionStartgreet
UserPromptSubmitthinking
PreToolUseworking
PostToolUsethinking
SubagentStartjuggling
SubagentStopthinking
Notificationneedsinput
Stoparchive → happy

The Stop hook also archives context: it reads the session transcript, keeps the last 6 turns (capped at ~6 KB), and POSTs a note to /api/insights under the claude-code group. The Stop hook always exits 0 — an archive failure never blocks Claude Code.

The states idle, sleeping, sweeping, and presenting are owned by OpenLoomi's Loop watcher; don't set them manually from Claude.


Readiness JSON

/openloomi:status (bridge setup-status --json) returns a stable shape:

FieldMeaning
modeenv | packaged | source | unconfigured
installeddesktop app found
versiondetected OpenLoomi version
tokenPresenta local auth token exists
aiProviderConfigureda conversation provider is configured (runtime-sourced signal, see nativeRuntime)
nativeRuntimeprobe of the host's claude CLI: available, authenticated, reason
apiReachablelocal HTTP API responded
hooksInstalledPet/archive hooks present
readyeverything needed is in place
nextActionwhat to do next (see reasons below)
reasonmachine-readable status code
sourcehow the install was discovered

aiProviderConfigured is derived from the runtime's nativeRuntime probe (authenticated = true means the host's claude CLI is signed in), with user-saved anthropic_compatible rows as a fallback. The plugin never reads AI provider env vars and never publishes their values.


Troubleshooting

Reason codes → next action:

reasonnextActionFix
READYrunAll good.
OPENLOOMI_NOT_INSTALLEDinstall_openloomiInstall the desktop app.
OPENLOOMI_NOT_FINALIZEDlaunch_openloomi_to_finalizeLaunch the app once so the helper binary is written.
SOURCE_FOUND_CLI_NOT_BUILTbuild_or_stage_openloomicd $OPENLOOMI_REPO_DIR/apps/web/src-tauri && cargo build --release.
LOGIN_REQUIREDlogin_openloomi/openloomi:setup mints a guest bearer.
AI_PROVIDER_REQUIREDconfigure_ai_providerSign in to the host claude CLI (claude auth login), or save an Anthropic-compatible endpoint in Preferences → API Settings.
  • Pet doesn't switch states. Confirm hooks are installed (/openloomi:hooks status) and the app is running (/openloomi:statusapiReachable). ENDPOINT_MISSING is non-blocking.
  • Where do Stop archives go? They're posted to /api/insights under the claude-code group and surface in your Insight Box.
  • unconfigured mode. The plugin couldn't locate an install — run /openloomi:setup or provide a path.

Architecture

Claude Code
   → /openloomi:* slash command
      → skills/openloomi/SKILL.md
         → scripts/loomi-bridge.mjs
            → local OpenLoomi runtime (127.0.0.1:3414 / :3515)

The bridge discovers the install through an ordered chain (OPENLOOMI_BINOPENLOOMI_HOMEOPENLOOMI_REPO_DIRPATH → platform defaults → saved config → --bin-path flag).