capacitor-mobile-claw 1.6.3 → 1.6.4
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.
- package/README.md +153 -39
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
**On-device AI agent engine for mobile apps** — run Claude directly on your phone with file tools, code execution, git, and extensible MCP tool support.
|
|
8
8
|
|
|
9
|
-
Mobile Claw is a [Capacitor](https://capacitorjs.com/) plugin that embeds a full AI agent runtime on Android and iOS
|
|
9
|
+
Mobile Claw is a [Capacitor](https://capacitorjs.com/) plugin that embeds a full AI agent runtime on Android and iOS. Two execution modes: a **WebView agent** for instant cold start (agent loop runs in-process) or a **Node.js worker** for full sandboxed tooling. Both talk directly to the Anthropic API — no cloud relay, no proxy. Includes native Kotlin + Swift plugins for streaming HTTP (CORS bypass), background heartbeat scheduling, cron jobs, and on-device vector memory.
|
|
10
10
|
|
|
11
11
|
> Built on [OpenClaw](https://github.com/openclaw/openclaw) and the [Pi framework](https://www.npmjs.com/package/@mariozechner/pi-ai) by [Mario Zechner](https://github.com/badlogic). Pi's philosophy of *"what you leave out matters more than what you put in"* — just 4 core tools and a system prompt under 1,000 tokens — is what makes running a capable AI agent on a phone possible at all.
|
|
12
12
|
|
|
@@ -79,13 +79,16 @@ npx cap open ios
|
|
|
79
79
|
### Running Tests
|
|
80
80
|
|
|
81
81
|
```bash
|
|
82
|
-
#
|
|
82
|
+
# Unit tests (64 tests)
|
|
83
|
+
npm test
|
|
84
|
+
|
|
85
|
+
# Android E2E (111 tests, requires ADB device)
|
|
83
86
|
npm run test:android
|
|
84
87
|
|
|
85
|
-
# iOS E2E (
|
|
88
|
+
# iOS E2E (111 tests, requires booted Simulator)
|
|
86
89
|
npm run test:ios
|
|
87
90
|
|
|
88
|
-
# Full suite:
|
|
91
|
+
# Full suite: unit + Android + iOS (skips unavailable platforms)
|
|
89
92
|
npm run test:full
|
|
90
93
|
```
|
|
91
94
|
|
|
@@ -93,29 +96,54 @@ Once the app launches, enter your Anthropic API key in settings and start chatti
|
|
|
93
96
|
|
|
94
97
|
## How It Works
|
|
95
98
|
|
|
99
|
+
Mobile Claw supports two agent execution modes:
|
|
100
|
+
|
|
101
|
+
### WebView Agent (recommended)
|
|
102
|
+
|
|
103
|
+
The agent loop runs directly in the WebView for instant cold start. LLM API calls go through a native HTTP plugin (OkHttp on Android, URLSession on iOS) that bypasses WebView CORS restrictions and provides true streaming via `ReadableStream`. Worker tools are transparently proxied via the bridge.
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
┌──────────────────────────────────────────────────────────┐
|
|
107
|
+
│ Your App (Vue, React, Svelte, vanilla JS) │
|
|
108
|
+
│ ┌────────────────────────────────────────────────────┐ │
|
|
109
|
+
│ │ MobileClawEngine (useWebViewAgent: true) │ │
|
|
110
|
+
│ │ ┌──────────────┐ ┌───────────────────────────┐ │ │
|
|
111
|
+
│ │ │ Pi Agent │ │ HttpStreamPlugin (native) │ │ │
|
|
112
|
+
│ │ │ (in WebView) │ │ - OkHttp (Android) │ │ │
|
|
113
|
+
│ │ │ │──│ - URLSession (iOS) │ │ │
|
|
114
|
+
│ │ │ │ │ - CORS bypass │ │ │
|
|
115
|
+
│ │ │ │ │ - ReadableStream assembly │ │ │
|
|
116
|
+
│ │ └──────┬───────┘ └───────────────────────────┘ │ │
|
|
117
|
+
│ │ │ ToolProxy (bridge IPC) │ │
|
|
118
|
+
│ │ ┌──────▼───────────────────────────────────────┐ │ │
|
|
119
|
+
│ │ │ Node.js Worker (file tools, git, code exec) │ │ │
|
|
120
|
+
│ │ └──────────────────────────────────────────────┘ │ │
|
|
121
|
+
│ └────────────────────────────────────────────────────┘ │
|
|
122
|
+
└──────────────────────────────────────────────────────────┘
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Worker Agent (legacy)
|
|
126
|
+
|
|
127
|
+
The full agent loop runs inside the embedded Node.js worker. Higher cold start latency but full isolation.
|
|
128
|
+
|
|
96
129
|
```
|
|
97
|
-
|
|
98
|
-
│ Your App
|
|
99
|
-
│
|
|
100
|
-
│ │ MobileClawEngine
|
|
101
|
-
│
|
|
102
|
-
│
|
|
103
|
-
│
|
|
104
|
-
│ │
|
|
105
|
-
│
|
|
106
|
-
│
|
|
107
|
-
│
|
|
108
|
-
│ │
|
|
109
|
-
│ │
|
|
110
|
-
│ │
|
|
111
|
-
│ │
|
|
112
|
-
│
|
|
113
|
-
|
|
114
|
-
│ │ └──────┬───────┘ └──────────────────────┘ │ │
|
|
115
|
-
│ │ │ │ │
|
|
116
|
-
│ │ ▼ Anthropic Messages API │ │
|
|
117
|
-
│ └────────────────────────────────────────────────┘ │
|
|
118
|
-
└─────────────────────────────────────────────────────┘
|
|
130
|
+
┌──────────────────────────────────────────────────────────┐
|
|
131
|
+
│ Your App │
|
|
132
|
+
│ ┌────────────────────────────────────────────────────┐ │
|
|
133
|
+
│ │ MobileClawEngine │ │
|
|
134
|
+
│ └──────────────────┬─────────────────────────────────┘ │
|
|
135
|
+
│ │ Bridge Protocol (IPC) │
|
|
136
|
+
│ ┌──────────────────▼─────────────────────────────────┐ │
|
|
137
|
+
│ │ Node.js Worker (Capacitor-NodeJS) │ │
|
|
138
|
+
│ │ ┌──────────────┐ ┌──────────────────────┐ │ │
|
|
139
|
+
│ │ │ Pi Agent │ │ MCP Server │ │ │
|
|
140
|
+
│ │ │ (pi-ai) │ │ - Bridge transport │ │ │
|
|
141
|
+
│ │ │ │ │ - STOMP transport │ │ │
|
|
142
|
+
│ │ │ │ │ - Custom tools (BYO) │ │ │
|
|
143
|
+
│ │ └──────┬───────┘ └──────────────────────┘ │ │
|
|
144
|
+
│ │ ▼ Anthropic Messages API │ │
|
|
145
|
+
│ └─────────────────────────────────────────────────────┘ │
|
|
146
|
+
└──────────────────────────────────────────────────────────┘
|
|
119
147
|
```
|
|
120
148
|
|
|
121
149
|
## Install in Your Own App
|
|
@@ -124,6 +152,16 @@ Once the app launches, enter your Anthropic API key in settings and start chatti
|
|
|
124
152
|
npm install capacitor-mobile-claw @capacitor/core @capacitor/device @choreruiz/capacitor-node-js @capacitor-community/sqlite
|
|
125
153
|
```
|
|
126
154
|
|
|
155
|
+
If using Vite, add the bundler plugin to `vite.config.js` (stubs Node.js-only transitive deps):
|
|
156
|
+
|
|
157
|
+
```javascript
|
|
158
|
+
import { mobileClawVitePlugin } from 'capacitor-mobile-claw/vite-plugin'
|
|
159
|
+
|
|
160
|
+
export default defineConfig({
|
|
161
|
+
plugins: [mobileClawVitePlugin(), vue()],
|
|
162
|
+
})
|
|
163
|
+
```
|
|
164
|
+
|
|
127
165
|
Then add these scripts to your `package.json`:
|
|
128
166
|
|
|
129
167
|
```json
|
|
@@ -156,13 +194,13 @@ import { MobileClawEngine } from 'capacitor-mobile-claw'
|
|
|
156
194
|
|
|
157
195
|
const engine = new MobileClawEngine()
|
|
158
196
|
|
|
159
|
-
//
|
|
160
|
-
await engine.init()
|
|
197
|
+
// WebView agent — instant cold start, streaming via native HTTP
|
|
198
|
+
await engine.init({ useWebViewAgent: true })
|
|
161
199
|
|
|
162
200
|
// Listen for streaming text
|
|
163
201
|
engine.addListener('agentEvent', (event) => {
|
|
164
202
|
if (event.eventType === 'text_delta') {
|
|
165
|
-
|
|
203
|
+
console.log(event.data.text)
|
|
166
204
|
}
|
|
167
205
|
})
|
|
168
206
|
|
|
@@ -189,12 +227,55 @@ const engine = new MobileClawEngine()
|
|
|
189
227
|
|
|
190
228
|
await engine.init({
|
|
191
229
|
tools: myTools,
|
|
192
|
-
|
|
230
|
+
useWebViewAgent: true,
|
|
231
|
+
})
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### With Heartbeat Scheduling
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
const engine = new MobileClawEngine()
|
|
238
|
+
await engine.init({ useWebViewAgent: true, mobileCron: MobileCron })
|
|
239
|
+
|
|
240
|
+
// Enable scheduler + heartbeat (runs every 30 minutes)
|
|
241
|
+
await engine.setSchedulerConfig({ enabled: true, schedulingMode: 'balanced' })
|
|
242
|
+
await engine.setHeartbeat({ enabled: true, everyMs: 1800000 })
|
|
243
|
+
|
|
244
|
+
// Listen for heartbeat results
|
|
245
|
+
engine.addListener('heartbeatCompleted', (event) => {
|
|
246
|
+
console.log(`Heartbeat: ${event.status} (${event.durationMs}ms)`)
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
// Manual trigger
|
|
250
|
+
await engine.triggerHeartbeatWake('manual')
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### With Cron Jobs
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
// Create a skill (reusable prompt + tool constraints)
|
|
257
|
+
const skill = await engine.addSkill({
|
|
258
|
+
name: 'daily-summary',
|
|
259
|
+
maxTurns: 3,
|
|
260
|
+
timeoutMs: 60000,
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
// Schedule a cron job
|
|
264
|
+
await engine.addCronJob({
|
|
265
|
+
name: 'morning-briefing',
|
|
266
|
+
enabled: true,
|
|
267
|
+
sessionTarget: 'isolated',
|
|
268
|
+
schedule: { kind: 'every', everyMs: 86400000 }, // 24h
|
|
269
|
+
skillId: skill.id,
|
|
270
|
+
prompt: 'Summarize my workspace changes since yesterday',
|
|
271
|
+
deliveryMode: 'notification',
|
|
193
272
|
})
|
|
194
273
|
```
|
|
195
274
|
|
|
196
275
|
## Features
|
|
197
276
|
|
|
277
|
+
- **Two agent modes** — WebView (instant cold start) or Node.js worker (full isolation)
|
|
278
|
+
- **Native streaming HTTP** — OkHttp (Android) + URLSession (iOS) bypass CORS, stream SSE chunks as `ReadableStream`
|
|
198
279
|
- **Real-time streaming** — text deltas, tool use, and thinking events
|
|
199
280
|
- **Multi-turn conversations** — session persistence via native SQLite
|
|
200
281
|
- **OAuth PKCE + API key** — sign in with Claude Max or use a direct API key
|
|
@@ -202,8 +283,12 @@ await engine.init({
|
|
|
202
283
|
- **Code execution** — JavaScript (sandbox) + Python (Pyodide/WebAssembly)
|
|
203
284
|
- **Git** — clone, commit, push, diff via isomorphic-git
|
|
204
285
|
- **MCP device tools** — extensible via Model Context Protocol
|
|
205
|
-
- **Tool approval gate** — approve/deny tool executions before they run
|
|
286
|
+
- **Tool approval gate** — approve/deny tool executions before they run (120s TTL)
|
|
206
287
|
- **Agent steering** — inject follow-up instructions into a running turn
|
|
288
|
+
- **Background heartbeat** — scheduled agent check-ins via MobileCron + WorkManager
|
|
289
|
+
- **Cron jobs** — recurring agent tasks with skills, schedules, and delivery modes
|
|
290
|
+
- **On-device vector memory** — store/recall/search via LanceDB (capacitor-lancedb)
|
|
291
|
+
- **Vite plugin** — stubs Node.js-only transitive deps for browser bundling
|
|
207
292
|
|
|
208
293
|
## API Reference
|
|
209
294
|
|
|
@@ -211,18 +296,38 @@ await engine.init({
|
|
|
211
296
|
|
|
212
297
|
| Method | Description |
|
|
213
298
|
|--------|-------------|
|
|
214
|
-
| `init(options?)` | Start
|
|
299
|
+
| `init(options?)` | Start engine. Options: `useWebViewAgent`, `tools`, `mobileCron`, `enableBridge`, `enableStomp` |
|
|
215
300
|
| `sendMessage(prompt, agentId?)` | Send a prompt to the agent |
|
|
216
301
|
| `stopTurn()` | Cancel the running agent turn |
|
|
217
|
-
| `
|
|
302
|
+
| `respondToPreExecute(toolCallId, args, deny?)` | Approve/deny a tool execution |
|
|
218
303
|
| `steerAgent(text)` | Inject a follow-up instruction |
|
|
219
|
-
| `updateConfig(config)` | Update
|
|
220
|
-
| `
|
|
221
|
-
| `
|
|
304
|
+
| `updateConfig(config)` | Update config (auth, model, provider) |
|
|
305
|
+
| `exchangeOAuthCode(tokenUrl, body)` | OAuth token exchange via native HTTP |
|
|
306
|
+
| `getAuthStatus(provider?)` | Get current auth profile status |
|
|
307
|
+
| `getModels(provider?)` | List available models |
|
|
222
308
|
| `readFile(path)` / `writeFile(path, content)` | Workspace file operations |
|
|
223
309
|
| `listSessions()` / `resumeSession(key)` | Session management |
|
|
224
310
|
| `invokeTool(toolName, args?)` | Call a tool directly |
|
|
225
|
-
| `addListener(eventName, handler)` | Subscribe to
|
|
311
|
+
| `addListener(eventName, handler)` | Subscribe to events |
|
|
312
|
+
|
|
313
|
+
#### Scheduler & Heartbeat
|
|
314
|
+
|
|
315
|
+
| Method | Description |
|
|
316
|
+
|--------|-------------|
|
|
317
|
+
| `setSchedulerConfig(config)` | Set scheduler state (enabled, mode, runOnCharging, activeHours) |
|
|
318
|
+
| `getSchedulerConfig()` | Read scheduler + heartbeat config |
|
|
319
|
+
| `setHeartbeat(config)` | Configure heartbeat (enabled, interval, skillId, prompt) |
|
|
320
|
+
| `triggerHeartbeatWake(source?)` | Trigger immediate heartbeat (`manual` bypasses scheduler gate) |
|
|
321
|
+
|
|
322
|
+
#### Cron Jobs & Skills
|
|
323
|
+
|
|
324
|
+
| Method | Description |
|
|
325
|
+
|--------|-------------|
|
|
326
|
+
| `addCronJob(job)` / `updateCronJob(id, patch)` / `removeCronJob(id)` | CRUD for cron jobs |
|
|
327
|
+
| `listCronJobs()` / `runCronJob(id)` | List or manually trigger a job |
|
|
328
|
+
| `getCronRunHistory(jobId?, limit?)` | Get historical run records |
|
|
329
|
+
| `addSkill(skill)` / `updateSkill(id, patch)` / `removeSkill(id)` | CRUD for skills |
|
|
330
|
+
| `listSkills()` | List all defined skills |
|
|
226
331
|
|
|
227
332
|
### Events
|
|
228
333
|
|
|
@@ -231,8 +336,11 @@ await engine.init({
|
|
|
231
336
|
| `agentEvent` | Text delta, tool use, tool result, or thinking update |
|
|
232
337
|
| `agentCompleted` | Agent turn finished (includes token usage) |
|
|
233
338
|
| `agentError` | Agent execution failed |
|
|
234
|
-
| `
|
|
339
|
+
| `toolPreExecute` | Agent wants to run a tool (approval gate) |
|
|
235
340
|
| `workerReady` | Node.js worker initialized |
|
|
341
|
+
| `heartbeatStarted` / `heartbeatCompleted` / `heartbeatSkipped` | Heartbeat lifecycle |
|
|
342
|
+
| `cronJobStarted` / `cronJobCompleted` / `cronJobError` | Cron job lifecycle |
|
|
343
|
+
| `schedulerStatus` | Scheduler state changed (next run times) |
|
|
236
344
|
|
|
237
345
|
## Documentation
|
|
238
346
|
|
|
@@ -243,6 +351,8 @@ await engine.init({
|
|
|
243
351
|
## Related Packages
|
|
244
352
|
|
|
245
353
|
- [capacitor-mobile-claw-device-tools](https://www.npmjs.com/package/capacitor-mobile-claw-device-tools) — 64+ pre-built device tools (camera, clipboard, sensors, SSH, etc.)
|
|
354
|
+
- [capacitor-lancedb](https://www.npmjs.com/package/capacitor-lancedb) — on-device vector database for agent memory
|
|
355
|
+
- [capacitor-mobilecron](https://www.npmjs.com/package/capacitor-mobilecron) — native background scheduling (WorkManager / BGTaskScheduler)
|
|
246
356
|
|
|
247
357
|
## Contributing
|
|
248
358
|
|
|
@@ -255,13 +365,17 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, workflow, and guid
|
|
|
255
365
|
| Mobile framework | [Capacitor 8](https://capacitorjs.com/) |
|
|
256
366
|
| Agent core | [Pi](https://www.npmjs.com/package/@mariozechner/pi-ai) by Mario Zechner |
|
|
257
367
|
| Embedded runtime | [@choreruiz/capacitor-node-js](https://github.com/rogelioRuiz/capacitor-node-js) |
|
|
368
|
+
| Native HTTP | OkHttp (Android) + URLSession (iOS) — streaming, CORS bypass |
|
|
258
369
|
| Tool protocol | [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) |
|
|
259
370
|
| LLM provider | [Anthropic Claude](https://anthropic.com/) |
|
|
371
|
+
| Vector memory | [LanceDB](https://lancedb.com/) via [capacitor-lancedb](https://www.npmjs.com/package/capacitor-lancedb) |
|
|
372
|
+
| Background scheduling | [capacitor-mobilecron](https://www.npmjs.com/package/capacitor-mobilecron) (WorkManager / BGTaskScheduler) |
|
|
260
373
|
| Git | [isomorphic-git](https://isomorphic-git.org/) |
|
|
261
374
|
| Database | [@capacitor-community/sqlite](https://github.com/nicepkg/capacitor-community-sqlite) (native SQLite via JSON-RPC bridge) |
|
|
262
375
|
| Python | [Pyodide](https://pyodide.org/) (CPython via WebAssembly) |
|
|
263
376
|
| Type system | TypeScript (strict mode) |
|
|
264
|
-
|
|
|
377
|
+
| Lint | [Biome](https://biomejs.dev/) |
|
|
378
|
+
| Tests | [Vitest](https://vitest.dev/) (64 unit) + Sentinel E2E (111 on-device) |
|
|
265
379
|
|
|
266
380
|
## Acknowledgments
|
|
267
381
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "capacitor-mobile-claw",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.4",
|
|
4
4
|
"description": "On-device AI agent engine for Capacitor apps — embedded Node.js worker with LLM, file tools, code execution, git, and extensible MCP server",
|
|
5
5
|
"main": "dist/esm/index.js",
|
|
6
6
|
"types": "dist/esm/index.d.ts",
|