create-yonderclaw 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 (93) hide show
  1. package/LICENSE +44 -0
  2. package/README.md +288 -0
  3. package/bin/create-yonderclaw.mjs +43 -0
  4. package/docs/assets/favicon.png +0 -0
  5. package/docs/assets/metaclaw-banner.svg +86 -0
  6. package/docs/assets/qis-logo.png +0 -0
  7. package/docs/assets/yz-favicon.png +0 -0
  8. package/docs/assets/yz-logo.png +0 -0
  9. package/docs/index.html +1155 -0
  10. package/installer/assets/favicon.png +0 -0
  11. package/installer/auto-start.ts +330 -0
  12. package/installer/brand.ts +115 -0
  13. package/installer/core-scaffold.ts +448 -0
  14. package/installer/dashboard-generator.ts +657 -0
  15. package/installer/detect.ts +129 -0
  16. package/installer/index.ts +355 -0
  17. package/installer/module-loader.ts +412 -0
  18. package/installer/modules/boardroom/boardroom/client.ts.txt +201 -0
  19. package/installer/modules/boardroom/boardroom/db.ts.txt +322 -0
  20. package/installer/modules/boardroom/boardroom/meeting-agent.ts.txt +129 -0
  21. package/installer/modules/boardroom/boardroom/meeting-scheduler.ts.txt +194 -0
  22. package/installer/modules/boardroom/boardroom/server.ts.txt +473 -0
  23. package/installer/modules/boardroom/boardroom/start-boardroom.bat.txt +26 -0
  24. package/installer/modules/boardroom/boardroom/summons.ts.txt +76 -0
  25. package/installer/modules/boardroom/boardroom/turn-v2.ts.txt +172 -0
  26. package/installer/modules/boardroom/boardroom/turn.ts.txt +208 -0
  27. package/installer/modules/boardroom/boardroom/types.ts.txt +100 -0
  28. package/installer/modules/boardroom/metaclaw-module.json +35 -0
  29. package/installer/modules/boardroom/scripts/meeting-check.bat.txt +38 -0
  30. package/installer/modules/core/metaclaw-module.json +51 -0
  31. package/installer/modules/core/src/db.ts.txt +277 -0
  32. package/installer/modules/core/src/health-check.ts.txt +128 -0
  33. package/installer/modules/core/src/observability.ts.txt +20 -0
  34. package/installer/modules/core/src/safety.ts.txt +26 -0
  35. package/installer/modules/core/src/scan-capabilities.ts.txt +196 -0
  36. package/installer/modules/core/src/self-improve.ts.txt +48 -0
  37. package/installer/modules/core/src/self-update.ts.txt +345 -0
  38. package/installer/modules/core/src/sync-context.ts.txt +133 -0
  39. package/installer/modules/core/src/tasks.ts.txt +159 -0
  40. package/installer/modules/custom/metaclaw-module.json +15 -0
  41. package/installer/modules/custom/src/agent-custom.ts.txt +100 -0
  42. package/installer/modules/dashboard/metaclaw-module.json +23 -0
  43. package/installer/modules/dashboard/scripts/build-dashboard.cjs.txt +51 -0
  44. package/installer/modules/dashboard/src/update-dashboard.ts.txt +126 -0
  45. package/installer/modules/outreach/metaclaw-module.json +29 -0
  46. package/installer/modules/outreach/src/agent-outreach.ts.txt +193 -0
  47. package/installer/modules/outreach/src/inbox-agent.ts.txt +283 -0
  48. package/installer/modules/outreach/src/morning-report.ts.txt +124 -0
  49. package/installer/modules/research/metaclaw-module.json +15 -0
  50. package/installer/modules/research/src/agent-research.ts.txt +127 -0
  51. package/installer/modules/scheduler/metaclaw-module.json +27 -0
  52. package/installer/modules/scheduler/scripts/agent-cycle.bat.txt +85 -0
  53. package/installer/modules/scheduler/scripts/detect-session.bat.txt +41 -0
  54. package/installer/modules/scheduler/scripts/launch.bat.txt +120 -0
  55. package/installer/modules/scheduler/src/cron-manager.ts.txt +273 -0
  56. package/installer/modules/social/metaclaw-module.json +15 -0
  57. package/installer/modules/social/src/agent-social.ts.txt +110 -0
  58. package/installer/modules/support/metaclaw-module.json +15 -0
  59. package/installer/modules/support/src/agent-support.ts.txt +60 -0
  60. package/installer/modules/swarm/metaclaw-module.json +25 -0
  61. package/installer/modules/swarm/swarm/dht-client.ts.txt +376 -0
  62. package/installer/modules/swarm/swarm/relay-server.ts.txt +348 -0
  63. package/installer/modules/swarm/swarm/swarm-client.ts.txt +303 -0
  64. package/installer/modules/swarm/swarm/types.ts.txt +51 -0
  65. package/installer/modules/voice/metaclaw-module.json +16 -0
  66. package/installer/questionnaire.ts +277 -0
  67. package/installer/research.ts +258 -0
  68. package/installer/scaffold-from-config.ts +270 -0
  69. package/installer/task-generator.ts +324 -0
  70. package/installer/templates/agent-custom.ts.txt +100 -0
  71. package/installer/templates/agent-cycle.bat.txt +19 -0
  72. package/installer/templates/agent-outreach.ts.txt +193 -0
  73. package/installer/templates/agent-research.ts.txt +127 -0
  74. package/installer/templates/agent-social.ts.txt +110 -0
  75. package/installer/templates/agent-support.ts.txt +60 -0
  76. package/installer/templates/build-dashboard.cjs.txt +51 -0
  77. package/installer/templates/cron-manager.ts.txt +273 -0
  78. package/installer/templates/dashboard.html.txt +450 -0
  79. package/installer/templates/db.ts.txt +277 -0
  80. package/installer/templates/detect-session.bat.txt +41 -0
  81. package/installer/templates/health-check.ts.txt +128 -0
  82. package/installer/templates/inbox-agent.ts.txt +283 -0
  83. package/installer/templates/launch.bat.txt +120 -0
  84. package/installer/templates/morning-report.ts.txt +124 -0
  85. package/installer/templates/observability.ts.txt +20 -0
  86. package/installer/templates/safety.ts.txt +26 -0
  87. package/installer/templates/self-improve.ts.txt +48 -0
  88. package/installer/templates/self-update.ts.txt +345 -0
  89. package/installer/templates/state.json.txt +33 -0
  90. package/installer/templates/system-context.json.txt +33 -0
  91. package/installer/templates/update-dashboard.ts.txt +126 -0
  92. package/package.json +31 -0
  93. package/setup.bat +178 -0
@@ -0,0 +1,270 @@
1
+ /**
2
+ * MetaClaw v3.3 — Module-Driven Scaffold
3
+ *
4
+ * Reads config JSON, discovers modules, resolves dependencies,
5
+ * copies templates with placeholders, assembles CLAUDE.md, generates dashboard.
6
+ *
7
+ * Usage: npx tsx installer/scaffold-from-config.ts <config.json> <output-dir> [modules-dir]
8
+ */
9
+
10
+ import fs from "fs";
11
+ import path from "path";
12
+ import { fileURLToPath } from "url";
13
+ import { generateDashboard } from "./dashboard-generator.js";
14
+ import { generateStarterTasks } from "./task-generator.js";
15
+ import {
16
+ discoverModules, resolveModulesToInstall, buildPlaceholders,
17
+ processModuleContributes, mergeNpmScripts, mergeDependencies,
18
+ buildClaudeMd, writeModulesJson, copyTemplate,
19
+ type LoadedModule, type InstallConfig
20
+ } from "./module-loader.js";
21
+
22
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
23
+
24
+ const configPath = process.argv[2];
25
+ const outputDir = process.argv[3];
26
+ const modulesArg = process.argv[4];
27
+
28
+ if (!configPath || !outputDir) {
29
+ console.error("Usage: npx tsx installer/scaffold-from-config.ts <config.json> <output-dir> [modules-dir]");
30
+ process.exit(1);
31
+ }
32
+
33
+ // --- Find modules directory ---
34
+ // Tauri flattens resources, so modules might be in several locations
35
+ const candidates = [
36
+ modulesArg,
37
+ path.join(__dirname, "modules"),
38
+ path.join(outputDir, "installer", "modules"),
39
+ path.join(outputDir, "modules"),
40
+ path.join(process.cwd(), "installer", "modules"),
41
+ path.join(process.cwd(), "modules"),
42
+ // Tauri extracts resources — check multiple possible locations
43
+ ...(modulesArg ? [path.join(modulesArg, "modules"), path.join(modulesArg, "installer", "modules")] : []),
44
+ ].filter(Boolean) as string[];
45
+
46
+ let MODULES_DIR = "";
47
+ for (const c of candidates) {
48
+ const coreManifest = path.join(c, "core", "metaclaw-module.json");
49
+ if (fs.existsSync(coreManifest)) { MODULES_DIR = c; break; }
50
+ }
51
+
52
+ // Fallback: check if templates are in flat structure (old format / Tauri bundle)
53
+ if (!MODULES_DIR) {
54
+ // Try old templates dir for backward compatibility
55
+ const oldCandidates = [
56
+ path.join(__dirname, "templates"),
57
+ path.join(outputDir, "installer", "templates"),
58
+ outputDir,
59
+ ];
60
+ for (const c of oldCandidates) {
61
+ if (fs.existsSync(path.join(c, "db.ts.txt"))) {
62
+ console.warn("WARNING: Using legacy flat templates. Module system not found.");
63
+ console.warn("Tried: " + candidates.join(", "));
64
+ // Fall through to legacy mode below
65
+ break;
66
+ }
67
+ }
68
+ }
69
+
70
+ if (!MODULES_DIR) {
71
+ // Debug: list what's actually in the output dir
72
+ console.error("Module system not found. Tried:");
73
+ for (const c of candidates) {
74
+ const exists = fs.existsSync(c);
75
+ const coreExists = fs.existsSync(path.join(c, "core", "metaclaw-module.json"));
76
+ console.error(` ${c} (exists: ${exists}, core: ${coreExists})`);
77
+ }
78
+ console.error("Output dir contents:");
79
+ try {
80
+ const listDir = (p: string, indent: number) => {
81
+ for (const f of fs.readdirSync(p)) {
82
+ if (f === "node_modules") continue;
83
+ const fp = path.join(p, f);
84
+ console.error(" ".repeat(indent) + f);
85
+ if (fs.statSync(fp).isDirectory() && indent < 3) listDir(fp, indent + 1);
86
+ }
87
+ };
88
+ listDir(outputDir, 1);
89
+ } catch {}
90
+ process.exit(1);
91
+ }
92
+
93
+ console.log("Using modules: " + MODULES_DIR);
94
+
95
+ // --- Load config ---
96
+ const config: InstallConfig = JSON.parse(fs.readFileSync(configPath, "utf-8"));
97
+ const agentName = config.agentName || "Atlas";
98
+ const clawType = config.clawType || "custom";
99
+ const sessionName = agentName.toLowerCase().replace(/[^a-z0-9]/g, "-");
100
+
101
+ console.log(`Scaffolding ${agentName} (${clawType}) to ${outputDir}...`);
102
+
103
+ // --- Discover and resolve modules ---
104
+ const allModules = discoverModules(MODULES_DIR);
105
+ console.log(`Discovered ${allModules.length} modules: ${allModules.map(m => m.manifest.name).join(", ")}`);
106
+
107
+ const modulesToInstall = resolveModulesToInstall(allModules, config);
108
+ console.log(`Installing ${modulesToInstall.length} modules: ${modulesToInstall.map(m => m.manifest.name).join(", ")}`);
109
+
110
+ // --- Build placeholders ---
111
+ const systemPrompt = buildSystemPrompt(config);
112
+ const placeholders = buildPlaceholders(config, outputDir);
113
+ // Add system prompt (needs special escaping for template embedding)
114
+ placeholders["__SYSTEM_PROMPT__"] = systemPrompt.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$/g, "\\$");
115
+
116
+ // --- Create base directories ---
117
+ for (const d of ["src", "src/tools", "data", "data/logs", "scripts"]) {
118
+ fs.mkdirSync(path.join(outputDir, d), { recursive: true });
119
+ }
120
+
121
+ // --- Process each module ---
122
+ const packageJson: any = {
123
+ name: config.projectName || sessionName,
124
+ version: "1.0.0",
125
+ type: "module",
126
+ description: `${clawType} agent — MetaClaw v3.3.0`,
127
+ scripts: {},
128
+ dependencies: {},
129
+ };
130
+
131
+ for (const mod of modulesToInstall) {
132
+ console.log(` Installing module: ${mod.manifest.displayName}`);
133
+ processModuleContributes(mod, outputDir, placeholders);
134
+ }
135
+
136
+ // Merge npm scripts and dependencies from all modules
137
+ mergeNpmScripts(packageJson, modulesToInstall);
138
+ mergeDependencies(packageJson, modulesToInstall);
139
+
140
+ // Add test script
141
+ packageJson.scripts.test = "echo Tests not configured";
142
+
143
+ // Write package.json
144
+ fs.writeFileSync(path.join(outputDir, "package.json"), JSON.stringify(packageJson, null, 2));
145
+
146
+ // --- Assemble CLAUDE.md ---
147
+ const claudeMd = buildClaudeMd(modulesToInstall, config, systemPrompt);
148
+ fs.writeFileSync(path.join(outputDir, "CLAUDE.md"), claudeMd);
149
+
150
+ // --- SOUL.md ---
151
+ fs.writeFileSync(path.join(outputDir, "SOUL.md"), [
152
+ `# ${agentName} — Principles`, "",
153
+ "1. Verify outputs before presenting",
154
+ "2. Acknowledge uncertainty",
155
+ "3. Prefer established approaches",
156
+ "4. Break into verifiable sub-tasks",
157
+ "5. Explain reasoning",
158
+ "6. Stop on failure loops",
159
+ "7. No irreversible actions without confirmation",
160
+ "8. Track cost and impact",
161
+ "9. ALWAYS deposit insights to QIS buckets after completing tasks",
162
+ "10. ALWAYS check relevant buckets before starting work",
163
+ "", "## System Prompt", systemPrompt
164
+ ].join("\n"));
165
+
166
+ // --- HEARTBEAT.md ---
167
+ fs.writeFileSync(path.join(outputDir, "HEARTBEAT.md"), "# Heartbeat\nLast run: never");
168
+
169
+ // --- Dashboard ---
170
+ fs.writeFileSync(path.join(outputDir, "dashboard.html"), generateDashboard(agentName, clawType, config));
171
+
172
+ // Favicon
173
+ const favCandidates = [
174
+ path.join(__dirname, "assets", "favicon.png"),
175
+ path.join(outputDir, "installer", "assets", "favicon.png"),
176
+ path.join(outputDir, "favicon.png"),
177
+ path.join(process.cwd(), "favicon.png"),
178
+ ];
179
+ const fav = favCandidates.find(f => fs.existsSync(f)) || "";
180
+ if (fs.existsSync(fav)) fs.copyFileSync(fav, path.join(outputDir, "favicon.png"));
181
+
182
+ // --- Init scripts (these are config-specific, generated inline) ---
183
+ const ms = (parseInt(config.updateInterval) || 6) * 60 * 60 * 1000;
184
+ fs.writeFileSync(path.join(outputDir, "src", "init-config.ts"),
185
+ `import{getDb,setConfig}from"./db.js";getDb();setConfig("self_update_interval_ms","${ms}");setConfig("agent_name",${JSON.stringify(agentName)});setConfig("template",${JSON.stringify(clawType)});setConfig("created_at",new Date().toISOString());console.log("Config initialized.");`);
186
+ fs.writeFileSync(path.join(outputDir, "src", "init-prompts.ts"),
187
+ `import{getDb}from"./db.js";const db=getDb();const t=${JSON.stringify(clawType)};const c=${JSON.stringify(systemPrompt)};const e=db.prepare("SELECT 1 FROM prompt_versions WHERE prompt_type=?").get(t);if(!e){db.prepare("INSERT INTO prompt_versions(prompt_type,version,content,created_by)VALUES(?,1,?,?)").run(t,c,"installer");console.log("Prompt seeded");}else{console.log("Prompt exists");}`);
188
+
189
+ // --- Data files ---
190
+ fs.writeFileSync(path.join(outputDir, "data", "vip-emails.json"), "[]");
191
+
192
+ // --- HT/AT Task System ---
193
+ const tasks = generateStarterTasks({
194
+ agentName, clawType,
195
+ senderEmail: config.senderEmail,
196
+ toolsUsed: config.toolsUsed,
197
+ autonomy: config.autonomy,
198
+ enableLocalSwarm: config.enableLocalSwarm,
199
+ enableGlobalSwarm: config.enableGlobalSwarm,
200
+ relayUrl: config.relayUrl,
201
+ });
202
+ fs.writeFileSync(path.join(outputDir, "data", "tasks.json"), JSON.stringify(tasks, null, 2));
203
+ console.log(` Generated ${tasks.human_tasks.length} starter HTs + ${tasks.ai_tasks.length} starter ATs`);
204
+
205
+ // Swarm config
206
+ const swarmConfig = {
207
+ agentName,
208
+ relayUrl: config.relayUrl || "http://localhost:7891",
209
+ enableLocal: config.enableLocalSwarm !== false,
210
+ enableGlobal: config.enableGlobalSwarm !== false,
211
+ };
212
+ fs.writeFileSync(path.join(outputDir, "data", "swarm-config.json"), JSON.stringify(swarmConfig, null, 2));
213
+
214
+ // --- Desktop launcher ---
215
+ fs.writeFileSync(path.join(outputDir, `Launch ${agentName}.bat`),
216
+ `@echo off\r\nstart "" cmd /k "cd /d ""${outputDir}"" && scripts\\launch.bat"\r\n`);
217
+
218
+ // --- Open dashboard script ---
219
+ fs.writeFileSync(path.join(outputDir, "scripts", "open-dashboard.bat"),
220
+ `@echo off\r\ncd /d "${outputDir}"\r\ncall npx tsx src/update-dashboard.ts 2>nul\r\nstart "" "${path.join(outputDir, "dashboard.html")}"\r\n`);
221
+
222
+ // --- .gitignore ---
223
+ fs.writeFileSync(path.join(outputDir, ".gitignore"), "node_modules/\ndist/\ndata/\n*.db\n.env\n");
224
+
225
+ // --- Claude Code permissions (auto mode — no permission prompts) ---
226
+ const claudeSettingsDir = path.join(outputDir, ".claude");
227
+ fs.mkdirSync(claudeSettingsDir, { recursive: true });
228
+ fs.writeFileSync(path.join(claudeSettingsDir, "settings.json"), JSON.stringify({
229
+ permissions: {
230
+ defaultMode: "auto",
231
+ allow: [
232
+ "Bash(npx *)", "Bash(npm *)", "Bash(node *)", "Bash(tsx *)",
233
+ "Bash(cd *)", "Bash(ls *)", "Bash(cat *)", "Bash(echo *)", "Bash(mkdir *)",
234
+ "Bash(curl *)", "Bash(git *)", "Bash(schtasks *)",
235
+ "Edit", "Read", "Glob", "Grep",
236
+ "WebFetch", "WebSearch"
237
+ ],
238
+ deny: [
239
+ "Bash(rm -rf /)",
240
+ "Bash(curl * | bash)",
241
+ "Bash(format *)"
242
+ ]
243
+ }
244
+ }, null, 2));
245
+
246
+ // --- Write modules.json ---
247
+ writeModulesJson(outputDir, modulesToInstall);
248
+
249
+ console.log(`\nScaffold complete — ${modulesToInstall.length} modules installed.`);
250
+ console.log(`Modules: ${modulesToInstall.map(m => m.manifest.name).join(", ")}`);
251
+
252
+ // --- System prompt builder ---
253
+ function buildSystemPrompt(cfg: any): string {
254
+ const p = [`You are ${cfg.agentName || "Atlas"}, an autonomous AI agent.`, `Type: ${cfg.clawType || "custom"}`];
255
+ if (cfg.taskDescription) p.push("Task: " + cfg.taskDescription);
256
+ if (cfg.toolsUsed) p.push("Tools: " + cfg.toolsUsed);
257
+ if (cfg.autonomy === "supervised") p.push("Always suggest and wait for approval.");
258
+ if (cfg.autonomy === "full") p.push("Fully autonomous. Alert on errors only.");
259
+ if (cfg.autonomy === "semi") p.push("Act on routine. Ask on important.");
260
+ if (cfg.volume) p.push("Volume: " + cfg.volume);
261
+ if (cfg.specialInstructions) p.push("Special: " + cfg.specialInstructions);
262
+ if (cfg.clawType === "outreach") {
263
+ if (cfg.senderName) p.push("Send as: " + cfg.senderName);
264
+ if (cfg.senderEmail) p.push("From: " + cfg.senderEmail);
265
+ if (cfg.targetAudience) p.push("Target: " + cfg.targetAudience);
266
+ if (cfg.purpose) p.push("Goal: " + cfg.purpose);
267
+ }
268
+ p.push("\nRules:\n- Read data/state.json first\n- Update state.json last\n- Self-update AFTER tasks\n- Read SOUL.md for principles\n- Check QIS buckets before work, deposit after");
269
+ return p.join("\n");
270
+ }
@@ -0,0 +1,324 @@
1
+ /**
2
+ * MetaClaw Task Generator
3
+ * Creates starter HT/AT tasks based on questionnaire answers.
4
+ * Called during scaffold to generate data/tasks.json.
5
+ */
6
+
7
+ interface TaskConfig {
8
+ agentName: string;
9
+ clawType: string;
10
+ senderEmail?: string;
11
+ toolsUsed?: string;
12
+ autonomy?: string;
13
+ enableLocalSwarm?: boolean;
14
+ enableGlobalSwarm?: boolean;
15
+ relayUrl?: string;
16
+ }
17
+
18
+ export function generateStarterTasks(config: TaskConfig): any {
19
+ const relayUrl = config.relayUrl || "http://localhost:7891";
20
+ const hts: any[] = [];
21
+ const ats: any[] = [];
22
+ let htNum = 1;
23
+ let atNum = 1;
24
+
25
+ const ht = (data: any) => {
26
+ const id = `ht-${String(htNum++).padStart(3, "0")}`;
27
+ return { id, status: "pending", created_at: new Date().toISOString(), completed_at: null, created_by: "system", notes: null, ...data };
28
+ };
29
+
30
+ const at = (data: any) => {
31
+ const id = `at-${String(atNum++).padStart(3, "0")}`;
32
+ return { id, status: data.requires_ht ? "blocked" : "pending", created_at: new Date().toISOString(), created_by: "system", ...data };
33
+ };
34
+
35
+ // === UNIVERSAL HTs (every claw type) ===
36
+
37
+ hts.push(ht({
38
+ title: "Verify Claude Code is authenticated",
39
+ description: "Make sure Claude Code can connect to your account.",
40
+ priority: "critical", category: "auth",
41
+ blocks: [`at-${String(atNum).padStart(3, "0")}`],
42
+ instructions: [
43
+ "Open a terminal in this project directory",
44
+ "Run: claude --version",
45
+ "If it shows a version number, you're good",
46
+ "If not, run: claude auth login",
47
+ "Follow the browser prompts to authenticate"
48
+ ],
49
+ why: "The agent cannot function without Claude Code authentication. This is step zero.",
50
+ outcome: "Agent can start working autonomously.",
51
+ estimated_minutes: 2
52
+ }));
53
+
54
+ ats.push(at({
55
+ title: "Run first health check and status report",
56
+ priority: "critical", category: "setup",
57
+ requires_ht: ["ht-001"],
58
+ description: "Verify all systems are working after install."
59
+ }));
60
+
61
+ hts.push(ht({
62
+ title: "Review agent personality and instructions",
63
+ description: "Read CLAUDE.md and SOUL.md — customize if needed.",
64
+ priority: "high", category: "config",
65
+ blocks: [],
66
+ instructions: [
67
+ "Open CLAUDE.md in a text editor",
68
+ "Review the system prompt — does it match what you want?",
69
+ "Open SOUL.md — these are the agent's principles",
70
+ "Edit either file if you want to adjust behavior",
71
+ "Save and the agent will pick up changes next session"
72
+ ],
73
+ why: "The agent's personality and rules come from these files. Customizing them makes the agent truly yours.",
74
+ outcome: "Agent behavior matches your expectations.",
75
+ estimated_minutes: 5
76
+ }));
77
+
78
+ hts.push(ht({
79
+ title: "Set your timezone",
80
+ description: "Tell the agent your local timezone so it schedules correctly.",
81
+ priority: "high", category: "config",
82
+ blocks: [],
83
+ instructions: [
84
+ "Open data/state.json",
85
+ "Add or update the field: \"timezone\": \"America/Phoenix\" (or your timezone)",
86
+ "Save the file",
87
+ "Common values: America/New_York, America/Chicago, America/Denver, America/Los_Angeles, America/Phoenix (no DST)"
88
+ ],
89
+ why: "Without your timezone, the agent hallucinates times and schedules things at wrong hours.",
90
+ outcome: "Agent knows what time it is in your world.",
91
+ estimated_minutes: 1
92
+ }));
93
+
94
+ // === OUTREACH-SPECIFIC HTs ===
95
+ if (config.clawType === "outreach") {
96
+ const emailHtId = `ht-${String(htNum).padStart(3, "0")}`;
97
+ hts.push(ht({
98
+ title: "Create a dedicated outreach email account",
99
+ description: "Set up a separate Gmail for outreach. Never use your personal email — protects your main inbox from deliverability issues.",
100
+ priority: "critical", category: "auth",
101
+ blocks: [`at-${String(atNum + 1).padStart(3, "0")}`, `at-${String(atNum + 2).padStart(3, "0")}`],
102
+ instructions: [
103
+ "Go to accounts.google.com and create a new Google account",
104
+ "Use a professional address (e.g., yourname.outreach@gmail.com)",
105
+ "Enable 2-Step Verification: Security > 2-Step Verification",
106
+ "Generate an App Password: Security > 2-Step Verification > App passwords",
107
+ "Select 'Mail' and your device, click Generate",
108
+ "Copy the 16-character app password — you'll need it next"
109
+ ],
110
+ why: "Your agent sends emails from this account. A dedicated account protects your personal email reputation and lets the agent operate without risk to your main inbox.",
111
+ outcome: "Agent can send outreach emails autonomously.",
112
+ estimated_minutes: 10
113
+ }));
114
+
115
+ const credsHtId = `ht-${String(htNum).padStart(3, "0")}`;
116
+ hts.push(ht({
117
+ title: "Add email credentials to .env file",
118
+ description: "Enter your outreach Gmail and app password so the agent can send.",
119
+ priority: "critical", category: "auth",
120
+ depends_on_ht: [emailHtId],
121
+ status: "blocked",
122
+ blocks: [`at-${String(atNum + 1).padStart(3, "0")}`],
123
+ instructions: [
124
+ "Create a file called .env in the project root (if it doesn't exist)",
125
+ "Add these lines:",
126
+ "SMTP_HOST=smtp.gmail.com",
127
+ "SMTP_PORT=587",
128
+ `SMTP_USER=${config.senderEmail || "your.outreach@gmail.com"}`,
129
+ "SMTP_PASS=your-16-char-app-password",
130
+ "Save the file"
131
+ ],
132
+ deliver_to: ".env",
133
+ why: "The agent reads these credentials to connect to Gmail's SMTP server.",
134
+ outcome: "Agent can authenticate with Gmail and start sending emails.",
135
+ estimated_minutes: 2
136
+ }));
137
+
138
+ hts.push(ht({
139
+ title: "Provide initial prospect list or target description",
140
+ description: "Give the agent a starting point — who should it reach out to?",
141
+ priority: "high", category: "data",
142
+ blocks: [],
143
+ instructions: [
144
+ "Option A: Create data/prospects.csv with columns: name, email, company, role",
145
+ "Option B: Describe your ideal prospect in CLAUDE.md under 'Target Audience'",
146
+ "Option C: Just tell the agent in your first conversation who to target",
147
+ "Any of these works — the agent will refine from there"
148
+ ],
149
+ why: "The agent needs a starting direction. It can research and expand from any seed list.",
150
+ outcome: "Agent can start finding and qualifying prospects.",
151
+ estimated_minutes: 10
152
+ }));
153
+
154
+ hts.push(ht({
155
+ title: "Review and approve first batch of draft emails",
156
+ description: "Before the agent sends to real people, review its first drafts.",
157
+ priority: "high", category: "approval",
158
+ blocks: [],
159
+ instructions: [
160
+ "Run: npm run dry-run",
161
+ "Review the generated email drafts",
162
+ "Provide feedback on tone, length, personalization",
163
+ "When satisfied, tell the agent to go live"
164
+ ],
165
+ why: "First impressions matter. Reviewing early drafts catches issues before they reach real prospects.",
166
+ outcome: "Agent transitions from draft mode to live sending.",
167
+ estimated_minutes: 15
168
+ }));
169
+
170
+ ats.push(at({ title: "Send test email to operator's personal address", priority: "high", requires_ht: [credsHtId] }));
171
+ ats.push(at({ title: "Research first 20 prospects based on target description", priority: "high", requires_ht: [emailHtId] }));
172
+ }
173
+
174
+ // === RESEARCH-SPECIFIC HTs ===
175
+ if (config.clawType === "research") {
176
+ hts.push(ht({
177
+ title: "Define research scope and output format",
178
+ description: "Tell the agent what to research and how to deliver results.",
179
+ priority: "critical", category: "config",
180
+ blocks: [],
181
+ instructions: [
182
+ "Open CLAUDE.md",
183
+ "Under 'System Prompt', add a 'Research Scope' section",
184
+ "Define: what topics to research, how deep to go, what format for reports",
185
+ "Example: 'Research competitor pricing in the SaaS space. Output as markdown reports in data/reports/.'"
186
+ ],
187
+ why: "Without a clear scope, the agent will research broadly and waste tokens on irrelevant topics.",
188
+ outcome: "Agent produces focused, useful research reports.",
189
+ estimated_minutes: 10
190
+ }));
191
+
192
+ hts.push(ht({
193
+ title: "Set up web search API key (optional)",
194
+ description: "For deeper research, the agent can use Brave Search or similar APIs.",
195
+ priority: "normal", category: "auth",
196
+ blocks: [],
197
+ instructions: [
198
+ "Go to https://api.search.brave.com/ and create a free account",
199
+ "Generate an API key",
200
+ "Add to .env: BRAVE_SEARCH_API_KEY=your-key-here",
201
+ "This is optional — the agent can research without it, but results will be better with it"
202
+ ],
203
+ why: "API-powered search gives more structured, recent, and comprehensive results than scraping.",
204
+ outcome: "Agent research quality improves significantly.",
205
+ estimated_minutes: 5
206
+ }));
207
+ }
208
+
209
+ // === SUPPORT-SPECIFIC HTs ===
210
+ if (config.clawType === "support") {
211
+ hts.push(ht({
212
+ title: "Connect support inbox (IMAP credentials)",
213
+ description: "Give the agent access to the support email inbox.",
214
+ priority: "critical", category: "auth",
215
+ blocks: [],
216
+ instructions: [
217
+ "Add to .env:",
218
+ "IMAP_HOST=imap.gmail.com",
219
+ "IMAP_PORT=993",
220
+ "IMAP_USER=support@yourcompany.com",
221
+ "IMAP_PASS=your-app-password",
222
+ "Save the file"
223
+ ],
224
+ why: "The agent monitors this inbox for support tickets. Without access, it can't triage or respond.",
225
+ outcome: "Agent can read incoming support emails and start auto-triaging.",
226
+ estimated_minutes: 5
227
+ }));
228
+
229
+ hts.push(ht({
230
+ title: "Define escalation rules",
231
+ description: "Tell the agent when to handle tickets vs when to escalate to you.",
232
+ priority: "high", category: "config",
233
+ blocks: [],
234
+ instructions: [
235
+ "Open CLAUDE.md",
236
+ "Add an 'Escalation Rules' section",
237
+ "Define: what the agent can auto-resolve, what needs human review",
238
+ "Example: 'Auto-resolve password resets and how-to questions. Escalate billing disputes and anything mentioning legal.'"
239
+ ],
240
+ why: "Without clear rules, the agent either escalates everything (useless) or handles things it shouldn't (dangerous).",
241
+ outcome: "Agent handles routine tickets autonomously, escalates important ones.",
242
+ estimated_minutes: 10
243
+ }));
244
+ }
245
+
246
+ // === SOCIAL-SPECIFIC HTs ===
247
+ if (config.clawType === "social") {
248
+ hts.push(ht({
249
+ title: "Connect social media accounts",
250
+ description: "Provide API keys or credentials for the platforms you want to post on.",
251
+ priority: "critical", category: "auth",
252
+ blocks: [],
253
+ instructions: [
254
+ "For each platform you want the agent to post on:",
255
+ "LinkedIn: Create an app at linkedin.com/developers, get access token",
256
+ "Twitter/X: Create an app at developer.twitter.com, get API keys",
257
+ "Dev.to: Go to dev.to/settings/extensions, generate API key",
258
+ "Add each to .env: LINKEDIN_TOKEN=xxx, TWITTER_API_KEY=xxx, DEVTO_API_KEY=xxx"
259
+ ],
260
+ why: "The agent needs API access to post on your behalf.",
261
+ outcome: "Agent can publish content to your social channels.",
262
+ estimated_minutes: 20
263
+ }));
264
+
265
+ hts.push(ht({
266
+ title: "Define brand voice and content guidelines",
267
+ description: "Tell the agent what your brand sounds like.",
268
+ priority: "high", category: "config",
269
+ blocks: [],
270
+ instructions: [
271
+ "Open CLAUDE.md",
272
+ "Add a 'Brand Voice' section with:",
273
+ "- Tone (professional, casual, technical, friendly)",
274
+ "- Topics to cover and topics to avoid",
275
+ "- Example posts you like",
276
+ "- Any hashtags or formatting preferences"
277
+ ],
278
+ why: "Consistent brand voice builds audience trust. Without guidelines, the agent's content will feel generic.",
279
+ outcome: "Agent produces on-brand content that sounds like you.",
280
+ estimated_minutes: 15
281
+ }));
282
+ }
283
+
284
+ // === UNIVERSAL SETUP ATs ===
285
+ ats.push(at({ title: "Initialize database and seed config", priority: "critical", category: "setup" }));
286
+ ats.push(at({ title: "Generate initial dashboard", priority: "high", category: "setup" }));
287
+ ats.push(at({ title: "Set up scheduled cron tasks", priority: "high", category: "setup" }));
288
+
289
+ if (config.enableLocalSwarm !== false || config.enableGlobalSwarm !== false) {
290
+ ats.push(at({
291
+ title: "Register with global intelligence network (${relayUrl})",
292
+ priority: "critical",
293
+ category: "setup",
294
+ description: `Run: curl -s -X POST ${relayUrl}/nodes/register -H 'Content-Type: application/json' -d '{"node_id":"mc_anon_${config.agentName?.toLowerCase().replace(/[^a-z0-9]/g, '') || 'agent'}","agent_name":"${config.agentName || 'agent'}"}'`
295
+ }));
296
+ ats.push(at({
297
+ title: "Sync CAPABILITIES.md with auto-scanned inventory",
298
+ priority: "high",
299
+ category: "setup",
300
+ description: "Run: npm run scan — then read memory/capabilities/_auto.md and update memory/CAPABILITIES.md to match what actually exists"
301
+ }));
302
+ ats.push(at({
303
+ title: "Query global relay for insight on your agent type before first task",
304
+ priority: "high",
305
+ category: "setup",
306
+ description: `Run: curl -s ${relayUrl}/buckets?q=${config.clawType || 'agent'}`
307
+ }));
308
+ }
309
+
310
+ return {
311
+ version: "1.0.0",
312
+ agent_name: config.agentName,
313
+ template: config.clawType,
314
+ generated_at: new Date().toISOString(),
315
+ setup_progress: {
316
+ phase: "getting_started" as const,
317
+ total_ht: hts.length,
318
+ completed_ht: 0,
319
+ percent: 0,
320
+ },
321
+ human_tasks: hts,
322
+ ai_tasks: ats,
323
+ };
324
+ }