# oomi-ai

Managed Oomi channel, bridge, voice, and persona app API tooling for OpenClaw.

`oomi-ai` connects an OpenClaw machine to Oomi. Persona UI creation and rendering happen inside Oomi-managed systems. The OpenClaw machine uses API actions only.

The current model is:

- OpenClaw talks to Oomi through managed channel and bridge APIs.
- Oomi clients render persona apps from approved templates, components, data bindings, actions, and permissions.
- The agent may inspect and update persona app state through approved Oomi API actions.
- The user adds persona apps from the Oomi client so platform permissions and data hydration happen in the right place.

## What This Package Ships

1. OpenClaw channel extension

- File: `openclaw.extension.js`
- Purpose: managed text transport through the Oomi backend channel API.

2. Local bridge and CLI

- Files: `bin/oomi-ai.js`, `bin/sessionBridgeState.js`
- Purpose: pair a device, manage the OpenClaw bridge worker, and support managed gateway traffic for device-backed chat and voice.

3. Persona app API tools

- Files: `persona-app/*`, `lib/personaApiClient.js`, `bin/oomi-ai.js`
- Purpose: inspect account-linked component-composed persona apps and apply approved backend actions.

4. Permissioned context tools

- Files: `lib/personaApiClient.js`, `bin/oomi-ai.js`
- Purpose: read user-approved Oomi backend context, such as HealthKit summaries synced by the mobile app.

5. Agent/operator instructions

- Files: `agent_instructions.md`, `skills/oomi/*`
- Purpose: tell OpenClaw agents how to connect, repair, and use Oomi without local UI code generation.

## Boundary

Persona UI is an Oomi-managed client capability, not an OpenClaw-machine responsibility.

This package exposes connection, bridge, voice, and persona app state APIs. It does not include a local persona app workspace, local persona runtime manager, queued UI job runner, or app framework bundle.

## Install And Upgrade

Global install:

```bash
pnpm add -g oomi-ai@latest
```

Fallback:

```bash
npm install -g oomi-ai@latest
```

Install or update the OpenClaw plugin:

```bash
openclaw plugins install oomi-ai@latest
```

After upgrading, refresh the running bridge so stale gateway connections do not keep using the previous package:

```bash
oomi openclaw refresh --skip-version-check
oomi openclaw bridge ps
```

If the bridge still looks stale, restart it explicitly:

```bash
oomi openclaw bridge restart --detach
oomi openclaw bridge ps
```

On macOS supervised installs:

```bash
oomi openclaw bridge service restart
oomi openclaw bridge service status
```

Healthy update expectation:

- exactly one bridge worker is active
- the worker reports the newly installed package version
- bridge status reaches `connected`

## Standard Connect Flow

Pair the machine:

```bash
oomi openclaw pair --app-url https://www.oomi.ai --no-start
```

Print the OpenClaw config:

```bash
oomi openclaw plugin --show-secrets --backend-url https://api.oomi.ai
```

Apply the printed `channels.oomi.accounts.default` config and restart OpenClaw.

Start or repair the bridge:

```bash
oomi openclaw bridge ensure --detach
```

## Configuration

OpenClaw channel config lives under:

```json
{
  "channels": {
    "oomi": {
      "defaultAccountId": "default",
      "accounts": {
        "default": {
          "backendUrl": "https://api.oomi.ai",
          "deviceToken": "...",
          "defaultSessionKey": "agent:main:webchat:channel:oomi",
          "requestTimeoutMs": 15000
        }
      }
    }
  }
}
```

Required fields:

- `backendUrl`
- `deviceToken`

Optional fields:

- `defaultSessionKey`
- `requestTimeoutMs`

## Persona App API Tools

Component-composed persona apps are the default Oomi mini-app path. Use these commands when the user asks about or updates an existing Oomi persona app such as Fitness Today:

```bash
oomi fitness show --json
oomi persona-apps list --json
oomi persona-apps show fitness-today --json
oomi persona-apps apply-action fitness-today --action fitness.complete_workout --payload-json '{"goalId":"easy-run","minutes":20}' --json
```

Rules for agents:

- Answer from returned `appState.bindings`, not from memory.
- For Fitness questions, prefer `oomi fitness show --json` because it returns the Fitness mini-app state and approved health context together.
- Apply updates only through approved `persona-apps apply-action` actions.
- If the persona app does not exist, tell the user to add it from the Oomi client first.
- Do not create local persona UI projects.

For the Fitness slice:

```bash
oomi persona-apps apply-action fitness-today --action fitness.set_goal --payload-json '{"goalId":"move_more"}' --json
oomi persona-apps apply-action fitness-today --action fitness.complete_goal --payload-json '{"goalId":"easy-run"}' --json
oomi persona-apps apply-action fitness-today --action fitness.complete_workout --payload-json '{"goalId":"easy-run","minutes":20}' --json
```

Supported `fitness.set_goal` values are `move_more`, `sleep_better`, and `build_workout_habit`.

## Context Tools

Use context tools when the user asks a data-backed question that should come from Oomi-approved mobile permissions, not model memory. For health and fitness questions, read the latest backend HealthKit context first:

```bash
oomi context health --json
```

Rules for agents:

- Answer from `healthContext.summary` and `healthContext.derived`.
- Respect `healthContext.agentGuidance.canAnswerFromContext`.
- If `healthContext.agentGuidance.recommendedCommand` is present, run it before answering current/latest health questions.
- If context is `stale` or `needs_sync`, run `oomi context health sync --wait --json`; answer only after fresh context is uploaded, or tell the user the phone sync is still pending if it times out.
- If context is `missing`, `permission_denied`, `disabled_by_user`, or `unavailable`, tell the user what repair action is needed instead of guessing.
- Never present stale HealthKit values as current values.
- Do not ask the phone for HealthKit directly; the Oomi mobile app syncs HealthKit to the backend.

## Voice Contract

Managed voice uses the same Oomi plugin and bridge layer as managed chat.

For assistant replies, visible chat text stays user-facing. Optional hidden TTS metadata may live at `metadata.spoken`:

```json
{
  "metadata": {
    "spoken": {
      "text": "Speech-optimized text for TTS only.",
      "language": "English",
      "instructions": "Speak with warm, upbeat conversational energy and natural pacing."
    }
  }
}
```

Rules:

- visible `content` is the source of truth for chat rendering
- `metadata.spoken.text` is backend TTS input only
- visible chat text should not contain raw speaking tags
- the package preserves valid `metadata.spoken`
- if omitted, the package may synthesize a bounded fallback from visible assistant text

## Health Checks

Use these when chat or voice is failing:

```bash
oomi openclaw bridge ps
oomi openclaw bridge service status
oomi openclaw status
tail -f ~/.openclaw/logs/oomi-bridge-live.log
tail -f ~/.openclaw/logs/gateway.log
tail -f ~/.openclaw/logs/gateway.err.log
```

Bridge status meanings:

- `starting`: bridge booting or waiting for managed subscription
- `connected`: ready for managed chat and voice traffic
- `reconnecting`: transport dropped and retry is scheduled
- `degraded`: bridge caught a runtime fault but is still alive
- `error`: startup or auth failure blocked useful operation
- `stopped`: not running or intentionally stopped

## Troubleshooting

Duplicate plugin id warning:

- Cause: multiple discoverable `oomi-ai` installs.
- Action: remove stale extension copies and reinstall once.

`invalid handshake: first request must be connect`:

- Cause: a gateway request was sent before `connect` had been accepted.
- Action: update `oomi-ai`, restart the bridge, and confirm only one bridge worker is running.

STT works but the assistant does not reply:

- Cause: the voice turn likely reached Oomi, but the managed gateway or OpenClaw run failed later.
- Action: inspect `gateway.log`, `gateway.err.log`, and the session JSONL for auth, network, or bridge restart errors.

Bridge keeps using an old package after update:

- Action: run `oomi openclaw refresh --skip-version-check`.
- If still stale: run `oomi openclaw bridge restart --detach`.
- On macOS service installs: run `oomi openclaw bridge service restart`.
- Confirm with `oomi openclaw bridge ps`.

## Developer Verification

From `packages/oomi-ai`:

```bash
npm run check
npm test
npm pack --dry-run
npm publish --dry-run --no-git-checks --access public
```

Expected package contents are restricted by the `files` allowlist in `package.json`.
