@rubytech/taskmaster 1.0.44 → 1.0.45

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 (32) hide show
  1. package/dist/browser/routes/screencast.js +22 -2
  2. package/dist/browser/screencast.js +9 -1
  3. package/dist/build-info.json +3 -3
  4. package/dist/control-ui/assets/{index-CpAWYZjj.js → index-BKYdwFD8.js} +172 -163
  5. package/dist/control-ui/assets/index-BKYdwFD8.js.map +1 -0
  6. package/dist/control-ui/assets/{index-D5w5UtCL.css → index-BjsEHhKc.css} +1 -1
  7. package/dist/control-ui/index.html +2 -2
  8. package/dist/gateway/server-methods/browser-screencast.js +25 -5
  9. package/extensions/diagnostics-otel/node_modules/.bin/acorn +0 -0
  10. package/extensions/googlechat/node_modules/.bin/taskmaster +0 -0
  11. package/extensions/line/node_modules/.bin/taskmaster +0 -0
  12. package/extensions/matrix/node_modules/.bin/markdown-it +0 -0
  13. package/extensions/matrix/node_modules/.bin/taskmaster +0 -0
  14. package/extensions/memory-lancedb/node_modules/.bin/arrow2csv +0 -0
  15. package/extensions/memory-lancedb/node_modules/.bin/openai +0 -0
  16. package/extensions/msteams/node_modules/.bin/taskmaster +0 -0
  17. package/extensions/nostr/node_modules/.bin/taskmaster +0 -0
  18. package/extensions/nostr/node_modules/.bin/tsc +0 -0
  19. package/extensions/nostr/node_modules/.bin/tsserver +0 -0
  20. package/extensions/zalo/node_modules/.bin/taskmaster +0 -0
  21. package/extensions/zalouser/node_modules/.bin/taskmaster +0 -0
  22. package/package.json +64 -54
  23. package/scripts/install.sh +0 -0
  24. package/skills/google-ai/references/browser-setup.md +2 -0
  25. package/skills/tavily/references/browser-setup.md +1 -0
  26. package/taskmaster-docs/USER-GUIDE.md +7 -4
  27. package/templates/customer/agents/admin/BOOTSTRAP.md +49 -12
  28. package/dist/control-ui/assets/index-CpAWYZjj.js.map +0 -1
  29. package/templates/.DS_Store +0 -0
  30. package/templates/customer/.DS_Store +0 -0
  31. package/templates/customer/agents/.DS_Store +0 -0
  32. package/templates/taskmaster/.gitignore +0 -1
@@ -1,7 +1,9 @@
1
+ import { createSubsystemLogger } from "../../logging/subsystem.js";
1
2
  import { ErrorCodes, errorShape } from "../protocol/index.js";
2
3
  import { registerScreencastFrameListener, removeScreencastFrameListener, getActiveScreencastSession, } from "../../browser/routes/screencast.js";
3
4
  import { stopScreencast } from "../../browser/screencast.js";
4
5
  import { resolveHandoff, getPendingHandoff } from "../../browser/handoff.js";
6
+ const log = createSubsystemLogger("browser").child("screencast-rpc");
5
7
  /**
6
8
  * Gateway RPC handlers for browser screencast.
7
9
  * These relay between the UI WebSocket clients and the browser bridge.
@@ -11,9 +13,11 @@ export const browserScreencastHandlers = {
11
13
  const quality = typeof params.quality === "number" ? params.quality : 60;
12
14
  const maxWidth = typeof params.maxWidth === "number" ? params.maxWidth : 1280;
13
15
  const maxHeight = typeof params.maxHeight === "number" ? params.maxHeight : 720;
16
+ log.info(`screencast.start requested quality=${quality} maxWidth=${maxWidth} maxHeight=${maxHeight}`);
14
17
  // Stop existing session if any
15
18
  const existing = getActiveScreencastSession();
16
19
  if (existing?.active) {
20
+ log.info("stopping existing screencast session");
17
21
  stopScreencast(existing);
18
22
  }
19
23
  // Remove old listener
@@ -30,9 +34,11 @@ export const browserScreencastHandlers = {
30
34
  try {
31
35
  const bridgeUrl = await resolveBridgeUrl(context);
32
36
  if (!bridgeUrl) {
37
+ log.warn("screencast.start failed: bridge URL could not be resolved");
33
38
  respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, "Browser bridge not configured"));
34
39
  return;
35
40
  }
41
+ log.info(`forwarding screencast.start to bridge at ${bridgeUrl}`);
36
42
  const res = await fetch(`${bridgeUrl}/screencast/start`, {
37
43
  method: "POST",
38
44
  headers: { "Content-Type": "application/json" },
@@ -40,21 +46,27 @@ export const browserScreencastHandlers = {
40
46
  });
41
47
  if (!res.ok) {
42
48
  const body = (await res.json().catch(() => ({ error: "Unknown error" })));
43
- respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, body?.error ?? `HTTP ${res.status}`));
49
+ const msg = body?.error ?? `HTTP ${res.status}`;
50
+ log.error(`bridge returned error: ${msg}`);
51
+ respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, msg));
44
52
  return;
45
53
  }
46
54
  const result = (await res.json());
55
+ log.info(`screencast started: sessionId=${result.sessionId}`);
47
56
  respond(true, result);
48
57
  }
49
58
  catch (err) {
59
+ log.error(`screencast.start failed: ${err}`);
50
60
  respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, String(err)));
51
61
  }
52
62
  },
53
63
  "browser.screencast.stop": async ({ respond, context }) => {
64
+ log.info("screencast.stop requested");
54
65
  removeScreencastFrameListener("gateway");
55
66
  try {
56
67
  const bridgeUrl = await resolveBridgeUrl(context);
57
68
  if (!bridgeUrl) {
69
+ log.info("screencast.stop: no bridge URL, returning ok");
58
70
  respond(true, { ok: true });
59
71
  return;
60
72
  }
@@ -63,9 +75,11 @@ export const browserScreencastHandlers = {
63
75
  headers: { "Content-Type": "application/json" },
64
76
  body: JSON.stringify({}),
65
77
  });
78
+ log.info("screencast stopped");
66
79
  respond(true, { ok: true });
67
80
  }
68
81
  catch (err) {
82
+ log.error(`screencast.stop failed: ${err}`);
69
83
  respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, String(err)));
70
84
  }
71
85
  },
@@ -133,18 +147,24 @@ export const browserScreencastHandlers = {
133
147
  async function resolveBridgeUrl(context) {
134
148
  const health = context.getHealthCache();
135
149
  const browserUrl = health?.browser?.controlUrl;
136
- if (browserUrl)
150
+ if (browserUrl) {
151
+ log.debug(`bridge URL from health cache: ${browserUrl}`);
137
152
  return browserUrl;
153
+ }
154
+ log.debug("no bridge URL in health cache, resolving from config");
138
155
  try {
139
156
  const { loadConfig } = await import("../../config/config.js");
140
157
  const { resolveBrowserConfig } = await import("../../browser/config.js");
141
158
  const cfg = loadConfig();
142
159
  const resolved = resolveBrowserConfig(cfg.browser);
143
- if (resolved.enabled && resolved.controlUrl)
160
+ if (resolved.enabled && resolved.controlUrl) {
161
+ log.debug(`bridge URL from config: ${resolved.controlUrl}`);
144
162
  return resolved.controlUrl;
163
+ }
164
+ log.warn(`browser config resolved but not usable: enabled=${resolved.enabled} controlUrl=${resolved.controlUrl ?? "null"}`);
145
165
  }
146
- catch {
147
- // ignore
166
+ catch (err) {
167
+ log.error(`failed to resolve browser config: ${err}`);
148
168
  }
149
169
  return null;
150
170
  }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/taskmaster",
3
- "version": "1.0.44",
3
+ "version": "1.0.45",
4
4
  "description": "AI-powered business assistant for small businesses",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -77,12 +77,66 @@
77
77
  "dist/filler/**",
78
78
  "dist/license/**"
79
79
  ],
80
+ "scripts": {
81
+ "dev": "node scripts/run-node.mjs",
82
+ "postinstall": "node scripts/postinstall.js",
83
+ "prepack": "pnpm build && pnpm ui:build",
84
+ "docs:list": "node scripts/docs-list.js",
85
+ "docs:bin": "node scripts/build-docs-list.mjs",
86
+ "docs:dev": "cd docs && mint dev",
87
+ "docs:build": "cd docs && pnpm dlx --reporter append-only mint broken-links",
88
+ "build": "tsc -p tsconfig.json && node --import tsx scripts/canvas-a2ui-copy.ts && node --import tsx scripts/copy-hook-metadata.ts && node --import tsx scripts/write-build-info.ts",
89
+ "plugins:sync": "node --import tsx scripts/sync-plugin-versions.ts",
90
+ "release:check": "node --import tsx scripts/release-check.ts",
91
+ "ui:install": "node scripts/ui.js install",
92
+ "ui:dev": "node scripts/ui.js dev",
93
+ "ui:build": "node scripts/ui.js build",
94
+ "start": "node scripts/run-node.mjs",
95
+ "taskmaster": "node scripts/run-node.mjs",
96
+ "gateway:watch": "node scripts/watch-node.mjs gateway --force",
97
+ "logs": "npx tsx scripts/session-viewer.ts",
98
+ "gateway:dev": "TASKMASTER_SKIP_CHANNELS=1 node scripts/run-node.mjs --dev gateway",
99
+ "gateway:dev:reset": "TASKMASTER_SKIP_CHANNELS=1 node scripts/run-node.mjs --dev gateway --reset",
100
+ "tui": "node scripts/run-node.mjs tui",
101
+ "tui:dev": "TASKMASTER_PROFILE=dev node scripts/run-node.mjs tui",
102
+ "taskmaster:rpc": "node scripts/run-node.mjs agent --mode rpc --json",
103
+ "lint": "oxlint --type-aware src test",
104
+ "lint:fix": "pnpm format:fix && oxlint --type-aware --fix src test",
105
+ "format": "oxfmt --check src test",
106
+ "format:fix": "oxfmt --write src test",
107
+ "test": "node scripts/test-parallel.mjs",
108
+ "test:watch": "vitest",
109
+ "test:ui": "pnpm --dir ui test",
110
+ "test:force": "node --import tsx scripts/test-force.ts",
111
+ "test:coverage": "vitest run --coverage",
112
+ "test:e2e": "vitest run --config vitest.e2e.config.ts",
113
+ "test:live": "TASKMASTER_LIVE_TEST=1 vitest run --config vitest.live.config.ts",
114
+ "test:docker:onboard": "bash scripts/e2e/onboard-docker.sh",
115
+ "test:docker:gateway-network": "bash scripts/e2e/gateway-network-docker.sh",
116
+ "test:docker:live-models": "bash scripts/test-live-models-docker.sh",
117
+ "test:docker:live-gateway": "bash scripts/test-live-gateway-models-docker.sh",
118
+ "test:docker:qr": "bash scripts/e2e/qr-import-docker.sh",
119
+ "test:docker:doctor-switch": "bash scripts/e2e/doctor-install-switch-docker.sh",
120
+ "test:docker:plugins": "bash scripts/e2e/plugins-docker.sh",
121
+ "test:docker:cleanup": "bash scripts/test-cleanup-docker.sh",
122
+ "test:docker:all": "pnpm test:docker:live-models && pnpm test:docker:live-gateway && pnpm test:docker:onboard && pnpm test:docker:gateway-network && pnpm test:docker:qr && pnpm test:docker:doctor-switch && pnpm test:docker:plugins && pnpm test:docker:cleanup",
123
+ "test:all": "pnpm lint && pnpm build && pnpm test && pnpm test:e2e && pnpm test:live && pnpm test:docker:all",
124
+ "test:install:e2e": "bash scripts/test-install-sh-e2e-docker.sh",
125
+ "test:install:smoke": "bash scripts/test-install-sh-docker.sh",
126
+ "test:install:e2e:openai": "TASKMASTER_E2E_MODELS=openai bash scripts/test-install-sh-e2e-docker.sh",
127
+ "test:install:e2e:anthropic": "TASKMASTER_E2E_MODELS=anthropic bash scripts/test-install-sh-e2e-docker.sh",
128
+ "protocol:gen": "node --import tsx scripts/protocol-gen.ts",
129
+ "protocol:check": "pnpm protocol:gen && git diff --exit-code -- dist/protocol.schema.json",
130
+ "canvas:a2ui:bundle": "bash scripts/bundle-a2ui.sh",
131
+ "check:loc": "node --import tsx scripts/check-ts-max-loc.ts --max 500"
132
+ },
80
133
  "keywords": [],
81
134
  "author": "",
82
135
  "license": "MIT",
83
136
  "engines": {
84
137
  "node": ">=22.12.0"
85
138
  },
139
+ "packageManager": "pnpm@10.23.0",
86
140
  "dependencies": {
87
141
  "@agentclientprotocol/sdk": "0.13.1",
88
142
  "@aws-sdk/client-bedrock": "^3.975.0",
@@ -172,6 +226,14 @@
172
226
  "vitest": "^4.0.18",
173
227
  "wireit": "^0.14.12"
174
228
  },
229
+ "pnpm": {
230
+ "minimumReleaseAge": 2880,
231
+ "overrides": {
232
+ "@sinclair/typebox": "0.34.47",
233
+ "hono": "4.11.4",
234
+ "tar": "7.5.4"
235
+ }
236
+ },
175
237
  "vitest": {
176
238
  "coverage": {
177
239
  "provider": "v8",
@@ -200,57 +262,5 @@
200
262
  "**/vendor/**",
201
263
  "dist/Taskmaster.app/**"
202
264
  ]
203
- },
204
- "scripts": {
205
- "dev": "node scripts/run-node.mjs",
206
- "postinstall": "node scripts/postinstall.js",
207
- "docs:list": "node scripts/docs-list.js",
208
- "docs:bin": "node scripts/build-docs-list.mjs",
209
- "docs:dev": "cd docs && mint dev",
210
- "docs:build": "cd docs && pnpm dlx --reporter append-only mint broken-links",
211
- "build": "tsc -p tsconfig.json && node --import tsx scripts/canvas-a2ui-copy.ts && node --import tsx scripts/copy-hook-metadata.ts && node --import tsx scripts/write-build-info.ts",
212
- "plugins:sync": "node --import tsx scripts/sync-plugin-versions.ts",
213
- "release:check": "node --import tsx scripts/release-check.ts",
214
- "ui:install": "node scripts/ui.js install",
215
- "ui:dev": "node scripts/ui.js dev",
216
- "ui:build": "node scripts/ui.js build",
217
- "start": "node scripts/run-node.mjs",
218
- "taskmaster": "node scripts/run-node.mjs",
219
- "gateway:watch": "node scripts/watch-node.mjs gateway --force",
220
- "logs": "npx tsx scripts/session-viewer.ts",
221
- "gateway:dev": "TASKMASTER_SKIP_CHANNELS=1 node scripts/run-node.mjs --dev gateway",
222
- "gateway:dev:reset": "TASKMASTER_SKIP_CHANNELS=1 node scripts/run-node.mjs --dev gateway --reset",
223
- "tui": "node scripts/run-node.mjs tui",
224
- "tui:dev": "TASKMASTER_PROFILE=dev node scripts/run-node.mjs tui",
225
- "taskmaster:rpc": "node scripts/run-node.mjs agent --mode rpc --json",
226
- "lint": "oxlint --type-aware src test",
227
- "lint:fix": "pnpm format:fix && oxlint --type-aware --fix src test",
228
- "format": "oxfmt --check src test",
229
- "format:fix": "oxfmt --write src test",
230
- "test": "node scripts/test-parallel.mjs",
231
- "test:watch": "vitest",
232
- "test:ui": "pnpm --dir ui test",
233
- "test:force": "node --import tsx scripts/test-force.ts",
234
- "test:coverage": "vitest run --coverage",
235
- "test:e2e": "vitest run --config vitest.e2e.config.ts",
236
- "test:live": "TASKMASTER_LIVE_TEST=1 vitest run --config vitest.live.config.ts",
237
- "test:docker:onboard": "bash scripts/e2e/onboard-docker.sh",
238
- "test:docker:gateway-network": "bash scripts/e2e/gateway-network-docker.sh",
239
- "test:docker:live-models": "bash scripts/test-live-models-docker.sh",
240
- "test:docker:live-gateway": "bash scripts/test-live-gateway-models-docker.sh",
241
- "test:docker:qr": "bash scripts/e2e/qr-import-docker.sh",
242
- "test:docker:doctor-switch": "bash scripts/e2e/doctor-install-switch-docker.sh",
243
- "test:docker:plugins": "bash scripts/e2e/plugins-docker.sh",
244
- "test:docker:cleanup": "bash scripts/test-cleanup-docker.sh",
245
- "test:docker:all": "pnpm test:docker:live-models && pnpm test:docker:live-gateway && pnpm test:docker:onboard && pnpm test:docker:gateway-network && pnpm test:docker:qr && pnpm test:docker:doctor-switch && pnpm test:docker:plugins && pnpm test:docker:cleanup",
246
- "test:all": "pnpm lint && pnpm build && pnpm test && pnpm test:e2e && pnpm test:live && pnpm test:docker:all",
247
- "test:install:e2e": "bash scripts/test-install-sh-e2e-docker.sh",
248
- "test:install:smoke": "bash scripts/test-install-sh-docker.sh",
249
- "test:install:e2e:openai": "TASKMASTER_E2E_MODELS=openai bash scripts/test-install-sh-e2e-docker.sh",
250
- "test:install:e2e:anthropic": "TASKMASTER_E2E_MODELS=anthropic bash scripts/test-install-sh-e2e-docker.sh",
251
- "protocol:gen": "node --import tsx scripts/protocol-gen.ts",
252
- "protocol:check": "pnpm protocol:gen && git diff --exit-code -- dist/protocol.schema.json",
253
- "canvas:a2ui:bundle": "bash scripts/bundle-a2ui.sh",
254
- "check:loc": "node --import tsx scripts/check-ts-max-loc.ts --max 500"
255
265
  }
256
- }
266
+ }
File without changes
@@ -53,6 +53,8 @@ Take a snapshot and check the page content.
53
53
  - Copy the new key
54
54
  - Screenshot: "Created a new key for you."
55
55
 
56
+ **Send the key as a separate message** — just the key on its own line, nothing else. This lets the user tap and copy it easily from their chat app.
57
+
56
58
  ## Step 6: Add to Taskmaster
57
59
 
58
60
  Tell the user how to add the key:
@@ -44,6 +44,7 @@ Take a snapshot of the dashboard.
44
44
  - If the key is masked, click the eye icon to reveal it
45
45
  - Screenshot: "Here's your Tavily dashboard. Copying your API key..."
46
46
  - Copy the key value
47
+ - **Send the key as a separate message** — just the key on its own line, nothing else. This lets the user tap and copy it easily from their chat app.
47
48
 
48
49
  ## Step 6: Add to Taskmaster
49
50
 
@@ -107,7 +107,7 @@ Once your license is activated:
107
107
  2. Sign in with your Claude Pro account
108
108
  3. Copy the code shown and paste it into the setup page
109
109
  4. Tap **Submit**
110
- 5. When connected, tap **"Continue to WhatsApp"**
110
+ 5. When connected, tap **"Continue to Chat"** to start configuring your assistant
111
111
 
112
112
  > **Don't have Claude Pro?** Click "Or enter your API key" below the Connect button. Paste your Anthropic API key and tap Submit. This is the advanced option — most people find signing in with Claude Pro much easier.
113
113
 
@@ -206,13 +206,16 @@ Taskmaster runs two assistants on the same WhatsApp number, each with a differen
206
206
 
207
207
  **The Public Assistant** handles messages from your customers. It can reply to messages and look up information you've taught it, but it cannot access your files, run commands, or see private notes. If a customer tries to trick it into doing something it shouldn't, it simply can't — those capabilities don't exist for it.
208
208
 
209
- **The Admin Assistant** is your personal assistant. When you message yourself on WhatsApp (or use the Chat page), you're talking to this one. It has full access — it can manage files, browse the web, run scheduled tasks, and read everything.
209
+ **The Admin Assistant** is your personal assistant. When you use the Chat page (or message yourself on WhatsApp), you're talking to this one. It has full access — it can manage files, browse the web, run scheduled tasks, and read everything.
210
210
 
211
211
  ### How does Taskmaster know which is which?
212
212
 
213
- Your phone number (the one you paired during setup) is marked as an admin. Messages from your number go to the admin assistant. Messages from everyone else go to the public assistant.
213
+ There are two concepts to understand:
214
214
 
215
- You can add more admin numbers on the **Admins** page for example, your personal phone, a business partner or manager who should also get full access.
215
+ - **Paired WhatsApp number** the WhatsApp account linked to your Pi during setup. This is the number your customers message. When you send yourself a message on this WhatsApp account (self-chat), it goes to the admin assistant.
216
+ - **Admin phones** — additional phone numbers that get admin access when they message the paired WhatsApp. Useful if you have a separate personal phone, or if a business partner needs admin access from their own number.
217
+
218
+ By default, messages from anyone other than registered admin phones go to the public assistant. You can add admin phones on the **Admins** page.
216
219
 
217
220
  ---
218
221
 
@@ -16,7 +16,7 @@ Explain that there's a second assistant — the **public agent** — that handle
16
16
 
17
17
  Ask conversationally, one thing at a time:
18
18
  - **Owner's name** (the person you're talking to)
19
- - **Phone number** (international format, e.g., +44 7504 472444)
19
+ - **Phone number** — their personal mobile number (international format, e.g., +44 7591 215452). This is *not* the WhatsApp number they'll pair later — it's the owner's own contact number for business records.
20
20
  - **Business name**
21
21
  - **Location**
22
22
  - **Working hours**
@@ -43,33 +43,70 @@ All other files (SOUL.md, AGENTS.md, etc.) are already generic and reference USE
43
43
 
44
44
  ## Step 5: Authorize Admin Devices
45
45
 
46
- The paired device (self-chat) already has admin access. Ask if they want to add their personal phone as an additional admin device.
46
+ At this point, WhatsApp has not been paired yet that happens later via the Setup page. No phone numbers have admin access yet.
47
47
 
48
- If yes, use the `authorize_admin` tool with their phone number (international format, e.g., +447504472444).
48
+ Ask the owner whether they'd like to register their personal phone number (the one they gave you in Step 3) as an **admin device**. Explain what this means: when they message from that number via WhatsApp, they'll get full admin access to you rather than being treated as a customer.
49
+
50
+ If they confirm, use the `authorize_admin` tool with their phone number (international format with no spaces, e.g., +447504472444). Do not assume any number is already authorized — always call `authorize_admin` explicitly and confirm success to the user.
51
+
52
+ If they have additional phone numbers they want to authorize (e.g., a business partner), authorize those too.
49
53
 
50
54
  ## Step 6: Help with API Keys
51
55
 
52
- Two free API keys unlock important capabilities. Offer to help the admin get them — use the browser to walk through signup and show screenshots so the user can follow along.
56
+ Two free API keys unlock important capabilities. Offer to walk the admin through getting them — you can use the browser to guide them through signup and show screenshots so they can follow along.
53
57
 
54
- - **Tavily** (web search) — load the `tavily` skill's `references/browser-setup.md` and follow its steps
55
58
  - **Google AI** (voice notes + video) — load the `google-ai` skill's `references/browser-setup.md` and follow its steps
59
+ - **Tavily** (web search) — load the `tavily` skill's `references/browser-setup.md` and follow its steps. The admin can use the same Google email they just set up to register.
56
60
 
57
- If the admin prefers to do it themselves, direct them to their Taskmaster setup page (API Keys section) and explain where to sign up: [app.tavily.com](https://app.tavily.com) for Tavily, [aistudio.google.com](https://aistudio.google.com) for Google AI.
61
+ If the admin prefers to do it themselves later, they can manage API keys through the **Setup page** (API Keys section) this requires logging in with the **admin PIN**, not an account PIN. Direct them to [app.tavily.com](https://app.tavily.com) for Tavily and [aistudio.google.com](https://aistudio.google.com) for Google AI.
58
62
 
59
63
  These keys are optional — the assistant works without them. Don't pressure. If the admin wants to skip this and come back later, that's fine.
60
64
 
61
- ## Step 7: Explain What's Next
65
+ If they need help with anything at all — setup, API keys, or general questions — suggest they reach out to **Dave at Taskmaster** via WhatsApp: [wa.me/447591215452](https://wa.me/447591215452).
66
+
67
+ ## Step 7: Rename the Account
68
+
69
+ The default account is called "taskmaster" in the Setup page header. Suggest the owner renames it to their business name or assistant name — they can do this by tapping the edit icon next to the account name at the top of the Setup page.
70
+
71
+ **Important:** This only changes the display name. Do **not** rename any folders in the filesystem — that will break the system.
72
+
73
+ ## Step 8: Set an Account PIN
74
+
75
+ Suggest the owner sets an **account PIN** for their account. Explain the difference:
76
+
77
+ - The **admin PIN** was set during initial setup (the very first screen). It unlocks full access to all accounts and device settings.
78
+ - An **account PIN** is specific to one account. It lets someone access only that account without seeing others. This matters if they later add more accounts or share the device with a business partner.
79
+
80
+ They can set the account PIN on the Setup page — look for the **Account PIN** row and tap **Set PIN**.
81
+
82
+ ## Step 9: Pair WhatsApp
83
+
84
+ The assistant can't receive customer messages until a WhatsApp number is paired. Explain this to the owner:
85
+
86
+ > "Everything's configured — but to start receiving customer messages, you need to pair a WhatsApp number. This is the business phone number that customers will message. It can be the same phone you use personally, or a separate business number."
87
+
88
+ Guide them to do this via the Setup page:
89
+
90
+ 1. Go to the **Setup page** and find the **WhatsApp** row
91
+ 2. Tap **Link WhatsApp** (or **Relink WhatsApp** if re-pairing)
92
+ 3. Follow the QR code pairing flow on their phone
93
+
94
+ Once paired, any message to that WhatsApp number from an unrecognized number goes to the **public agent**. Messages from authorized admin numbers (like the one registered in Step 5) go to the **admin agent** instead.
95
+
96
+ If they're not ready to pair now, that's fine — they can do it anytime from the Setup page. Everything else is already configured and waiting.
97
+
98
+ ## Step 10: Explain What's Next
62
99
 
63
100
  Tell them:
64
- - They can message anytime to update business info
65
- - Customers who message will get the public agent (restricted access)
66
- - They (admin) get full access to configure everything
101
+ - They can message you anytime to update business info, ask questions, or configure settings
102
+ - Once WhatsApp is paired, customers who message the business number will talk to the public assistant automatically
103
+ - Messages from their authorized phone number will reach you (the admin assistant) instead
67
104
  - You'll learn their business as you go
68
105
 
69
- ## Step 8: Delete This File
106
+ ## Step 11: Delete This File
70
107
 
71
108
  Once setup is complete, create a file called `.bootstrap-done` in this directory (empty content is fine), then delete this file. The `.bootstrap-done` marker prevents this onboarding from reappearing.
72
109
 
73
110
  ---
74
111
 
75
- **Remember:** Be conversational, not robotic. This is WhatsApp, not a form. Ask one thing at a time.
112
+ **Remember:** Be conversational, not robotic. This is a chat, not a form. Ask one thing at a time.