nextclaw 0.5.3 → 0.5.5

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/dist/cli/index.js CHANGED
@@ -954,6 +954,7 @@ var CliRuntime = class {
954
954
  logo;
955
955
  restartCoordinator;
956
956
  serviceRestartTask = null;
957
+ selfRelaunchArmed = false;
957
958
  constructor(options = {}) {
958
959
  this.logo = options.logo ?? LOGO;
959
960
  this.restartCoordinator = new RestartCoordinator({
@@ -1002,7 +1003,99 @@ var CliRuntime = class {
1002
1003
  this.serviceRestartTask = null;
1003
1004
  }
1004
1005
  }
1006
+ armManagedServiceRelaunch(params) {
1007
+ const strategy = params.strategy ?? "background-service-or-manual";
1008
+ if (strategy !== "background-service-or-exit" && strategy !== "exit-process") {
1009
+ return;
1010
+ }
1011
+ if (this.selfRelaunchArmed) {
1012
+ return;
1013
+ }
1014
+ const state = readServiceState();
1015
+ if (!state || state.pid !== process.pid) {
1016
+ return;
1017
+ }
1018
+ const uiPort = typeof state.uiPort === "number" && Number.isFinite(state.uiPort) ? state.uiPort : 18791;
1019
+ const delayMs = typeof params.delayMs === "number" && Number.isFinite(params.delayMs) ? Math.max(0, Math.floor(params.delayMs)) : 100;
1020
+ const cliPath = process.env.NEXTCLAW_SELF_RELAUNCH_CLI?.trim() || fileURLToPath2(new URL("./index.js", import.meta.url));
1021
+ const startArgs = [cliPath, "start", "--ui-port", String(uiPort)];
1022
+ const serviceStatePath = resolve4(getDataDir2(), "run", "service.json");
1023
+ const helperScript = [
1024
+ 'const { spawnSync } = require("node:child_process");',
1025
+ 'const { readFileSync } = require("node:fs");',
1026
+ `const parentPid = ${process.pid};`,
1027
+ `const delayMs = ${delayMs};`,
1028
+ "const maxWaitMs = 120000;",
1029
+ "const retryIntervalMs = 1000;",
1030
+ "const startTimeoutMs = 60000;",
1031
+ `const nodePath = ${JSON.stringify(process.execPath)};`,
1032
+ `const startArgs = ${JSON.stringify(startArgs)};`,
1033
+ `const serviceStatePath = ${JSON.stringify(serviceStatePath)};`,
1034
+ "function isRunning(pid) {",
1035
+ " try {",
1036
+ " process.kill(pid, 0);",
1037
+ " return true;",
1038
+ " } catch {",
1039
+ " return false;",
1040
+ " }",
1041
+ "}",
1042
+ "function hasReplacementService() {",
1043
+ " try {",
1044
+ ' const raw = readFileSync(serviceStatePath, "utf-8");',
1045
+ " const state = JSON.parse(raw);",
1046
+ " const pid = Number(state?.pid);",
1047
+ " return Number.isFinite(pid) && pid > 0 && pid !== parentPid && isRunning(pid);",
1048
+ " } catch {",
1049
+ " return false;",
1050
+ " }",
1051
+ "}",
1052
+ "function tryStart() {",
1053
+ " spawnSync(nodePath, startArgs, {",
1054
+ ' stdio: "ignore",',
1055
+ " env: process.env,",
1056
+ " timeout: startTimeoutMs",
1057
+ " });",
1058
+ "}",
1059
+ "setTimeout(() => {",
1060
+ " const startedAt = Date.now();",
1061
+ " const tick = () => {",
1062
+ " if (hasReplacementService()) {",
1063
+ " process.exit(0);",
1064
+ " return;",
1065
+ " }",
1066
+ " if (Date.now() - startedAt >= maxWaitMs) {",
1067
+ " process.exit(0);",
1068
+ " return;",
1069
+ " }",
1070
+ " tryStart();",
1071
+ " if (hasReplacementService()) {",
1072
+ " process.exit(0);",
1073
+ " return;",
1074
+ " }",
1075
+ " setTimeout(tick, retryIntervalMs);",
1076
+ " };",
1077
+ " tick();",
1078
+ "}, delayMs);"
1079
+ ].join("\n");
1080
+ try {
1081
+ const helper = spawn2(process.execPath, ["-e", helperScript], {
1082
+ detached: true,
1083
+ stdio: "ignore",
1084
+ env: process.env
1085
+ });
1086
+ helper.unref();
1087
+ this.selfRelaunchArmed = true;
1088
+ console.warn(`Gateway self-restart armed (${params.reason}).`);
1089
+ } catch (error) {
1090
+ console.error(`Failed to arm gateway self-restart: ${String(error)}`);
1091
+ }
1092
+ }
1005
1093
  async requestRestart(params) {
1094
+ this.armManagedServiceRelaunch({
1095
+ reason: params.reason,
1096
+ strategy: params.strategy,
1097
+ delayMs: params.delayMs
1098
+ });
1006
1099
  const result = await this.restartCoordinator.requestRestart({
1007
1100
  reason: params.reason,
1008
1101
  strategy: params.strategy,
@@ -2786,6 +2879,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
2786
2879
  { source: "USER.md", target: "USER.md" },
2787
2880
  { source: "IDENTITY.md", target: "IDENTITY.md" },
2788
2881
  { source: "TOOLS.md", target: "TOOLS.md" },
2882
+ { source: "USAGE.md", target: "USAGE.md" },
2789
2883
  { source: "BOOT.md", target: "BOOT.md" },
2790
2884
  { source: "BOOTSTRAP.md", target: "BOOTSTRAP.md" },
2791
2885
  { source: "HEARTBEAT.md", target: "HEARTBEAT.md" },
@@ -2830,10 +2924,6 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
2830
2924
  return 0;
2831
2925
  }
2832
2926
  const force = Boolean(options.force);
2833
- const existing = readdirSync(targetDir, { withFileTypes: true }).filter((entry) => !entry.name.startsWith("."));
2834
- if (!force && existing.length > 0) {
2835
- return 0;
2836
- }
2837
2927
  let seeded = 0;
2838
2928
  for (const entry of readdirSync(sourceDir, { withFileTypes: true })) {
2839
2929
  if (!entry.isDirectory()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nextclaw",
3
- "version": "0.5.3",
3
+ "version": "0.5.5",
4
4
  "description": "Lightweight personal AI assistant with CLI, multi-provider routing, and channel integrations.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -38,9 +38,9 @@
38
38
  "dependencies": {
39
39
  "chokidar": "^3.6.0",
40
40
  "commander": "^12.1.0",
41
- "@nextclaw/core": "^0.5.1",
41
+ "@nextclaw/core": "^0.5.3",
42
42
  "@nextclaw/server": "^0.3.7",
43
- "@nextclaw/openclaw-compat": "^0.1.3"
43
+ "@nextclaw/openclaw-compat": "^0.1.4"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/node": "^20.17.6",
@@ -57,7 +57,7 @@
57
57
  "scripts": {
58
58
  "dev": "tsx watch --tsconfig tsconfig.json src/cli/index.ts",
59
59
  "dev:build": "tsx src/cli/index.ts",
60
- "build": "tsup src/index.ts src/cli/index.ts --format esm --dts --out-dir dist && node scripts/copy-ui-dist.mjs",
60
+ "build": "node scripts/sync-usage-template.mjs && tsup src/index.ts src/cli/index.ts --format esm --dts --out-dir dist && node scripts/copy-ui-dist.mjs",
61
61
  "start": "node dist/cli.js",
62
62
  "lint": "eslint .",
63
63
  "tsc": "tsc -p tsconfig.json",
@@ -14,6 +14,7 @@ Before doing anything else:
14
14
  2. Read `USER.md` (who you are helping)
15
15
  3. Read `memory/YYYY-MM-DD.md` for today and yesterday
16
16
  4. If in the main session with your human, also read `MEMORY.md`
17
+ 5. For NextClaw self-management tasks (service/plugins/channels/config/cron), read `USAGE.md` first
17
18
 
18
19
  ## Memory
19
20
 
@@ -0,0 +1,617 @@
1
+ <!-- Generated by packages/nextclaw/scripts/sync-usage-template.mjs -->
2
+ <!-- Do not edit this file directly; edit docs/USAGE.md instead. -->
3
+ # NextClaw User Guide
4
+
5
+ This guide covers installation, configuration, channels, tools, automation, and troubleshooting for NextClaw.
6
+
7
+ ---
8
+
9
+ ## AI Self-Management Contract
10
+
11
+ When NextClaw AI needs to operate the product itself (status/doctor/plugins/channels/config/cron), follow these rules:
12
+
13
+ 1. **Read this guide first** (`USAGE.md`) before executing management commands.
14
+ 2. **Prefer machine-readable output** (`--json`) whenever available.
15
+ 3. **Close the loop after changes** with `nextclaw status --json` (and `nextclaw doctor --json` when needed).
16
+ 4. **Be explicit about restart semantics** (hot-apply, auto-restart, or manual restart required).
17
+ 5. **Never invent commands**; use documented commands or `nextclaw --help` / `nextclaw <subcommand> --help`.
18
+
19
+ ---
20
+
21
+ ## Table of contents
22
+
23
+ - [AI Self-Management Contract](#ai-self-management-contract)
24
+ - [Quick Start](#quick-start)
25
+ - [Configuration](#configuration)
26
+ - [Workspace](#workspace)
27
+ - [Commands](#commands)
28
+ - [Plugins (OpenClaw compatibility)](#plugins-openclaw-compatibility)
29
+ - [Channels](#channels)
30
+ - [Tools](#tools)
31
+ - [Cron & Heartbeat](#cron--heartbeat)
32
+ - [Troubleshooting](#troubleshooting)
33
+
34
+ ---
35
+
36
+ ## Quick Start
37
+
38
+ 1. Install:
39
+
40
+ ```bash
41
+ npm i -g nextclaw
42
+ ```
43
+
44
+ 2. Start the service (gateway + config UI in the background):
45
+
46
+ ```bash
47
+ nextclaw start
48
+ ```
49
+
50
+ 3. Open **http://127.0.0.1:18791** in your browser. Set a provider (e.g. OpenRouter) and model in the UI.
51
+
52
+ 4. Optionally run `nextclaw init` to create a workspace with agent templates, or chat from the CLI:
53
+
54
+ ```bash
55
+ nextclaw agent -m "Hello!"
56
+ ```
57
+
58
+ 5. Stop the service when done:
59
+
60
+ ```bash
61
+ nextclaw stop
62
+ ```
63
+
64
+ ---
65
+
66
+ ## Configuration
67
+
68
+ - **Config file:** `~/.nextclaw/config.json`
69
+ - **Data directory:** Override with `NEXTCLAW_HOME=/path/to/dir` (config path becomes `$NEXTCLAW_HOME/config.json`).
70
+
71
+ ### Minimal config
72
+
73
+ ```json
74
+ {
75
+ "providers": {
76
+ "openrouter": { "apiKey": "sk-or-v1-xxx" }
77
+ },
78
+ "agents": {
79
+ "defaults": { "model": "minimax/MiniMax-M2.5" }
80
+ }
81
+ }
82
+ ```
83
+
84
+ ### Provider examples
85
+
86
+ **OpenRouter (recommended)**
87
+
88
+ ```json
89
+ {
90
+ "providers": { "openrouter": { "apiKey": "sk-or-v1-xxx" } },
91
+ "agents": { "defaults": { "model": "minimax/MiniMax-M2.5" } }
92
+ }
93
+ ```
94
+
95
+ **MiniMax (Mainland China)**
96
+
97
+ ```json
98
+ {
99
+ "providers": {
100
+ "minimax": {
101
+ "apiKey": "sk-api-xxx",
102
+ "apiBase": "https://api.minimaxi.com/v1"
103
+ }
104
+ },
105
+ "agents": { "defaults": { "model": "minimax/MiniMax-M2.5" } }
106
+ }
107
+ ```
108
+
109
+ **Local vLLM (or any OpenAI-compatible server)**
110
+
111
+ ```json
112
+ {
113
+ "providers": {
114
+ "vllm": {
115
+ "apiKey": "dummy",
116
+ "apiBase": "http://localhost:8000/v1"
117
+ }
118
+ },
119
+ "agents": { "defaults": { "model": "meta-llama/Llama-3.1-8B-Instruct" } }
120
+ }
121
+ ```
122
+
123
+ Supported providers include OpenRouter, OpenAI, Anthropic, MiniMax, Moonshot, Gemini, DeepSeek, DashScope, Zhipu, Groq, vLLM, and AiHubMix. You can configure them in the UI or by editing `config.json`.
124
+
125
+ ### Runtime config apply behavior (no restart)
126
+
127
+ When the gateway is already running, config changes from the UI or `nextclaw config set` are hot-applied for these paths:
128
+
129
+ - `providers.*`
130
+ - `channels.*`
131
+ - `agents.defaults.model`
132
+ - `agents.defaults.maxToolIterations`
133
+ - `agents.defaults.maxTokens`
134
+ - `agents.defaults.temperature`
135
+ - `agents.context.*`
136
+ - `tools.*`
137
+
138
+ Restart is still required for:
139
+
140
+ - `plugins.*`
141
+ - UI bind port (`--port` / `--ui-port`)
142
+
143
+ To confirm hot reload succeeded, check gateway console logs or `${NEXTCLAW_HOME:-~/.nextclaw}/logs/service.log` for messages like `Config reload: ... applied.`
144
+
145
+ ---
146
+
147
+ ## Workspace
148
+
149
+ - **Default path:** `~/.nextclaw/workspace`
150
+ - Override in config:
151
+
152
+ ```json
153
+ {
154
+ "agents": { "defaults": { "workspace": "~/my-nextclaw" } }
155
+ }
156
+ ```
157
+
158
+ Initialize the workspace (creates template files if missing):
159
+
160
+ ```bash
161
+ nextclaw init
162
+ ```
163
+
164
+ Use `nextclaw init --force` to overwrite existing template files.
165
+
166
+ Created under the workspace:
167
+
168
+ | File / folder | Purpose |
169
+ |-----------------|----------------------------------|
170
+ | `AGENTS.md` | System instructions for the agent |
171
+ | `SOUL.md` | Personality and values |
172
+ | `USER.md` | User profile hints |
173
+ | `IDENTITY.md` | Identity context |
174
+ | `TOOLS.md` | Tool usage guidelines |
175
+ | `USAGE.md` | CLI operation guide for users and AI |
176
+ | `BOOT.md` / `BOOTSTRAP.md` | Boot context |
177
+ | `HEARTBEAT.md` | Tasks checked periodically |
178
+ | `memory/MEMORY.md` | Long-term notes |
179
+ | `skills/` | Custom skills |
180
+
181
+ **Heartbeat:** When the gateway is running, `HEARTBEAT.md` in the workspace is checked every 30 minutes. If it contains actionable tasks, the agent will process them.
182
+
183
+ ---
184
+
185
+ ## Commands
186
+
187
+ | Command | Description |
188
+ |---------|-------------|
189
+ | `nextclaw start` | Start gateway + UI in the background |
190
+ | `nextclaw restart` | Restart the background service with optional start flags |
191
+ | `nextclaw stop` | Stop the background service |
192
+ | `nextclaw ui` | Start UI and gateway in the foreground |
193
+ | `nextclaw gateway` | Start gateway only (for channels) |
194
+ | `nextclaw serve` | Run gateway + UI in the foreground (no background) |
195
+ | `nextclaw agent -m "message"` | Send a one-off message to the agent |
196
+ | `nextclaw agent` | Interactive chat in the terminal |
197
+ | `nextclaw status` | Show runtime process/health/config status (`--json`, `--verbose`, `--fix`) |
198
+ | `nextclaw init` | Initialize workspace and template files |
199
+ | `nextclaw init --force` | Re-run init and overwrite templates |
200
+ | `nextclaw update` | Self-update the CLI |
201
+ | `nextclaw channels status` | Show enabled channels and status |
202
+ | `nextclaw doctor` | Run runtime diagnostics (`--json`, `--verbose`, `--fix`) |
203
+ | `nextclaw channels login` | Open QR login for supported channels |
204
+ | `nextclaw channels add --channel <id> [--code/--token/...]` | Run plugin channel setup (OpenClaw-compatible) and write config |
205
+ | `nextclaw cron list` | List scheduled jobs |
206
+ | `nextclaw cron add ...` | Add a cron job (see [Cron](#cron--heartbeat)) |
207
+ | `nextclaw cron remove <jobId>` | Remove a job |
208
+ | `nextclaw cron enable <jobId>` | Enable a job (use `--disable` to disable) |
209
+ | `nextclaw cron run <jobId>` | Run a job once (optionally with `--force` if disabled) |
210
+ | `nextclaw skills install <slug>` | Install a skill from ClawHub |
211
+ | `nextclaw clawhub install <slug>` | Same as `skills install` |
212
+ | `nextclaw plugins list` | List discovered OpenClaw-compatible plugins |
213
+ | `nextclaw plugins info <id>` | Show details of a plugin |
214
+ | `nextclaw config get <path>` | Get config value by path (use `--json` for structured output) |
215
+ | `nextclaw config set <path> <value>` | Set config value by path (use `--json` to parse value as JSON) |
216
+ | `nextclaw config unset <path>` | Remove config value by path |
217
+ | `nextclaw plugins install <path-or-spec>` | Install from local path, archive, or npm package |
218
+ | `nextclaw plugins enable <id>` | Enable a plugin in config |
219
+ | `nextclaw plugins disable <id>` | Disable a plugin in config |
220
+ | `nextclaw plugins uninstall <id>` | Remove plugin config/install record (supports `--dry-run`, `--force`, `--keep-files`) |
221
+ | `nextclaw plugins doctor` | Diagnose plugin load conflicts/errors |
222
+
223
+ Gateway options (when running `nextclaw gateway` or `nextclaw start`):
224
+
225
+ - `--ui` — enable the UI server with the gateway
226
+ - `--ui-port <port>` — UI port (default 18791 for start)
227
+ - `--ui-open` — open the browser when the UI starts
228
+
229
+ If service is already running, new UI port flags do not hot-apply; use `nextclaw restart ...` to apply them.
230
+
231
+ Status/diagnostics tips:
232
+
233
+ - `nextclaw status` shows runtime truth (process + health + config summary).
234
+ - `nextclaw status --json` outputs machine-readable status and sets exit code (`0` healthy, `1` degraded, `2` stopped).
235
+ - `nextclaw status --fix` safely clears stale service state if PID is dead.
236
+ - `nextclaw doctor` runs additional checks (state coherence, health, port availability, provider readiness).
237
+
238
+ ---
239
+
240
+ ## Plugins (OpenClaw compatibility)
241
+
242
+ NextClaw supports OpenClaw-compatible plugins while keeping compatibility logic isolated in `@nextclaw/openclaw-compat`.
243
+ For architecture boundaries and capability matrix, see [OpenClaw plugin compatibility guide](./openclaw-plugin-compat.md).
244
+
245
+ Typical flow:
246
+
247
+ ```bash
248
+ # 1) Inspect discovered plugins
249
+ nextclaw plugins list
250
+
251
+ # 2) Install (path/archive/npm)
252
+ nextclaw plugins install ./my-plugin
253
+ nextclaw plugins install ./my-plugin.tgz
254
+ nextclaw plugins install @scope/openclaw-plugin
255
+
256
+ # 3) Inspect and toggle
257
+ nextclaw plugins info my-plugin
258
+ nextclaw config get plugins.entries.my-plugin.config --json
259
+ nextclaw plugins disable my-plugin
260
+ nextclaw plugins enable my-plugin
261
+
262
+ # 4) Uninstall
263
+ nextclaw plugins uninstall my-plugin --dry-run
264
+ nextclaw plugins uninstall my-plugin --force
265
+ ```
266
+
267
+ Notes:
268
+
269
+ - Plugin config is merged under `plugins.entries.<id>.config`.
270
+ - `plugins uninstall --keep-config` is accepted as a backward-compatible alias of `--keep-files`.
271
+ - If a plugin tool/channel/provider conflicts with a built-in capability, NextClaw rejects the conflicting registration and reports diagnostics.
272
+
273
+ ---
274
+
275
+ ## Self-update
276
+
277
+ Use the built-in updater:
278
+
279
+ ```bash
280
+ nextclaw update
281
+ ```
282
+
283
+ Behavior:
284
+
285
+ - If `NEXTCLAW_UPDATE_COMMAND` is set, the CLI executes it (useful for custom update flows).
286
+ - Otherwise it falls back to `npm i -g nextclaw`.
287
+ - If the background service is running, restart it after the update to apply changes.
288
+ - When update is triggered from the running gateway (agent `update.run`), NextClaw arms a self-relaunch helper before exiting, so the service comes back automatically (like an OS reboot flow).
289
+
290
+ If the gateway is running, you can also ask the agent to update; the agent will call the gateway update tool only when you explicitly request it, and restart/relaunch will be scheduled afterward.
291
+
292
+ ---
293
+
294
+ ## Channels
295
+
296
+ All message channels use a common **allowFrom** rule:
297
+
298
+ - **Empty `allowFrom`** (`[]`): allow all senders.
299
+ - **Non-empty `allowFrom`**: only messages from the listed user IDs are accepted.
300
+
301
+ Configure channels in the UI at http://127.0.0.1:18791 or in `~/.nextclaw/config.json` under `channels`.
302
+
303
+ ### Discord
304
+
305
+ 1. Create a bot in the [Discord Developer Portal](https://discord.com/developers/applications) and get the bot token.
306
+ 2. Enable **MESSAGE CONTENT INTENT** for the bot.
307
+ 3. Invite the bot to your server with permissions to read and send messages.
308
+
309
+ ```json
310
+ {
311
+ "channels": {
312
+ "discord": {
313
+ "enabled": true,
314
+ "token": "YOUR_BOT_TOKEN",
315
+ "allowFrom": []
316
+ }
317
+ }
318
+ }
319
+ ```
320
+
321
+ ### Telegram
322
+
323
+ 1. Create a bot via [@BotFather](https://t.me/BotFather) and get the token.
324
+ 2. Get your user ID (e.g. from [@userinfobot](https://t.me/userinfobot)).
325
+ 3. Add your user ID to `allowFrom` to restrict who can use the bot.
326
+
327
+ ```json
328
+ {
329
+ "channels": {
330
+ "telegram": {
331
+ "enabled": true,
332
+ "token": "YOUR_BOT_TOKEN",
333
+ "allowFrom": ["YOUR_USER_ID"]
334
+ }
335
+ }
336
+ }
337
+ ```
338
+
339
+ Optional: set `"proxy": "http://localhost:7890"` (or your proxy URL) for network access.
340
+
341
+ ### Slack
342
+
343
+ Socket mode is the typical setup. You need a **Bot Token** and an **App-Level Token** (with `connections:write`).
344
+
345
+ ```json
346
+ {
347
+ "channels": {
348
+ "slack": {
349
+ "enabled": true,
350
+ "mode": "socket",
351
+ "botToken": "xoxb-...",
352
+ "appToken": "xapp-...",
353
+ "dm": { "enabled": true, "allowFrom": [] }
354
+ }
355
+ }
356
+ }
357
+ ```
358
+
359
+ - `dm.enabled`: allow DMs to the bot.
360
+ - `dm.allowFrom`: restrict DMs to these user IDs; empty means allow all.
361
+
362
+ ### Feishu (Lark)
363
+
364
+ Create an app in the [Feishu open platform](https://open.feishu.com/), obtain App ID, App Secret, and (if using encryption) Encrypt Key and Verification Token.
365
+
366
+ ```json
367
+ {
368
+ "channels": {
369
+ "feishu": {
370
+ "enabled": true,
371
+ "appId": "YOUR_APP_ID",
372
+ "appSecret": "YOUR_APP_SECRET",
373
+ "encryptKey": "",
374
+ "verificationToken": "",
375
+ "allowFrom": []
376
+ }
377
+ }
378
+ }
379
+ ```
380
+
381
+ ### DingTalk
382
+
383
+ Create an app in the [DingTalk open platform](https://open.dingtalk.com/) and get Client ID and Client Secret.
384
+
385
+ ```json
386
+ {
387
+ "channels": {
388
+ "dingtalk": {
389
+ "enabled": true,
390
+ "clientId": "YOUR_CLIENT_ID",
391
+ "clientSecret": "YOUR_CLIENT_SECRET",
392
+ "allowFrom": []
393
+ }
394
+ }
395
+ }
396
+ ```
397
+
398
+ ### WhatsApp
399
+
400
+ WhatsApp typically requires a bridge (e.g. a companion service). Configure the bridge URL and optional allowlist:
401
+
402
+ ```json
403
+ {
404
+ "channels": {
405
+ "whatsapp": {
406
+ "enabled": true,
407
+ "bridgeUrl": "ws://localhost:3001",
408
+ "allowFrom": []
409
+ }
410
+ }
411
+ }
412
+ ```
413
+
414
+ Use `nextclaw channels login` when the bridge supports QR-based linking.
415
+
416
+ ### Email
417
+
418
+ Configure IMAP (inbox) and SMTP (sending). The agent can read and reply to emails.
419
+
420
+ ```json
421
+ {
422
+ "channels": {
423
+ "email": {
424
+ "enabled": true,
425
+ "consentGranted": true,
426
+ "imapHost": "imap.example.com",
427
+ "imapPort": 993,
428
+ "imapUsername": "you@example.com",
429
+ "imapPassword": "YOUR_PASSWORD",
430
+ "imapMailbox": "INBOX",
431
+ "imapUseSsl": true,
432
+ "smtpHost": "smtp.example.com",
433
+ "smtpPort": 587,
434
+ "smtpUsername": "you@example.com",
435
+ "smtpPassword": "YOUR_PASSWORD",
436
+ "smtpUseTls": true,
437
+ "fromAddress": "you@example.com",
438
+ "autoReplyEnabled": true,
439
+ "pollIntervalSeconds": 30,
440
+ "allowFrom": []
441
+ }
442
+ }
443
+ }
444
+ ```
445
+
446
+ Set `consentGranted` to `true` after you understand that the agent will read and send mail. Use `allowFrom` to restrict to certain sender addresses if desired.
447
+
448
+ ### QQ
449
+
450
+ Use the QQ open platform app credentials.
451
+
452
+ ```json
453
+ {
454
+ "channels": {
455
+ "qq": {
456
+ "enabled": true,
457
+ "appId": "YOUR_APP_ID",
458
+ "secret": "YOUR_SECRET",
459
+ "markdownSupport": false,
460
+ "allowFrom": []
461
+ }
462
+ }
463
+ }
464
+ ```
465
+
466
+ ### Mochat
467
+
468
+ Mochat uses a claw token and optional socket URL. Configure base URL, socket, and (optionally) sessions/panels and group rules.
469
+
470
+ ```json
471
+ {
472
+ "channels": {
473
+ "mochat": {
474
+ "enabled": true,
475
+ "baseUrl": "https://mochat.io",
476
+ "socketUrl": "",
477
+ "clawToken": "YOUR_CLAW_TOKEN",
478
+ "agentUserId": "",
479
+ "sessions": [],
480
+ "panels": [],
481
+ "allowFrom": []
482
+ }
483
+ }
484
+ }
485
+ ```
486
+
487
+ After changing channel config, NextClaw hot-reloads channel runtime automatically when the gateway is running.
488
+
489
+ ---
490
+
491
+ ## Tools
492
+
493
+ ### Web search (Brave)
494
+
495
+ Add a Brave Search API key to enable web search for the agent:
496
+
497
+ ```json
498
+ {
499
+ "tools": {
500
+ "web": {
501
+ "search": { "apiKey": "YOUR_BRAVE_KEY", "maxResults": 5 }
502
+ }
503
+ }
504
+ }
505
+ ```
506
+
507
+ ### Command execution (exec)
508
+
509
+ Allow the agent to run shell commands:
510
+
511
+ ```json
512
+ {
513
+ "tools": {
514
+ "exec": { "timeout": 60 }
515
+ },
516
+ "restrictToWorkspace": false
517
+ }
518
+ ```
519
+
520
+ - `timeout`: max seconds per command.
521
+ - `restrictToWorkspace`: if `true`, commands are restricted to the agent workspace directory; if `false`, the agent can run commands in other paths (use with care).
522
+
523
+ ---
524
+
525
+ ## Cron & Heartbeat
526
+
527
+ ### Cron
528
+
529
+ Schedule one-off or recurring tasks. The agent receives the message at the scheduled time.
530
+
531
+ List jobs:
532
+
533
+ ```bash
534
+ nextclaw cron list
535
+ ```
536
+
537
+ Add a one-time job (run at a specific time, ISO format):
538
+
539
+ ```bash
540
+ nextclaw cron add -n "reminder" -m "Stand up and stretch" --at "2026-02-15T09:00:00"
541
+ ```
542
+
543
+ Add a recurring job (cron expression):
544
+
545
+ ```bash
546
+ nextclaw cron add -n "daily-summary" -m "Summarize yesterday" -c "0 9 * * *"
547
+ ```
548
+
549
+ Add a job that runs every N seconds:
550
+
551
+ ```bash
552
+ nextclaw cron add -n "ping" -m "Ping" -e 3600
553
+ ```
554
+
555
+ Optional: deliver the agent’s reply to a channel:
556
+
557
+ ```bash
558
+ nextclaw cron add -n "daily" -m "Daily briefing" -c "0 9 * * *" --deliver --to <recipient> --channel <channel>
559
+ ```
560
+
561
+ Remove, enable, or disable a job:
562
+
563
+ ```bash
564
+ nextclaw cron remove <jobId>
565
+ nextclaw cron enable <jobId>
566
+ nextclaw cron enable <jobId> --disable
567
+ ```
568
+
569
+ Run a job once (e.g. for testing):
570
+
571
+ ```bash
572
+ nextclaw cron run <jobId>
573
+ ```
574
+
575
+ ### Heartbeat
576
+
577
+ When the gateway is running, it checks the workspace file `HEARTBEAT.md` periodically (e.g. every 30 minutes). If the file contains actionable tasks, the agent processes them. Edit `HEARTBEAT.md` in your workspace to add or change tasks.
578
+
579
+ ---
580
+
581
+ ## UI (optional)
582
+
583
+ You can tune the UI server in config:
584
+
585
+ ```json
586
+ {
587
+ "ui": {
588
+ "enabled": true,
589
+ "host": "0.0.0.0",
590
+ "port": 18791,
591
+ "open": false
592
+ }
593
+ }
594
+ ```
595
+
596
+ - `enabled`: whether the UI server is started with the gateway (e.g. when using `nextclaw start`).
597
+ - `host` / `port`: bind address and port; `ui.host` is read-only in practice (CLI start paths always enforce `0.0.0.0`).
598
+ - `open`: open the default browser when the UI starts.
599
+
600
+ Default URL when using `nextclaw start`: **http://127.0.0.1:18791**.
601
+
602
+ NextClaw binds UI to `0.0.0.0` by default and attempts to detect/print a public IP-based URL at startup.
603
+
604
+ ---
605
+
606
+ ## Troubleshooting
607
+
608
+ | Issue | What to check |
609
+ |-------|----------------|
610
+ | **401 / invalid API key** | Verify the provider `apiKey` and `apiBase` in config or UI. Ensure no extra spaces or wrong key. |
611
+ | **Unknown model** | Confirm the model ID is supported by your provider (e.g. OpenRouter model list). |
612
+ | **No replies on a channel** | Ensure the channel is `enabled`, `allowFrom` includes your user ID if set, and the gateway is running (`nextclaw start` or `nextclaw gateway`). Run `nextclaw channels status` to see channel status. |
613
+ | **Port already in use** | Change `ui.port` in config or use `--ui-port` when starting. Default UI port is 18791, gateway 18790. |
614
+ | **Config not loading** | Ensure `NEXTCLAW_HOME` (if set) points to the directory that contains `config.json`. Run `nextclaw status` to see which config file is used. |
615
+ | **Agent not responding in CLI** | Run `nextclaw init` if you have not yet; ensure a provider and model are set and the provider key is valid. |
616
+
617
+ ---