oomi-ai 0.2.50 → 0.3.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.
Files changed (88) hide show
  1. package/README.md +203 -507
  2. package/agent_instructions.md +244 -253
  3. package/bin/oomi-ai.js +4026 -5795
  4. package/bin/sessionBridgeState.js +78 -78
  5. package/lib/openclawPaths.js +70 -71
  6. package/lib/openclawProfile.js +216 -216
  7. package/lib/personaApiClient.js +133 -303
  8. package/lib/spokenMetadata.js +137 -137
  9. package/openclaw.extension.js +341 -341
  10. package/openclaw.plugin.json +17 -17
  11. package/package.json +59 -59
  12. package/persona-app/README.md +27 -0
  13. package/persona-app/registry/v1.json +63 -0
  14. package/persona-app/schema/persona-app.v1.schema.json +90 -0
  15. package/skills/oomi/SKILL.md +165 -182
  16. package/skills/oomi/agent_instructions.md +99 -80
  17. package/lib/channelPluginClient.js +0 -119
  18. package/lib/openclawDevGateway.js +0 -384
  19. package/lib/personaJobExecutor.js +0 -139
  20. package/lib/personaJobPoller.js +0 -112
  21. package/lib/personaPortAllocator.js +0 -36
  22. package/lib/personaRuntimeManager.js +0 -496
  23. package/lib/personaRuntimeProcess.js +0 -924
  24. package/lib/personaRuntimeRegistry.js +0 -67
  25. package/lib/personaRuntimeSupervisor.js +0 -330
  26. package/lib/scaffold.js +0 -108
  27. package/lib/template.js +0 -45
  28. package/skills/oomi/config.json +0 -3
  29. package/skills/oomi/scripts/get_avatar_capabilities.py +0 -40
  30. package/skills/oomi/scripts/get_data.py +0 -49
  31. package/skills/oomi/scripts/install_agent_instructions.py +0 -78
  32. package/skills/oomi/scripts/send_goal.py +0 -53
  33. package/skills/oomi/scripts/sync.py +0 -46
  34. package/skills/oomi/setup.py +0 -41
  35. package/templates/persona-app/.env.example +0 -8
  36. package/templates/persona-app/README.md +0 -58
  37. package/templates/persona-app/eslint.config.js +0 -28
  38. package/templates/persona-app/index.html +0 -18
  39. package/templates/persona-app/oomi.runtime.json +0 -13
  40. package/templates/persona-app/package.json +0 -44
  41. package/templates/persona-app/persona/brief.md +0 -14
  42. package/templates/persona-app/persona.json +0 -14
  43. package/templates/persona-app/public/manifest.webmanifest +0 -8
  44. package/templates/persona-app/public/oomi.health.json +0 -6
  45. package/templates/persona-app/src/App.css +0 -379
  46. package/templates/persona-app/src/App.tsx +0 -17
  47. package/templates/persona-app/src/index.css +0 -53
  48. package/templates/persona-app/src/main.tsx +0 -23
  49. package/templates/persona-app/src/pages/HomePage.tsx +0 -127
  50. package/templates/persona-app/src/pages/ScenePage.tsx +0 -158
  51. package/templates/persona-app/src/persona/config.ts +0 -6
  52. package/templates/persona-app/src/persona/notes.ts +0 -10
  53. package/templates/persona-app/src/spatial.ts +0 -82
  54. package/templates/persona-app/src/vite-env.d.ts +0 -3
  55. package/templates/persona-app/template.json +0 -13
  56. package/templates/persona-app/tsconfig.app.json +0 -23
  57. package/templates/persona-app/tsconfig.json +0 -7
  58. package/templates/persona-app/tsconfig.node.json +0 -21
  59. package/templates/persona-app/vendor/webspatial/FORK.md +0 -6
  60. package/templates/persona-app/vendor/webspatial/core-sdk/LICENSE +0 -21
  61. package/templates/persona-app/vendor/webspatial/core-sdk/dist/iife/index.d.ts +0 -906
  62. package/templates/persona-app/vendor/webspatial/core-sdk/dist/iife/index.global.js +0 -75
  63. package/templates/persona-app/vendor/webspatial/core-sdk/dist/iife/index.global.js.map +0 -1
  64. package/templates/persona-app/vendor/webspatial/core-sdk/dist/index.d.ts +0 -906
  65. package/templates/persona-app/vendor/webspatial/core-sdk/dist/index.js +0 -3131
  66. package/templates/persona-app/vendor/webspatial/core-sdk/dist/index.js.map +0 -1
  67. package/templates/persona-app/vendor/webspatial/core-sdk/package.json +0 -45
  68. package/templates/persona-app/vendor/webspatial/react-sdk/LICENSE +0 -21
  69. package/templates/persona-app/vendor/webspatial/react-sdk/dist/default/index.d.ts +0 -365
  70. package/templates/persona-app/vendor/webspatial/react-sdk/dist/default/index.js +0 -4167
  71. package/templates/persona-app/vendor/webspatial/react-sdk/dist/default/index.js.map +0 -1
  72. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.d.ts +0 -82
  73. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.js +0 -66
  74. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.js.map +0 -1
  75. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.web.d.ts +0 -2
  76. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.web.js +0 -18
  77. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.web.js.map +0 -1
  78. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.d.ts +0 -5
  79. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.js +0 -66
  80. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.js.map +0 -1
  81. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.web.d.ts +0 -1
  82. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.web.js +0 -18
  83. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.web.js.map +0 -1
  84. package/templates/persona-app/vendor/webspatial/react-sdk/dist/web/index.d.ts +0 -365
  85. package/templates/persona-app/vendor/webspatial/react-sdk/dist/web/index.js +0 -4207
  86. package/templates/persona-app/vendor/webspatial/react-sdk/dist/web/index.js.map +0 -1
  87. package/templates/persona-app/vendor/webspatial/react-sdk/package.json +0 -94
  88. package/templates/persona-app/vite.config.ts +0 -31
@@ -2,270 +2,261 @@
2
2
 
3
3
  Use these instructions when you need to connect, repair, or verify an OpenClaw machine that should talk to Oomi.
4
4
 
5
- This is the packaged agent-facing reference for:
6
- - managed OpenClaw connect and repair flows
7
- - device-backed chat and voice bridge recovery
8
- - XR-first persona generation and persona runtime repair
9
-
10
- ## Primary Goal
11
-
12
- Get OpenClaw into a state where:
13
- - Oomi managed text chat works
14
- - Oomi device-backed voice can start cleanly
15
- - the bridge is supervised or restartable
16
- - the user never has to paste raw pair identifiers or gateway secrets manually when managed connect is available
17
-
18
- ## Standard Connect Flow
19
-
20
- If the user asks to connect OpenClaw to Oomi chat or voice:
21
-
22
- 1. Refresh bootstrap first:
23
- - `curl -fsSL https://www.oomi.ai/install.sh | bash`
24
- 2. Ensure `oomi-ai` is installed:
25
- - `pnpm add -g oomi-ai@latest`
26
- - fallback: `npm install -g oomi-ai@latest`
27
- 3. Pair the device without starting a legacy one-off flow:
28
- - `oomi openclaw pair --app-url https://www.oomi.ai --no-start`
29
- 4. Install the OpenClaw plugin:
30
- - `openclaw plugins install oomi-ai@latest`
31
- 5. Print the config block and secrets:
32
- - `oomi openclaw plugin --show-secrets --backend-url https://api.oomi.ai`
33
- 6. Apply the printed `channels.oomi.accounts.default` config.
34
- 7. Restart OpenClaw.
35
- 8. Start or repair the bridge:
36
- - `oomi openclaw bridge ensure --detach`
37
- - if stale: `oomi openclaw bridge restart --detach`
38
- - on macOS, prefer supervision: `oomi openclaw bridge service install`
39
-
40
- If the user provides a specific app URL, use it directly in the pair flow:
41
- - `oomi openclaw pair --app-url <URL> --no-start`
42
-
43
- ## Required User-Facing Result
44
-
45
- When pairing completes successfully, return this exact format:
46
- - `Oomi Connect Ready`
47
- - `Auth Link: ...`
48
-
49
- Do not add extra narrative before or after those lines.
50
- Do not ask the user to enter raw pair codes, gateway passwords, or nonce values manually.
51
-
52
- ## Runtime Checks
53
-
54
- Use these commands to inspect the installed machine:
55
-
56
- ```bash
57
- oomi openclaw bridge ps
58
- oomi openclaw bridge service status
59
- oomi openclaw status
60
- tail -f ~/.openclaw/logs/oomi-bridge-live.log
61
- tail -f ~/.openclaw/logs/gateway.log
62
- tail -f ~/.openclaw/logs/gateway.err.log
63
- ```
64
-
65
- Useful local files:
66
- - `~/.openclaw/oomi-bridge-status.json`
67
- - `~/.openclaw/logs/oomi-bridge-live.log`
68
- - `~/.openclaw/logs/gateway.log`
69
- - `~/.openclaw/logs/gateway.err.log`
70
- - `~/.openclaw/agents/main/sessions/*.jsonl`
71
-
72
- ## Healthy State
73
-
74
- Treat the machine as healthy when all of the following are true:
75
- - OpenClaw loads the `oomi-ai` plugin without duplicate-id conflicts
76
- - `channels.oomi.accounts.default` is populated with a valid `backendUrl` and `deviceToken`
77
- - the bridge shows `connected` after managed subscription is confirmed
78
- - text chat reaches the Oomi assistant
79
- - voice STT can produce `asr.final`
80
- - assistant replies can come back without the bridge dropping into `stopped`
81
-
82
- Bridge status meanings:
83
- - `starting`: bridge booting or waiting for managed subscription
84
- - `connected`: ready for managed chat and voice traffic
85
- - `reconnecting`: transport dropped and retry is scheduled
86
- - `degraded`: bridge caught a runtime fault but is still alive
87
- - `error`: startup/auth failure blocked useful operation
88
- - `stopped`: not running or intentionally stopped
89
-
90
- ## Troubleshooting
91
-
92
- ### Duplicate plugin id warning
93
-
94
- Symptom:
95
- - OpenClaw reports `duplicate plugin id detected`
96
-
97
- Action:
98
- - ensure only one active `oomi-ai` plugin install is discoverable
99
- - remove stale extension copies before reinstalling
100
-
101
- ### `invalid handshake: first request must be connect`
102
-
103
- Meaning:
104
- - a gateway request was sent before `connect` had been accepted
105
-
106
- Action:
107
- - update `oomi-ai`
108
- - restart the bridge
109
- - confirm only one bridge worker is running
110
-
111
- ### Device is linked but voice start still fails
112
-
113
- Meaning:
114
- - linked ownership is not enough; the device side still needs to be live
115
-
116
- Action:
117
- - confirm the device websocket is actually online
118
- - confirm the bridge is `connected`
119
- - restart the bridge if it is stuck in `reconnecting` or `degraded`
120
-
121
- ### STT works but the assistant does not reply
122
-
123
- Meaning:
124
- - the voice turn likely reached Oomi, but the managed gateway or OpenClaw run failed later
125
-
126
- Action:
127
- - inspect `gateway.log`, `gateway.err.log`, and the session JSONL
128
- - check for `network_error`, auth failures, or repeated bridge restarts
129
-
130
- ### Bridge keeps restarting with `reason: stopped`
131
-
132
- Action:
133
- - confirm the newest `oomi-ai` is installed
134
- - inspect `~/.openclaw/logs/oomi-bridge-live.log` for runtime exceptions
135
- - use supervised mode on macOS: `oomi openclaw bridge service install`
136
- - if the process is alive but faulted, expect `degraded` rather than an immediate hard stop on newer bridge builds
137
-
138
- ## Voice Notes
139
-
140
- Voice depends on the same Oomi plugin and bridge layer as managed chat.
141
- That means:
142
- - if plugin install or bridge health is wrong, voice replies will also fail
143
- - STT can succeed even when assistant reply delivery is broken later in the run
144
- - a `voice_session_*` failure should be investigated, but it should not automatically be treated as proof that all normal Oomi chat is down
145
-
146
- ### Hidden Speech Payload
147
-
148
- For managed voice turns, keep visible assistant chat text natural and user-facing.
149
- Do not put spoken-style tags like `[happy]`, `[sad]`, or `[excited]` into visible chat text.
150
-
151
- When the runtime supports it, voice turns may include a hidden speech sidecar on the assistant message:
152
-
153
- ```json
154
- {
155
- "metadata": {
156
- "spoken": {
157
- "text": "Speech-optimized text for TTS only.",
158
- "instructions": "Speak with upbeat, warm excitement and slightly rising intonation.",
159
- "style": {
160
- "emotion": "excited",
161
- "energy": "medium_high"
162
- }
163
- }
164
- }
165
- }
166
- ```
167
-
5
+ This package is for managed Oomi connectivity. Persona UI creation and rendering happen inside Oomi-managed systems. The OpenClaw machine uses API actions only.
6
+
7
+ ## Primary Goal
8
+
9
+ Get OpenClaw into a state where:
10
+
11
+ - Oomi managed text chat works
12
+ - Oomi device-backed voice can start cleanly
13
+ - the bridge is supervised or restartable
14
+ - component-composed persona apps can be inspected and updated through Oomi API tools
15
+ - the user never has to paste raw pair identifiers or gateway secrets manually when managed connect is available
16
+
17
+ ## Standard Connect Flow
18
+
19
+ If the user asks to connect OpenClaw to Oomi chat or voice:
20
+
21
+ 1. Refresh bootstrap first:
22
+ - `curl -fsSL https://www.oomi.ai/install.sh | bash`
23
+ 2. Ensure `oomi-ai` is installed:
24
+ - `pnpm add -g oomi-ai@latest`
25
+ - fallback: `npm install -g oomi-ai@latest`
26
+ 3. Pair the device without starting a legacy one-off flow:
27
+ - `oomi openclaw pair --app-url https://www.oomi.ai --no-start`
28
+ 4. Install the OpenClaw plugin:
29
+ - `openclaw plugins install oomi-ai@latest`
30
+ 5. Print the config block and secrets:
31
+ - `oomi openclaw plugin --show-secrets --backend-url https://api.oomi.ai`
32
+ 6. Apply the printed `channels.oomi.accounts.default` config.
33
+ 7. Restart OpenClaw.
34
+ 8. Start or repair the bridge:
35
+ - `oomi openclaw bridge ensure --detach`
36
+ - if stale: `oomi openclaw bridge restart --detach`
37
+ - on macOS, prefer supervision: `oomi openclaw bridge service install`
38
+
39
+ If the user provides a specific app URL, use it directly in the pair flow:
40
+
41
+ - `oomi openclaw pair --app-url <URL> --no-start`
42
+
43
+ ## Required User-Facing Result
44
+
45
+ When pairing completes successfully, return this exact format:
46
+
47
+ - `Oomi Connect Ready`
48
+ - `Auth Link: ...`
49
+
50
+ Do not add extra narrative before or after those lines.
51
+ Do not ask the user to enter raw pair codes, gateway passwords, or nonce values manually.
52
+
53
+ ## Update And Stale Bridge Repair
54
+
55
+ After updating `oomi-ai`, always make sure the running bridge is not still using an old package or dead gateway connection.
56
+
57
+ Preferred update flow:
58
+
59
+ ```bash
60
+ pnpm add -g oomi-ai@latest
61
+ openclaw plugins install oomi-ai@latest
62
+ oomi openclaw refresh --skip-version-check
63
+ oomi openclaw bridge ps
64
+ ```
65
+
66
+ If the bridge is stale, disconnected, duplicated, or reporting the wrong version:
67
+
68
+ ```bash
69
+ oomi openclaw bridge restart --detach
70
+ oomi openclaw bridge ps
71
+ ```
72
+
73
+ On macOS supervised installs:
74
+
75
+ ```bash
76
+ oomi openclaw bridge service restart
77
+ oomi openclaw bridge service status
78
+ ```
79
+
80
+ Healthy result:
81
+
82
+ - one bridge worker is active
83
+ - bridge status reaches `connected`
84
+ - the bridge version matches the newly installed package
85
+
86
+ ## Runtime Checks
87
+
88
+ Use these commands to inspect the installed machine:
89
+
90
+ ```bash
91
+ oomi openclaw bridge ps
92
+ oomi openclaw bridge service status
93
+ oomi openclaw status
94
+ tail -f ~/.openclaw/logs/oomi-bridge-live.log
95
+ tail -f ~/.openclaw/logs/gateway.log
96
+ tail -f ~/.openclaw/logs/gateway.err.log
97
+ ```
98
+
99
+ Useful local files:
100
+
101
+ - `~/.openclaw/oomi-bridge-status.json`
102
+ - `~/.openclaw/logs/oomi-bridge-live.log`
103
+ - `~/.openclaw/logs/gateway.log`
104
+ - `~/.openclaw/logs/gateway.err.log`
105
+ - `~/.openclaw/agents/main/sessions/*.jsonl`
106
+
107
+ ## Healthy State
108
+
109
+ Treat the machine as healthy when all of the following are true:
110
+
111
+ - OpenClaw loads the `oomi-ai` plugin without duplicate-id conflicts
112
+ - `channels.oomi.accounts.default` is populated with a valid `backendUrl` and `deviceToken`
113
+ - the bridge shows `connected` after managed subscription is confirmed
114
+ - text chat reaches the Oomi assistant
115
+ - voice STT can produce `asr.final`
116
+ - assistant replies can come back without the bridge dropping into `stopped`
117
+
118
+ Bridge status meanings:
119
+
120
+ - `starting`: bridge booting or waiting for managed subscription
121
+ - `connected`: ready for managed chat and voice traffic
122
+ - `reconnecting`: transport dropped and retry is scheduled
123
+ - `degraded`: bridge caught a runtime fault but is still alive
124
+ - `error`: startup or auth failure blocked useful operation
125
+ - `stopped`: not running or intentionally stopped
126
+
127
+ ## Troubleshooting
128
+
129
+ ### Duplicate plugin id warning
130
+
131
+ Symptom:
132
+
133
+ - OpenClaw reports `duplicate plugin id detected`
134
+
135
+ Action:
136
+
137
+ - ensure only one active `oomi-ai` plugin install is discoverable
138
+ - remove stale extension copies before reinstalling
139
+
140
+ ### `invalid handshake: first request must be connect`
141
+
142
+ Meaning:
143
+
144
+ - a gateway request was sent before `connect` had been accepted
145
+
146
+ Action:
147
+
148
+ - update `oomi-ai`
149
+ - restart the bridge
150
+ - confirm only one bridge worker is running
151
+
152
+ ### Device is linked but voice start still fails
153
+
154
+ Meaning:
155
+
156
+ - linked ownership is not enough; the device side still needs to be live
157
+
158
+ Action:
159
+
160
+ - confirm the device websocket is actually online
161
+ - confirm the bridge is `connected`
162
+ - restart the bridge if it is stuck in `reconnecting` or `degraded`
163
+
164
+ ### STT works but the assistant does not reply
165
+
166
+ Meaning:
167
+
168
+ - the voice turn likely reached Oomi, but the managed gateway or OpenClaw run failed later
169
+
170
+ Action:
171
+
172
+ - inspect `gateway.log`, `gateway.err.log`, and the session JSONL
173
+ - check for `network_error`, auth failures, repeated bridge restarts, or stale package versions
174
+
175
+ ## Voice Notes
176
+
177
+ Voice depends on the same Oomi plugin and bridge layer as managed chat.
178
+
179
+ That means:
180
+
181
+ - if plugin install or bridge health is wrong, voice replies will also fail
182
+ - STT can succeed even when assistant reply delivery is broken later in the run
183
+ - a `voice_session_*` failure should be investigated, but it should not automatically be treated as proof that all normal Oomi chat is down
184
+
185
+ ### Hidden Speech Payload
186
+
187
+ For managed voice turns, keep visible assistant chat text natural and user-facing.
188
+ Do not put spoken-style tags like `[happy]`, `[sad]`, or `[excited]` into visible chat text.
189
+
190
+ When the runtime supports it, voice turns may include a hidden speech sidecar on the assistant message:
191
+
192
+ ```json
193
+ {
194
+ "metadata": {
195
+ "spoken": {
196
+ "text": "Speech-optimized text for TTS only.",
197
+ "instructions": "Speak with upbeat, warm excitement and slightly rising intonation.",
198
+ "style": {
199
+ "emotion": "excited",
200
+ "energy": "medium_high"
201
+ }
202
+ }
203
+ }
204
+ }
205
+ ```
206
+
168
207
  Rules:
208
+
169
209
  - visible `content` remains the source of truth for Oomi chat rendering
170
- - for managed cloned-voice replies, include `metadata.spoken` whenever backend TTS should speak the turn
210
+ - for managed voice replies, include `metadata.spoken` whenever backend TTS should speak the turn
171
211
  - `metadata.spoken.text` is for backend TTS only
172
- - `metadata.spoken.language` should be one of the supported Qwen language values such as `English`
212
+ - `metadata.spoken.language` should use the backend-supported language value for the active provider; use `English` only when no more specific locale is supplied
173
213
  - `metadata.spoken.segments` can carry bounded per-segment prosody for pace, pitch, volume, and pause timing
174
214
  - `metadata.spoken.instructions` should be natural-language guidance, not raw bracket tags
175
- - `metadata.spoken.style` is optional metadata for debugging/future mapping
176
-
177
- Current package behavior:
178
- - if you provide `metadata.spoken`, the package preserves it unchanged
179
- - if you omit `metadata.spoken`, the shared package helper may synthesize it as a compatibility guardrail before backend TTS
180
215
  - visible chat text is never rewritten by the package
181
- - backend cloned voice is strict: if `metadata.spoken` does not reach Oomi, playback fails instead of falling back to flat speech
182
-
183
- ## Avatar Commands
184
-
185
- Before using avatar commands, call `get_avatar_capabilities` and prefer canonical values.
186
- Inline tags are stripped from user-visible text.
187
-
188
- Use inline tags like:
189
- - `[anim:Waving]`, `[anim:Walking]`, `[anim:Idle]`, `[anim:Sitting Idle]`
190
- - `[face:happy]`, `[face:sad]`, `[face:surprised]`, `[face:focused]`, `[face:gentle]`, `[face:thinking]`
191
- - `[gesture:nod]`, `[gesture:think]`, `[gesture:shrug]`, `[gesture:wave]`, `[gesture:bow]`
216
+
217
+ ## Avatar Commands
218
+
219
+ Prefer canonical avatar values.
220
+ Inline tags are stripped from user-visible text.
221
+
222
+ Use inline tags like:
223
+
224
+ - `[anim:Waving]`, `[anim:Walking]`, `[anim:Idle]`, `[anim:Sitting Idle]`
225
+ - `[face:happy]`, `[face:sad]`, `[face:surprised]`, `[face:focused]`, `[face:gentle]`, `[face:thinking]`
226
+ - `[gesture:nod]`, `[gesture:think]`, `[gesture:shrug]`, `[gesture:wave]`, `[gesture:bow]`
192
227
  - `[look:camera]`, `[look:left]`, `[look:right]`, `[look:up]`, `[look:down]`
193
228
 
194
229
  Aliases allowed if needed:
230
+
195
231
  - `wave -> Waving`
196
232
  - `walk -> Walking`
197
233
  - `idle -> Idle`
198
234
  - `sit` or `sitting -> Sitting Idle`
199
235
 
200
- ## Persona App Generation
201
-
202
- For persona app work, treat the scaffold as a runtime contract, not a disposable starting point.
203
-
204
- When a user asks you in chat to create a new persona for Oomi:
205
-
206
- 1. First clarify the persona `name`, `slug`, `description`, permissions, tools, and the ideal work surface.
207
- 2. After that, use this exact manual creation order on the OpenClaw machine:
208
- - `export WORKSPACE_ROOT="$HOME/.openclaw/workspace/personas"`
209
- - `export SLUG="<persona-slug>"`
210
- - `export NAME="<persona-name>"`
211
- - `export DESCRIPTION="<persona-description>"`
212
- - `oomi personas scaffold "$SLUG" --name "$NAME" --description "$DESCRIPTION" --out "$WORKSPACE_ROOT/$SLUG" --force`
213
- - `test -f "$WORKSPACE_ROOT/$SLUG/persona.json"`
214
- - `test -f "$WORKSPACE_ROOT/$SLUG/oomi.runtime.json"`
215
- - `test -f "$WORKSPACE_ROOT/$SLUG/package.json"`
216
- - `oomi personas create-managed "$SLUG" --name "$NAME" --description "$DESCRIPTION" --json`
217
- - `oomi personas launch-managed "$SLUG" --workspace-root "$WORKSPACE_ROOT" --force-install --json`
218
- - `test -f "$WORKSPACE_ROOT/$SLUG/.oomi/runtime.json"`
219
- - `cat "$WORKSPACE_ROOT/$SLUG/.oomi/runtime.json"`
220
- - `oomi personas status "$SLUG" --json`
221
- - `PORT="$(jq -r '.localPort' "$WORKSPACE_ROOT/$SLUG/.oomi/runtime.json")"`
222
- - `oomi personas heartbeat "$SLUG" --local-port "$PORT" --json`
223
- 3. Fail fast if scaffold verification fails or if any `--json` command does not return success.
224
- 4. Treat backend registration as incomplete until `create-managed`, `launch-managed`, `status`, and `heartbeat` all succeed.
225
- 5. Do not present a localhost URL like `http://127.0.0.1:4789` as the final persona runtime URL for Oomi clients.
226
- 6. Do not rely on `launch-managed` auto-creating the backend persona record. Run `create-managed` explicitly first.
227
- 7. Do not use `oomi personas runtime-register <slug>` or `oomi personas heartbeat <slug>` before `create-managed` succeeds.
228
- 8. Do not use manual `npm run dev` or any unmanaged dev server as the persona launch path.
229
-
230
- When generating a managed persona app for Oomi:
231
-
232
- 1. Do not build the app shell from scratch.
233
- 2. Always run `oomi personas scaffold <slug> --name "<name>" --description "<description>" --out <path>` first.
234
- 3. Only customize persona-specific files inside `src/persona/` and `persona/` unless Oomi explicitly instructs otherwise.
235
- 4. Preserve the scaffolded WebSpatial/Vite shell, `public/oomi.health.json`, `oomi.runtime.json`, `public/manifest.webmanifest`, and the vendored WebSpatial fork.
236
- 5. Keep the browser route and the XR route split. In XR mode, the index route should open directly into the mounted scene component, not a flat homepage.
237
- 6. Call `configurePersonaScene()` from that mounted scene component and log `detectSpatialEnvironment()` on scene boot so the runtime can be verified in headset.
238
- 7. Author multiple meaningful XR surfaces with `enable-xr`, `--xr-back`, and `--xr-background-material` values instead of putting one outer `enable-xr` wrapper around the whole page.
239
- 8. Keep `html.is-spatial` shell styles transparent so the host recedes and the authored panels carry the spatial material.
240
- 9. Keep `snapdom` and `html2canvas` exposed from `main.tsx` because AndroidXR DOM capture depends on them.
241
- 10. After customization, bring the persona online through `oomi personas launch-managed <slug> --workspace-root <root> --force-install --json`, then verify `oomi personas status <slug> --json`, then heartbeat using the assigned local port from `.oomi/runtime.json`.
242
- 11. For normal OpenClaw-hosted persona apps on the same LAN, the managed runtime registration contract is:
243
- - backend `entryUrl`: LAN-reachable host such as `http://192.168.x.x:<port>`
244
- - backend `healthcheckUrl`: local loopback such as `http://127.0.0.1:<port>/webspatial/avp/oomi.health.json`
245
- 12. Do not override `--endpoint` with `127.0.0.1` unless the persona is intentionally local-only and not meant to open from Oomi web/XR.
246
- 13. Do not replace the managed runtime flow with manual `npm run dev`, ad hoc `runtime-register`, or ad hoc `heartbeat` commands during first-time creation.
247
-
248
- When editing an existing managed persona that is already open in Oomi:
249
-
250
- 1. Do not ask the user to find the app path manually if Oomi already selected the persona tab for you.
251
- 2. First run `oomi personas status <slug> --json`.
252
- 3. Use `editableWorkspacePath` from that command as the authoritative directory for reads, edits, and verification.
253
- 4. Treat `compatibilityWorkspacePath` only as a fallback or migration clue.
254
- 5. Preserve the scaffolded WebSpatial shell and runtime health files unless the user explicitly asks for a deeper structural change, and do not regress the XR route back into a flat home page.
255
- 6. Do not claim the persona changed unless you have verified the file contents changed in `editableWorkspacePath` or the runtime reflects the update.
256
-
257
- When executing a structured persona job from Oomi:
258
-
259
- 1. Prefer `oomi persona-jobs execute --message-file <job.json>` when the backend has already produced a machine-readable job payload.
260
- 2. That command is allowed to scaffold the app, install dependencies, start the local runtime, wait for the health document, register the runtime, and report job success or failure.
261
- 3. Use the lower-level commands only for recovery or partial reruns:
262
- - `oomi personas runtime-register <slug> --local-port 4789`
263
- - `oomi personas heartbeat <slug> --local-port 4789`
264
- - `oomi persona-jobs start <jobId>`
265
- - `oomi persona-jobs succeed <jobId> --workspace-path <path> --local-port 4789`
266
- - `oomi persona-jobs fail <jobId> --code <code> --message "<text>"`
267
- 4. Before any low-level `runtime-register` or `heartbeat` recovery command, make sure the backend persona already exists via `create-managed`.
268
- 5. If you use the low-level `runtime-register` or `heartbeat` commands, prefer `--local-port` by itself and let `oomi-ai` derive the LAN-reachable endpoint automatically.
269
- 6. If you must pass `--endpoint` explicitly, it must be the LAN-reachable host or a relay URL, not `127.0.0.1`.
270
-
271
- When the Oomi bridge is running on the machine, queued persona jobs from Oomi are now polled and executed automatically through the filtered control-message lane. You should still use the explicit commands above for manual retries, recovery, or direct operator workflows.
236
+ ## Persona App API Tools
237
+
238
+ Oomi persona apps are component-composed client surfaces backed by approved templates, components, data bindings, actions, and permissions.
239
+
240
+ The OpenClaw agent should inspect and update persona app state through the Oomi API tools in this package.
241
+
242
+ When a user asks about an existing persona app:
243
+
244
+ 1. Run `oomi persona-apps list --json` to see the persona apps linked to this user's account.
245
+ 2. Run `oomi persona-apps show <slug> --json` before answering detailed questions about that persona's state.
246
+ 3. Answer from the returned `appState.bindings`, not from memory or guesses.
247
+ 4. To update state, use a validated action: `oomi persona-apps apply-action <slug> --action <action-id> --payload-json '<json>' --json`.
248
+ 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.
249
+
250
+ For the Fitness v0 slice:
251
+
252
+ - Use `fitness.complete_goal` with payload `{"goalId":"easy-run"}` to mark a known goal complete.
253
+ - Use `fitness.complete_workout` with payload like `{"goalId":"easy-run","minutes":20}` when the user says they finished a workout.
254
+
255
+ Strict rules:
256
+
257
+ - Do not create local persona UI projects.
258
+ - Do not run local persona app runtimes.
259
+ - Do not execute persona UI jobs.
260
+ - Do not install app framework dependencies for persona UI work.
261
+ - Do not present local URLs as persona app URLs.
262
+ - 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.