@rubytech/taskmaster 1.2.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/dist/agents/auth-profiles/oauth.js +24 -0
  2. package/dist/agents/auth-profiles/profiles.js +37 -0
  3. package/dist/agents/auth-profiles.js +1 -1
  4. package/dist/agents/pi-tools.policy.js +4 -0
  5. package/dist/agents/taskmaster-tools.js +14 -0
  6. package/dist/agents/tool-policy.js +5 -2
  7. package/dist/agents/tools/apikeys-tool.js +16 -5
  8. package/dist/agents/tools/contact-create-tool.js +59 -0
  9. package/dist/agents/tools/contact-delete-tool.js +48 -0
  10. package/dist/agents/tools/contact-update-tool.js +17 -2
  11. package/dist/agents/tools/file-delete-tool.js +137 -0
  12. package/dist/agents/tools/file-list-tool.js +127 -0
  13. package/dist/agents/tools/message-history-tool.js +2 -3
  14. package/dist/auto-reply/media-note.js +11 -0
  15. package/dist/auto-reply/reply/commands-tts.js +7 -2
  16. package/dist/auto-reply/reply/get-reply.js +4 -0
  17. package/dist/build-info.json +3 -3
  18. package/dist/cli/provision-seed.js +1 -2
  19. package/dist/commands/doctor-config-flow.js +13 -0
  20. package/dist/config/agent-tools-reconcile.js +53 -0
  21. package/dist/config/defaults.js +10 -1
  22. package/dist/config/legacy.migrations.part-3.js +26 -0
  23. package/dist/config/zod-schema.core.js +9 -1
  24. package/dist/config/zod-schema.js +1 -0
  25. package/dist/control-ui/assets/{index-N8du4fwV.js → index-BDETQp97.js} +692 -600
  26. package/dist/control-ui/assets/index-BDETQp97.js.map +1 -0
  27. package/dist/control-ui/assets/index-CPawOl_z.css +1 -0
  28. package/dist/control-ui/index.html +2 -2
  29. package/dist/gateway/chat-sanitize.js +5 -1
  30. package/dist/gateway/config-reload.js +1 -0
  31. package/dist/gateway/media-http.js +28 -0
  32. package/dist/gateway/server/tls.js +2 -2
  33. package/dist/gateway/server-http.js +34 -4
  34. package/dist/gateway/server-methods/apikeys.js +56 -4
  35. package/dist/gateway/server-methods/chat.js +64 -25
  36. package/dist/gateway/server-methods/tts.js +11 -2
  37. package/dist/gateway/server.impl.js +38 -5
  38. package/dist/infra/tls/gateway.js +19 -3
  39. package/dist/media-understanding/apply.js +35 -0
  40. package/dist/media-understanding/providers/deepgram/audio.js +1 -1
  41. package/dist/media-understanding/providers/google/audio.js +1 -1
  42. package/dist/media-understanding/providers/google/video.js +1 -1
  43. package/dist/media-understanding/providers/index.js +2 -0
  44. package/dist/media-understanding/providers/openai/audio.js +1 -1
  45. package/dist/media-understanding/providers/sherpa-onnx/index.js +10 -0
  46. package/dist/media-understanding/runner.js +61 -72
  47. package/dist/media-understanding/sherpa-onnx-local.js +223 -0
  48. package/dist/memory/audit.js +9 -0
  49. package/dist/memory/manager.js +1 -1
  50. package/dist/records/records-manager.js +10 -0
  51. package/dist/tts/tts.js +98 -10
  52. package/dist/web/auto-reply/monitor/process-message.js +45 -17
  53. package/dist/web/inbound/monitor.js +9 -1
  54. package/extensions/diagnostics-otel/node_modules/.bin/acorn +0 -0
  55. package/extensions/googlechat/node_modules/.bin/taskmaster +2 -2
  56. package/extensions/googlechat/package.json +2 -2
  57. package/extensions/line/node_modules/.bin/taskmaster +2 -2
  58. package/extensions/line/package.json +1 -1
  59. package/extensions/matrix/node_modules/.bin/markdown-it +0 -0
  60. package/extensions/matrix/node_modules/.bin/taskmaster +2 -2
  61. package/extensions/matrix/package.json +1 -1
  62. package/extensions/memory-lancedb/node_modules/.bin/arrow2csv +0 -0
  63. package/extensions/memory-lancedb/node_modules/.bin/openai +0 -0
  64. package/extensions/msteams/node_modules/.bin/taskmaster +2 -2
  65. package/extensions/msteams/package.json +1 -1
  66. package/extensions/nostr/node_modules/.bin/taskmaster +2 -2
  67. package/extensions/nostr/node_modules/.bin/tsc +0 -0
  68. package/extensions/nostr/node_modules/.bin/tsserver +0 -0
  69. package/extensions/nostr/package.json +1 -1
  70. package/extensions/zalo/node_modules/.bin/taskmaster +2 -2
  71. package/extensions/zalo/package.json +1 -1
  72. package/extensions/zalouser/node_modules/.bin/taskmaster +2 -2
  73. package/extensions/zalouser/package.json +1 -1
  74. package/package.json +56 -65
  75. package/scripts/install.sh +0 -0
  76. package/scripts/postinstall.js +76 -0
  77. package/skills/business-assistant/references/crm.md +32 -8
  78. package/taskmaster-docs/USER-GUIDE.md +111 -6
  79. package/templates/.DS_Store +0 -0
  80. package/templates/beagle/agents/admin/AGENTS.md +4 -2
  81. package/templates/customer/.DS_Store +0 -0
  82. package/templates/customer/agents/.DS_Store +0 -0
  83. package/templates/maxy/.DS_Store +0 -0
  84. package/templates/maxy/.gitignore +1 -0
  85. package/templates/maxy/agents/.DS_Store +0 -0
  86. package/templates/maxy/agents/admin/.DS_Store +0 -0
  87. package/templates/maxy/memory/.DS_Store +0 -0
  88. package/templates/maxy/skills/.DS_Store +0 -0
  89. package/templates/taskmaster/.gitignore +1 -0
  90. package/templates/taskmaster/agents/admin/AGENTS.md +1 -0
  91. package/dist/control-ui/assets/index-DtQHRIVD.css +0 -1
  92. package/dist/control-ui/assets/index-N8du4fwV.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/taskmaster",
3
- "version": "1.2.1",
3
+ "version": "1.4.0",
4
4
  "description": "AI-powered business assistant for small businesses",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -77,66 +77,12 @@
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
- },
133
80
  "keywords": [],
134
81
  "author": "",
135
82
  "license": "MIT",
136
83
  "engines": {
137
84
  "node": ">=22.12.0"
138
85
  },
139
- "packageManager": "pnpm@10.23.0",
140
86
  "dependencies": {
141
87
  "@agentclientprotocol/sdk": "0.13.1",
142
88
  "@aws-sdk/client-bedrock": "^3.975.0",
@@ -195,7 +141,8 @@
195
141
  },
196
142
  "optionalDependencies": {
197
143
  "@napi-rs/canvas": "^0.1.88",
198
- "node-llama-cpp": "3.15.0"
144
+ "node-llama-cpp": "3.15.0",
145
+ "sherpa-onnx-node": "^1.12.26"
199
146
  },
200
147
  "devDependencies": {
201
148
  "@grammyjs/types": "^3.23.0",
@@ -226,14 +173,6 @@
226
173
  "vitest": "^4.0.18",
227
174
  "wireit": "^0.14.12"
228
175
  },
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
- },
237
176
  "vitest": {
238
177
  "coverage": {
239
178
  "provider": "v8",
@@ -262,5 +201,57 @@
262
201
  "**/vendor/**",
263
202
  "dist/Taskmaster.app/**"
264
203
  ]
204
+ },
205
+ "scripts": {
206
+ "dev": "node scripts/run-node.mjs",
207
+ "postinstall": "node scripts/postinstall.js",
208
+ "docs:list": "node scripts/docs-list.js",
209
+ "docs:bin": "node scripts/build-docs-list.mjs",
210
+ "docs:dev": "cd docs && mint dev",
211
+ "docs:build": "cd docs && pnpm dlx --reporter append-only mint broken-links",
212
+ "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",
213
+ "plugins:sync": "node --import tsx scripts/sync-plugin-versions.ts",
214
+ "release:check": "node --import tsx scripts/release-check.ts",
215
+ "ui:install": "node scripts/ui.js install",
216
+ "ui:dev": "node scripts/ui.js dev",
217
+ "ui:build": "node scripts/ui.js build",
218
+ "start": "node scripts/run-node.mjs",
219
+ "taskmaster": "node scripts/run-node.mjs",
220
+ "gateway:watch": "node scripts/watch-node.mjs gateway --force",
221
+ "logs": "npx tsx scripts/session-viewer.ts",
222
+ "gateway:dev": "TASKMASTER_SKIP_CHANNELS=1 node scripts/run-node.mjs --dev gateway",
223
+ "gateway:dev:reset": "TASKMASTER_SKIP_CHANNELS=1 node scripts/run-node.mjs --dev gateway --reset",
224
+ "tui": "node scripts/run-node.mjs tui",
225
+ "tui:dev": "TASKMASTER_PROFILE=dev node scripts/run-node.mjs tui",
226
+ "taskmaster:rpc": "node scripts/run-node.mjs agent --mode rpc --json",
227
+ "lint": "oxlint --type-aware src test",
228
+ "lint:fix": "pnpm format:fix && oxlint --type-aware --fix src test",
229
+ "format": "oxfmt --check src test",
230
+ "format:fix": "oxfmt --write src test",
231
+ "test": "node scripts/test-parallel.mjs",
232
+ "test:watch": "vitest",
233
+ "test:ui": "pnpm --dir ui test",
234
+ "test:force": "node --import tsx scripts/test-force.ts",
235
+ "test:coverage": "vitest run --coverage",
236
+ "test:e2e": "vitest run --config vitest.e2e.config.ts",
237
+ "test:live": "TASKMASTER_LIVE_TEST=1 vitest run --config vitest.live.config.ts",
238
+ "test:docker:onboard": "bash scripts/e2e/onboard-docker.sh",
239
+ "test:docker:gateway-network": "bash scripts/e2e/gateway-network-docker.sh",
240
+ "test:docker:live-models": "bash scripts/test-live-models-docker.sh",
241
+ "test:docker:live-gateway": "bash scripts/test-live-gateway-models-docker.sh",
242
+ "test:docker:qr": "bash scripts/e2e/qr-import-docker.sh",
243
+ "test:docker:doctor-switch": "bash scripts/e2e/doctor-install-switch-docker.sh",
244
+ "test:docker:plugins": "bash scripts/e2e/plugins-docker.sh",
245
+ "test:docker:cleanup": "bash scripts/test-cleanup-docker.sh",
246
+ "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",
247
+ "test:all": "pnpm lint && pnpm build && pnpm test && pnpm test:e2e && pnpm test:live && pnpm test:docker:all",
248
+ "test:install:e2e": "bash scripts/test-install-sh-e2e-docker.sh",
249
+ "test:install:smoke": "bash scripts/test-install-sh-docker.sh",
250
+ "test:install:e2e:openai": "TASKMASTER_E2E_MODELS=openai bash scripts/test-install-sh-e2e-docker.sh",
251
+ "test:install:e2e:anthropic": "TASKMASTER_E2E_MODELS=anthropic bash scripts/test-install-sh-e2e-docker.sh",
252
+ "protocol:gen": "node --import tsx scripts/protocol-gen.ts",
253
+ "protocol:check": "pnpm protocol:gen && git diff --exit-code -- dist/protocol.schema.json",
254
+ "canvas:a2ui:bundle": "bash scripts/bundle-a2ui.sh",
255
+ "check:loc": "node --import tsx scripts/check-ts-max-loc.ts --max 500"
265
256
  }
266
- }
257
+ }
File without changes
@@ -311,6 +311,81 @@ function ensurePlatformDeps() {
311
311
  }
312
312
  }
313
313
 
314
+ /**
315
+ * Download the sherpa-onnx speech recognition model for offline voice note
316
+ * transcription. Runs on global installs (deployed devices) and dev setups
317
+ * where sherpa-onnx-node is available. The model is platform-independent;
318
+ * only the native bindings (installed via npm optionalDeps) are platform-specific.
319
+ */
320
+ function ensureSherpaOnnxModel() {
321
+ const homeDir = process.env.HOME || process.env.USERPROFILE || "";
322
+ if (!homeDir) return;
323
+
324
+ const libDir = path.join(homeDir, ".taskmaster", "lib", "sherpa-onnx");
325
+ const modelDir = path.join(libDir, "nemo-ctc-en-conformer-small");
326
+ const modelFile = path.join(modelDir, "model.int8.onnx");
327
+ const tokensFile = path.join(modelDir, "tokens.txt");
328
+
329
+ // Already downloaded — nothing to do
330
+ if (fs.existsSync(modelFile) && fs.existsSync(tokensFile)) return;
331
+
332
+ // Only download if sherpa-onnx-node is installed (optional dep)
333
+ try {
334
+ const repoRoot = getRepoRoot();
335
+ const sherpaEntry = path.join(repoRoot, "node_modules", "sherpa-onnx-node");
336
+ if (!fs.existsSync(sherpaEntry)) return;
337
+ } catch {
338
+ return;
339
+ }
340
+
341
+ // Check that curl and tar are available (always true on macOS/Linux)
342
+ const hasCurl = spawnSync("curl", ["--version"], { stdio: "ignore" }).status === 0;
343
+ const hasTar = spawnSync("tar", ["--version"], { stdio: "ignore" }).status === 0;
344
+ if (!hasCurl || !hasTar) return;
345
+
346
+ const archiveUrl =
347
+ "https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-nemo-ctc-en-conformer-small.tar.bz2";
348
+ const archiveName = "nemo-ctc-en-conformer-small.tar.bz2";
349
+ const archivePath = path.join(libDir, archiveName);
350
+ const extractedDir = path.join(libDir, "sherpa-onnx-nemo-ctc-en-conformer-small");
351
+
352
+ console.log("[postinstall] Downloading sherpa-onnx speech recognition model…");
353
+ fs.mkdirSync(libDir, { recursive: true });
354
+
355
+ const curl = spawnSync("curl", ["-fsSL", "-o", archivePath, archiveUrl], {
356
+ stdio: "inherit",
357
+ timeout: 300_000,
358
+ });
359
+ if (curl.status !== 0) {
360
+ console.warn("[postinstall] sherpa-onnx model download failed (voice notes will use cloud STT)");
361
+ try { fs.unlinkSync(archivePath); } catch {}
362
+ return;
363
+ }
364
+
365
+ const tar = spawnSync("tar", ["-xjf", archivePath, "-C", libDir], {
366
+ stdio: "inherit",
367
+ timeout: 120_000,
368
+ });
369
+ if (tar.status !== 0) {
370
+ console.warn("[postinstall] sherpa-onnx model extraction failed (voice notes will use cloud STT)");
371
+ try { fs.unlinkSync(archivePath); } catch {}
372
+ return;
373
+ }
374
+
375
+ // Rename extracted directory (strip sherpa-onnx- prefix)
376
+ if (fs.existsSync(extractedDir) && extractedDir !== modelDir) {
377
+ try { fs.rmSync(modelDir, { recursive: true, force: true }); } catch {}
378
+ fs.renameSync(extractedDir, modelDir);
379
+ }
380
+
381
+ // Clean up: archive, full-precision model (keep int8), test wavs
382
+ try { fs.unlinkSync(archivePath); } catch {}
383
+ try { fs.unlinkSync(path.join(modelDir, "model.onnx")); } catch {}
384
+ try { fs.rmSync(path.join(modelDir, "test_wavs"), { recursive: true, force: true }); } catch {}
385
+
386
+ console.log("[postinstall] sherpa-onnx model installed (offline voice note transcription)");
387
+ }
388
+
314
389
  function main() {
315
390
  const repoRoot = getRepoRoot();
316
391
  process.chdir(repoRoot);
@@ -318,6 +393,7 @@ function main() {
318
393
  ensureExecutable(path.join(repoRoot, "dist", "entry.js"));
319
394
  setupGitHooks({ repoRoot });
320
395
  ensurePlatformDeps();
396
+ ensureSherpaOnnxModel();
321
397
 
322
398
  if (!shouldApplyPnpmPatchedDependenciesFallback()) {
323
399
  return;
@@ -1,9 +1,33 @@
1
1
  # Customer Records (CRM)
2
2
 
3
+ ## Contacts as Source of Truth
4
+
5
+ The **contact record** is the highest-level directory for every customer relationship. Its phone number and name are the canonical identifiers — all user-scoped data (memory profiles, conversations, documents, events) hangs off the contact via the phone number.
6
+
7
+ | Concept | What it is | Storage |
8
+ |---------|-----------|---------|
9
+ | **Contact record** | Structured directory entry (phone, name, pipeline status, address) | `~/.taskmaster/records.json` via `contact_*` tools |
10
+ | **User memory** | Freeform narrative, conversation history, media, documents | `memory/users/{phone}/` via `memory_*` tools |
11
+
12
+ The contact record determines the relationship. User memory provides the detail. A memory profile without a contact record is orphaned data. A contact record without memory is a directory entry awaiting context.
13
+
3
14
  ## Tools
4
15
 
5
- - `contact_lookup` Search by phone number or name. Use before every customer interaction.
6
- - `contact_update` — Update record fields. Use after every meaningful event.
16
+ | Tool | Access | Purpose |
17
+ |------|--------|---------|
18
+ | `contact_create` | Admin only | Create a new contact record (phone + name + optional fields) |
19
+ | `contact_lookup` | All agents | Search by phone number or name. Use before every customer interaction |
20
+ | `contact_update` | Admin only | Update record fields or rename a contact. Use after every meaningful event |
21
+ | `contact_delete` | Admin only | Remove a contact record. Does not delete user memory |
22
+
23
+ ### Creating a Contact Record vs Creating User Memory
24
+
25
+ These are distinct operations:
26
+
27
+ - **`contact_create`** — Creates a structured directory entry in the secure records store. Use when you have a name and phone number for a new customer.
28
+ - **`memory_write` to `memory/users/{phone}/profile.md`** — Creates or updates the freeform narrative profile. Use to store context, personality, preferences, and history.
29
+
30
+ On first meaningful interaction, do **both**: create the contact record, then write an initial memory profile.
7
31
 
8
32
  ## When to Create a Record
9
33
 
@@ -26,7 +50,7 @@ Update the contact record after every event that changes the customer's status o
26
50
 
27
51
  | Field | Description | Example |
28
52
  |-------|-------------|---------|
29
- | `name` | Full name | `Mrs Sarah Jenkins` |
53
+ | `name` | Full name (set via `contact_create`, update via `contact_update` with field `name`) | `Mrs Sarah Jenkins` |
30
54
  | `status` | Pipeline stage | `enquiry`, `quoted`, `booked`, `completed`, `invoiced`, `paid`, `archived` |
31
55
  | `address` | Full postal address | `42 Oak Lane, Stansted, CM23 4AB` |
32
56
  | `postcode` | Extracted postcode (for geographic clustering) | `CM23 4AB` |
@@ -53,15 +77,15 @@ enquiry → quoted → booked → completed → invoiced → paid
53
77
 
54
78
  Update the status at each transition. This enables the business owner to see their pipeline at a glance.
55
79
 
56
- ## Memory vs Records
80
+ ## Contact Records vs User Memory
57
81
 
58
82
  Contact records and memory serve different purposes. Use both.
59
83
 
60
- | | Contact Records | Memory |
84
+ | | Contact Records | User Memory |
61
85
  |---|---|---|
62
- | **Store** | `contact_lookup` / `contact_update` | `memory/users/{phone}/profile.md` |
86
+ | **Store** | `contact_create` / `contact_update` / `contact_lookup` | `memory/users/{phone}/profile.md` |
63
87
  | **Structure** | Key-value fields (name, status, address, etc.) | Freeform narrative |
64
- | **Purpose** | Pipeline tracking, structured queries | Context, personality, history |
88
+ | **Purpose** | Directory entry, pipeline tracking, structured queries | Context, personality, history |
65
89
  | **Example** | `status: invoiced`, `postcode: CM23 4AB` | "Mrs Jenkins is elderly, lives alone, prefers morning appointments. She had a boiler service last month and was very happy with the work." |
66
90
 
67
91
  When searching for a customer, check **both**: `contact_lookup` for structured data, `memory_search` for context.
@@ -72,6 +96,6 @@ Customer documents are filed at `memory/users/{phone}/documents/`. The phone num
72
96
 
73
97
  When creating documents for a customer, always:
74
98
  1. Verify the contact record exists (`contact_lookup`)
75
- 2. Create or update the record if needed (`contact_update`)
99
+ 2. Create the record if needed (`contact_create`) or update it (`contact_update`)
76
100
  3. File the document in the correct path
77
101
  4. Update the contact record status
@@ -171,6 +171,8 @@ The very first time you open the dashboard, you'll be asked to **set a PIN** (4-
171
171
 
172
172
  When you return, a login screen asks for your PIN. If you have multiple accounts, pick the account you want to operate on from the dropdown and enter the account PIN (this is different to the admin PIN). If you log into the admin account, you have access to all the other registered accounts.
173
173
 
174
+ Each PIN field has an **eye icon** on the right — tap it to reveal the PIN digits so you can check what you've typed. Tap again to hide them.
175
+
174
176
  ### Account PINs
175
177
 
176
178
  If you share your device with other people (e.g. a business partner who manages a different account), each account can have its own PIN:
@@ -200,6 +202,32 @@ If you forget your PIN, you'll need to edit the configuration file on the device
200
202
 
201
203
  ---
202
204
 
205
+ ## Secure Connection (HTTPS)
206
+
207
+ Taskmaster automatically uses a secure (HTTPS) connection when you access it from another device on your network. This is required for features like voice notes, which need microphone access — browsers only allow microphone use on secure connections.
208
+
209
+ ### First-Time Certificate Warning
210
+
211
+ The first time you open Taskmaster in your browser, you'll see a security warning that says something like **"Your connection is not private"** or **"This site's certificate is not trusted."** This is normal and expected.
212
+
213
+ Taskmaster creates its own security certificate so your connection is encrypted. Because it's self-issued (not from a public authority like Google or Let's Encrypt), your browser doesn't recognise it automatically. Your data is still encrypted — the warning is about trust, not security.
214
+
215
+ **To proceed:**
216
+
217
+ - **Chrome / Edge:** Click **Advanced**, then **Proceed to taskmaster.local (unsafe)**
218
+ - **Safari:** Click **Show Details**, then **visit this website**, then confirm
219
+ - **Firefox:** Click **Advanced**, then **Accept the Risk and Continue**
220
+
221
+ You only need to do this once per browser. After accepting, the warning won't appear again until the certificate expires (1 year).
222
+
223
+ > **Tip (Mac):** To permanently trust the certificate and remove the warning entirely, open Terminal and run:
224
+ > ```
225
+ > sudo security add-trusted-cert -d -r trustAsRoot -k /Library/Keychains/System.keychain ~/.taskmaster/tls/gateway-cert.pem
226
+ > ```
227
+ > Enter your Mac password when prompted. After this, all browsers on that Mac will trust Taskmaster's certificate.
228
+
229
+ ---
230
+
203
231
  ## Two Assistants, One WhatsApp
204
232
 
205
233
  Taskmaster runs two assistants on the same WhatsApp number, each with a different job:
@@ -238,6 +266,15 @@ You can send files to your assistant by dragging and dropping them onto the chat
238
266
 
239
267
  **Via WhatsApp** you can also send **voice notes** and **videos** — these are automatically transcribed or analysed before your assistant sees them (see "Voice Notes & Video" below).
240
268
 
269
+ ### Voice Notes (Chat Page)
270
+
271
+ You can record and send voice notes directly from the Chat page. When the message box is empty, a microphone button appears in place of the send button.
272
+
273
+ - **Tap** the microphone to start recording. A recording indicator with a timer appears. Tap the **send button** to send, or the **trash button** to discard.
274
+ - **Press and hold** the microphone to record hands-free. Release to send automatically, or slide left to cancel.
275
+
276
+ Your assistant transcribes the voice note and responds to the content, the same as a WhatsApp voice note. Sent voice notes appear as audio players in the conversation so you can replay them.
277
+
241
278
  ### Sending Messages While the Assistant is Working
242
279
 
243
280
  If your assistant is busy thinking, you can still type and send more messages. They appear immediately in the chat as normal messages and are delivered to your assistant in order once it finishes its current task.
@@ -289,12 +326,16 @@ The Files page shows a **status indicator** next to the Re-index button — a gr
289
326
  | Search knowledge | Find information across all your business files and notes |
290
327
  | Read files | Open and read any file in your workspace |
291
328
  | Write and update files | Create new notes, update existing files, or reorganise content |
329
+ | List files and folders | Browse what's in any workspace directory |
330
+ | Delete files and folders | Remove files or folders you no longer need (protected paths like agents/ cannot be deleted) |
292
331
  | Save photos | Store images to customer folders or your workspace |
293
332
 
294
333
  **Try asking:**
295
334
  - "What's our pricing for a full bathroom refit?"
296
335
  - "Save a note that Mrs. Jones prefers morning appointments"
297
336
  - "What do we know about the customer on +44 7700 900123?"
337
+ - "List what's in memory/users"
338
+ - "Delete the file memory/public/old-pricelist.md"
298
339
 
299
340
  ### Web Search
300
341
 
@@ -310,6 +351,21 @@ Your assistant can search the web and read web pages to find information for you
310
351
  - "What are the opening hours for Travis Perkins in Bromley?"
311
352
  - "Read this page and summarise it: https://example.com/article"
312
353
 
354
+ ### Weather
355
+
356
+ Your assistant can check the weather for any location — current conditions, forecasts, humidity, wind, and more. No API key is needed.
357
+
358
+ | Capability | Description |
359
+ |------------|-------------|
360
+ | Current conditions | Temperature, weather conditions, humidity, and wind speed for any city |
361
+ | Forecasts | Multi-day weather forecasts for planning ahead |
362
+ | Any location | Look up weather by city name, airport code, or coordinates |
363
+
364
+ **Try asking:**
365
+ - "What's the weather like in London?"
366
+ - "Will it rain tomorrow in Manchester?"
367
+ - "What's the forecast for this week?"
368
+
313
369
  ### Images & Documents
314
370
 
315
371
  Your assistant can analyse photos you send it and read common document formats.
@@ -354,7 +410,7 @@ When someone sends a voice note, image, or video, your assistant processes it au
354
410
  | Images | Automatically described — your assistant sees what's in the picture |
355
411
  | Video | Key frames extracted and described — your assistant understands the content |
356
412
 
357
- Voice note transcription and video analysis require a Google AI (Gemini) API key (see API Keys below). Image analysis uses your Claude connection directly — no extra key needed.
413
+ Voice note transcription works out of the box — Taskmaster includes a built-in offline speech recognition model that runs locally on your device with no API key required. For higher accuracy or video analysis, add a Google AI (Gemini) API key (see API Keys below). Image analysis uses your Claude connection directly — no extra key needed.
358
414
 
359
415
  ### Customer Records
360
416
 
@@ -466,6 +522,23 @@ Your assistant can open and interact with websites in a built-in browser — fil
466
522
 
467
523
  > **Tip:** Keep the Browser page open while your assistant browses — you can see exactly what it's doing and step in if a site asks for a CAPTCHA or login.
468
524
 
525
+ ### Business Idea Validation
526
+
527
+ Thinking about a new product, service, or direction for your business? Your assistant can walk you through the process of validating the idea before you invest time and money — from initial concept through customer discovery and assumption testing to a clear product brief.
528
+
529
+ | Phase | What happens |
530
+ |-------|-------------|
531
+ | Discovery | Clarify your idea, define your target customer, plan customer conversations, and assess the market |
532
+ | Validation | Identify the riskiest assumptions in your idea and design quick tests to check them |
533
+ | Product brief | Turn the validated concept into a clear document — problem, audience, features, success metrics, and next steps |
534
+
535
+ Your assistant guides you through each phase conversationally — you don't need to know any frameworks or jargon. Just describe your idea and it will ask the right questions.
536
+
537
+ **Try asking:**
538
+ - "I have an idea for a new service — can you help me think it through?"
539
+ - "Help me validate whether this product idea is worth pursuing"
540
+ - "I want to write a product brief for a new offering"
541
+
469
542
  ---
470
543
 
471
544
  ### API Keys
@@ -496,16 +569,17 @@ Additional keys for advanced use cases:
496
569
  |----------|----------------|------------|
497
570
  | **Brave** | Web search — alternative to Tavily | Yes (free plan available) |
498
571
  | **OpenAI** | Voice note transcription, alternative AI models | No |
499
- | **ElevenLabs** | Text-to-speech (for future voice features) | Yes (limited free tier) |
572
+ | **ElevenLabs** | Text-to-speech voice replies | Yes (limited free tier) |
500
573
  | **Replicate** | Image and media AI models | No |
501
- | **Hume** | Voice and emotion AI | No |
574
+ | **Hume** | Text-to-speech voice replies (expressive voice) | Yes |
502
575
 
503
576
  #### Managing Keys
504
577
 
505
578
  1. Go to the **Setup** page
506
579
  2. Click on the **API Keys** row in the status dashboard
507
580
  3. Enter a key next to any provider and click **Save**
508
- 4. To remove a key, click **Remove** next to it
581
+ 4. To temporarily turn off a key without losing it, click the **power icon** next to it — the row dims and the key stops being used. Click the power icon again to re-enable it.
582
+ 5. To permanently remove a key, click the **trash icon** next to it
509
583
 
510
584
  #### Recommended Free Keys
511
585
 
@@ -533,7 +607,7 @@ You get 1,000 free search credits per month — more than enough for daily busin
533
607
  4. **Copy the key** (it starts with `AIza`)
534
608
  5. Go to your Taskmaster **Setup** page, click the **API Keys** row, find **Google**, paste the key, and click **Save**
535
609
 
536
- The free tier works for low-volume use (a handful of voice notes or images per day). For higher volumes, you'll need to enable billing in your Google Cloud account — see [Google AI pricing](https://ai.google.dev/pricing) for details.
610
+ Voice notes work without this key (using the built-in offline model), but adding a Google key enables higher-accuracy cloud transcription and video analysis. The free tier works for low-volume use (a handful of voice notes or images per day). For higher volumes, you'll need to enable billing in your Google Cloud account — see [Google AI pricing](https://ai.google.dev/pricing) for details.
537
611
 
538
612
  ---
539
613
 
@@ -929,7 +1003,7 @@ If the Pi checks pass but the control panel still doesn't load from another devi
929
1003
  If you can't load the Control Panel in your browser:
930
1004
 
931
1005
  1. **Same network?** — Make sure your device is on the same WiFi or LAN as Taskmaster
932
- 2. **Check the URL** — go to **http://taskmaster.local:18789**. Make sure you're using `http` (not `https`) and port `18789`
1006
+ 2. **Check the URL** — go to **http://taskmaster.local:18789** (the browser will redirect to HTTPS automatically). If you see a certificate warning, see "Secure Connection (HTTPS)" above
933
1007
  3. **Wait for boot** — after powering on the device, it takes 2–3 minutes for everything to start. If you just plugged it in, give it a moment
934
1008
  4. **Try a different browser** — some browsers (especially on older devices) have trouble with `.local` addresses. Try Chrome or Safari
935
1009
  5. **Use the IP address** — if `.local` doesn't resolve, find the device's IP address on your router and go to `http://<ip-address>:18789` instead
@@ -1381,6 +1455,31 @@ You can control your assistant's behaviour by typing slash commands in any conve
1381
1455
  | `/activation always` | Make the assistant respond to every group message (not just @mentions) |
1382
1456
  | `/activation mention` | Make the assistant only respond when @mentioned in groups |
1383
1457
 
1458
+ ### Voice replies (Text-to-Speech)
1459
+
1460
+ Your assistant can reply with voice notes instead of text. Two providers are available out of the box:
1461
+
1462
+ | Provider | Requires API key? | Notes |
1463
+ |----------|------------------|-------|
1464
+ | **Edge** (Microsoft) | No — free, works immediately | Good quality neural voices, many languages |
1465
+ | **Hume** | Yes — add in Setup > API Keys | Expressive, emotionally-aware voice (Octave TTS) |
1466
+
1467
+ Voice replies are controlled with the `/tts` command:
1468
+
1469
+ | Command | What it does |
1470
+ |---------|-------------|
1471
+ | `/tts` | Show current TTS status and available providers |
1472
+ | `/tts always` | Every reply is sent as a voice note |
1473
+ | `/tts inbound` | Reply with voice only when you send a voice note |
1474
+ | `/tts off` | Turn off voice replies |
1475
+ | `/tts provider edge` | Use Microsoft Edge TTS (free, no key needed) |
1476
+ | `/tts provider hume` | Use Hume Octave TTS (requires Hume API key) |
1477
+ | `/tts status` | Show current mode, provider, and fallback chain |
1478
+
1479
+ **How it works:** When TTS is enabled, the assistant writes its reply as normal text, and the system automatically converts it to a voice note before sending. If the selected provider fails (e.g. missing API key), it falls back to the next available provider. Emojis are automatically stripped so they don't get read aloud.
1480
+
1481
+ **Quick start:** Just type `/tts always` — Edge TTS will work immediately with no setup. To upgrade to Hume's expressive voice, add a Hume API key in the Control Panel and type `/tts provider hume`.
1482
+
1384
1483
  ### Examples
1385
1484
 
1386
1485
  > **You:** `/filler`
@@ -1392,6 +1491,12 @@ You can control your assistant's behaviour by typing slash commands in any conve
1392
1491
  > **You:** `/think high`
1393
1492
  > **System:** Thinking level set to high.
1394
1493
 
1494
+ > **You:** `/tts always`
1495
+ > **System:** TTS mode set to always.
1496
+
1497
+ > **You:** `/tts provider hume`
1498
+ > **System:** TTS provider set to hume (fallbacks: edge).
1499
+
1395
1500
  ---
1396
1501
 
1397
1502
  ## Groups
Binary file
@@ -80,11 +80,13 @@ stripe refunds create --payment-intent {pi_id}
80
80
 
81
81
  ## Customer Record Management
82
82
 
83
- You have write access to customer records (`contact_update`). Use this for:
83
+ You have full access to customer records (`contact_create`, `contact_update`, `contact_delete`). Use this for:
84
+ - Creating contact records on first meaningful interaction
84
85
  - Updating trust scores after job completion
85
86
  - Setting blacklist status after fee escalation
86
87
  - Reinstating customers after payment
87
88
  - Recording provider opt-out/opt-in
89
+ - Deleting records for data erasure requests
88
90
 
89
91
  The public agent (Beagle) can read records but cannot modify them — this prevents prompt injection from changing payment status.
90
92
 
@@ -93,7 +95,7 @@ The public agent (Beagle) can read records but cannot modify them — this preve
93
95
  ## Data Compliance (Admin-Side Execution)
94
96
 
95
97
  When the Beagle agent receives a data erasure request, you execute the deletion sequence:
96
- 1. Delete the customer record (`contact_update` with DELETE)
98
+ 1. Delete the customer record (`contact_delete`)
97
99
  2. Clear the memory profile
98
100
  3. Redact booking files (replace customer phone/name with [REDACTED])
99
101
  4. Delete member files from booking groups
Binary file
Binary file
@@ -0,0 +1 @@
1
+ .DS_Store
Binary file
Binary file
Binary file
@@ -0,0 +1 @@
1
+ .DS_Store
@@ -106,6 +106,7 @@ You have tool access within your workspace:
106
106
  - Session management
107
107
  - Config commands
108
108
  - File system access (within workspace)
109
+ - **Contact management** — `contact_create`, `contact_lookup`, `contact_update`, `contact_delete` (see skill reference `references/crm.md`)
109
110
  - **Document reading** — use `document_read` to extract text from PDFs, DOCX, XLSX, PPTX files
110
111
  - **Message relay** — use `relay_message` to inject a missed WhatsApp message into the public agent's session (see below)
111
112