@rubytech/taskmaster 1.0.106 → 1.0.107

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 (36) hide show
  1. package/dist/agents/skills-status.js +23 -3
  2. package/dist/agents/skills.js +1 -0
  3. package/dist/agents/system-prompt.js +1 -0
  4. package/dist/agents/tools/memory-tool.js +2 -1
  5. package/dist/build-info.json +3 -3
  6. package/dist/config/zod-schema.js +12 -1
  7. package/dist/control-ui/assets/index-2XyxmiR6.css +1 -0
  8. package/dist/control-ui/assets/{index-DtuDNTAC.js → index-B_zHmTQU.js} +823 -645
  9. package/dist/control-ui/assets/index-B_zHmTQU.js.map +1 -0
  10. package/dist/control-ui/index.html +2 -2
  11. package/dist/control-ui/maxy-icon.png +0 -0
  12. package/dist/gateway/config-reload.js +1 -0
  13. package/dist/gateway/control-ui.js +111 -5
  14. package/dist/gateway/protocol/index.js +6 -1
  15. package/dist/gateway/protocol/schema/agents-models-skills.js +23 -0
  16. package/dist/gateway/protocol/schema/protocol-schemas.js +6 -1
  17. package/dist/gateway/server-http.js +6 -1
  18. package/dist/gateway/server-methods/brand.js +160 -0
  19. package/dist/gateway/server-methods/skills.js +159 -3
  20. package/dist/gateway/server-methods-list.js +5 -0
  21. package/dist/gateway/server-methods.js +2 -0
  22. package/dist/memory/manager.js +12 -3
  23. package/package.json +1 -1
  24. package/skills/skill-builder/SKILL.md +97 -0
  25. package/skills/skill-builder/references/lean-pattern.md +118 -0
  26. package/skills/zero-to-prototype/SKILL.md +35 -0
  27. package/skills/zero-to-prototype/references/discovery.md +64 -0
  28. package/skills/zero-to-prototype/references/prd.md +83 -0
  29. package/skills/zero-to-prototype/references/validation.md +67 -0
  30. package/taskmaster-docs/USER-GUIDE.md +58 -2
  31. package/templates/customer/agents/public/AGENTS.md +3 -10
  32. package/templates/taskmaster/agents/public/SOUL.md +0 -4
  33. package/templates/tradesupport/agents/public/AGENTS.md +3 -10
  34. package/dist/control-ui/assets/index-DjhCZlZd.css +0 -1
  35. package/dist/control-ui/assets/index-DtuDNTAC.js.map +0 -1
  36. package/skills/taskmaster/SKILL.md +0 -164
@@ -1,10 +1,13 @@
1
- import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../../agents/agent-scope.js";
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { resolveAgentWorkspaceDir, resolveAgentWorkspaceRoot, resolveDefaultAgentId } from "../../agents/agent-scope.js";
2
4
  import { installSkill } from "../../agents/skills-install.js";
3
5
  import { buildWorkspaceSkillStatus } from "../../agents/skills-status.js";
4
- import { loadWorkspaceSkillEntries } from "../../agents/skills.js";
6
+ import { loadWorkspaceSkillEntries, resolveBundledSkillsDir } from "../../agents/skills.js";
7
+ import { bumpSkillsSnapshotVersion } from "../../agents/skills/refresh.js";
5
8
  import { loadConfig, writeConfigFile } from "../../config/config.js";
6
9
  import { getRemoteSkillEligibility } from "../../infra/skills-remote.js";
7
- import { ErrorCodes, errorShape, formatValidationErrors, validateSkillsBinsParams, validateSkillsInstallParams, validateSkillsStatusParams, validateSkillsUpdateParams, } from "../protocol/index.js";
10
+ import { ErrorCodes, errorShape, formatValidationErrors, validateSkillsBinsParams, validateSkillsCreateParams, validateSkillsDeleteDraftParams, validateSkillsDeleteParams, validateSkillsDraftsParams, validateSkillsInstallParams, validateSkillsReadParams, validateSkillsStatusParams, validateSkillsUpdateParams, } from "../protocol/index.js";
8
11
  function listWorkspaceDirs(cfg) {
9
12
  const dirs = new Set();
10
13
  const list = cfg.agents?.list;
@@ -45,6 +48,21 @@ function collectSkillBins(entries) {
45
48
  }
46
49
  return [...bins].sort();
47
50
  }
51
+ function resolveWorkspaceRoot(cfg) {
52
+ return resolveAgentWorkspaceRoot(cfg, resolveDefaultAgentId(cfg));
53
+ }
54
+ function isPreloadedSkill(skillKey) {
55
+ const dir = resolveBundledSkillsDir();
56
+ if (!dir)
57
+ return false;
58
+ try {
59
+ return fs.existsSync(`${dir}/${skillKey}`) &&
60
+ fs.statSync(`${dir}/${skillKey}`).isDirectory();
61
+ }
62
+ catch {
63
+ return false;
64
+ }
65
+ }
48
66
  export const skillsHandlers = {
49
67
  "skills.status": ({ params, respond }) => {
50
68
  if (!validateSkillsStatusParams(params)) {
@@ -97,6 +115,10 @@ export const skillsHandlers = {
97
115
  return;
98
116
  }
99
117
  const p = params;
118
+ if (p.enabled === false && isPreloadedSkill(p.skillKey)) {
119
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "preloaded skills cannot be disabled"));
120
+ return;
121
+ }
100
122
  const cfg = loadConfig();
101
123
  const skills = cfg.skills ? { ...cfg.skills } : {};
102
124
  const entries = skills.entries ? { ...skills.entries } : {};
@@ -134,4 +156,138 @@ export const skillsHandlers = {
134
156
  await writeConfigFile(nextConfig);
135
157
  respond(true, { ok: true, skillKey: p.skillKey, config: current }, undefined);
136
158
  },
159
+ "skills.read": ({ params, respond }) => {
160
+ if (!validateSkillsReadParams(params)) {
161
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `invalid skills.read params: ${formatValidationErrors(validateSkillsReadParams.errors)}`));
162
+ return;
163
+ }
164
+ const p = params;
165
+ const cfg = loadConfig();
166
+ const root = resolveWorkspaceRoot(cfg);
167
+ const skillDir = path.join(root, "skills", p.name);
168
+ const skillFile = path.join(skillDir, "SKILL.md");
169
+ if (!fs.existsSync(skillFile)) {
170
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `skill "${p.name}" not found`));
171
+ return;
172
+ }
173
+ const content = fs.readFileSync(skillFile, "utf-8");
174
+ const references = [];
175
+ const refsDir = path.join(skillDir, "references");
176
+ if (fs.existsSync(refsDir) && fs.statSync(refsDir).isDirectory()) {
177
+ for (const entry of fs.readdirSync(refsDir, { withFileTypes: true })) {
178
+ if (entry.isFile() && entry.name.endsWith(".md")) {
179
+ references.push({
180
+ name: entry.name,
181
+ content: fs.readFileSync(path.join(refsDir, entry.name), "utf-8"),
182
+ });
183
+ }
184
+ }
185
+ references.sort((a, b) => a.name.localeCompare(b.name));
186
+ }
187
+ respond(true, { name: p.name, content, references }, undefined);
188
+ },
189
+ "skills.create": async ({ params, respond }) => {
190
+ if (!validateSkillsCreateParams(params)) {
191
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `invalid skills.create params: ${formatValidationErrors(validateSkillsCreateParams.errors)}`));
192
+ return;
193
+ }
194
+ const p = params;
195
+ if (isPreloadedSkill(p.name)) {
196
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "cannot overwrite a preloaded skill"));
197
+ return;
198
+ }
199
+ const cfg = loadConfig();
200
+ const root = resolveWorkspaceRoot(cfg);
201
+ const skillDir = path.join(root, "skills", p.name);
202
+ // If the skill already exists (user skill), remove it first so we get a clean replace
203
+ if (fs.existsSync(skillDir)) {
204
+ fs.rmSync(skillDir, { recursive: true, force: true });
205
+ }
206
+ fs.mkdirSync(skillDir, { recursive: true });
207
+ fs.writeFileSync(path.join(skillDir, "SKILL.md"), p.skillContent, "utf-8");
208
+ if (p.references && p.references.length > 0) {
209
+ const refsDir = path.join(skillDir, "references");
210
+ fs.mkdirSync(refsDir, { recursive: true });
211
+ for (const ref of p.references) {
212
+ const safeName = ref.name.replace(/[^a-zA-Z0-9._-]/g, "-");
213
+ fs.writeFileSync(path.join(refsDir, safeName), ref.content, "utf-8");
214
+ }
215
+ }
216
+ bumpSkillsSnapshotVersion();
217
+ respond(true, { ok: true, name: p.name }, undefined);
218
+ },
219
+ "skills.delete": async ({ params, respond }) => {
220
+ if (!validateSkillsDeleteParams(params)) {
221
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `invalid skills.delete params: ${formatValidationErrors(validateSkillsDeleteParams.errors)}`));
222
+ return;
223
+ }
224
+ const p = params;
225
+ if (isPreloadedSkill(p.name)) {
226
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "preloaded skills cannot be deleted"));
227
+ return;
228
+ }
229
+ const cfg = loadConfig();
230
+ const root = resolveWorkspaceRoot(cfg);
231
+ const skillDir = path.join(root, "skills", p.name);
232
+ if (!fs.existsSync(skillDir)) {
233
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `skill "${p.name}" not found`));
234
+ return;
235
+ }
236
+ fs.rmSync(skillDir, { recursive: true, force: true });
237
+ bumpSkillsSnapshotVersion();
238
+ respond(true, { ok: true, name: p.name }, undefined);
239
+ },
240
+ "skills.drafts": ({ params, respond }) => {
241
+ if (!validateSkillsDraftsParams(params)) {
242
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `invalid skills.drafts params: ${formatValidationErrors(validateSkillsDraftsParams.errors)}`));
243
+ return;
244
+ }
245
+ const cfg = loadConfig();
246
+ const root = resolveWorkspaceRoot(cfg);
247
+ const draftsDir = path.join(root, ".skill-drafts");
248
+ if (!fs.existsSync(draftsDir)) {
249
+ respond(true, { drafts: [] }, undefined);
250
+ return;
251
+ }
252
+ const drafts = [];
253
+ for (const entry of fs.readdirSync(draftsDir, { withFileTypes: true })) {
254
+ if (!entry.isDirectory())
255
+ continue;
256
+ const skillFile = path.join(draftsDir, entry.name, "SKILL.md");
257
+ if (!fs.existsSync(skillFile))
258
+ continue;
259
+ const skillContent = fs.readFileSync(skillFile, "utf-8");
260
+ const references = [];
261
+ const refsDir = path.join(draftsDir, entry.name, "references");
262
+ if (fs.existsSync(refsDir) && fs.statSync(refsDir).isDirectory()) {
263
+ for (const ref of fs.readdirSync(refsDir, { withFileTypes: true })) {
264
+ if (ref.isFile() && ref.name.endsWith(".md")) {
265
+ references.push({
266
+ name: ref.name,
267
+ content: fs.readFileSync(path.join(refsDir, ref.name), "utf-8"),
268
+ });
269
+ }
270
+ }
271
+ references.sort((a, b) => a.name.localeCompare(b.name));
272
+ }
273
+ drafts.push({ name: entry.name, skillContent, references });
274
+ }
275
+ respond(true, { drafts }, undefined);
276
+ },
277
+ "skills.deleteDraft": ({ params, respond }) => {
278
+ if (!validateSkillsDeleteDraftParams(params)) {
279
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `invalid skills.deleteDraft params: ${formatValidationErrors(validateSkillsDeleteDraftParams.errors)}`));
280
+ return;
281
+ }
282
+ const p = params;
283
+ const cfg = loadConfig();
284
+ const root = resolveWorkspaceRoot(cfg);
285
+ const draftDir = path.join(root, ".skill-drafts", p.name);
286
+ if (!fs.existsSync(draftDir)) {
287
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `draft "${p.name}" not found`));
288
+ return;
289
+ }
290
+ fs.rmSync(draftDir, { recursive: true, force: true });
291
+ respond(true, { ok: true, name: p.name }, undefined);
292
+ },
137
293
  };
@@ -41,6 +41,11 @@ const BASE_METHODS = [
41
41
  "skills.bins",
42
42
  "skills.install",
43
43
  "skills.update",
44
+ "skills.read",
45
+ "skills.create",
46
+ "skills.delete",
47
+ "skills.drafts",
48
+ "skills.deleteDraft",
44
49
  "update.status",
45
50
  "update.run",
46
51
  "voicewake.get",
@@ -36,6 +36,7 @@ import { publicChatHandlers } from "./server-methods/public-chat.js";
36
36
  import { tailscaleHandlers } from "./server-methods/tailscale.js";
37
37
  import { wifiHandlers } from "./server-methods/wifi.js";
38
38
  import { workspacesHandlers } from "./server-methods/workspaces.js";
39
+ import { brandHandlers } from "./server-methods/brand.js";
39
40
  const ADMIN_SCOPE = "operator.admin";
40
41
  const READ_SCOPE = "operator.read";
41
42
  const WRITE_SCOPE = "operator.write";
@@ -236,6 +237,7 @@ export const coreGatewayHandlers = {
236
237
  ...memoryHandlers,
237
238
  ...recordsHandlers,
238
239
  ...workspacesHandlers,
240
+ ...brandHandlers,
239
241
  ...publicChatHandlers,
240
242
  ...tailscaleHandlers,
241
243
  ...wifiHandlers,
@@ -74,6 +74,15 @@ function expandPathTemplate(pattern, ctx) {
74
74
  result = result.replaceAll("{agentId}", ctx.agentId);
75
75
  return result;
76
76
  }
77
+ /**
78
+ * Ensure phone numbers in memory/users/ paths include the canonical + prefix.
79
+ * AI agents sometimes omit the + when constructing paths (e.g. "memory/users/447734875155/...")
80
+ * but the session peer and filesystem convention always use + (e.g. "+447734875155").
81
+ * Without this, scope patterns like memory/users/{peer}/** won't match the path.
82
+ */
83
+ function normalizePhoneInMemoryPath(relPath) {
84
+ return relPath.replace(/^(memory\/users\/)(\d)/i, "$1+$2");
85
+ }
77
86
  /**
78
87
  * Simple glob pattern matcher supporting * and **.
79
88
  * - * matches any characters except /
@@ -517,7 +526,7 @@ export class MemoryIndexManager {
517
526
  return this.syncing;
518
527
  }
519
528
  async readFile(params) {
520
- const relPath = normalizeRelPath(params.relPath);
529
+ const relPath = normalizePhoneInMemoryPath(normalizeRelPath(params.relPath));
521
530
  if (!relPath || !isMemoryPath(relPath)) {
522
531
  throw new Error("path required");
523
532
  }
@@ -552,7 +561,7 @@ export class MemoryIndexManager {
552
561
  * matching the session's scope configuration.
553
562
  */
554
563
  async writeFile(params) {
555
- const relPath = normalizeRelPath(params.relPath);
564
+ const relPath = normalizePhoneInMemoryPath(normalizeRelPath(params.relPath));
556
565
  if (!relPath || !isMemoryPath(relPath)) {
557
566
  throw new Error("path required (must be in memory/ directory)");
558
567
  }
@@ -598,7 +607,7 @@ export class MemoryIndexManager {
598
607
  let relPath;
599
608
  if (params.destFolder) {
600
609
  // Explicit folder — use as-is (scope checking enforces access)
601
- relPath = `${params.destFolder}/${params.destFilename}`;
610
+ relPath = normalizePhoneInMemoryPath(`${params.destFolder}/${params.destFilename}`);
602
611
  }
603
612
  else {
604
613
  // Default: memory/users/{peer}/media/{filename}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/taskmaster",
3
- "version": "1.0.106",
3
+ "version": "1.0.107",
4
4
  "description": "AI-powered business assistant for small businesses",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -0,0 +1,97 @@
1
+ ---
2
+ name: skill-builder
3
+ description: "Guide the user through creating a new lean skill — collect name, description, behaviour rules, and references, then save as a draft for the user to install via the Control Panel."
4
+ user-invocable: true
5
+ disable-model-invocation: true
6
+ ---
7
+
8
+ # Skill Builder
9
+
10
+ A deterministic walkthrough for creating new lean skills. Follow each step in order. Be conversational — one question at a time.
11
+
12
+ ## When to Activate
13
+
14
+ The admin requests a new skill, asks to "create a skill", "add a skill", or invokes `/skill-builder`.
15
+
16
+ ## Before Starting
17
+
18
+ Load `references/lean-pattern.md` for the template and examples. Use it throughout as your reference for correct structure.
19
+
20
+ ## Step 1: Understand the Purpose
21
+
22
+ Ask: **"What should this skill do?"**
23
+
24
+ Listen for:
25
+ - What capability it adds (scheduling, quoting, inventory, etc.)
26
+ - When it should activate (what triggers it)
27
+ - What tools or data it needs (memory, web search, file access, etc.)
28
+
29
+ Clarify until you can describe the skill in one sentence. This becomes the `description` in frontmatter.
30
+
31
+ ## Step 2: Choose a Name
32
+
33
+ Propose a name based on the purpose. Names must be:
34
+ - Lowercase
35
+ - Hyphen-separated (e.g. `inventory-management`)
36
+ - Short and descriptive
37
+
38
+ Confirm with the user.
39
+
40
+ ## Step 3: Define Behaviour
41
+
42
+ Ask what rules the agent should follow when using this skill:
43
+ - **Tone and style** — formal, casual, WhatsApp-short?
44
+ - **Activation conditions** — when exactly should the agent use this skill?
45
+ - **Hard boundaries** — what should the agent never do?
46
+ - **Data sources** — where does the skill's knowledge live? (memory, external API, files)
47
+ - **Escalation** — when should it hand off to admin?
48
+
49
+ Not every skill needs all of these. Only include what's relevant.
50
+
51
+ ## Step 4: Decide on References
52
+
53
+ If the skill has detailed procedures, templates, or data formats, those belong in `references/` files — not inline in SKILL.md.
54
+
55
+ Ask: **"Are there any detailed procedures, templates, or formats this skill needs?"**
56
+
57
+ For each reference file:
58
+ - Give it a descriptive filename (e.g. `event-format.md`, `quoting-rules.md`)
59
+ - Collect the content from the user — they can dictate, paste, or describe it and you draft it
60
+
61
+ If the skill is simple enough to fit in SKILL.md alone (under ~30 lines of instructions), skip references.
62
+
63
+ ## Step 5: Compose the Skill
64
+
65
+ Using the lean pattern from `references/lean-pattern.md`, compose:
66
+
67
+ 1. **SKILL.md** — frontmatter (`name`, `description`) + activation conditions + behaviour rules + references index
68
+ 2. **Reference files** — one per detailed topic
69
+
70
+ Show the user the complete SKILL.md content and each reference file. Ask them to review.
71
+
72
+ ## Step 6: Save the Draft
73
+
74
+ Use your `write` tool to save the skill as a draft:
75
+
76
+ 1. Create `../../.skill-drafts/{name}/SKILL.md` with the composed content
77
+ 2. For each reference file: create `../../.skill-drafts/{name}/references/{filename}`
78
+
79
+ The `../../` resolves from your agent directory to the workspace root. The `.skill-drafts/` folder at the workspace root is where the Control Panel looks for drafts.
80
+
81
+ **Important:** Write to `.skill-drafts/`, NOT directly to `skills/`. The user installs the skill through the Control Panel.
82
+
83
+ ## Step 7: Direct to Control Panel
84
+
85
+ Tell the user:
86
+
87
+ > "Your skill draft is ready. To install it:
88
+ > 1. Open the **Control Panel** → **Advanced** → **Skills**
89
+ > 2. Click **Add Skill**
90
+ > 3. Your draft will appear under 'Import from draft' — click it to load
91
+ > 4. Review the content and click **Save Skill**
92
+ >
93
+ > Once saved, the skill will be available to agents on the next message."
94
+
95
+ ---
96
+
97
+ **Remember:** Be conversational. Don't dump all questions at once. Guide through each step one at a time.
@@ -0,0 +1,118 @@
1
+ # Lean SKILL.md Pattern
2
+
3
+ Skills teach agents specialised capabilities. Each skill is a directory containing a `SKILL.md` file and optional `references/` subdirectory.
4
+
5
+ ## Directory Structure
6
+
7
+ ```
8
+ skills/
9
+ my-skill/
10
+ SKILL.md ← Main file (lean index)
11
+ references/
12
+ detailed-guide.md ← Loaded on demand via skill_read
13
+ templates.md
14
+ ```
15
+
16
+ ## SKILL.md Template
17
+
18
+ ```markdown
19
+ ---
20
+ name: my-skill
21
+ description: "One-line summary of what this skill does — used for agent routing."
22
+ ---
23
+
24
+ # My Skill
25
+
26
+ Applies when [activation conditions].
27
+
28
+ ## When to Activate
29
+
30
+ - [Trigger condition 1]
31
+ - [Trigger condition 2]
32
+
33
+ ## Behaviour
34
+
35
+ [Concise rules — keep this section short. Move detailed procedures to references.]
36
+
37
+ ## References
38
+
39
+ Load `references/detailed-guide.md` for [what it covers].
40
+ Load `references/templates.md` for [what it covers].
41
+ ```
42
+
43
+ ## Principles
44
+
45
+ 1. **SKILL.md is an index, not a manual.** Keep it under 30 lines of instructions. The agent reads it on every activation — bloated skills waste context.
46
+
47
+ 2. **References hold the detail.** Procedures, templates, data formats, and examples go in `references/`. The agent loads them on demand with `skill_read`.
48
+
49
+ 3. **Frontmatter is required.** Every SKILL.md must start with YAML frontmatter containing `name` and `description`. Missing `description` causes the skill to be silently skipped.
50
+
51
+ 4. **Description drives routing.** The description is injected into the agent's prompt as part of the available skills list. Make it specific enough that the agent activates the skill for the right messages.
52
+
53
+ 5. **Behaviour, not data.** Skills define how the agent should act. Business-specific data (pricing, customer info, hours) belongs in memory, not in the skill file. Skills are generic; memory is specific.
54
+
55
+ ## Optional Frontmatter Fields
56
+
57
+ ```yaml
58
+ metadata: {"taskmaster":{"always":true,"emoji":"📦","primaryEnv":"MY_API_KEY"}}
59
+ ```
60
+
61
+ | Field | Purpose |
62
+ |-------|---------|
63
+ | `always` | Always include in prompt (skip eligibility checks) |
64
+ | `emoji` | Display emoji in the Control Panel |
65
+ | `primaryEnv` | Env var for API key — enables the key input field in the UI |
66
+ | `requires.bins` | Required binaries (e.g. `["curl"]`) |
67
+ | `requires.env` | Required environment variables |
68
+
69
+ Most user-created skills need only `name` and `description`.
70
+
71
+ ## Examples
72
+
73
+ ### Simple skill (no references)
74
+
75
+ ```markdown
76
+ ---
77
+ name: weather
78
+ description: "Provide weather context for scheduling and outdoor work decisions."
79
+ ---
80
+
81
+ # Weather
82
+
83
+ When scheduling or planning outdoor work, check weather conditions.
84
+
85
+ ## When to Activate
86
+
87
+ - Customer asks about weather
88
+ - Scheduling outdoor appointments
89
+ - Weather might affect planned work
90
+
91
+ ## Behaviour
92
+
93
+ Use the `web_search` tool to check current weather for the business location.
94
+ Keep weather info brief — one or two sentences unless asked for detail.
95
+ ```
96
+
97
+ ### Lean skill with references
98
+
99
+ ```markdown
100
+ ---
101
+ name: event-management
102
+ description: "Manage anything time-bound: appointments, meetings, reminders, follow-ups."
103
+ ---
104
+
105
+ # Event Management
106
+
107
+ Applies when handling anything time-bound.
108
+
109
+ ## When to Activate
110
+
111
+ - Customer requests or confirms an appointment
112
+ - Business owner asks to schedule, reschedule, or cancel something
113
+ - A reminder or follow-up needs to be recorded
114
+
115
+ ## References
116
+
117
+ Load `references/events.md` for the standard event template, file naming, and calendar query instructions.
118
+ ```
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: zero-to-prototype
3
+ description: "Guide business owners from a raw idea to a validated concept — customer discovery, assumption testing, value proposition, and a simple PRD. For entrepreneurs exploring new products, services, or pivots."
4
+ metadata: {"taskmaster":{"emoji":"🚀"}}
5
+ ---
6
+
7
+ # Zero to Prototype
8
+
9
+ Helps business owners validate ideas before investing time and money. Covers the full journey from initial concept to a clear product requirement document.
10
+
11
+ ## When to Activate
12
+
13
+ - Owner says they have an idea for a new product, service, or offering
14
+ - Owner wants to validate whether something is worth pursuing
15
+ - Owner asks about customer discovery, market validation, or testing assumptions
16
+ - Owner wants to write a PRD or product brief
17
+ - Phrases like "pressure test this idea", "is this worth building", "help me think through this"
18
+
19
+ ## Workflow
20
+
21
+ Walk through each phase conversationally. Don't dump all phases at once — progress naturally based on where the owner is.
22
+
23
+ **Phase 1 — Capture the idea.** Understand what they want to build and why. Load `references/discovery.md`.
24
+
25
+ **Phase 2 — Validate assumptions.** Identify and test the riskiest assumptions. Load `references/validation.md`.
26
+
27
+ **Phase 3 — Define the product.** Turn validated concepts into a clear PRD. Load `references/prd.md`.
28
+
29
+ ## References
30
+
31
+ Load reference files on demand as each phase is reached — not all at once.
32
+
33
+ - `references/discovery.md` — customer discovery framework, interview questions, market signals
34
+ - `references/validation.md` — assumption mapping, validation techniques, go/no-go criteria
35
+ - `references/prd.md` — PRD template, prioritisation, scope definition
@@ -0,0 +1,64 @@
1
+ # Customer Discovery
2
+
3
+ ## Goal
4
+
5
+ Understand the problem before designing the solution. Most failed products solve a problem nobody has, or solve the right problem for the wrong audience.
6
+
7
+ ## Step 1: Articulate the Idea
8
+
9
+ Get the owner to state their idea in one sentence:
10
+
11
+ > "[Product/service] helps [target audience] [solve problem] by [mechanism]."
12
+
13
+ If they can't fill this in, they don't have a clear idea yet. Help them by asking:
14
+ - Who specifically would use this?
15
+ - What problem does it solve for them?
16
+ - How do they solve this problem today (without your product)?
17
+ - Why would they switch to your solution?
18
+
19
+ ## Step 2: Identify the Target Customer
20
+
21
+ Don't accept "everyone" or "small businesses". Get specific:
22
+ - **Demographics** — age, location, income, profession
23
+ - **Behaviour** — what do they currently do? where do they hang out?
24
+ - **Pain** — what frustrates them about the current solution?
25
+
26
+ Ask: "If you could only sell to one type of person, who would it be?"
27
+
28
+ ## Step 3: Customer Conversations
29
+
30
+ The owner needs to talk to potential customers. Not friends. Not family. Real prospects.
31
+
32
+ ### What to Ask (5 Key Questions)
33
+
34
+ 1. **"Tell me about the last time you [experienced the problem]."** — Gets real stories, not hypotheticals.
35
+ 2. **"What did you do about it?"** — Reveals current solutions and willingness to act.
36
+ 3. **"What's the most annoying part of how you handle this today?"** — Finds the pain point.
37
+ 4. **"If you could wave a magic wand, what would be different?"** — Reveals desires without anchoring to your solution.
38
+ 5. **"Would you pay to solve this? How much?"** — Tests willingness to pay.
39
+
40
+ ### Rules
41
+
42
+ - **Don't pitch.** You're learning, not selling.
43
+ - **Don't ask "would you use this?"** — everyone says yes to be polite.
44
+ - **Talk to at least 5 people** before drawing conclusions.
45
+ - **Look for patterns** — one person's pain is anecdotal. Three people's pain is a signal.
46
+
47
+ ## Step 4: Market Signals
48
+
49
+ Help the owner assess whether the market supports the idea:
50
+
51
+ - **Search volume** — are people searching for solutions? (Use web search to check)
52
+ - **Competitors** — who else solves this? What do they charge? What do reviews say?
53
+ - **Market size** — how many potential customers exist? Is the market growing?
54
+ - **Timing** — why now? What's changed that makes this possible or necessary?
55
+
56
+ ## Output
57
+
58
+ By the end of discovery, the owner should have:
59
+ 1. A clear one-sentence idea statement
60
+ 2. A specific target customer profile
61
+ 3. At least 3 customer conversation summaries (or a plan to do them)
62
+ 4. A market landscape overview
63
+
64
+ Save these to memory for use in the validation and PRD phases.
@@ -0,0 +1,83 @@
1
+ # Product Requirement Document
2
+
3
+ ## Goal
4
+
5
+ Turn the validated idea into a clear, actionable document that defines what to build, for whom, and why.
6
+
7
+ ## PRD Template
8
+
9
+ Walk the owner through each section. Write the PRD collaboratively — don't generate it in isolation.
10
+
11
+ ### 1. Problem Statement
12
+
13
+ One paragraph. What problem exists, who has it, and why current solutions fall short.
14
+
15
+ Draw from discovery phase: customer conversations, pain points, market gaps.
16
+
17
+ ### 2. Target Customer
18
+
19
+ Specific profile from discovery:
20
+ - Who they are (demographics, role, context)
21
+ - What they currently do (workarounds, competitors they use)
22
+ - What they need (the gap your product fills)
23
+
24
+ ### 3. Value Proposition
25
+
26
+ One sentence: "We help [target customer] [achieve outcome] by [mechanism], unlike [current alternative] which [limitation]."
27
+
28
+ ### 4. Core Features
29
+
30
+ List the minimum features needed for the product to deliver its value proposition. No more.
31
+
32
+ For each feature:
33
+ - **What it does** (user-facing description)
34
+ - **Why it matters** (which customer need it addresses)
35
+ - **Priority** (Must-have / Should-have / Nice-to-have)
36
+
37
+ Use the MoSCoW method:
38
+ - **Must-have** — Product is useless without these
39
+ - **Should-have** — Significantly improves the product
40
+ - **Could-have** — Nice but not critical
41
+ - **Won't-have** — Explicitly out of scope for v1
42
+
43
+ ### 5. User Journey
44
+
45
+ Walk through the primary use case step by step:
46
+ 1. How does the customer discover the product?
47
+ 2. What's their first interaction?
48
+ 3. How do they get value for the first time?
49
+ 4. What keeps them coming back?
50
+
51
+ ### 6. Success Metrics
52
+
53
+ How will the owner know this is working?
54
+
55
+ | Metric | Target | Timeframe |
56
+ |--------|--------|-----------|
57
+ | e.g. Signups | 50 | First month |
58
+ | e.g. Paying customers | 10 | First 3 months |
59
+ | e.g. Retention | 70% month-over-month | Month 2+ |
60
+
61
+ Pick 3-5 metrics. No more. Focus on outcomes, not vanity metrics.
62
+
63
+ ### 7. Scope and Constraints
64
+
65
+ - **Budget** — what can the owner invest?
66
+ - **Timeline** — when do they need it by?
67
+ - **Technical constraints** — platform, integrations, dependencies
68
+ - **Regulatory** — compliance, data protection, licensing
69
+
70
+ ### 8. Risks and Mitigations
71
+
72
+ Top 3 risks from validation phase and how to address them.
73
+
74
+ ### 9. Next Steps
75
+
76
+ Concrete actions with owners and deadlines:
77
+ 1. What needs to happen first?
78
+ 2. Who does what?
79
+ 3. When is the first checkpoint?
80
+
81
+ ## Output
82
+
83
+ Save the completed PRD to memory. The owner now has a document they can share with developers, investors, or partners.