clementine-agent 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 (190) hide show
  1. package/.env.example +44 -0
  2. package/LICENSE +21 -0
  3. package/README.md +795 -0
  4. package/dist/agent/agent-manager.d.ts +69 -0
  5. package/dist/agent/agent-manager.js +441 -0
  6. package/dist/agent/assistant.d.ts +225 -0
  7. package/dist/agent/assistant.js +3888 -0
  8. package/dist/agent/auto-update.d.ts +32 -0
  9. package/dist/agent/auto-update.js +186 -0
  10. package/dist/agent/daily-planner.d.ts +24 -0
  11. package/dist/agent/daily-planner.js +379 -0
  12. package/dist/agent/execution-advisor.d.ts +10 -0
  13. package/dist/agent/execution-advisor.js +272 -0
  14. package/dist/agent/hooks.d.ts +45 -0
  15. package/dist/agent/hooks.js +564 -0
  16. package/dist/agent/insight-engine.d.ts +66 -0
  17. package/dist/agent/insight-engine.js +225 -0
  18. package/dist/agent/intent-classifier.d.ts +48 -0
  19. package/dist/agent/intent-classifier.js +214 -0
  20. package/dist/agent/link-extractor.d.ts +19 -0
  21. package/dist/agent/link-extractor.js +90 -0
  22. package/dist/agent/mcp-bridge.d.ts +62 -0
  23. package/dist/agent/mcp-bridge.js +435 -0
  24. package/dist/agent/metacognition.d.ts +66 -0
  25. package/dist/agent/metacognition.js +221 -0
  26. package/dist/agent/orchestrator.d.ts +81 -0
  27. package/dist/agent/orchestrator.js +790 -0
  28. package/dist/agent/profiles.d.ts +22 -0
  29. package/dist/agent/profiles.js +91 -0
  30. package/dist/agent/prompt-cache.d.ts +24 -0
  31. package/dist/agent/prompt-cache.js +68 -0
  32. package/dist/agent/prompt-evolver.d.ts +28 -0
  33. package/dist/agent/prompt-evolver.js +279 -0
  34. package/dist/agent/role-scaffolds.d.ts +28 -0
  35. package/dist/agent/role-scaffolds.js +433 -0
  36. package/dist/agent/safe-restart.d.ts +41 -0
  37. package/dist/agent/safe-restart.js +150 -0
  38. package/dist/agent/self-improve.d.ts +66 -0
  39. package/dist/agent/self-improve.js +1706 -0
  40. package/dist/agent/session-event-log.d.ts +114 -0
  41. package/dist/agent/session-event-log.js +233 -0
  42. package/dist/agent/skill-extractor.d.ts +72 -0
  43. package/dist/agent/skill-extractor.js +435 -0
  44. package/dist/agent/source-mods.d.ts +61 -0
  45. package/dist/agent/source-mods.js +230 -0
  46. package/dist/agent/source-preflight.d.ts +25 -0
  47. package/dist/agent/source-preflight.js +100 -0
  48. package/dist/agent/stall-guard.d.ts +62 -0
  49. package/dist/agent/stall-guard.js +109 -0
  50. package/dist/agent/strategic-planner.d.ts +60 -0
  51. package/dist/agent/strategic-planner.js +352 -0
  52. package/dist/agent/team-bus.d.ts +89 -0
  53. package/dist/agent/team-bus.js +556 -0
  54. package/dist/agent/team-router.d.ts +26 -0
  55. package/dist/agent/team-router.js +37 -0
  56. package/dist/agent/tool-loop-detector.d.ts +59 -0
  57. package/dist/agent/tool-loop-detector.js +242 -0
  58. package/dist/agent/workflow-runner.d.ts +36 -0
  59. package/dist/agent/workflow-runner.js +317 -0
  60. package/dist/agent/workflow-variables.d.ts +16 -0
  61. package/dist/agent/workflow-variables.js +62 -0
  62. package/dist/channels/discord-agent-bot.d.ts +101 -0
  63. package/dist/channels/discord-agent-bot.js +881 -0
  64. package/dist/channels/discord-bot-manager.d.ts +80 -0
  65. package/dist/channels/discord-bot-manager.js +262 -0
  66. package/dist/channels/discord-utils.d.ts +51 -0
  67. package/dist/channels/discord-utils.js +293 -0
  68. package/dist/channels/discord.d.ts +12 -0
  69. package/dist/channels/discord.js +1832 -0
  70. package/dist/channels/slack-agent-bot.d.ts +73 -0
  71. package/dist/channels/slack-agent-bot.js +320 -0
  72. package/dist/channels/slack-bot-manager.d.ts +66 -0
  73. package/dist/channels/slack-bot-manager.js +236 -0
  74. package/dist/channels/slack-utils.d.ts +39 -0
  75. package/dist/channels/slack-utils.js +189 -0
  76. package/dist/channels/slack.d.ts +11 -0
  77. package/dist/channels/slack.js +196 -0
  78. package/dist/channels/telegram.d.ts +10 -0
  79. package/dist/channels/telegram.js +235 -0
  80. package/dist/channels/webhook.d.ts +9 -0
  81. package/dist/channels/webhook.js +78 -0
  82. package/dist/channels/whatsapp.d.ts +11 -0
  83. package/dist/channels/whatsapp.js +181 -0
  84. package/dist/cli/chat.d.ts +14 -0
  85. package/dist/cli/chat.js +220 -0
  86. package/dist/cli/cron.d.ts +17 -0
  87. package/dist/cli/cron.js +552 -0
  88. package/dist/cli/dashboard.d.ts +15 -0
  89. package/dist/cli/dashboard.js +17677 -0
  90. package/dist/cli/index.d.ts +3 -0
  91. package/dist/cli/index.js +2474 -0
  92. package/dist/cli/routes/delegations.d.ts +19 -0
  93. package/dist/cli/routes/delegations.js +154 -0
  94. package/dist/cli/routes/digest.d.ts +17 -0
  95. package/dist/cli/routes/digest.js +375 -0
  96. package/dist/cli/routes/goals.d.ts +14 -0
  97. package/dist/cli/routes/goals.js +258 -0
  98. package/dist/cli/routes/workflows.d.ts +18 -0
  99. package/dist/cli/routes/workflows.js +97 -0
  100. package/dist/cli/setup.d.ts +8 -0
  101. package/dist/cli/setup.js +619 -0
  102. package/dist/cli/tunnel.d.ts +35 -0
  103. package/dist/cli/tunnel.js +141 -0
  104. package/dist/config.d.ts +145 -0
  105. package/dist/config.js +278 -0
  106. package/dist/events/bus.d.ts +43 -0
  107. package/dist/events/bus.js +136 -0
  108. package/dist/gateway/cron-scheduler.d.ts +166 -0
  109. package/dist/gateway/cron-scheduler.js +1767 -0
  110. package/dist/gateway/delivery-queue.d.ts +30 -0
  111. package/dist/gateway/delivery-queue.js +110 -0
  112. package/dist/gateway/heartbeat-scheduler.d.ts +99 -0
  113. package/dist/gateway/heartbeat-scheduler.js +1298 -0
  114. package/dist/gateway/heartbeat.d.ts +3 -0
  115. package/dist/gateway/heartbeat.js +3 -0
  116. package/dist/gateway/lanes.d.ts +24 -0
  117. package/dist/gateway/lanes.js +76 -0
  118. package/dist/gateway/notifications.d.ts +29 -0
  119. package/dist/gateway/notifications.js +75 -0
  120. package/dist/gateway/router.d.ts +210 -0
  121. package/dist/gateway/router.js +1330 -0
  122. package/dist/index.d.ts +12 -0
  123. package/dist/index.js +1015 -0
  124. package/dist/memory/chunker.d.ts +28 -0
  125. package/dist/memory/chunker.js +226 -0
  126. package/dist/memory/consolidation.d.ts +44 -0
  127. package/dist/memory/consolidation.js +171 -0
  128. package/dist/memory/context-assembler.d.ts +50 -0
  129. package/dist/memory/context-assembler.js +149 -0
  130. package/dist/memory/embeddings.d.ts +38 -0
  131. package/dist/memory/embeddings.js +180 -0
  132. package/dist/memory/graph-store.d.ts +66 -0
  133. package/dist/memory/graph-store.js +613 -0
  134. package/dist/memory/mmr.d.ts +21 -0
  135. package/dist/memory/mmr.js +75 -0
  136. package/dist/memory/search.d.ts +26 -0
  137. package/dist/memory/search.js +67 -0
  138. package/dist/memory/store.d.ts +530 -0
  139. package/dist/memory/store.js +2022 -0
  140. package/dist/security/integrity.d.ts +24 -0
  141. package/dist/security/integrity.js +58 -0
  142. package/dist/security/patterns.d.ts +34 -0
  143. package/dist/security/patterns.js +110 -0
  144. package/dist/security/scanner.d.ts +32 -0
  145. package/dist/security/scanner.js +263 -0
  146. package/dist/tools/admin-tools.d.ts +12 -0
  147. package/dist/tools/admin-tools.js +1278 -0
  148. package/dist/tools/external-tools.d.ts +11 -0
  149. package/dist/tools/external-tools.js +1327 -0
  150. package/dist/tools/goal-tools.d.ts +9 -0
  151. package/dist/tools/goal-tools.js +159 -0
  152. package/dist/tools/mcp-server.d.ts +13 -0
  153. package/dist/tools/mcp-server.js +141 -0
  154. package/dist/tools/memory-tools.d.ts +10 -0
  155. package/dist/tools/memory-tools.js +568 -0
  156. package/dist/tools/session-tools.d.ts +6 -0
  157. package/dist/tools/session-tools.js +146 -0
  158. package/dist/tools/shared.d.ts +216 -0
  159. package/dist/tools/shared.js +340 -0
  160. package/dist/tools/team-tools.d.ts +6 -0
  161. package/dist/tools/team-tools.js +447 -0
  162. package/dist/tools/tool-meta.d.ts +34 -0
  163. package/dist/tools/tool-meta.js +133 -0
  164. package/dist/tools/vault-tools.d.ts +8 -0
  165. package/dist/tools/vault-tools.js +457 -0
  166. package/dist/types.d.ts +716 -0
  167. package/dist/types.js +16 -0
  168. package/dist/vault-migrations/0001-add-execution-framework.d.ts +10 -0
  169. package/dist/vault-migrations/0001-add-execution-framework.js +47 -0
  170. package/dist/vault-migrations/0002-add-agentic-communication.d.ts +12 -0
  171. package/dist/vault-migrations/0002-add-agentic-communication.js +79 -0
  172. package/dist/vault-migrations/0003-update-execution-pipeline-narration.d.ts +11 -0
  173. package/dist/vault-migrations/0003-update-execution-pipeline-narration.js +73 -0
  174. package/dist/vault-migrations/helpers.d.ts +14 -0
  175. package/dist/vault-migrations/helpers.js +44 -0
  176. package/dist/vault-migrations/runner.d.ts +14 -0
  177. package/dist/vault-migrations/runner.js +139 -0
  178. package/dist/vault-migrations/types.d.ts +42 -0
  179. package/dist/vault-migrations/types.js +9 -0
  180. package/install.sh +320 -0
  181. package/package.json +84 -0
  182. package/scripts/postinstall.js +125 -0
  183. package/vault/00-System/AGENTS.md +66 -0
  184. package/vault/00-System/CRON.md +71 -0
  185. package/vault/00-System/HEARTBEAT.md +58 -0
  186. package/vault/00-System/MEMORY.md +16 -0
  187. package/vault/00-System/SOUL.md +96 -0
  188. package/vault/05-Tasks/TASKS.md +19 -0
  189. package/vault/06-Templates/_Daily-Template.md +28 -0
  190. package/vault/06-Templates/_People-Template.md +22 -0
@@ -0,0 +1,433 @@
1
+ /**
2
+ * Clementine TypeScript — Role scaffolding templates.
3
+ *
4
+ * When an agent is created with a role template, these generate the full
5
+ * working directory: CRON.md, playbook, sequence definitions, and email
6
+ * writing guidelines. This is what turns an empty agent into a working employee.
7
+ */
8
+ /**
9
+ * Generate scaffolding files for an SDR agent.
10
+ * @param agentName — Display name (e.g., "Alex the SDR")
11
+ * @param agentSlug — URL-safe slug (e.g., "alex-the-sdr")
12
+ */
13
+ export function scaffoldSdr(agentName, agentSlug) {
14
+ const cronMd = `---
15
+ type: agent-cron
16
+ agent: ${agentSlug}
17
+ jobs:
18
+ - name: sequence-processor
19
+ schedule: "0 9 * * 1-5"
20
+ prompt: >-
21
+ You are ${agentName}. Run the daily outbound sequence processor.
22
+ Follow every step exactly.
23
+
24
+
25
+ STEP 1 — CHECK FOR DUE SEQUENCE STEPS
26
+
27
+ Call the sequence_due tool to get all enrollments where the next step
28
+ is due now or overdue.
29
+
30
+ If no results: log "No sequence steps due" to the daily note and stop.
31
+
32
+
33
+ STEP 2 — FOR EACH DUE ENROLLMENT, LOAD CONTEXT
34
+
35
+ For each enrollment returned:
36
+ a) Note the lead_id, sequence_name, current_step, email, name, company
37
+ b) Call activity_history with that lead_id to see what emails were already sent
38
+ c) Call lead_search with the lead's email to get full lead record
39
+ d) Read the sequence definition from your playbook to know what this step requires
40
+
41
+
42
+ STEP 3 — CHECK SUPPRESSION + DEDUP
43
+
44
+ Before writing any email:
45
+ a) Call suppression_check with the lead's email — if suppressed, skip and
46
+ advance the sequence to status 'opted_out'
47
+ b) Check activity_history — if an email was already sent today to this lead, skip
48
+ c) If the lead status is 'replied' or 'meeting_booked', skip — sequence should
49
+ already be paused but double-check
50
+
51
+
52
+ STEP 4 — WRITE THE EMAIL
53
+
54
+ Read the playbook file in your agent directory for email writing rules.
55
+ Key rules:
56
+ - Every email must be personalized to the recipient's company and role
57
+ - Reference something specific about their business (use web_search if needed)
58
+ - Keep under 150 words
59
+ - One clear CTA (usually a 15-minute call)
60
+ - Never repeat an angle used in a previous email to the same lead
61
+ - The email should sound like a human peer, not an AI or a sales template
62
+
63
+ Adapt the tone based on which step in the sequence:
64
+ - Step 0 (intro): Lead with a specific observation about their business
65
+ - Step 1 (follow-up): Reference the first email, add a new data point
66
+ - Step 2 (value add): Share a relevant insight or case study
67
+ - Step 3 (social proof): Reference a similar company's results
68
+ - Step 4 (breakup): Short, direct, leave the door open
69
+
70
+
71
+ STEP 5 — SEND THE EMAIL
72
+
73
+ Call outlook_send with:
74
+ - to: the lead's email
75
+ - subject: your crafted subject line
76
+ - body: your email body
77
+
78
+ If the send succeeds:
79
+ a) Call activity_log with type='email_sent', the lead_id, subject, and template info
80
+ b) Calculate the next step due date based on the sequence definition
81
+ c) Call sequence_advance to increment current_step and set next_step_due_at
82
+ d) If this was the final step, set status='completed'
83
+
84
+ If the send fails:
85
+ a) Log the failure but do NOT retry — move on to the next lead
86
+ b) The next day's run will try again
87
+
88
+
89
+ STEP 6 — REPORT
90
+
91
+ Output a summary as your final response (delivered to owner via DM):
92
+
93
+ **Sequence Processing — [Today's Date]**
94
+ Due: X | Sent: Y | Skipped: Z (suppressed/replied/dedup)
95
+
96
+ Then list each sent email:
97
+ **[Name] — [Company]**
98
+ Subject: [subject line]
99
+ Step: [N] of [total steps]
100
+ enabled: true
101
+ tier: 2
102
+ mode: unleashed
103
+ max_hours: 1
104
+
105
+ - name: inbox-monitor
106
+ schedule: "0 8-18 * * 1-5"
107
+ prompt: >-
108
+ You are ${agentName}. Check the inbox for replies from prospects.
109
+ This runs hourly during business hours.
110
+
111
+
112
+ STEP 1 — CHECK INBOX FOR RECENT EMAILS
113
+
114
+ Call outlook_inbox with unread_only=true, count=25.
115
+ If no unread emails, log "Inbox check [HH:MM] — no new emails" to daily
116
+ note and stop.
117
+
118
+
119
+ STEP 2 — IDENTIFY PROSPECT REPLIES
120
+
121
+ For each unread email:
122
+ a) Check if the sender's email matches any lead in the system:
123
+ Call lead_search with query=[sender email]
124
+ b) If no match: skip — not a prospect
125
+ c) If match found: this is a prospect reply. Read the full email with
126
+ outlook_read_email
127
+
128
+
129
+ STEP 3 — CLASSIFY THE REPLY
130
+
131
+ Read the email content and classify:
132
+ - POSITIVE: interested, wants to meet, asks questions about the offering
133
+ - NEGATIVE: not interested, asks to stop, says no
134
+ - OUT_OF_OFFICE: auto-reply, OOO message
135
+ - BOUNCE: delivery failure, invalid address
136
+ - QUESTION: asks a specific question that needs answering
137
+ - UNSUBSCRIBE: explicitly asks to be removed
138
+
139
+
140
+ STEP 4 — TAKE ACTION BASED ON CLASSIFICATION
141
+
142
+ POSITIVE reply:
143
+ a) Update lead status to 'replied' via lead_upsert
144
+ b) Pause the sequence: sequence_advance with status='replied'
145
+ c) Log activity: activity_log type='email_received'
146
+ d) Alert the owner via your DM response (this gets delivered)
147
+
148
+ NEGATIVE reply:
149
+ a) Update lead status to 'opted_out'
150
+ b) Stop the sequence: sequence_advance with status='opted_out'
151
+ c) Add to suppression list: suppression_add with reason='unsubscribe'
152
+ d) Log activity
153
+
154
+ OUT_OF_OFFICE:
155
+ a) Pause the sequence: sequence_advance with status='paused'
156
+ b) Log activity with detail noting the return date if mentioned
157
+ c) Do not alert owner unless urgent
158
+
159
+ BOUNCE:
160
+ a) Add to suppression: suppression_add with reason='bounce'
161
+ b) Update lead status to 'opted_out'
162
+ c) Stop the sequence
163
+
164
+ UNSUBSCRIBE:
165
+ a) Add to suppression: suppression_add with reason='unsubscribe'
166
+ b) Stop the sequence
167
+ c) Update lead status to 'opted_out'
168
+
169
+ QUESTION:
170
+ a) Log activity
171
+ b) Alert owner with the question — do not auto-respond to questions
172
+
173
+
174
+ STEP 5 — REPORT
175
+
176
+ If no prospect replies found: stay quiet, no DM.
177
+
178
+ If replies found, output:
179
+
180
+ **Reply detected — [Name], [Company]**
181
+ Classification: [POSITIVE/NEGATIVE/etc.]
182
+ Preview: "[first 150 chars]"
183
+ Action taken: [what you did]
184
+ enabled: true
185
+ tier: 2
186
+ mode: standard
187
+
188
+ - name: daily-report
189
+ schedule: "0 18 * * 1-5"
190
+ prompt: >-
191
+ You are ${agentName}. Generate the end-of-day activity report.
192
+
193
+
194
+ STEP 1 — GATHER TODAY'S METRICS
195
+
196
+ Call activity_history with type filters to count today's activities:
197
+ a) Emails sent today (type='email_sent')
198
+ b) Replies received (type='email_received')
199
+ c) Meetings booked (type='meeting_booked')
200
+
201
+ Call lead_search to count:
202
+ d) New leads created today
203
+ e) Total active leads by status
204
+
205
+ Call sequence_due to check:
206
+ f) How many sequence steps are due tomorrow
207
+
208
+
209
+ STEP 2 — COMPILE REPORT
210
+
211
+ Output the report as your final response (delivered via DM):
212
+
213
+ **Daily SDR Report — [Today's Date]**
214
+
215
+ **Today's Activity**
216
+ - Emails sent: X
217
+ - Replies received: Y
218
+ - Meetings booked: Z
219
+ - New leads added: W
220
+
221
+ **Pipeline**
222
+ - New: X | Contacted: Y | Replied: Z | Qualified: W
223
+ - Meetings booked: X | Active sequences: Y
224
+
225
+ **Tomorrow**
226
+ - Sequence steps due: X
227
+ - Follow-ups needed: Y
228
+
229
+ Keep it brief. If there are notable wins (positive reply, meeting booked),
230
+ call them out. If there are concerns (0 sends, high bounce rate), flag them.
231
+ enabled: true
232
+ tier: 1
233
+ mode: standard
234
+
235
+ - name: salesforce-sync
236
+ schedule: "0 7,12,17 * * 1-5"
237
+ prompt: >-
238
+ You are ${agentName}. Run the Salesforce CRM sync.
239
+
240
+ STEP 1 — Run sf_sync with direction='both' to synchronize leads
241
+ bidirectionally with Salesforce.
242
+
243
+ STEP 2 — Review the sync results. If there are errors, log them
244
+ to the daily note using memory_write. If there is an auth failure
245
+ or rate limit issue, alert the owner.
246
+
247
+ STEP 3 — For any newly pulled leads, check if they match
248
+ the ICP defined in your playbook. If they do, flag them for
249
+ outreach consideration.
250
+
251
+ Output a brief sync summary as your final response.
252
+ enabled: false
253
+ tier: 1
254
+ mode: standard
255
+ ---
256
+ `;
257
+ const playbook = `# ${agentName} — SDR Playbook
258
+
259
+ ## Ideal Customer Profile (ICP)
260
+
261
+ > **Edit this section** to define who ${agentName} should target.
262
+
263
+ - **Industry:** [e.g., SaaS, Legal, Healthcare]
264
+ - **Company size:** [e.g., 10-200 employees]
265
+ - **Title targets:** [e.g., VP of Marketing, Head of Growth, CEO]
266
+ - **Geography:** [e.g., United States, specific metros]
267
+ - **Signals:** [e.g., recently funded, hiring for marketing roles, new website]
268
+
269
+ ## Qualification Framework
270
+
271
+ Use BANT to qualify prospects during conversations:
272
+ - **Budget:** Can they afford the solution?
273
+ - **Authority:** Is the contact a decision-maker?
274
+ - **Need:** Do they have a clear pain point we solve?
275
+ - **Timeline:** Are they looking to act in the next 1-3 months?
276
+
277
+ ## Email Writing Rules
278
+
279
+ ### Hard Rules (non-negotiable)
280
+ - Under 150 words body copy
281
+ - No em dashes — use commas, periods, or colons
282
+ - No signature block (the email system handles this)
283
+ - One CTA only (typically a 15-minute call)
284
+ - Every email must reference something specific about the recipient's business
285
+ - Never repeat an angle already used with the same lead
286
+
287
+ ### Banned Phrases
288
+ - "I hope this email finds you well"
289
+ - "In today's competitive landscape"
290
+ - "Game-changer", "Cutting-edge", "Innovative", "Leverage", "Empower"
291
+ - "One thing is clear", "This isn't just a... it's a..."
292
+
293
+ ### Subject Line Rules
294
+ - Sentence case, under 50 characters
295
+ - Use one of these formulas:
296
+ - Data point: "[Company] is [specific observation]"
297
+ - Question: "How is [Company] handling [specific challenge]?"
298
+ - Curiosity: "The [competitor/peer] outperforming [Company] in [area]"
299
+ - Direct: "Quick question about [Company]'s [area]"
300
+
301
+ ### Email Structure
302
+ 1. **Opening line:** Specific observation about their business (NOT generic)
303
+ 2. **Body (2-3 sentences):** Connect the observation to a pain point → outcome
304
+ 3. **CTA:** Low-pressure question asking for 15 minutes
305
+
306
+ ### Self-Check Before Sending
307
+ Ask yourself:
308
+ 1. Does it sound like a human who noticed something, not a bot running a sequence?
309
+ 2. Is the observation specific (not "I noticed your company is growing")?
310
+ 3. Is it under 150 words?
311
+ 4. Does it have exactly one ask?
312
+ 5. Would a busy executive read this between meetings?
313
+
314
+ ## Sequence Cadence
315
+
316
+ ### Default 5-Touch Sequence
317
+ | Step | Day | Type | Approach |
318
+ |------|-----|------|----------|
319
+ | 0 | Day 0 | Email | Lead with specific business observation |
320
+ | 1 | Day 3 | Email | Reference first email + new data point |
321
+ | 2 | Day 7 | Email | Value-add: share insight or case study |
322
+ | 3 | Day 14 | Email | Social proof: similar company's results |
323
+ | 4 | Day 21 | Email | Breakup: short, direct, leave door open |
324
+
325
+ ### Step Delays (in days)
326
+ - After step 0: wait 3 days
327
+ - After step 1: wait 4 days
328
+ - After step 2: wait 7 days
329
+ - After step 3: wait 7 days
330
+ - After step 4: sequence complete (60-day blackout)
331
+
332
+ ## Escalation Rules
333
+
334
+ Escalate to the owner (via DM) when:
335
+ - A prospect asks about pricing
336
+ - A prospect is C-level (CEO, CFO, CTO, COO)
337
+ - A prospect replies with a complex objection you can't address
338
+ - A prospect wants to involve additional stakeholders
339
+ - Any negative sentiment that might affect the relationship
340
+
341
+ Do NOT escalate:
342
+ - Simple questions you can answer from the playbook
343
+ - Out-of-office replies (just pause the sequence)
344
+ - "Not interested" (just stop the sequence and suppress)
345
+
346
+ ## Objection Handling
347
+
348
+ | Objection | Response Approach |
349
+ |-----------|-------------------|
350
+ | "Not interested" | Respect it. Stop sequence. Add to suppression. |
351
+ | "Too busy" | Acknowledge. Offer to follow up in 2-4 weeks. |
352
+ | "Already have a solution" | Ask what they like about it. Note for future. |
353
+ | "Send me info" | Send a brief 1-pager. Schedule follow-up in 3 days. |
354
+ | "What's the cost?" | Escalate to owner — pricing conversations need human touch. |
355
+ | "Who are you?" | Brief intro: your name, your company, why you reached out. |
356
+ `;
357
+ const sequences = `# Sequence Definitions
358
+
359
+ ## intro-5step
360
+
361
+ The default introductory outbound sequence. 5 touches over 21 days.
362
+
363
+ ### Steps
364
+
365
+ | Step | Delay (days) | Type | Guidelines |
366
+ |------|-------------|------|------------|
367
+ | 0 | 0 | email | Lead with specific observation about their business. Research their website/company first. |
368
+ | 1 | 3 | email | Reference the first email. Add a new angle or data point. |
369
+ | 2 | 7 | email | Share a relevant insight, case study, or industry trend. |
370
+ | 3 | 14 | email | Social proof — reference similar companies or results. |
371
+ | 4 | 21 | email | Breakup email — short, direct, leave the door open. |
372
+
373
+ ### After Completion
374
+ - Lead enters 60-day blackout (do not contact)
375
+ - Update lead status to 'contacted' if no reply received
376
+
377
+ ### On Reply
378
+ - Immediately pause the sequence
379
+ - Classify the reply and take appropriate action (see playbook)
380
+ `;
381
+ return { cronMd, playbook, sequences };
382
+ }
383
+ /**
384
+ * Generate scaffolding files for a Researcher agent.
385
+ */
386
+ export function scaffoldResearcher(agentName, agentSlug) {
387
+ const cronMd = `---
388
+ type: agent-cron
389
+ agent: ${agentSlug}
390
+ jobs:
391
+ - name: daily-research-digest
392
+ schedule: "0 8 * * 1-5"
393
+ prompt: >-
394
+ You are ${agentName}. Compile the daily research digest.
395
+
396
+ STEP 1 — Check for research tasks assigned to you.
397
+ Look at your tasks list and any pending requests from other agents.
398
+
399
+ STEP 2 — For each task, research the topic using web_search and
400
+ any relevant tools. Take thorough notes using note_create.
401
+
402
+ STEP 3 — Write a summary of findings and post to your daily note.
403
+
404
+ Keep research focused and actionable. Cite sources.
405
+ enabled: true
406
+ tier: 1
407
+ mode: standard
408
+ ---
409
+ `;
410
+ const playbook = `# ${agentName} — Research Playbook
411
+
412
+ ## Research Standards
413
+ - Always cite sources
414
+ - Distinguish between facts and opinions
415
+ - Note the date of information (may be outdated)
416
+ - Cross-reference multiple sources for important claims
417
+
418
+ ## Output Format
419
+ - Start with a 2-3 sentence executive summary
420
+ - Follow with detailed findings organized by topic
421
+ - End with recommended next steps or open questions
422
+ `;
423
+ return { cronMd, playbook };
424
+ }
425
+ /** Get scaffold generator for a role, or null if no scaffold exists. */
426
+ export function getScaffoldForRole(role) {
427
+ switch (role) {
428
+ case 'sdr': return scaffoldSdr;
429
+ case 'researcher': return scaffoldResearcher;
430
+ default: return null;
431
+ }
432
+ }
433
+ //# sourceMappingURL=role-scaffolds.js.map
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Clementine TypeScript — Safe Restart Orchestrator.
3
+ *
4
+ * Central coordinator for source self-editing. Replaces bare SIGUSR1-based
5
+ * source editing with a validated pipeline:
6
+ * preflight → apply → record → build → sentinel → restart
7
+ *
8
+ * Source modifications are recorded in ~/.clementine/self-improve/source-mods/
9
+ * (not in git). This keeps the repo clean so `git pull` always works, and
10
+ * modifications are re-applied intelligently after updates.
11
+ */
12
+ export interface SafeEditResult {
13
+ success: boolean;
14
+ error?: string;
15
+ preflightErrors?: string[];
16
+ sourceModId?: string;
17
+ }
18
+ /**
19
+ * Safely edit Clementine's own source code:
20
+ * 1. Preflight — validate in a staging worktree
21
+ * 2. Snapshot — capture "before" content for rollback
22
+ * 3. Apply — write validated .ts files to the real src/
23
+ * 4. Record — save modification to ~/.clementine/ registry
24
+ * 5. Build — run tsc; revert if it fails
25
+ * 6. Write sentinel — context for the new process
26
+ * 7. Signal restart — SIGUSR1
27
+ */
28
+ export declare function safeSourceEdit(pkgDir: string, changes: Array<{
29
+ relativePath: string;
30
+ content: string;
31
+ }>, opts?: {
32
+ experimentId?: string;
33
+ reason?: string;
34
+ sessionKey?: string;
35
+ description?: string;
36
+ }): Promise<SafeEditResult>;
37
+ /**
38
+ * Get the path to the restart sentinel file.
39
+ */
40
+ export declare function getSentinelPath(): string;
41
+ //# sourceMappingURL=safe-restart.d.ts.map
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Clementine TypeScript — Safe Restart Orchestrator.
3
+ *
4
+ * Central coordinator for source self-editing. Replaces bare SIGUSR1-based
5
+ * source editing with a validated pipeline:
6
+ * preflight → apply → record → build → sentinel → restart
7
+ *
8
+ * Source modifications are recorded in ~/.clementine/self-improve/source-mods/
9
+ * (not in git). This keeps the repo clean so `git pull` always works, and
10
+ * modifications are re-applied intelligently after updates.
11
+ */
12
+ import { execSync } from 'node:child_process';
13
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
14
+ import { randomBytes } from 'node:crypto';
15
+ import path from 'node:path';
16
+ import pino from 'pino';
17
+ import { BASE_DIR } from '../config.js';
18
+ import { preflightSourceChange } from './source-preflight.js';
19
+ import { recordSourceMod } from './source-mods.js';
20
+ const logger = pino({ name: 'clementine.safe-restart' });
21
+ const SENTINEL_PATH = path.join(BASE_DIR, '.restart-sentinel.json');
22
+ /** Files that cannot be self-edited (security-critical or self-referential). */
23
+ const BLOCKLIST = new Set([
24
+ 'src/config.ts',
25
+ 'src/types.ts',
26
+ 'src/gateway/router.ts',
27
+ 'src/gateway/lanes.ts',
28
+ 'src/gateway/heartbeat-scheduler.ts',
29
+ 'src/gateway/cron-scheduler.ts',
30
+ 'src/gateway/security-scanner.ts',
31
+ 'src/agent/self-improve.ts',
32
+ 'src/agent/safe-restart.ts',
33
+ 'src/agent/source-mods.ts',
34
+ 'src/cli/index.ts',
35
+ 'src/cli/dashboard.ts',
36
+ 'src/security/scanner.ts',
37
+ ]);
38
+ /**
39
+ * Safely edit Clementine's own source code:
40
+ * 1. Preflight — validate in a staging worktree
41
+ * 2. Snapshot — capture "before" content for rollback
42
+ * 3. Apply — write validated .ts files to the real src/
43
+ * 4. Record — save modification to ~/.clementine/ registry
44
+ * 5. Build — run tsc; revert if it fails
45
+ * 6. Write sentinel — context for the new process
46
+ * 7. Signal restart — SIGUSR1
47
+ */
48
+ export async function safeSourceEdit(pkgDir, changes, opts) {
49
+ const reason = opts?.reason ?? 'source self-edit';
50
+ // Validate against blocklist
51
+ for (const change of changes) {
52
+ if (BLOCKLIST.has(change.relativePath)) {
53
+ return {
54
+ success: false,
55
+ error: `Blocked: ${change.relativePath} is on the security blocklist and cannot be self-edited.`,
56
+ };
57
+ }
58
+ }
59
+ // 1. Preflight
60
+ logger.info({ fileCount: changes.length, reason }, 'Starting safe source edit');
61
+ const preflight = await preflightSourceChange(pkgDir, changes);
62
+ if (!preflight.success) {
63
+ logger.warn({ errors: preflight.errors }, 'Preflight failed — aborting source edit');
64
+ return {
65
+ success: false,
66
+ error: 'Compilation failed in staging worktree.',
67
+ preflightErrors: preflight.errors,
68
+ };
69
+ }
70
+ // 2. Snapshot "before" content for each file
71
+ const filesWithSnapshots = changes.map(change => {
72
+ const targetFile = path.join(pkgDir, change.relativePath);
73
+ const beforeContent = existsSync(targetFile) ? readFileSync(targetFile, 'utf-8') : '';
74
+ return {
75
+ relativePath: change.relativePath,
76
+ beforeContent,
77
+ afterContent: change.content,
78
+ };
79
+ });
80
+ // 3. Apply — write validated files to the real tree
81
+ const changedFiles = [];
82
+ for (const change of changes) {
83
+ const targetFile = path.join(pkgDir, change.relativePath);
84
+ const targetDir = path.dirname(targetFile);
85
+ if (!existsSync(targetDir)) {
86
+ mkdirSync(targetDir, { recursive: true });
87
+ }
88
+ writeFileSync(targetFile, change.content);
89
+ changedFiles.push(change.relativePath);
90
+ }
91
+ // 4. Record source modification in the registry
92
+ const modId = opts?.experimentId ?? randomBytes(4).toString('hex');
93
+ try {
94
+ recordSourceMod(modId, filesWithSnapshots, {
95
+ reason,
96
+ description: opts?.description ?? reason,
97
+ experimentId: opts?.experimentId,
98
+ });
99
+ }
100
+ catch (err) {
101
+ logger.warn({ err }, 'Failed to record source mod (non-fatal)');
102
+ }
103
+ // 5. Build — use `tsc` directly instead of `npm run build` because
104
+ // the build script does `rm -rf dist` which would nuke the currently
105
+ // running process's loaded modules. tsc alone overwrites only changed .js files.
106
+ try {
107
+ execSync('./node_modules/.bin/tsc', {
108
+ cwd: pkgDir,
109
+ stdio: 'pipe',
110
+ timeout: 120_000,
111
+ });
112
+ logger.info('Build succeeded after source edit');
113
+ }
114
+ catch (err) {
115
+ // Build failed (shouldn't happen since preflight passed) — revert
116
+ logger.error({ err }, 'Build failed after source edit — reverting');
117
+ try {
118
+ // Restore "before" content
119
+ for (const file of filesWithSnapshots) {
120
+ writeFileSync(path.join(pkgDir, file.relativePath), file.beforeContent);
121
+ }
122
+ execSync('./node_modules/.bin/tsc', { cwd: pkgDir, stdio: 'pipe', timeout: 120_000 });
123
+ }
124
+ catch (revertErr) {
125
+ logger.error({ revertErr }, 'Revert + rebuild also failed');
126
+ }
127
+ return { success: false, error: `Build failed after applying changes: ${String(err)}` };
128
+ }
129
+ // 6. Write sentinel
130
+ const sentinel = {
131
+ previousPid: process.pid,
132
+ restartedAt: new Date().toISOString(),
133
+ reason: 'source-edit',
134
+ sourceChangeId: modId,
135
+ sessionKey: opts?.sessionKey,
136
+ changedFiles,
137
+ };
138
+ writeFileSync(SENTINEL_PATH, JSON.stringify(sentinel, null, 2));
139
+ logger.info({ sentinel }, 'Restart sentinel written');
140
+ // 7. Signal restart
141
+ process.kill(process.pid, 'SIGUSR1');
142
+ return { success: true, sourceModId: modId };
143
+ }
144
+ /**
145
+ * Get the path to the restart sentinel file.
146
+ */
147
+ export function getSentinelPath() {
148
+ return SENTINEL_PATH;
149
+ }
150
+ //# sourceMappingURL=safe-restart.js.map
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Clementine TypeScript — Self-Improvement Loop Engine.
3
+ *
4
+ * Implements Karpathy's autoresearch iterative loop for autonomous self-improvement:
5
+ * hypothesize → execute → evaluate → keep/revert → repeat.
6
+ *
7
+ * Evaluates Clementine's own outputs (transcripts, feedback, cron logs) and proposes
8
+ * improvements to system prompts, cron job prompts, workflows, and memory settings.
9
+ * All proposed changes require Discord approval before being applied.
10
+ */
11
+ import type { SelfImproveConfig, SelfImproveExperiment, SelfImproveState } from '../types.js';
12
+ import type { PersonalAssistant } from './assistant.js';
13
+ export declare class SelfImproveLoop {
14
+ private config;
15
+ private assistant;
16
+ constructor(assistant: PersonalAssistant, config?: Partial<SelfImproveConfig>);
17
+ run(onProposal?: (experiment: SelfImproveExperiment) => Promise<void>): Promise<SelfImproveState>;
18
+ /** Run a focused self-improvement cycle for a specific agent. */
19
+ runForAgent(agentSlug: string, onProposal?: (experiment: SelfImproveExperiment) => Promise<void>): Promise<SelfImproveState>;
20
+ private gatherMetrics;
21
+ private hypothesize;
22
+ private readCurrentState;
23
+ private evaluate;
24
+ private savePendingChange;
25
+ applyApprovedChange(experimentId: string): Promise<string>;
26
+ /** Deny a pending change without applying it. */
27
+ denyChange(experimentId: string): string;
28
+ private runMemoryCleanup;
29
+ private synthesizeFeedbackPatterns;
30
+ /** Update the structured user model from interaction data. */
31
+ private updateUserModel;
32
+ loadExperimentLog(): SelfImproveExperiment[];
33
+ private appendExperimentLog;
34
+ private updateExperimentStatus;
35
+ loadState(): SelfImproveState;
36
+ /** Reconcile pendingApprovals counter with actual pending-changes/ directory. */
37
+ reconcileState(): SelfImproveState;
38
+ /** Expire pending proposals older than APPROVAL_TTL_MS. */
39
+ expireStaleProposals(): number;
40
+ /** Check impact of previously applied changes. Triggers auto-rollback on regression. */
41
+ private checkAppliedImpact;
42
+ /** Load evolution version history. */
43
+ private loadVersions;
44
+ /** Save evolution version history. */
45
+ private saveVersions;
46
+ /** Record a version when a change is applied. */
47
+ recordVersion(experimentId: string, area: string, target: string, rationale: string, beforeSnapshot: string): void;
48
+ /** Rollback a specific version by restoring its beforeSnapshot. */
49
+ rollbackVersion(experimentId: string): boolean;
50
+ private saveState;
51
+ getPendingChanges(): Array<SelfImproveExperiment & {
52
+ before: string;
53
+ }>;
54
+ /** Analyze experiment history for success patterns and failed approaches. */
55
+ private analyzeExperimentPatterns;
56
+ /** Validate that a proposed change has valid syntax for its target area. */
57
+ private validateProposal;
58
+ private resolveTargetPath;
59
+ private parseJsonResponse;
60
+ private withTimeout;
61
+ }
62
+ export declare function validateProposal(area: string, target: string, proposedChange: string): {
63
+ valid: boolean;
64
+ error?: string;
65
+ };
66
+ //# sourceMappingURL=self-improve.d.ts.map