@rubytech/taskmaster 1.7.2 → 1.8.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.
@@ -6,7 +6,7 @@
6
6
  <title>Taskmaster Control</title>
7
7
  <meta name="color-scheme" content="dark light" />
8
8
  <link rel="icon" type="image/png" href="./favicon.png" />
9
- <script type="module" crossorigin src="./assets/index-BFPQ4MXV.js"></script>
9
+ <script type="module" crossorigin src="./assets/index-D3tbqnfY.js"></script>
10
10
  <link rel="stylesheet" crossorigin href="./assets/index-CHIqq3Nn.css">
11
11
  </head>
12
12
  <body>
@@ -0,0 +1,165 @@
1
+ /**
2
+ * RPC handlers for network configuration (port + hostname).
3
+ *
4
+ * - network.status: Returns current gateway port (from config) and system hostname.
5
+ * - network.setHostname: Sets the system hostname so mDNS advertises the new .local name.
6
+ * - macOS: `scutil --set LocalHostName` (Bonjour picks it up immediately)
7
+ * - Linux: `hostnamectl set-hostname` + restart avahi-daemon
8
+ *
9
+ * Port changes are handled by the UI via config.patch to gateway.port —
10
+ * the existing reload rule triggers a gateway restart automatically.
11
+ */
12
+ import os from "node:os";
13
+ import { readConfigFileSnapshot } from "../../config/io.js";
14
+ import { resolveGatewayPort, DEFAULT_GATEWAY_PORT } from "../../config/paths.js";
15
+ import { runExec } from "../../process/exec.js";
16
+ import { ErrorCodes, errorShape } from "../protocol/index.js";
17
+ // ---------------------------------------------------------------------------
18
+ // Hostname helpers
19
+ // ---------------------------------------------------------------------------
20
+ /**
21
+ * Validate a hostname per RFC 1123: letters, digits, hyphens, 1–63 chars,
22
+ * cannot start or end with a hyphen.
23
+ */
24
+ function isValidHostname(name) {
25
+ return /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/.test(name);
26
+ }
27
+ /**
28
+ * Read the mDNS local hostname (the name before `.local`).
29
+ *
30
+ * - macOS: `scutil --get LocalHostName` returns the Bonjour name directly.
31
+ * - Linux: `hostname` (which is also what avahi-daemon advertises).
32
+ * - Fallback: `os.hostname()` (may include `.local` suffix on some systems).
33
+ */
34
+ async function readLocalHostname() {
35
+ const platform = os.platform();
36
+ try {
37
+ if (platform === "darwin") {
38
+ const { stdout } = await runExec("/usr/sbin/scutil", ["--get", "LocalHostName"], {
39
+ timeoutMs: 5_000,
40
+ });
41
+ const name = stdout.trim();
42
+ if (name)
43
+ return name;
44
+ }
45
+ else if (platform === "linux") {
46
+ const { stdout } = await runExec("hostname", [], { timeoutMs: 5_000 });
47
+ const name = stdout.trim();
48
+ if (name)
49
+ return name;
50
+ }
51
+ }
52
+ catch {
53
+ // Fall through to os.hostname()
54
+ }
55
+ // Strip any trailing .local that os.hostname() might include
56
+ return os.hostname().replace(/\.local$/, "");
57
+ }
58
+ /**
59
+ * Set the mDNS local hostname on the current platform.
60
+ *
61
+ * - macOS: `scutil --set LocalHostName <name>` — Bonjour picks it up immediately.
62
+ * - Linux: `hostnamectl set-hostname <name>` then restart avahi-daemon.
63
+ *
64
+ * Returns null on success, or an error message string on failure.
65
+ */
66
+ async function setLocalHostname(hostname, log) {
67
+ const platform = os.platform();
68
+ if (platform === "darwin") {
69
+ try {
70
+ await runExec("/usr/sbin/scutil", ["--set", "LocalHostName", hostname], {
71
+ timeoutMs: 10_000,
72
+ });
73
+ }
74
+ catch (err) {
75
+ const detail = err instanceof Error ? err.message : String(err);
76
+ log.warn(`network.setHostname: scutil failed: ${detail}`);
77
+ return `Failed to set hostname: ${detail}`;
78
+ }
79
+ return null;
80
+ }
81
+ if (platform === "linux") {
82
+ try {
83
+ await runExec("hostnamectl", ["set-hostname", hostname], { timeoutMs: 10_000 });
84
+ }
85
+ catch (err) {
86
+ const detail = err instanceof Error ? err.message : String(err);
87
+ log.warn(`network.setHostname: hostnamectl failed: ${detail}`);
88
+ return `Failed to set hostname: ${detail}`;
89
+ }
90
+ // Restart avahi-daemon so mDNS advertises the new hostname.
91
+ try {
92
+ await runExec("systemctl", ["restart", "avahi-daemon"], { timeoutMs: 10_000 });
93
+ }
94
+ catch (err) {
95
+ // Non-fatal — hostname was set, but mDNS may take time to propagate.
96
+ const detail = err instanceof Error ? err.message : String(err);
97
+ log.warn(`network.setHostname: avahi-daemon restart failed: ${detail}`);
98
+ }
99
+ return null;
100
+ }
101
+ return `Hostname management is not supported on ${platform}`;
102
+ }
103
+ // ---------------------------------------------------------------------------
104
+ // Handlers
105
+ // ---------------------------------------------------------------------------
106
+ export const networkHandlers = {
107
+ /**
108
+ * Return current gateway port and effective mDNS hostname.
109
+ * The hostname comes from discovery.bonjourHostname in config if set
110
+ * (this is what the gateway advertises via mDNS), otherwise the system hostname.
111
+ */
112
+ "network.status": async ({ respond }) => {
113
+ try {
114
+ const snapshot = await readConfigFileSnapshot();
115
+ const port = snapshot.valid ? resolveGatewayPort(snapshot.config) : DEFAULT_GATEWAY_PORT;
116
+ // Effective mDNS hostname: config override takes priority over system hostname
117
+ const configHostname = snapshot.valid
118
+ ? snapshot.config.discovery
119
+ ? snapshot.config.discovery
120
+ ?.bonjourHostname
121
+ : undefined
122
+ : undefined;
123
+ const hostname = typeof configHostname === "string" && configHostname
124
+ ? configHostname
125
+ : await readLocalHostname();
126
+ respond(true, { port, hostname });
127
+ }
128
+ catch (err) {
129
+ respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, `Failed to read network status: ${err instanceof Error ? err.message : String(err)}`));
130
+ }
131
+ },
132
+ /**
133
+ * Set the system hostname (macOS + Linux).
134
+ *
135
+ * - macOS: scutil --set LocalHostName (Bonjour picks it up immediately)
136
+ * - Linux: hostnamectl set-hostname + restart avahi-daemon
137
+ *
138
+ * Params: { hostname: string }
139
+ *
140
+ * The caller should also config.patch discovery.bonjourHostname to keep
141
+ * the gateway's Bonjour advertisement in sync.
142
+ */
143
+ "network.setHostname": async ({ params, respond, context }) => {
144
+ const platform = os.platform();
145
+ if (platform !== "darwin" && platform !== "linux") {
146
+ respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, `Hostname management is not supported on ${platform}`));
147
+ return;
148
+ }
149
+ const hostname = typeof params.hostname === "string" ? params.hostname.trim() : "";
150
+ if (!hostname) {
151
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "Missing required parameter: hostname"));
152
+ return;
153
+ }
154
+ if (!isValidHostname(hostname)) {
155
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "Invalid hostname — use letters, digits, and hyphens only (1–63 characters, cannot start or end with a hyphen)"));
156
+ return;
157
+ }
158
+ const error = await setLocalHostname(hostname, context.logGateway);
159
+ if (error) {
160
+ respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, error));
161
+ return;
162
+ }
163
+ respond(true, { hostname });
164
+ },
165
+ };
@@ -83,6 +83,8 @@ const BASE_METHODS = [
83
83
  "cron.remove",
84
84
  "cron.run",
85
85
  "cron.runs",
86
+ "network.status",
87
+ "network.setHostname",
86
88
  "system-presence",
87
89
  "system-event",
88
90
  "send",
@@ -34,6 +34,7 @@ import { webHandlers } from "./server-methods/web.js";
34
34
  import { wizardHandlers } from "./server-methods/wizard.js";
35
35
  import { publicChatHandlers } from "./server-methods/public-chat.js";
36
36
  import { tailscaleHandlers } from "./server-methods/tailscale.js";
37
+ import { networkHandlers } from "./server-methods/network.js";
37
38
  import { wifiHandlers } from "./server-methods/wifi.js";
38
39
  import { workspacesHandlers } from "./server-methods/workspaces.js";
39
40
  import { brandHandlers } from "./server-methods/brand.js";
@@ -239,6 +240,7 @@ export const coreGatewayHandlers = {
239
240
  ...workspacesHandlers,
240
241
  ...brandHandlers,
241
242
  ...publicChatHandlers,
243
+ ...networkHandlers,
242
244
  ...tailscaleHandlers,
243
245
  ...wifiHandlers,
244
246
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/taskmaster",
3
- "version": "1.7.2",
3
+ "version": "1.8.0",
4
4
  "description": "AI-powered business assistant for small businesses",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: taskmaster
3
+ description: "Product knowledge for Taskmaster — answers questions about features, setup, channels, tools, skills, troubleshooting, and what's new by fetching live documentation."
4
+ metadata: {"taskmaster":{"always":true,"emoji":"📚","skillKey":"taskmaster"}}
5
+ ---
6
+
7
+ # Taskmaster Product Knowledge
8
+
9
+ You can answer questions about Taskmaster itself — the platform your assistant runs on. Product documentation is available live at `docs.taskmaster.bot`.
10
+
11
+ ## When This Applies
12
+
13
+ Activate when the user asks about Taskmaster features, setup, configuration, channels, tools, skills, troubleshooting, updates, or anything about the platform itself — not their business.
14
+
15
+ ## How to Answer
16
+
17
+ Use `web_fetch` to pull documentation from `docs.taskmaster.bot`. Load `references/docs-guide.md` for the full strategy on discovering and fetching the right page.
18
+
19
+ **Quick path:**
20
+ 1. Fetch `https://docs.taskmaster.bot/sitemap` to see all available pages
21
+ 2. Identify the most relevant page for the question
22
+ 3. Fetch that page and answer from its content
23
+
24
+ For "what's new" or version questions, fetch `https://docs.taskmaster.bot/changelog`.
25
+
26
+ ## Boundaries
27
+
28
+ - Answer only from fetched documentation — never fabricate features or capabilities
29
+ - If the docs don't answer the question, say so honestly and escalate
30
+ - This skill covers product knowledge only — not the user's business operations
31
+
32
+ ## Escalation
33
+
34
+ When you cannot resolve a question from the documentation, direct the user to contact Taskmaster support by messaging the Taskmaster WhatsApp number. Frame it helpfully: "I couldn't find that in the docs — you can message the Taskmaster team on WhatsApp for help."
@@ -0,0 +1,74 @@
1
+ # Documentation Fetching Guide
2
+
3
+ ## Base URL
4
+
5
+ All documentation lives at `https://docs.taskmaster.bot`. Every page can be fetched with `web_fetch`.
6
+
7
+ ## Discovery Strategy
8
+
9
+ **Start with the sitemap.** Before guessing at page paths, fetch:
10
+
11
+ ```
12
+ https://docs.taskmaster.bot/sitemap
13
+ ```
14
+
15
+ This returns a structured index of every documentation page, organized by section (Getting Started, Channels, Tools, etc.) with brief descriptions. Scan it to find the right page for the user's question.
16
+
17
+ **You only need the sitemap once per session.** After the first fetch, you'll know the available pages and can go directly to specific ones.
18
+
19
+ ## Fetching Pages
20
+
21
+ Once you know the right page path from the sitemap, fetch it directly:
22
+
23
+ ```
24
+ https://docs.taskmaster.bot/channels/whatsapp
25
+ https://docs.taskmaster.bot/tools/skills
26
+ https://docs.taskmaster.bot/gateway/configuration
27
+ ```
28
+
29
+ The fetched content is the full documentation page in readable format. Answer the user's question from this content.
30
+
31
+ ## Common Query Patterns
32
+
33
+ | User asks about... | Fetch |
34
+ |---|---|
35
+ | Setting up a channel (WhatsApp, Telegram, etc.) | `/channels/{channel-name}` |
36
+ | A specific tool or capability | `/tools/{tool-name}` |
37
+ | Skills — creating, editing, managing | `/tools/skills` and `/tools/skills-config` |
38
+ | Gateway configuration or troubleshooting | `/gateway/configuration` or `/gateway/troubleshooting` |
39
+ | Installation or updating | `/install/installer` or `/install/updating` |
40
+ | What's new, recent changes, version info | `/changelog` |
41
+ | General help or getting unstuck | `/help` or `/help/troubleshooting` |
42
+ | How something works conceptually | `/concepts/{concept}` |
43
+ | CLI command usage | `/cli/{command}` |
44
+ | A specific AI provider | `/providers/{provider}` |
45
+ | Multi-agent setup | `/concepts/multi-agent` |
46
+ | Memory system | `/concepts/memory` |
47
+ | Cron jobs / scheduled tasks | `/automation/cron-jobs` |
48
+ | Webhooks | `/automation/webhook` |
49
+ | Remote access | `/gateway/remote` or `/gateway/tailscale` |
50
+
51
+ ## Response Guidelines
52
+
53
+ - **Keep answers concise.** The user asked a question — answer it. Don't dump the entire page.
54
+ - **Quote relevant sections** when precision matters (configuration keys, command syntax).
55
+ - **Link to the docs page** so the user can read more: "You can read more at docs.taskmaster.bot/tools/skills"
56
+ - **If the page doesn't fully answer the question**, say what you found and what's missing, then escalate.
57
+
58
+ ## What's New
59
+
60
+ For questions about recent changes, new features, or version history:
61
+
62
+ ```
63
+ https://docs.taskmaster.bot/changelog
64
+ ```
65
+
66
+ The changelog is organized by version with dates and categorized changes (features, fixes). Use this for "what's new?", "what changed in the latest update?", or version-specific questions.
67
+
68
+ ## Escalation
69
+
70
+ If the documentation doesn't answer the question:
71
+
72
+ 1. Tell the user what you searched and what you found (or didn't find)
73
+ 2. Direct them to contact Taskmaster support on WhatsApp for further help
74
+ 3. Don't guess or speculate — honesty builds trust
@@ -805,6 +805,8 @@ You can also create events by asking the assistant in chat ("remind me every Mon
805
805
 
806
806
  Skills are specialised abilities your assistant has — handling customer enquiries, creating quotes, checking the weather, generating images, and more. The Skills tab shows every skill that is installed, whether it is active, and flags anything that is missing (such as an API key a skill needs).
807
807
 
808
+ One of the preloaded skills is **Taskmaster Product Knowledge**. This lets your assistant answer questions about Taskmaster itself — features, setup, channels, tools, troubleshooting, and what's new. It pulls answers from the live documentation at [docs.taskmaster.bot](https://docs.taskmaster.bot). If it can't find an answer, it will direct you to contact Taskmaster support on WhatsApp.
809
+
808
810
  Each skill has a label:
809
811
 
810
812
  | Label | Meaning |
@@ -868,28 +870,27 @@ If your Pi is connected by Ethernet cable, you can switch to WiFi directly from
868
870
 
869
871
  1. Go to the **Setup** page
870
872
  2. Find the **WiFi** row in the status dashboard (only appears on Raspberry Pi)
871
- 3. Tap **Scan** — a list of nearby WiFi networks appears, sorted by signal strength
872
- 4. Tap the network you want to connect to
873
- 5. If the network is password-protected, enter the password and tap **Connect** (or press Enter)
874
- 6. The row updates to show the connected network name, signal strength, and IP address
873
+ 3. Tap **Edit** — a modal opens with WiFi management controls
874
+ 4. Tap **Scan** inside the modal a list of nearby WiFi networks appears, sorted by signal strength
875
+ 5. Tap the network you want to connect to
876
+ 6. If the network is password-protected, enter the password and tap **Connect** (or press Enter)
877
+ 7. The WiFi row updates to show the connected network name, signal strength, and IP address
875
878
 
876
879
  **Signal bars** next to each network name show the signal strength — more lit bars means a stronger signal.
877
880
 
878
881
  **Auto-reconnect:** Once connected, your Pi remembers the WiFi network and password. If the connection drops (e.g. router reboot, temporary signal loss), the Pi automatically reconnects without any action needed. The WiFi row shows "Saved: (network name)" when a saved network exists but the connection is temporarily down.
879
882
 
880
- **Reconnecting:** If WiFi was manually disconnected and you want to reconnect to the saved network, tap **Reconnect** — no need to re-enter the password.
881
-
882
- **Disconnecting:** Tap **Disconnect** to intentionally drop the current WiFi connection. This prevents auto-reconnect until you tap **Reconnect** or connect to a new network.
883
+ **Reconnecting:** If WiFi was manually disconnected and you want to reconnect to the saved network, tap **Reconnect** inside the WiFi modal — no need to re-enter the password.
883
884
 
884
- **Forgetting a network:** Tap **Forget** to remove the saved WiFi password entirely. After forgetting, you'll need to scan and enter the password again to reconnect.
885
+ **Disconnecting:** Tap **Disconnect** inside the modal to intentionally drop the current WiFi connection. This prevents auto-reconnect until you tap **Reconnect** or connect to a new network.
885
886
 
886
- **Closing the list:** Tap **Close** to dismiss the network list without making changes. You can also tap the network you're already connected to (marked with a green tick) to dismiss the list.
887
+ **Forgetting a network:** Tap **Forget** inside the modal to remove the saved WiFi password entirely. After forgetting, you'll need to scan and enter the password again to reconnect.
887
888
 
888
889
  > **Tip:** Connect an Ethernet cable first, open the Control Panel, then use the WiFi row to connect. Once WiFi is working, you can remove the Ethernet cable.
889
890
 
890
891
  ### Changing Network Settings
891
892
 
892
- You might need to change two network settings after your Pi is deployed:
893
+ You can change the port and hostname from the Setup page no terminal access needed.
893
894
 
894
895
  - **Port** — The number at the end of your control panel URL (e.g., `http://taskmaster.local:18789`)
895
896
  - **mDNS hostname** — The friendly name before `.local` (e.g., `taskmaster` in `taskmaster.local`)
@@ -907,7 +908,7 @@ The port is like an apartment number for your Taskmaster server. The default is
907
908
 
908
909
  #### What is the mDNS hostname and why would I change it?
909
910
 
910
- The mDNS hostname is the friendly name you use to access your Pi on your local network. The default is `taskmaster`, so your control panel is at `taskmaster.local`.
911
+ The mDNS hostname is the friendly name you use to access your device on your local network. The default is `taskmaster`, so your control panel is at `taskmaster.local`.
911
912
 
912
913
  **When to change it:**
913
914
  - You're running multiple Taskmaster instances on the same network (they'll conflict if they all use `taskmaster.local`)
@@ -915,128 +916,45 @@ The mDNS hostname is the friendly name you use to access your Pi on your local n
915
916
 
916
917
  **What happens when you change it:** Your control panel URL changes. If you set the hostname to `dave`, you'll access Taskmaster at `http://dave.local:18789`.
917
918
 
918
- #### How to make these changes
919
+ #### How to change port and hostname (from the Control Panel)
919
920
 
920
- You have two options for accessing your Pi:
921
-
922
- **Option 1: Direct Access (Keyboard + Monitor)**
923
- 1. Plug a keyboard and monitor into your Pi
924
- 2. Log in (default user: `taskmaster`, password: `taskmaster`)
925
- 3. Follow the instructions below
921
+ 1. Go to the **Setup** page
922
+ 2. Find the **Network** row in the status dashboard — it shows your current hostname and port
923
+ 3. Tap **Edit** a modal opens with two fields: **Hostname** and **Port**
924
+ 4. Change whichever values you need (hostname must be letters, digits, and hyphens only, 1–63 characters; port must be between 1024 and 65535)
925
+ 5. Tap **Save**
926
+ 6. The gateway restarts automatically and your browser redirects to the new URL
926
927
 
927
- **Option 2: SSH (from another computer)**
928
- 1. Open Terminal (Mac/Linux) or PowerShell (Windows)
929
- 2. Connect to your Pi: `ssh admin@taskmaster.local`
930
- 3. Enter the password when prompted (default: `password`)
931
- 4. Follow the instructions below
928
+ > **Note:** After saving, there is a brief pause while the gateway restarts. Your browser will redirect to the new address automatically. If the page doesn't load within a few seconds, navigate to the new URL manually (e.g. `http://dave.local:19000`).
932
929
 
933
- #### Changing the Port
930
+ #### Fallback: CLI method
934
931
 
935
- Once you're logged in (either method):
932
+ If you can't reach the Control Panel (e.g. the gateway is down), you can make the same changes from the terminal.
936
933
 
937
- **Step 1:** Update the configuration
934
+ **Changing the port:**
938
935
 
939
936
  ```bash
940
937
  taskmaster config set gateway.port 19000
941
- ```
942
-
943
- (Replace `19000` with whatever port you want)
944
-
945
- **Step 2:** Reinstall the daemon service (this rewrites the service file with the new port)
946
-
947
- ```bash
948
938
  taskmaster daemon install --force
949
939
  ```
950
940
 
951
- > **Important:** Do not use `taskmaster daemon restart` here — that restarts the service with the old port. You must use `taskmaster daemon install --force` to pick up the new port from the configuration.
952
-
953
- **Step 3:** Access the control panel at the new URL: `http://taskmaster.local:19000` (use your new port number)
941
+ > **Important:** Use `taskmaster daemon install --force` (not `taskmaster daemon restart`) to pick up the new port.
954
942
 
955
- #### Changing the mDNS Hostname
956
-
957
- Once you're logged in (either method):
958
-
959
- **Step 1:** Set the new hostname
943
+ **Changing the hostname (Linux / Raspberry Pi):**
960
944
 
961
945
  ```bash
962
946
  sudo hostnamectl set-hostname dave
963
- ```
964
-
965
- (Replace `dave` with whatever name you want — letters and hyphens only, no spaces)
966
-
967
- > You will see a warning on every `sudo` command until Step 2 completes: `sudo: unable to resolve host dave: Name or service not known`. This is normal — the hostname was changed but the system hasn't been told where to find it yet. Every command still succeeds despite the warning.
968
-
969
- **Step 2:** Update `/etc/hosts` to match
970
-
971
- ```bash
972
947
  sudo sed -i "s/127\.0\.1\.1.*/127.0.1.1\tdave/" /etc/hosts
973
- ```
974
-
975
- (Replace `dave` with the same name you used in Step 1. You'll see the same warning one last time — after this command, it's gone.)
976
-
977
- **Step 3:** Restart the mDNS service
978
-
979
- ```bash
980
948
  sudo systemctl restart avahi-daemon
981
949
  ```
982
950
 
983
- > **If you're connected via SSH**, your connection will stop working after this step because the old hostname is no longer valid. Reconnect using the new hostname: `ssh admin@dave.local`
984
-
985
- **Step 4:** Access the control panel at the new URL: `http://dave.local:18789` (use your new hostname)
986
-
987
- > **Note:** This changes the hostname for the entire Pi, not just Taskmaster.
988
-
989
- #### Changing Both
990
-
991
- If you need to change both the port and hostname:
992
-
993
- 1. Change the port first (Steps 1–2 under "Changing the Port")
994
- 2. Change the hostname (Steps 1–2 under "Changing the mDNS Hostname")
995
- 3. Access the control panel at the new combined URL: `http://dave.local:19000` (use your new hostname + new port)
996
-
997
- #### Verifying Your Changes
998
-
999
- After completing the steps above, run these checks **on the Pi** to confirm everything is correct.
1000
-
1001
- **Check the hostname is set:**
1002
-
1003
- ```bash
1004
- hostname
1005
- ```
1006
-
1007
- This should print your new hostname (e.g. `dave`).
1008
-
1009
- **Check `/etc/hosts` matches:**
1010
-
1011
- ```bash
1012
- grep 127.0.1.1 /etc/hosts
1013
- ```
1014
-
1015
- This should show `127.0.1.1` followed by your new hostname (e.g. `127.0.1.1 dave`).
1016
-
1017
- **Check avahi is broadcasting the new hostname:**
1018
-
1019
- ```bash
1020
- avahi-resolve -n dave.local
1021
- ```
1022
-
1023
- (Replace `dave` with your hostname.) This should print your Pi's IP address. If it says "Failed to resolve", restart avahi: `sudo systemctl restart avahi-daemon` and try again.
1024
-
1025
- **Check the gateway is running on the correct port:**
1026
-
1027
- ```bash
1028
- taskmaster daemon status
1029
- ```
1030
-
1031
- This shows the port the gateway is listening on. Confirm it matches what you set.
1032
-
1033
- **Test locally on the Pi:**
951
+ **Changing the hostname (macOS):**
1034
952
 
1035
953
  ```bash
1036
- curl -s -o /dev/null -w "%{http_code}" http://localhost:18789
954
+ sudo scutil --set LocalHostName dave
1037
955
  ```
1038
956
 
1039
- (Use your new port number.) If this prints `200`, the gateway is running. If it fails, restart: `taskmaster daemon restart`.
957
+ After either method, access the control panel at the new URL (e.g. `http://dave.local:19000`).
1040
958
 
1041
959
  #### Flushing DNS Cache on Other Devices
1042
960
 
@@ -1711,7 +1629,7 @@ Taskmaster includes a command-line tool called `taskmaster` that you can run in
1711
1629
 
1712
1630
  - **Can't reach the Control Panel** — If the web UI is down, SSH into the device and use CLI commands to restart or update
1713
1631
  - **Updating from a specific version** — `taskmaster update` works even when the Control Panel can't load
1714
- - **Changing network settings** — Port and hostname changes require the terminal (see "Changing Network Settings" above)
1632
+ - **Changing network settings when the UI is unreachable** — Port and hostname are normally changed from the Setup page, but the CLI works as a fallback (see "Changing Network Settings" above)
1715
1633
  - **Diagnosing problems** — `taskmaster doctor` runs automated health checks that can detect and fix issues the UI can't show
1716
1634
  - **Scripting and automation** — CLI commands can be combined in scripts for advanced setups
1717
1635
 
@@ -1,58 +1,35 @@
1
1
  ---
2
2
  name: taskmaster
3
- description: "Handle enquiries about Taskmaster — the AI business assistant for small businesses. Product info, pricing, signup, licensing, and support."
3
+ description: "Handle enquiries about Taskmaster — the AI business assistant for small businesses. Product info, pricing, signup, licensing, and support. Fetches live documentation and uses memory for commercial data."
4
+ metadata: {"taskmaster":{"always":true,"emoji":"📚","skillKey":"taskmaster"}}
4
5
  ---
5
6
 
6
- # Taskmaster Product Skill
7
+ # Taskmaster Product & Sales Skill
7
8
 
8
- ## Core Principle: Memory First
9
+ You handle enquiries about Taskmaster itself — product info, features, pricing, signup, licensing, and support. You combine live documentation with commercial data from memory.
9
10
 
10
- **ALWAYS search memory before responding to any message.** Product info, pricing, FAQs, lessons, and guidelines all live in memory. Never answer from assumptions — check first.
11
+ ## When This Applies
11
12
 
12
- ```
13
- 1. Receive message
14
- 2. Search memory for relevant context (FAQ, product info, lessons)
15
- 3. Formulate response using what you found
16
- 4. Send response
17
- ```
13
+ Activate when someone asks about Taskmaster: what it does, how it works, pricing, how to sign up, licensing, or needs support with the product.
18
14
 
19
- A couple extra seconds for search is fine — this is async messaging, not a phone call.
15
+ ## Knowledge Sources
20
16
 
21
- ---
22
-
23
- ## What Lives in Memory (Not Here)
24
-
25
- The following are stored in memory and will change over time. **Never hardcode these:**
26
-
27
- - Pricing and plans
28
- - Features and capabilities
29
- - Setup process
30
- - Trial/guarantee terms
31
- - Programme details (founding members, etc.)
32
- - Specific objection responses
33
- - Brand positioning and tone guidelines
34
-
35
- Search `memory/public/` for product info and FAQs.
36
- Search `memory/shared/` for internal lessons and guidelines.
17
+ **Product knowledge → live docs.** Use `web_fetch` to pull from `docs.taskmaster.bot`. Fetch `/sitemap` first to discover pages, then fetch specific pages to answer feature/setup/troubleshooting questions. For "what's new", fetch `/changelog`.
37
18
 
38
- ---
19
+ **Commercial data → memory.** Pricing, plans, trial terms, programme details, objection responses, and prospect pipeline all live in memory. Search `memory/public/` for product info and FAQs. Search `memory/shared/` for internal guidelines and lessons.
39
20
 
40
- ## Behavior Guidelines
21
+ **Always check both sources.** Docs for product facts, memory for commercial context. A couple extra seconds for search is fine — this is async messaging.
41
22
 
42
- ### Tone
43
- - Friendly, direct, no waffle
44
- - WhatsApp-short messages (not walls of text)
45
- - Confident but not pushy
46
- - Honest about limitations
23
+ ## Conversation Flow
47
24
 
48
- ### Conversation Flow
49
25
  1. **Greet** — warm, ask what they'd like to know
50
- 2. **Search** — find relevant info in memory
51
- 3. **Answer** — use memory content, keep it concise
26
+ 2. **Search** — fetch relevant docs page AND search memory
27
+ 3. **Answer** — combine documentation with commercial context, keep it concise
52
28
  4. **Guide** — if interested, explain next steps (from memory)
53
- 5. **Capture** — if ready, collect their details
29
+ 5. **Capture** — if ready, collect prospect details
30
+
31
+ ## When Prospects Are Interested
54
32
 
55
- ### When Prospects Are Interested
56
33
  Collect:
57
34
  - Name
58
35
  - Industry or business type
@@ -61,7 +38,15 @@ Collect:
61
38
 
62
39
  Store in memory for follow-up.
63
40
 
64
- ### Escalation
41
+ ## Tone
42
+
43
+ - Friendly, direct, no waffle
44
+ - WhatsApp-short messages (not walls of text)
45
+ - Confident but not pushy
46
+ - Honest about limitations
47
+
48
+ ## Escalation
49
+
65
50
  Hand off to admin when:
66
51
  - Billing, refunds, or payment issues
67
52
  - Complaints or unhappy customers
@@ -69,20 +54,17 @@ Hand off to admin when:
69
54
  - Custom requests outside standard offering
70
55
  - Anything you're uncertain about
71
56
 
72
- ---
73
-
74
57
  ## Hard Boundaries
75
58
 
76
59
  **NEVER:**
77
60
  - Give industry-specific professional advice
78
- - Quote prices for their services (only product pricing from memory)
79
- - Make up features or capabilities — if not in memory, don't claim it
61
+ - Quote prices for their services (only Taskmaster product pricing from memory)
62
+ - Make up features or capabilities — if not in docs or memory, don't claim it
80
63
  - Make custom pricing promises without admin approval
81
- - Pretend to be the customer's assistant (you're the company assistant)
82
- - Answer product questions without checking memory first
64
+ - Pretend to be the customer's assistant (you're the Taskmaster company assistant)
83
65
 
84
66
  **ALWAYS:**
85
- - Search memory before every response
67
+ - Fetch docs for product questions, search memory for commercial questions
86
68
  - Be honest about limitations
87
69
  - Escalate what you can't handle
88
70
  - Keep messages short and scannable