oomi-ai 0.3.7 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,49 +1,84 @@
1
- # Oomi Avatar Control
1
+ # Oomi Local Agent Operator Guide
2
2
 
3
- Prefer canonical avatar values.
4
- Inline tags are stripped from user-visible text.
3
+ Connect the agent the user is speaking to. Identify your runtime and profile first. Never choose OpenClaw merely because it is installed on the same machine as Hermes.
5
4
 
6
- Use inline tags like:
7
- - [anim:Waving], [anim:Walking], [anim:Idle], [anim:Sitting Idle]
8
- - [face:happy], [face:sad], [face:surprised], [face:focused], [face:gentle], [face:thinking]
9
- - [gesture:nod], [gesture:think], [gesture:shrug], [gesture:wave], [gesture:bow]
10
- - [look:camera], [look:left], [look:right], [look:up], [look:down]
11
-
12
- Aliases allowed (if needed): wave -> Waving, walk -> Walking, idle -> Idle, sit/sitting -> Sitting Idle
13
-
14
- ## Oomi Connect Flow
15
-
16
- If the user asks to connect OpenClaw to Oomi voice or chat:
17
-
18
- 1. For a first-time install or missing local pairing state, run bootstrap exactly once using the requested app URL:
19
- - `curl -fsSL https://www.oomi.ai/install.sh | bash`
20
- - Bootstrap installs or updates `oomi-ai`, performs the one initial pair, installs the plugin, and starts the saved bridge detached.
21
- - Do not pair again after bootstrap.
22
- 2. Configure channel account (`channels.oomi.accounts.default`) from:
23
- - `oomi openclaw plugin --show-secrets --backend-url https://api.oomi.ai`
24
- 3. Restart OpenClaw.
25
- 4. Ensure exactly one bridge worker is running (singleton handler):
26
- - `oomi openclaw refresh --skip-version-check`
27
- - `oomi openclaw bridge ensure --detach`
28
- - If stale/disconnected: `oomi openclaw bridge restart --detach`
29
- - On macOS, prefer supervised mode: `oomi openclaw bridge service install`
30
- 5. If the Auth Link printed by bootstrap is missing or expired, create a replacement without re-pairing:
31
- - `oomi openclaw invite --app-url https://www.oomi.ai`
32
- 6. If the user provides an app URL, substitute it in both the bootstrap URL and the `invite --app-url` command.
33
- 7. If the machine is already paired, do not rerun bootstrap. Use `invite` for link recovery and `bridge ensure` or `bridge restart` for runtime recovery.
34
- 8. Return this exact result format to the user:
35
- - `Oomi Connect Ready`
36
- - `Auth Link: ...`
37
- - No extra narrative text before or after those lines.
38
-
39
- Primary UX requirement:
40
- - Never ask the user to enter raw pairing identifiers.
41
- - The user should open the auth link, complete sign-in, and land directly in connected chat.
42
- - Return `/connect/<invite-token>` auth links only.
43
-
44
- Do not ask users to paste gateway IP/token/password when managed connect is available.
45
-
46
- ## Hidden Speech Payload
5
+ ## Standard Connect Flow
6
+
7
+ Install or update the local package:
8
+
9
+ ```bash
10
+ npm install -g oomi-ai@latest
11
+ ```
12
+
13
+ Run ONE command for your runtime:
14
+
15
+ ```bash
16
+ # OpenClaw (reuses existing default OpenClaw pairing)
17
+ oomi connect --runtime openclaw --app-url https://www.oomi.ai
18
+
19
+ # Hermes (separate connection, no OpenClaw required)
20
+ oomi connect --runtime hermes --name hermes --app-url https://www.oomi.ai
21
+
22
+ # Another local agent, through its own adapter
23
+ oomi connect --runtime command --name my-agent --command '["/absolute/path/to/adapter"]' --app-url https://www.oomi.ai
24
+ ```
25
+
26
+ Use the user's app URL when provided. Hermes supports `--profile <profile>` and `--resume <exact-session-id>`. Without `--resume`, Oomi starts a persistent conversation with the same configured agent. Do not use `latest` or claim that an existing chat session was transferred unless its exact ID was selected. Hermes uses `chat --quiet --query-file -`, reads the final reply from stdout and the exact `session_id` from stderr, and resumes that ID on subsequent turns.
27
+
28
+ The command verifies a real local reply, reuses saved credentials or pairs once, starts the bridge, waits for Oomi's subscription, then creates a single-use Auth Link. Failed verification means setup is incomplete: repair the selected runtime, never substitute a different one.
29
+
30
+ The installer is an alternative to npm plus connect, and requires an explicit runtime:
31
+
32
+ ```bash
33
+ curl -fsSL https://www.oomi.ai/install.sh | bash -s -- --runtime hermes --name hermes
34
+ ```
35
+
36
+ ## Required User-Facing Result
37
+
38
+ Return the verified runtime/profile and the printed Auth Link. The human opens the link, signs in, and approves ownership. Only after a message receives a reply in Oomi can you claim end-to-end delivery works. Never expose raw tokens, pairing codes, or gateway credentials.
39
+
40
+ ## Repair and Reconnect
41
+
42
+ Use the SAME connection name from setup. Omit `--name` for default OpenClaw.
43
+
44
+ ```bash
45
+ oomi status --name hermes --json
46
+ oomi verify --name hermes
47
+ oomi bridge restart --name hermes --detach
48
+ oomi invite --name hermes --app-url https://www.oomi.ai
49
+ ```
50
+
51
+ Do not pair again to refresh an expired Auth Link. Re-running `connect` reuses the saved pairing and verifies the runtime again. A different command, profile, or working directory requires a new connection name, so one agent cannot silently replace another. Named connections store private state and logs under `~/.oomi/connections/<name>`; default OpenClaw keeps `~/.openclaw`. A detached worker requires the computer to remain awake and does not start automatically after reboot. Configure the host's process supervisor when persistence across reboot is needed.
52
+
53
+ `connected` describes the broker transport. Inspect `runtimeReady`, `verifiedAt`, and `lastReplyAt` separately. A process ID, Auth Link, or broker connection alone does not prove the agent is answering.
54
+
55
+ ## Other Runtime Adapter Contract
56
+
57
+ `--command` is a JSON argv array, not a shell command. Write an adapter against the selected agent's documented API or noninteractive CLI. The executable reads one JSON object from stdin:
58
+
59
+ ```json
60
+ {"sessionKey":"...","message":"...","idempotencyKey":"...","history":[],"runtimeSessionId":"..."}
61
+ ```
62
+
63
+ It writes `{"text":"final reply","sessionId":"optional-runtime-session"}` to stdout and exits zero on success. Errors must exit nonzero; diagnostics go to stderr. Resume `runtimeSessionId`, or use `history` for stateless runtimes. Never bypass the agent's existing approval rules. The adapter supports text (including voice transcripts); attachments are rejected explicitly. A failed or interrupted action is not silently repeated. Check the agent before sending a new message after a failure.
64
+
65
+ ## OpenClaw Channel Extension
66
+
67
+ Managed web text and voice connect through the local gateway. The optional OpenClaw `oomi-ai` channel plugin handles agent-initiated channel output. If you need that path, install the plugin, enable its entry in OpenClaw, apply `oomi openclaw plugin --show-secrets --backend-url https://api.oomi.ai` locally, and restart OpenClaw. Never share that secret config with the user. Disabling the plugin does not explain a gateway protocol rejection.
68
+
69
+ OpenClaw gateway protocols 3 and 4 are negotiated independently of the broker. For an existing install affected by a protocol mismatch, update `oomi-ai`, then run `oomi connect --runtime openclaw --app-url https://www.oomi.ai`.
70
+
71
+ ## Voice Notes
72
+
73
+ Voice depends on the same Oomi plugin and bridge layer as managed chat.
74
+
75
+ That means:
76
+
77
+ - if plugin install or bridge health is wrong, voice replies will also fail
78
+ - STT can succeed even when assistant reply delivery is broken later in the run
79
+ - a `voice_session_*` failure should be investigated, but it should not automatically be treated as proof that all normal Oomi chat is down
80
+
81
+ ### Hidden Speech Payload
47
82
 
48
83
  For managed voice turns, keep visible assistant chat text natural and user-facing.
49
84
  Do not put spoken-style tags like `[happy]`, `[sad]`, or `[excited]` into visible chat text.
@@ -66,38 +101,65 @@ When the runtime supports it, voice turns may include a hidden speech sidecar on
66
101
  ```
67
102
 
68
103
  Rules:
104
+
69
105
  - visible `content` remains the source of truth for Oomi chat rendering
70
- - for managed voice replies, include `metadata.spoken` when delivery benefits from cleaner phrasing or explicit speaking guidance
106
+ - for managed voice replies, include `metadata.spoken` whenever backend TTS should speak the turn
71
107
  - `metadata.spoken.text` is for backend TTS only
72
108
  - `metadata.spoken.language` should use the backend-supported language value for the active provider; use `English` only when no more specific locale is supplied
73
109
  - `metadata.spoken.segments` can carry bounded per-segment prosody for pace, pitch, volume, and pause timing
74
110
  - `metadata.spoken.instructions` should be natural-language guidance, not raw bracket tags
75
- - `metadata.spoken.style` is optional metadata for debugging or future mapping
76
- - if no hidden speech sidecar exists, Oomi falls back to speaking the visible assistant text
77
- - if you omit `metadata.spoken`, the plugin now synthesizes a bounded hidden fallback from visible assistant text
78
- - visible chat text should be clean before sending; the plugin may strip private runtime wrappers and avatar command tags as a safety guardrail
111
+ - visible chat text should be clean before sending; the package may strip private runtime wrappers and avatar command tags as a safety guardrail
112
+
113
+ ## Avatar Commands
114
+
115
+ Prefer canonical avatar values.
116
+ Inline tags are stripped from user-visible text.
117
+
118
+ Use inline tags like:
119
+
120
+ - `[anim:Waving]`, `[anim:Walking]`, `[anim:Idle]`, `[anim:Sitting Idle]`
121
+ - `[face:happy]`, `[face:sad]`, `[face:surprised]`, `[face:focused]`, `[face:gentle]`, `[face:thinking]`
122
+ - `[gesture:nod]`, `[gesture:think]`, `[gesture:shrug]`, `[gesture:wave]`, `[gesture:bow]`
123
+ - `[look:camera]`, `[look:left]`, `[look:right]`, `[look:up]`, `[look:down]`
124
+
125
+ Aliases allowed if needed:
126
+
127
+ - `wave -> Waving`
128
+ - `walk -> Walking`
129
+ - `idle -> Idle`
130
+ - `sit` or `sitting -> Sitting Idle`
79
131
 
80
132
  ## Persona App API Tools
81
133
 
82
134
  Oomi persona apps are component-composed client surfaces backed by approved templates, components, data bindings, actions, and permissions.
83
135
 
84
- Persona UI creation and rendering happen inside Oomi-managed systems. Use the Oomi API tools instead:
136
+ The OpenClaw agent should inspect and update persona app state through the Oomi API tools in this package.
85
137
 
86
- ```bash
87
- oomi persona-apps list --json
88
- oomi persona-apps show fitness-today --json
89
- oomi persona-apps apply-action fitness-today --action fitness.complete_workout --payload-json '{"goalId":"easy-run","minutes":20}' --json
90
- ```
138
+ When a user asks about an existing persona app:
91
139
 
92
- Rules:
93
- - answer from returned `appState.bindings`, not memory
94
- - apply updates only through approved `persona-apps apply-action` actions
95
- - if the persona app is missing, ask the user to add it from the Oomi client first so permissions and hydration can run
96
- - do not execute persona UI jobs or start local persona app runtimes
140
+ 1. Run `oomi persona-apps list --json` to see the persona apps linked to this user's account.
141
+ 2. Run `oomi persona-apps show <slug> --json` before answering detailed questions about that persona's state.
142
+ 3. Answer from the returned `appState.bindings`, not from memory or guesses.
143
+ 4. To update state, use a validated action: `oomi persona-apps apply-action <slug> --action <action-id> --payload-json '<json>' --json`.
144
+ 5. If `persona-apps list` returns no app for the user's request, tell the user they can add that persona from the Oomi client so the client can collect the right permissions and data sources.
145
+
146
+ For the Fitness v0 slice:
147
+
148
+ - Use `fitness.complete_goal` with payload `{"goalId":"easy-run"}` to mark a known goal complete.
149
+ - Use `fitness.complete_workout` with payload like `{"goalId":"easy-run","minutes":20}` when the user says they finished a workout.
150
+
151
+ Strict rules:
152
+
153
+ - Do not create local persona UI projects.
154
+ - Do not run local persona app runtimes.
155
+ - Do not execute persona UI jobs.
156
+ - Do not install app framework dependencies for persona UI work.
157
+ - Do not present local URLs as persona app URLs.
158
+ - If a persona app needs to be created, tell the user to add it from the Oomi client first so permissions and hydration run correctly.
97
159
 
98
160
  ## Permissioned Context Tools
99
161
 
100
- Use Oomi context tools when the user asks about personal data that should come from mobile permissions instead of memory.
162
+ Use Oomi context tools when the user asks about personal data that should come from mobile permissions instead of model memory.
101
163
 
102
164
  For health, fitness, sleep, workout, cardio, or movement questions:
103
165
 
@@ -106,11 +168,29 @@ oomi context health --json
106
168
  ```
107
169
 
108
170
  Rules:
109
- - answer only from `healthContext.summary` and `healthContext.derived`
110
- - respect `healthContext.agentGuidance.canAnswerFromContext`
111
- - if `healthContext.agentGuidance.recommendedCommand` is present, run it before answering current/latest health questions
112
- - if `healthContext.status` 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
113
- - if `canAnswerFromContext` is false and no sync command is recommended, tell the user the relevant `healthContext.repair.label` or `healthContext.repair.reason`
114
- - never present stale HealthKit values as current values
115
- - do not infer unavailable health fields
116
- - do not request HealthKit directly from the phone; the Oomi mobile app owns permission prompts and syncs approved data to the backend
171
+
172
+ - Answer only from `healthContext.summary` and `healthContext.derived`.
173
+ - Respect `healthContext.agentGuidance.canAnswerFromContext`.
174
+ - If `healthContext.agentGuidance.recommendedCommand` is present, run it before answering current/latest health questions.
175
+ - If `healthContext.status` 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.
176
+ - If `canAnswerFromContext` is false and no sync command is recommended, tell the user the relevant `healthContext.repair.label` or `healthContext.repair.reason`.
177
+ - Never present stale HealthKit values as current values.
178
+ - Do not infer unavailable health fields.
179
+ - Do not request HealthKit directly from the phone; the Oomi mobile app owns permission prompts and syncs approved data to the backend.
180
+
181
+ ## Phone Notifications
182
+
183
+ To reach the user on their phone when they are not in the conversation, send a push notification:
184
+
185
+ ```bash
186
+ oomi notify "Your 7-day plan is ready. Want to look now?" --title "Fitness" --json
187
+ ```
188
+
189
+ Rules:
190
+
191
+ - Notify only for things worth interrupting the user for: a reminder they asked for, a finished task, or something time-sensitive. Say everything else in chat.
192
+ - Keep the message short and specific. The title defaults to your agent name.
193
+ - Tapping the notification opens the Oomi app to the conversation, where the message also appears.
194
+ - Messages you send the user on the Oomi channel already notify their phone. Do not also run `oomi notify` for the same message.
195
+ - If `notification.status` is `skipped`, tell the user `notification.guidance` instead of retrying.
196
+ - If the request is rate limited, do not retry until `retryAfterSeconds` has passed.