@rubytech/create-maxy 1.0.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 (181) hide show
  1. package/dist/index.js +428 -0
  2. package/package.json +31 -0
  3. package/payload/maxy/.env.example +12 -0
  4. package/payload/maxy/app/admin/components/ActivityTimeline.tsx +348 -0
  5. package/payload/maxy/app/admin/components/MarkdownMessage.tsx +40 -0
  6. package/payload/maxy/app/api/admin/chat/route.ts +72 -0
  7. package/payload/maxy/app/api/admin/logs/route.ts +40 -0
  8. package/payload/maxy/app/api/admin/session/route.ts +74 -0
  9. package/payload/maxy/app/api/chat/route.ts +72 -0
  10. package/payload/maxy/app/api/health/route.ts +26 -0
  11. package/payload/maxy/app/api/onboarding/claude-auth/route.ts +216 -0
  12. package/payload/maxy/app/api/onboarding/set-pin/route.ts +44 -0
  13. package/payload/maxy/app/api/session/route.ts +51 -0
  14. package/payload/maxy/app/api/telegram/webhook/route.ts +107 -0
  15. package/payload/maxy/app/apple-icon.png +0 -0
  16. package/payload/maxy/app/bot/page.tsx +373 -0
  17. package/payload/maxy/app/favicon.ico +0 -0
  18. package/payload/maxy/app/globals.css +1681 -0
  19. package/payload/maxy/app/layout.tsx +58 -0
  20. package/payload/maxy/app/lib/claude-agent.ts +503 -0
  21. package/payload/maxy/app/og/layout.tsx +15 -0
  22. package/payload/maxy/app/og/page.tsx +252 -0
  23. package/payload/maxy/app/page.tsx +594 -0
  24. package/payload/maxy/app/privacy/page.tsx +72 -0
  25. package/payload/maxy/app/public/page.tsx +266 -0
  26. package/payload/maxy/next.config.mjs +26 -0
  27. package/payload/maxy/package-lock.json +2198 -0
  28. package/payload/maxy/package.json +25 -0
  29. package/payload/maxy/proxy.ts +41 -0
  30. package/payload/maxy/public/brand/claude.png +0 -0
  31. package/payload/maxy/public/brand/maxy-black.png +0 -0
  32. package/payload/maxy/public/brand/maxy.png +0 -0
  33. package/payload/maxy/public/favicon.ico +0 -0
  34. package/payload/maxy/public/og-landscape.png +0 -0
  35. package/payload/maxy/public/og-portrait.png +0 -0
  36. package/payload/maxy/public/og-square.png +0 -0
  37. package/payload/maxy/public/pi-5.jpg +0 -0
  38. package/payload/maxy/public/robots.txt +5 -0
  39. package/payload/maxy/tsconfig.json +41 -0
  40. package/payload/maxy/tsconfig.tsbuildinfo +1 -0
  41. package/payload/maxy/ui.md +28 -0
  42. package/payload/platform/config/cloudflared.yml +17 -0
  43. package/payload/platform/knowledge/maxy.md +161 -0
  44. package/payload/platform/neo4j/schema.cypher +108 -0
  45. package/payload/platform/package-lock.json +1835 -0
  46. package/payload/platform/package.json +17 -0
  47. package/payload/platform/plugins/admin/PLUGIN.md +24 -0
  48. package/payload/platform/plugins/admin/hooks/pre-tool-use.sh +56 -0
  49. package/payload/platform/plugins/admin/hooks/session-start.sh +20 -0
  50. package/payload/platform/plugins/admin/mcp/dist/index.d.ts +2 -0
  51. package/payload/platform/plugins/admin/mcp/dist/index.d.ts.map +1 -0
  52. package/payload/platform/plugins/admin/mcp/dist/index.js +149 -0
  53. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -0
  54. package/payload/platform/plugins/admin/mcp/package.json +18 -0
  55. package/payload/platform/plugins/anthropic/PLUGIN.md +30 -0
  56. package/payload/platform/plugins/anthropic/references/setup-guide.md +146 -0
  57. package/payload/platform/plugins/business-assistant/PLUGIN.md +46 -0
  58. package/payload/platform/plugins/business-assistant/references/crm.md +112 -0
  59. package/payload/platform/plugins/business-assistant/references/document-management.md +96 -0
  60. package/payload/platform/plugins/business-assistant/references/escalation.md +126 -0
  61. package/payload/platform/plugins/business-assistant/references/invoicing.md +163 -0
  62. package/payload/platform/plugins/business-assistant/references/quoting.md +56 -0
  63. package/payload/platform/plugins/business-assistant/references/scheduling.md +127 -0
  64. package/payload/platform/plugins/cloudflare/PLUGIN.md +31 -0
  65. package/payload/platform/plugins/cloudflare/mcp/dist/index.d.ts +2 -0
  66. package/payload/platform/plugins/cloudflare/mcp/dist/index.d.ts.map +1 -0
  67. package/payload/platform/plugins/cloudflare/mcp/dist/index.js +174 -0
  68. package/payload/platform/plugins/cloudflare/mcp/dist/index.js.map +1 -0
  69. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts +45 -0
  70. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts.map +1 -0
  71. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js +256 -0
  72. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js.map +1 -0
  73. package/payload/platform/plugins/cloudflare/mcp/package.json +18 -0
  74. package/payload/platform/plugins/cloudflare/references/setup-guide.md +110 -0
  75. package/payload/platform/plugins/contacts/PLUGIN.md +18 -0
  76. package/payload/platform/plugins/contacts/mcp/dist/index.d.ts +2 -0
  77. package/payload/platform/plugins/contacts/mcp/dist/index.d.ts.map +1 -0
  78. package/payload/platform/plugins/contacts/mcp/dist/index.js +182 -0
  79. package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -0
  80. package/payload/platform/plugins/contacts/mcp/dist/lib/neo4j.d.ts +5 -0
  81. package/payload/platform/plugins/contacts/mcp/dist/lib/neo4j.d.ts.map +1 -0
  82. package/payload/platform/plugins/contacts/mcp/dist/lib/neo4j.js +34 -0
  83. package/payload/platform/plugins/contacts/mcp/dist/lib/neo4j.js.map +1 -0
  84. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts +19 -0
  85. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts.map +1 -0
  86. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js +68 -0
  87. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js.map +1 -0
  88. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-list.d.ts +22 -0
  89. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-list.d.ts.map +1 -0
  90. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-list.js +46 -0
  91. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-list.js.map +1 -0
  92. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts +20 -0
  93. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts.map +1 -0
  94. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js +56 -0
  95. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js.map +1 -0
  96. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-update.d.ts +13 -0
  97. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-update.d.ts.map +1 -0
  98. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-update.js +54 -0
  99. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-update.js.map +1 -0
  100. package/payload/platform/plugins/contacts/mcp/package.json +19 -0
  101. package/payload/platform/plugins/documents/PLUGIN.md +12 -0
  102. package/payload/platform/plugins/documents/mcp/dist/index.d.ts +2 -0
  103. package/payload/platform/plugins/documents/mcp/dist/index.d.ts.map +1 -0
  104. package/payload/platform/plugins/documents/mcp/dist/index.js +82 -0
  105. package/payload/platform/plugins/documents/mcp/dist/index.js.map +1 -0
  106. package/payload/platform/plugins/documents/mcp/package.json +20 -0
  107. package/payload/platform/plugins/memory/PLUGIN.md +17 -0
  108. package/payload/platform/plugins/memory/mcp/dist/index.d.ts +2 -0
  109. package/payload/platform/plugins/memory/mcp/dist/index.d.ts.map +1 -0
  110. package/payload/platform/plugins/memory/mcp/dist/index.js +164 -0
  111. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -0
  112. package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.d.ts +3 -0
  113. package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.d.ts.map +1 -0
  114. package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.js +29 -0
  115. package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.js.map +1 -0
  116. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.d.ts +5 -0
  117. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.d.ts.map +1 -0
  118. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.js +34 -0
  119. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.js.map +1 -0
  120. package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.d.ts +8 -0
  121. package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.d.ts.map +1 -0
  122. package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.js +71 -0
  123. package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.js.map +1 -0
  124. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts +24 -0
  125. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts.map +1 -0
  126. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js +125 -0
  127. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js.map +1 -0
  128. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts +18 -0
  129. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -0
  130. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +56 -0
  131. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -0
  132. package/payload/platform/plugins/memory/mcp/package.json +19 -0
  133. package/payload/platform/plugins/sales/PLUGIN.md +65 -0
  134. package/payload/platform/plugins/sales/references/close-tracking.md +76 -0
  135. package/payload/platform/plugins/sales/references/closing-framework.md +108 -0
  136. package/payload/platform/plugins/sales/references/comparisons.md +99 -0
  137. package/payload/platform/plugins/sales/references/competitive-positioning.md +51 -0
  138. package/payload/platform/plugins/sales/references/faq.md +62 -0
  139. package/payload/platform/plugins/sales/references/objection-handling.md +157 -0
  140. package/payload/platform/plugins/sales/references/pricing.md +71 -0
  141. package/payload/platform/plugins/sales/references/waitlist.md +23 -0
  142. package/payload/platform/plugins/scheduling/PLUGIN.md +12 -0
  143. package/payload/platform/plugins/scheduling/mcp/dist/index.d.ts +2 -0
  144. package/payload/platform/plugins/scheduling/mcp/dist/index.d.ts.map +1 -0
  145. package/payload/platform/plugins/scheduling/mcp/dist/index.js +13 -0
  146. package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -0
  147. package/payload/platform/plugins/scheduling/mcp/package.json +18 -0
  148. package/payload/platform/plugins/telegram/PLUGIN.md +31 -0
  149. package/payload/platform/plugins/telegram/mcp/dist/index.d.ts +2 -0
  150. package/payload/platform/plugins/telegram/mcp/dist/index.d.ts.map +1 -0
  151. package/payload/platform/plugins/telegram/mcp/dist/index.js +101 -0
  152. package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -0
  153. package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.d.ts +27 -0
  154. package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.d.ts.map +1 -0
  155. package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.js +41 -0
  156. package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.js.map +1 -0
  157. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.d.ts +16 -0
  158. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.d.ts.map +1 -0
  159. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.js +62 -0
  160. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.js.map +1 -0
  161. package/payload/platform/plugins/telegram/mcp/dist/tools/message.d.ts +20 -0
  162. package/payload/platform/plugins/telegram/mcp/dist/tools/message.d.ts.map +1 -0
  163. package/payload/platform/plugins/telegram/mcp/dist/tools/message.js +34 -0
  164. package/payload/platform/plugins/telegram/mcp/dist/tools/message.js.map +1 -0
  165. package/payload/platform/plugins/telegram/mcp/package.json +19 -0
  166. package/payload/platform/plugins/telegram/references/setup-guide.md +50 -0
  167. package/payload/platform/plugins/web/PLUGIN.md +12 -0
  168. package/payload/platform/plugins/web/mcp/dist/index.d.ts +2 -0
  169. package/payload/platform/plugins/web/mcp/dist/index.d.ts.map +1 -0
  170. package/payload/platform/plugins/web/mcp/dist/index.js +12 -0
  171. package/payload/platform/plugins/web/mcp/dist/index.js.map +1 -0
  172. package/payload/platform/plugins/web/mcp/package.json +18 -0
  173. package/payload/platform/scripts/seed-neo4j.sh +73 -0
  174. package/payload/platform/scripts/setup.sh +177 -0
  175. package/payload/platform/scripts/start.sh +62 -0
  176. package/payload/platform/templates/account.json +4 -0
  177. package/payload/platform/templates/agents/admin/IDENTITY.md +28 -0
  178. package/payload/platform/templates/agents/admin/SOUL.md +1 -0
  179. package/payload/platform/templates/agents/public/IDENTITY.md +21 -0
  180. package/payload/platform/templates/agents/public/SOUL.md +1 -0
  181. package/payload/platform/tsconfig.base.json +18 -0
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "maxy-platform",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "workspaces": [
6
+ "plugins/*/mcp"
7
+ ],
8
+ "scripts": {
9
+ "build": "tsc -b plugins/*/mcp/tsconfig.json",
10
+ "build:memory": "tsc -p plugins/memory/mcp/tsconfig.json",
11
+ "build:contacts": "tsc -p plugins/contacts/mcp/tsconfig.json",
12
+ "build:telegram": "tsc -p plugins/telegram/mcp/tsconfig.json",
13
+ "build:admin": "tsc -p plugins/admin/mcp/tsconfig.json",
14
+ "build:cloudflare": "tsc -p plugins/cloudflare/mcp/tsconfig.json",
15
+ "build:stubs": "tsc -p plugins/scheduling/mcp/tsconfig.json && tsc -p plugins/documents/mcp/tsconfig.json && tsc -p plugins/web/mcp/tsconfig.json"
16
+ }
17
+ }
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: admin
3
+ description: "Platform administration plugin. Provides system-status, brand-settings, account-manage, logs-read, and plugin-read tools for managing the Maxy platform."
4
+ icon: ⚙️
5
+ tools:
6
+ - system-status
7
+ - brand-settings
8
+ - account-manage
9
+ - logs-read
10
+ - plugin-read
11
+ always: true
12
+ embed: false
13
+ ---
14
+
15
+ # Admin
16
+
17
+ Platform management tools for both the admin and public agents. The `plugin-read` tool is available to the public agent (read-only) for loading plugin definitions and references. All other tools are admin-only.
18
+
19
+ Tools are available via the `admin` MCP server.
20
+
21
+ ## Hooks
22
+
23
+ - `hooks/session-start.sh` — loads IDENTITY.md on session start
24
+ - `hooks/pre-tool-use.sh` — enforces public agent read-only lockdown
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env bash
2
+ # PreToolUse hook — enforces agent tool boundaries.
3
+ # Usage: pre-tool-use.sh <agent-type>
4
+ # Receives tool call JSON on stdin (from Claude Code hook protocol).
5
+ # Exit 0 = allow, exit 2 = block.
6
+
7
+ AGENT_TYPE="${1:-public}"
8
+
9
+ # Read stdin — fail closed if unavailable
10
+ if [ -t 0 ]; then
11
+ echo "Blocked: Cannot determine tool call (no stdin). Failing closed." >&2
12
+ exit 2
13
+ fi
14
+ INPUT=$(cat)
15
+ TOOL_NAME=$(echo "$INPUT" | grep -o '"tool_name":"[^"]*"' | head -1 | cut -d'"' -f4)
16
+
17
+ # ---------------------------------------------------------------------------
18
+ # Admin agent — allow all tools EXCEPT writes to protected code directories.
19
+ # The agent must never modify app source, platform code, or its own hooks.
20
+ # ---------------------------------------------------------------------------
21
+ if [ "$AGENT_TYPE" = "admin" ]; then
22
+ case "$TOOL_NAME" in
23
+ Write|Edit)
24
+ FILE_PATH=$(echo "$INPUT" | grep -o '"file_path":"[^"]*"' | head -1 | cut -d'"' -f4)
25
+ case "$FILE_PATH" in
26
+ # Next.js platform app source
27
+ */maxy/app/*|*/maxy/lib/*|*/maxy/*.ts|*/maxy/*.tsx|*/maxy/*.mjs)
28
+ echo "Blocked: Admin agent cannot modify app source at $FILE_PATH" >&2
29
+ exit 2
30
+ ;;
31
+ # Platform MCP server code, hooks, and scripts
32
+ */platform/plugins/*/mcp/*|*/platform/plugins/*/hooks/*|*/platform/scripts/*)
33
+ echo "Blocked: Admin agent cannot modify platform code at $FILE_PATH" >&2
34
+ exit 2
35
+ ;;
36
+ esac
37
+ ;;
38
+ esac
39
+ exit 0
40
+ fi
41
+
42
+ # ---------------------------------------------------------------------------
43
+ # Public agent — strict allowlist (memory-search only).
44
+ # ---------------------------------------------------------------------------
45
+ case "$TOOL_NAME" in
46
+ "memory-search"|"mcp__memory__memory-search")
47
+ exit 0
48
+ ;;
49
+ "plugin-read"|"mcp__admin__plugin-read")
50
+ exit 0
51
+ ;;
52
+ *)
53
+ echo "Blocked: Public agent cannot use tool '$TOOL_NAME'. Only memory-search and plugin-read are permitted." >&2
54
+ exit 2
55
+ ;;
56
+ esac
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env bash
2
+ # SessionStart hook — loads the agent's IDENTITY.md.
3
+ # IDENTITY.md is the single source of truth for character and capability.
4
+ # This hook does not add context — it ensures IDENTITY is loaded.
5
+ #
6
+ # Usage: session-start.sh <account-dir> <agent-name>
7
+ # Example: session-start.sh /path/to/accounts/uuid admin
8
+
9
+ ACCOUNT_DIR="${1:-}"
10
+ AGENT_NAME="${2:-}"
11
+
12
+ if [ -z "$ACCOUNT_DIR" ] || [ -z "$AGENT_NAME" ]; then
13
+ exit 0
14
+ fi
15
+
16
+ IDENTITY_PATH="$ACCOUNT_DIR/agents/$AGENT_NAME/IDENTITY.md"
17
+
18
+ if [ -f "$IDENTITY_PATH" ]; then
19
+ cat "$IDENTITY_PATH"
20
+ fi
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,149 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { z } from "zod";
4
+ import { readFile } from "node:fs/promises";
5
+ import { resolve, join } from "node:path";
6
+ import { execFileSync } from "node:child_process";
7
+ import { existsSync } from "node:fs";
8
+ const server = new McpServer({
9
+ name: "admin",
10
+ version: "0.1.0",
11
+ });
12
+ const PLATFORM_ROOT = process.env.PLATFORM_ROOT ?? resolve(import.meta.dirname, "../../../..");
13
+ const ACCOUNT_ID = process.env.ACCOUNT_ID;
14
+ if (!ACCOUNT_ID) {
15
+ throw new Error("ACCOUNT_ID environment variable is required");
16
+ }
17
+ // Resolve account directory
18
+ function getAccountDir() {
19
+ const dir = resolve(PLATFORM_ROOT, "config/accounts", ACCOUNT_ID);
20
+ if (!existsSync(dir)) {
21
+ throw new Error(`Account directory not found: ${dir}`);
22
+ }
23
+ return dir;
24
+ }
25
+ async function readAccountConfig() {
26
+ const configPath = join(getAccountDir(), "account.json");
27
+ const content = await readFile(configPath, "utf-8");
28
+ return JSON.parse(content);
29
+ }
30
+ // ===================================================================
31
+ // System tools
32
+ // ===================================================================
33
+ server.tool("system-status", "Check health of all Maxy platform services: Neo4j, Ollama, Cloudflare tunnel.", {}, async () => {
34
+ const checks = {};
35
+ try {
36
+ const neo4jUri = process.env.NEO4J_URI ?? "bolt://localhost:7687";
37
+ const res = await fetch(neo4jUri.replace("bolt://", "http://").replace("7687", "7474"), { signal: AbortSignal.timeout(3000) });
38
+ checks.neo4j = res.ok ? "healthy" : `unhealthy (${res.status})`;
39
+ }
40
+ catch (err) {
41
+ checks.neo4j = `unreachable: ${err instanceof Error ? err.message : String(err)}`;
42
+ }
43
+ try {
44
+ const ollamaUrl = process.env.OLLAMA_URL ?? "http://localhost:11434";
45
+ const res = await fetch(`${ollamaUrl}/api/tags`, {
46
+ signal: AbortSignal.timeout(3000),
47
+ });
48
+ if (res.ok) {
49
+ const data = (await res.json());
50
+ const models = data.models?.map((m) => m.name).join(", ") ?? "none";
51
+ checks.ollama = `healthy (models: ${models})`;
52
+ }
53
+ else {
54
+ checks.ollama = `unhealthy (${res.status})`;
55
+ }
56
+ }
57
+ catch (err) {
58
+ checks.ollama = `unreachable: ${err instanceof Error ? err.message : String(err)}`;
59
+ }
60
+ // Cloudflare tunnel: lightweight process check (full status via tunnel-status in cloudflare plugin)
61
+ try {
62
+ execFileSync("pgrep", ["-x", "cloudflared"], { timeout: 2000 });
63
+ checks.cloudflare = "running";
64
+ }
65
+ catch {
66
+ // pgrep exits non-zero if no process found
67
+ try {
68
+ execFileSync("which", ["cloudflared"], { encoding: "utf-8", timeout: 3000 });
69
+ checks.cloudflare = "installed but not running";
70
+ }
71
+ catch {
72
+ checks.cloudflare = "not installed";
73
+ }
74
+ }
75
+ const formatted = Object.entries(checks)
76
+ .map(([service, status]) => `${service}: ${status}`)
77
+ .join("\n");
78
+ return { content: [{ type: "text", text: formatted }] };
79
+ });
80
+ server.tool("brand-settings", "Read the brand/styling configuration for the current account.", {}, async () => {
81
+ try {
82
+ const config = await readAccountConfig();
83
+ return {
84
+ content: [{ type: "text", text: JSON.stringify(config.brand, null, 2) }],
85
+ };
86
+ }
87
+ catch (err) {
88
+ return {
89
+ content: [{ type: "text", text: `Failed: ${err instanceof Error ? err.message : String(err)}` }],
90
+ isError: true,
91
+ };
92
+ }
93
+ });
94
+ server.tool("account-manage", "Read the account configuration (tier, domains, settings).", {}, async () => {
95
+ try {
96
+ const config = await readAccountConfig();
97
+ return {
98
+ content: [{ type: "text", text: JSON.stringify(config, null, 2) }],
99
+ };
100
+ }
101
+ catch (err) {
102
+ return {
103
+ content: [{ type: "text", text: `Failed: ${err instanceof Error ? err.message : String(err)}` }],
104
+ isError: true,
105
+ };
106
+ }
107
+ });
108
+ server.tool("logs-read", "Read recent system or session logs.", {
109
+ type: z.enum(["system", "session", "error"]).optional(),
110
+ lines: z.number().optional(),
111
+ }, async ({ type = "system", lines = 50 }) => {
112
+ try {
113
+ const logFile = type === "error" ? "/tmp/maxy-error.log"
114
+ : type === "session" ? "/tmp/maxy-session.log"
115
+ : "/tmp/maxy-system.log";
116
+ const result = execFileSync("tail", ["-n", String(lines), logFile], {
117
+ timeout: 5000,
118
+ }).toString();
119
+ return { content: [{ type: "text", text: result }] };
120
+ }
121
+ catch {
122
+ return { content: [{ type: "text", text: `No logs found for type '${type}'.` }] };
123
+ }
124
+ });
125
+ server.tool("plugin-read", "Read a plugin definition (PLUGIN.md) or one of its reference files.", {
126
+ pluginName: z.string().describe("Name of the plugin directory (e.g. 'sales', 'business-assistant')"),
127
+ file: z.string().optional().describe("Specific file to read (e.g. 'references/pricing.md'). Defaults to PLUGIN.md."),
128
+ }, async ({ pluginName, file }) => {
129
+ try {
130
+ const pluginPath = resolve(PLATFORM_ROOT, "plugins", pluginName, file ?? "PLUGIN.md");
131
+ if (!existsSync(pluginPath)) {
132
+ return {
133
+ content: [{ type: "text", text: `Plugin file not found: ${pluginPath}` }],
134
+ isError: true,
135
+ };
136
+ }
137
+ const content = await readFile(pluginPath, "utf-8");
138
+ return { content: [{ type: "text", text: content }] };
139
+ }
140
+ catch (err) {
141
+ return {
142
+ content: [{ type: "text", text: `Failed: ${err instanceof Error ? err.message : String(err)}` }],
143
+ isError: true,
144
+ };
145
+ }
146
+ });
147
+ const transport = new StdioServerTransport();
148
+ await server.connect(transport);
149
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "@maxy/admin",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "start": "node dist/index.js"
10
+ },
11
+ "dependencies": {
12
+ "@modelcontextprotocol/sdk": "^1.12.1"
13
+ },
14
+ "devDependencies": {
15
+ "typescript": "^5.7.0",
16
+ "@types/node": "^22.0.0"
17
+ }
18
+ }
@@ -0,0 +1,30 @@
1
+ ---
2
+ name: anthropic
3
+ description: Guide users through connecting Claude — either via Claude Pro sign-in (recommended) or by pasting an Anthropic API key.
4
+ metadata: {"taskmaster":{"emoji":"🔑"}}
5
+ ---
6
+
7
+ # Anthropic / Claude Setup
8
+
9
+ Walks users through connecting Taskmaster to Claude. There are two paths — Claude Pro sign-in (no API key needed) and direct API key entry. The plugin determines which path to offer based on what the user is trying to do and what they already have configured.
10
+
11
+ ## When to activate
12
+
13
+ - User asks how to connect Claude, get an Anthropic key, or set up their AI
14
+ - User is on the Setup page and asks about the "Connect to Claude" button or API keys
15
+ - BOOTSTRAP detects no working Claude/Anthropic connection
16
+ - User sees an authentication error or "Connection expired" message
17
+ - User asks which provider to choose in the API keys dropdown
18
+
19
+ ## What it unlocks
20
+
21
+ - Claude as the primary AI model — powers all conversations, reasoning, and tool use
22
+ - Two connection methods: subscription-based (Claude Pro) or pay-per-use (API key)
23
+
24
+ ## References
25
+
26
+ | Task | When to use | Reference |
27
+ |------|-------------|-----------|
28
+ | Guided setup | User wants help connecting Claude | `references/setup-guide.md` |
29
+
30
+ Load the reference and follow its instructions.
@@ -0,0 +1,146 @@
1
+ # Anthropic / Claude — Setup Guide
2
+
3
+ Walk the user through connecting Taskmaster to Claude. There are two options — determine which one is right for the user, then guide them through it.
4
+
5
+ ---
6
+
7
+ ## The two options
8
+
9
+ | | Option A: Claude Pro sign-in | Option B: API key |
10
+ |---|---|---|
11
+ | **Best for** | Users with a Claude Pro/Team/Enterprise subscription | Users who want pay-per-use or don't have a Claude subscription |
12
+ | **Cost** | Included in existing subscription | Pay per API call (requires billing setup at Anthropic) |
13
+ | **How it works** | OAuth sign-in — no key to manage | Paste a secret key from console.anthropic.com |
14
+ | **Setup location** | Setup page → "Connect to Claude" | Setup page → API Keys → Add provider |
15
+
16
+ ---
17
+
18
+ ## Step 1: Determine which option
19
+
20
+ Ask the user which situation applies:
21
+
22
+ > "There are two ways to connect Claude:
23
+ >
24
+ > **Option A (recommended):** If you have a **Claude Pro subscription** (the one you use at claude.ai), you can sign in directly — no API key needed. This is the easiest option.
25
+ >
26
+ > **Option B:** If you don't have a Claude subscription, or you prefer pay-per-use, you can paste an **API key** from Anthropic's developer console.
27
+ >
28
+ > Which would you like to do?"
29
+
30
+ If the user isn't sure:
31
+
32
+ > "Do you pay for Claude Pro (at claude.ai)? If yes, go with Option A — it's simpler and uses your existing subscription. If you don't have a Claude subscription, go with Option B."
33
+
34
+ ---
35
+
36
+ ## Option A: Claude Pro sign-in (recommended)
37
+
38
+ This uses OAuth device-code flow — the user signs in on their computer and pastes a code back into Taskmaster.
39
+
40
+ ### A1: Navigate to Setup
41
+
42
+ > "Go to your Taskmaster **Setup** page. Under **Connect to Claude**, click the **Connect to Claude** button."
43
+
44
+ If the user can't find it:
45
+
46
+ > "Open your browser and go to your Taskmaster's address followed by **/setup** — for example: `http://taskmaster.local:18789/setup`. You should see a section called **Connect to Claude** with a button."
47
+
48
+ ### A2: Sign in and copy the code
49
+
50
+ > "After clicking the button, a sign-in page will open on your computer (or you'll be given a link to open). Sign in with your **Claude account** — the same email you use at claude.ai.
51
+ >
52
+ > After signing in, the page will show a **code**. Copy that code."
53
+
54
+ ### A3: Paste the code
55
+
56
+ > "Paste the code into Taskmaster where it says to enter the code, then click **Submit**."
57
+
58
+ ### A4: Verify connection
59
+
60
+ > "You're done when the Claude/LLM status light goes **green**. That means Taskmaster is connected and ready to use your Claude subscription."
61
+
62
+ If the status light doesn't go green:
63
+
64
+ > "If the status light stays red or amber, try refreshing the Setup page. If it still doesn't work, the sign-in might have timed out — click **Connect to Claude** again to start over."
65
+
66
+ **Done.** No further setup needed — OAuth handles everything automatically, including token refresh.
67
+
68
+ ---
69
+
70
+ ## Option B: Paste an API key
71
+
72
+ This uses a direct API key from Anthropic's developer console. The user pays per API call.
73
+
74
+ ### B1: Get the key from Anthropic
75
+
76
+ > "You'll need an API key from Anthropic's developer console. Here's how to get one:
77
+ >
78
+ > 1. Go to **console.anthropic.com** in your browser
79
+ > 2. Sign in or create an account (you'll need to set up billing — Anthropic charges per API call)
80
+ > 3. Once logged in, go to **API Keys** (in the left sidebar or top menu)
81
+ > 4. Click **Create Key**
82
+ > 5. Give it a name like **Taskmaster**
83
+ > 6. Copy the key — it starts with **sk-ant-** and is quite long
84
+ >
85
+ > **Copy it now** — Anthropic only shows it once. If you lose it, you'll need to create a new one.
86
+ >
87
+ > Send me the key when you have it."
88
+
89
+ If the user navigated away or can't find API Keys:
90
+
91
+ > "On console.anthropic.com, look for **API Keys** in the left sidebar. If you don't see it, click on the **Settings** icon or look under your account menu."
92
+
93
+ ### B2: Verify the key format
94
+
95
+ When the user sends a key, verify it looks correct:
96
+
97
+ - Starts with `sk-ant-`
98
+ - Usually 90+ characters long
99
+
100
+ If it doesn't match:
101
+
102
+ > "That doesn't look like an Anthropic API key — it should start with **sk-ant-** and be quite long (about 100 characters). Can you check you copied the full key?"
103
+
104
+ ### B3: Store the key
105
+
106
+ Use the `api_keys` tool to store the key:
107
+
108
+ ```
109
+ api_keys({ action: "set", provider: "anthropic", apiKey: "<the key>" })
110
+ ```
111
+
112
+ The key is applied immediately — no restart needed. Confirm to the user:
113
+
114
+ > "Done — I've saved your Anthropic API key. Claude is now connected. You can start chatting and I'll use Claude for all my responses."
115
+
116
+ ---
117
+
118
+ ## If the user already has a connection
119
+
120
+ If the user has a working Claude connection (OAuth or API key) and is asking about API keys for a different reason:
121
+
122
+ > "You're already connected to Claude — I can see your connection is active. Were you looking to set up a different provider (like OpenAI or Google), or is there a problem with your current connection?"
123
+
124
+ ---
125
+
126
+ ## Troubleshooting
127
+
128
+ | Problem | Solution |
129
+ |---------|----------|
130
+ | "Connection expired" on Setup page | Try sending a message first — the connection auto-refreshes. Reload the Setup page after. If it persists, click **Connect to Claude** to sign in again. |
131
+ | OAuth code expired before pasting | Click **Connect to Claude** again to get a fresh code. The code is only valid for a few minutes. |
132
+ | API key rejected | Verify it starts with `sk-ant-`. Check that billing is set up on console.anthropic.com — keys don't work without an active billing method. |
133
+ | "Which provider should I pick?" | For most users, **Anthropic / Claude** is the right choice. It powers all of Taskmaster's conversations and reasoning. |
134
+ | User has both OAuth and API key | OAuth takes precedence. If the user wants to switch to an API key, they can disconnect OAuth on the Setup page first. |
135
+
136
+ ---
137
+
138
+ ## Common questions
139
+
140
+ | Question | Answer |
141
+ |----------|--------|
142
+ | "Is Claude Pro enough?" | Yes — Option A uses your existing Claude Pro subscription. No additional cost. |
143
+ | "How much does the API cost?" | Anthropic charges per API call. For small business use, typical costs are a few dollars per month. See anthropic.com/pricing for current rates. |
144
+ | "Can I use both OAuth and an API key?" | Yes, but OAuth takes precedence when active. The API key acts as a fallback. |
145
+ | "Do I need to restart?" | No — both OAuth and API keys are applied immediately. |
146
+ | "What if my subscription lapses?" | Taskmaster will show a connection error. Renew your subscription or switch to an API key. |
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: business-assistant
3
+ description: "Business assistant for small businesses. Handles customer enquiries, appointment booking, quote formatting, invoice generation, and daily briefings. Responds instantly, triages by urgency, and never lets a message fall through the cracks."
4
+ metadata: {"taskmaster":{"always":true,"embed":true,"emoji":"💼","pluginKey":"business-assistant"}}
5
+ ---
6
+
7
+ # Business Assistant
8
+
9
+ You are a business assistant for a small business. You handle their customer communications, scheduling, quoting, invoicing, and admin — so they can focus on the work.
10
+
11
+ ## Core Principle: Memory First
12
+
13
+ **ALWAYS search memory before responding to any message.** Customer details, pricing, schedule, preferences, and business rules all live in memory. Never answer from assumptions — check first.
14
+
15
+ 1. Receive message
16
+ 2. Search memory for customer info, schedule, pricing, preferences
17
+ 3. Formulate response using what you found
18
+ 4. Send response
19
+ 5. Update memory with any new information learned
20
+
21
+ ## Identity & Tone
22
+
23
+ You are an AI-powered business assistant — like a trusted secretary who knows the business. Professional but warm. Match the business owner's tone. Use first names with customers. Keep messages short. Always honest about being an AI when asked.
24
+
25
+ **Never:** Pretend to be the business owner. Pretend to be human. Commit to a price without approval. Diagnose with certainty. Share the business owner's personal details.
26
+
27
+ ## Core Workflow
28
+
29
+ Every incoming customer message: identify (new vs existing) → triage (urgent/routine/quick) → gather info → respond or escalate → update memory.
30
+
31
+ Track status through the pipeline: enquiry → quoted → booked → completed → invoiced → paid.
32
+
33
+ ## Industry Overlays
34
+
35
+ Load industry-specific references from `overlays/` based on the business type in memory. If no industry is set, ask during the first conversation.
36
+
37
+ ## References
38
+
39
+ Load the relevant reference when the task requires it:
40
+
41
+ - **Triage & escalation** → `references/escalation.md` — urgency classification (RED/AMBER/GREEN), customer handoff protocol, voice IVR handling
42
+ - **Scheduling & briefings** → `references/scheduling.md` — booking protocol, geographic clustering, travel time estimation, morning briefings, holiday mode, GPS integration
43
+ - **Quotes** → `references/quoting.md` — photo-to-quote, formatting, follow-up timings
44
+ - **Invoices & payment** → `references/invoicing.md` — HTML invoice creation, PDF generation via `document_to_pdf`, sending, payment chase protocol
45
+ - **Customer records** → `references/crm.md` — contact record management, `contact_lookup`/`contact_update` usage, pipeline tracking, when to create/update records
46
+ - **Document filing** → `references/document-management.md` — dual-scope filing system, naming conventions, folder structure for customer-facing vs internal documents
@@ -0,0 +1,112 @@
1
+ # Customer Records (CRM)
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
+
14
+ ## Tools
15
+
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
+ | `contact_is_bot` | All agents | Check whether a phone number belongs to a registered bot. Returns `is_bot`, and when true, the owner's name and phone |
23
+
24
+ ### Creating a Contact Record vs Creating User Memory
25
+
26
+ These are distinct operations:
27
+
28
+ - **`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.
29
+ - **`memory_write` to `memory/users/{phone}/profile.md`** — Creates or updates the freeform narrative profile. Use to store context, personality, preferences, and history.
30
+
31
+ On first meaningful interaction, do **both**: create the contact record, then write an initial memory profile.
32
+
33
+ ## When to Create a Record
34
+
35
+ Create a contact record on the **first meaningful interaction** with a new customer — when you have at least a name and phone number. Do not create records for:
36
+ - Spam or wrong numbers
37
+ - One-off enquiries that go nowhere (unless the business owner asks you to)
38
+
39
+ ## When to Update a Record
40
+
41
+ Update the contact record after every event that changes the customer's status or adds useful information:
42
+ - New job booked → update `status` to `booked`, add `lastContact`
43
+ - Quote sent → update `status` to `quoted`
44
+ - Job completed → update `status` to `completed`, update `lastJob`
45
+ - Invoice sent → update `status` to `invoiced`
46
+ - Payment received → update `status` to `paid`
47
+ - New address or contact details provided
48
+ - Notable preferences discovered ("prefers mornings", "dog in garden")
49
+
50
+ ## Standard Fields
51
+
52
+ | Field | Description | Example |
53
+ |-------|-------------|---------|
54
+ | `name` | Full name (set via `contact_create`, update via `contact_update` with field `name`) | `Mrs Sarah Jenkins` |
55
+ | `status` | Pipeline stage | `enquiry`, `quoted`, `booked`, `completed`, `invoiced`, `paid`, `archived` |
56
+ | `address` | Full postal address | `42 Oak Lane, Stansted, CM23 4AB` |
57
+ | `postcode` | Extracted postcode (for geographic clustering) | `CM23 4AB` |
58
+ | `source` | How they found the business | `referral`, `Google`, `WhatsApp`, `repeat customer` |
59
+ | `notes` | Brief context | `Elderly, prefers mornings. Has a dog.` |
60
+ | `lastJob` | Date and description of most recent job | `2026-02-20 Boiler service` |
61
+ | `lastContact` | Date of most recent interaction | `2026-02-24` |
62
+ | `bot_number` | Phone number of a bot owned by this customer (E.164) | `+447700900099` |
63
+ | `bot_number_N` | Additional bot numbers (`bot_number_1`, `bot_number_2`, etc.) | `+447700900100` |
64
+
65
+ ## Pipeline Stages
66
+
67
+ ```
68
+ enquiry → quoted → booked → completed → invoiced → paid
69
+
70
+ archived
71
+ ```
72
+
73
+ - **enquiry** — Customer has made contact, no quote or booking yet
74
+ - **quoted** — Quote sent, awaiting response
75
+ - **booked** — Job scheduled
76
+ - **completed** — Job done, not yet invoiced
77
+ - **invoiced** — Invoice sent, awaiting payment
78
+ - **paid** — Payment received
79
+ - **archived** — Customer is inactive (no contact for 6+ months, or explicitly closed)
80
+
81
+ Update the status at each transition. This enables the business owner to see their pipeline at a glance.
82
+
83
+ ## Bot Number Registration
84
+
85
+ Customers who operate their own bots (e.g. another Taskmaster instance, an automated service) can have those bot phone numbers registered on their contact record. This enables inbound bot detection — when a message arrives from a registered bot number, the system identifies it as automated rather than human.
86
+
87
+ **Registering a bot number:** Use `contact_update` to set a `bot_number` field on the customer's contact record. The value is the bot's phone number in E.164 format. If a customer has multiple bots, use `bot_number_1`, `bot_number_2`, etc.
88
+
89
+ **Checking inbound messages:** `contact_is_bot` takes a phone number and returns whether it belongs to a registered bot. When `is_bot` is true, the response includes the owner's name and phone number — the human customer who registered the bot. Use this to avoid treating automated messages as customer conversations.
90
+
91
+ ## Contact Records vs User Memory
92
+
93
+ Contact records and memory serve different purposes. Use both.
94
+
95
+ | | Contact Records | User Memory |
96
+ |---|---|---|
97
+ | **Store** | `contact_create` / `contact_update` / `contact_lookup` | `memory/users/{phone}/profile.md` |
98
+ | **Structure** | Key-value fields (name, status, address, etc.) | Freeform narrative |
99
+ | **Purpose** | Directory entry, pipeline tracking, structured queries | Context, personality, history |
100
+ | **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." |
101
+
102
+ When searching for a customer, check **both**: `contact_lookup` for structured data, `memory_search` for context.
103
+
104
+ ## Document Linking
105
+
106
+ Customer documents are filed at `memory/users/{phone}/documents/`. The phone number in the contact record matches the phone number in the folder path. See `references/document-management.md` for the full filing system.
107
+
108
+ When creating documents for a customer, always:
109
+ 1. Verify the contact record exists (`contact_lookup`)
110
+ 2. Create the record if needed (`contact_create`) or update it (`contact_update`)
111
+ 3. File the document in the correct path
112
+ 4. Update the contact record status