@nebutra/outreach-engine 0.1.3 → 0.1.5

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @nebutra/outreach-engine
2
2
 
3
+ ## 0.1.5
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies []:
8
+ - @nebutra/capability-kit@2.0.0
9
+ - @nebutra/errors@2.0.0
10
+ - @nebutra/event-log@2.0.0
11
+ - @nebutra/content-store@0.1.5
12
+ - @nebutra/play-loader@0.1.4
13
+ - @nebutra/generation-context@0.1.4
14
+
3
15
  ## 0.1.3
4
16
 
5
17
  ### Patch Changes
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@nebutra/outreach-engine",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Compliance-first outreach campaign Play package for founder-led sales workflows",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "type": "module",
8
8
  "nebutra": {
9
+ "graph": "labs",
9
10
  "status": "wip",
10
11
  "productionReady": false,
11
12
  "surface": "play-product",
@@ -23,18 +24,22 @@
23
24
  "category": "ai",
24
25
  "summary": "Compliance-first outreach Play product that produces auditable campaign drafts"
25
26
  },
26
- "main": "./src/index.ts",
27
- "types": "./src/index.ts",
27
+ "main": "./dist/index.js",
28
+ "types": "./dist/index.d.ts",
28
29
  "exports": {
29
- ".": "./src/index.ts"
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "import": "./dist/index.js",
33
+ "default": "./dist/index.js"
34
+ }
30
35
  },
31
36
  "dependencies": {
32
- "@nebutra/capability-kit": "0.2.2",
33
- "@nebutra/content-store": "0.1.2",
34
- "@nebutra/event-log": "0.1.2",
35
- "@nebutra/errors": "0.1.2",
36
- "@nebutra/generation-context": "0.1.2",
37
- "@nebutra/play-loader": "0.1.2"
37
+ "@nebutra/capability-kit": "2.0.0",
38
+ "@nebutra/content-store": "0.1.5",
39
+ "@nebutra/errors": "2.0.0",
40
+ "@nebutra/event-log": "2.0.0",
41
+ "@nebutra/generation-context": "0.1.4",
42
+ "@nebutra/play-loader": "0.1.4"
38
43
  },
39
44
  "devDependencies": {
40
45
  "@types/node": "^25.9.1",
@@ -55,6 +60,12 @@
55
60
  "publishConfig": {
56
61
  "access": "public"
57
62
  },
63
+ "files": [
64
+ "dist",
65
+ "README.md",
66
+ "LICENSE",
67
+ "CHANGELOG.md"
68
+ ],
58
69
  "scripts": {
59
70
  "build": "tsup",
60
71
  "test": "vitest run",
@@ -1,21 +0,0 @@
1
- {"at":"2026-05-18T14:42:47.510Z","type":"reindex","tenantId":"tenant_a","files":0}
2
- {"at":"2026-05-18T14:42:47.514Z","type":"write","tenantId":"tenant_a","path":"outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbcrbs.json"}
3
- {"at":"2026-05-18T14:42:47.523Z","type":"reindex","tenantId":"tenant_a","files":0}
4
- {"at":"2026-05-18T14:43:18.065Z","type":"reindex","tenantId":"tenant_a","files":0}
5
- {"at":"2026-05-18T14:43:18.069Z","type":"write","tenantId":"tenant_a","path":"outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbdewj.json"}
6
- {"at":"2026-05-18T14:43:18.077Z","type":"reindex","tenantId":"tenant_a","files":0}
7
- {"at":"2026-05-18T14:46:58.856Z","type":"reindex","tenantId":"tenant_a","files":0}
8
- {"at":"2026-05-18T14:46:58.865Z","type":"write","tenantId":"tenant_a","path":"outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbi59p.json"}
9
- {"at":"2026-05-18T14:46:58.885Z","type":"reindex","tenantId":"tenant_a","files":0}
10
- {"at":"2026-05-18T14:49:15.266Z","type":"reindex","tenantId":"tenant_a","files":0}
11
- {"at":"2026-05-18T14:49:15.276Z","type":"write","tenantId":"tenant_a","path":"outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbl2iu.json"}
12
- {"at":"2026-05-18T14:49:15.290Z","type":"reindex","tenantId":"tenant_a","files":0}
13
- {"at":"2026-05-19T05:25:18.457Z","type":"reindex","tenantId":"tenant_a","files":0}
14
- {"at":"2026-05-19T05:25:18.462Z","type":"write","tenantId":"tenant_a","path":"outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpc6vojg.json"}
15
- {"at":"2026-05-19T05:25:18.470Z","type":"reindex","tenantId":"tenant_a","files":0}
16
- {"at":"2026-05-30T21:07:17.156Z","type":"reindex","tenantId":"tenant_a","files":0}
17
- {"at":"2026-05-30T21:07:17.165Z","type":"write","tenantId":"tenant_a","path":"outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpsudfzc.json"}
18
- {"at":"2026-05-30T21:07:17.184Z","type":"reindex","tenantId":"tenant_a","files":0}
19
- {"at":"2026-07-01T01:40:46.815Z","type":"reindex","tenantId":"tenant_a","files":0}
20
- {"at":"2026-07-01T01:40:46.834Z","type":"write","tenantId":"tenant_a","path":"outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mr1eskfc.json"}
21
- {"at":"2026-07-01T01:40:46.941Z","type":"reindex","tenantId":"tenant_a","files":0}
@@ -1,7 +0,0 @@
1
- {"traceId":"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbcrbs","kind":"content_write","affected":["outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbcrbs.json"],"parent":null,"snapshot":{"outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbcrbs.json":"{\n \"id\": \"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbcrbs\",\n \"status\": \"draft\",\n \"icp\": {\n \"industries\": [\n \"e-commerce\",\n \"D2C\"\n ],\n \"companySize\": {\n \"min\": 50,\n \"max\": 500\n },\n \"titles\": [\n \"VP Marketing\",\n \"Head of Growth\",\n \"CMO\"\n ],\n \"geo\": [\n \"US\",\n \"EU\"\n ],\n \"techStack\": []\n },\n \"leads\": [\n {\n \"id\": \"lead_001\",\n \"company\": \"e-commerce account 1\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_002\",\n \"company\": \"e-commerce account 2\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_003\",\n \"company\": \"e-commerce account 3\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_004\",\n \"company\": \"e-commerce account 4\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_005\",\n \"company\": \"e-commerce account 5\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_006\",\n \"company\": \"e-commerce account 6\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_007\",\n \"company\": \"e-commerce account 7\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_008\",\n \"company\": \"e-commerce account 8\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_009\",\n \"company\": \"e-commerce account 9\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_010\",\n \"company\": \"e-commerce account 10\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_011\",\n \"company\": \"e-commerce account 11\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_012\",\n \"company\": \"e-commerce account 12\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n }\n ],\n \"sequence\": [\n {\n \"step\": 1,\n \"subject\": \"Quick question\",\n \"body\": \"Hi {{first_name}},\\n\\nI noticed {{company}} may care about Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 0\n },\n {\n \"step\": 2,\n \"subject\": \"Following up 2\",\n \"body\": \"Hi {{first_name}},\\n\\nSharing one more angle on Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 3\n },\n {\n \"step\": 3,\n \"subject\": \"Following up 3\",\n \"body\": \"Hi {{first_name}},\\n\\nSharing one more angle on Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 4\n }\n ],\n \"schedule\": {\n \"dailyLimit\": 4,\n \"senderEmails\": [\n \"founder@loop.test\"\n ],\n \"requiresApprovalBeforeSend\": true\n }\n}\n"},"id":"780c782cada57106712f78d63b3eb8c75cf195dd1d972c5db165121df36a0546","tenantId":"tenant_a","at":"2026-05-18T14:42:47.516Z","summary":"content_write touched 1 path(s)","objectHashes":["067f3ad238443f3a1805e364f04996ac2e38b003477a9b7cfc374aa5026d0270"]}
2
- {"traceId":"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbdewj","kind":"content_write","affected":["outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbdewj.json"],"parent":null,"snapshot":{"outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbdewj.json":"{\n \"id\": \"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbdewj\",\n \"status\": \"draft\",\n \"icp\": {\n \"industries\": [\n \"e-commerce\",\n \"D2C\"\n ],\n \"companySize\": {\n \"min\": 50,\n \"max\": 500\n },\n \"titles\": [\n \"VP Marketing\",\n \"Head of Growth\",\n \"CMO\"\n ],\n \"geo\": [\n \"US\",\n \"EU\"\n ],\n \"techStack\": []\n },\n \"leads\": [\n {\n \"id\": \"lead_001\",\n \"company\": \"e-commerce account 1\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_002\",\n \"company\": \"e-commerce account 2\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_003\",\n \"company\": \"e-commerce account 3\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_004\",\n \"company\": \"e-commerce account 4\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_005\",\n \"company\": \"e-commerce account 5\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_006\",\n \"company\": \"e-commerce account 6\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_007\",\n \"company\": \"e-commerce account 7\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_008\",\n \"company\": \"e-commerce account 8\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_009\",\n \"company\": \"e-commerce account 9\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_010\",\n \"company\": \"e-commerce account 10\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_011\",\n \"company\": \"e-commerce account 11\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_012\",\n \"company\": \"e-commerce account 12\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n }\n ],\n \"sequence\": [\n {\n \"step\": 1,\n \"subject\": \"Quick question\",\n \"body\": \"Hi {{first_name}},\\n\\nI noticed {{company}} may care about Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 0\n },\n {\n \"step\": 2,\n \"subject\": \"Following up 2\",\n \"body\": \"Hi {{first_name}},\\n\\nSharing one more angle on Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 3\n },\n {\n \"step\": 3,\n \"subject\": \"Following up 3\",\n \"body\": \"Hi {{first_name}},\\n\\nSharing one more angle on Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 4\n }\n ],\n \"schedule\": {\n \"dailyLimit\": 4,\n \"senderEmails\": [\n \"founder@loop.test\"\n ],\n \"requiresApprovalBeforeSend\": true\n }\n}\n"},"id":"74ed99cce7fb29095eaa2b1da62713eb0319ad8167d978d308ca9ba048f7d7d1","tenantId":"tenant_a","at":"2026-05-18T14:43:18.071Z","summary":"content_write touched 1 path(s)","objectHashes":["2f1f975e351e27eec32da39a74e042512bdcc3110ad3a1bbd1a8a1a0a326f807"]}
3
- {"traceId":"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbi59p","kind":"content_write","affected":["outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbi59p.json"],"parent":null,"snapshot":{"outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbi59p.json":"{\n \"id\": \"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbi59p\",\n \"status\": \"draft\",\n \"icp\": {\n \"industries\": [\n \"e-commerce\",\n \"D2C\"\n ],\n \"companySize\": {\n \"min\": 50,\n \"max\": 500\n },\n \"titles\": [\n \"VP Marketing\",\n \"Head of Growth\",\n \"CMO\"\n ],\n \"geo\": [\n \"US\",\n \"EU\"\n ],\n \"techStack\": []\n },\n \"leads\": [\n {\n \"id\": \"lead_001\",\n \"company\": \"e-commerce account 1\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_002\",\n \"company\": \"e-commerce account 2\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_003\",\n \"company\": \"e-commerce account 3\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_004\",\n \"company\": \"e-commerce account 4\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_005\",\n \"company\": \"e-commerce account 5\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_006\",\n \"company\": \"e-commerce account 6\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_007\",\n \"company\": \"e-commerce account 7\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_008\",\n \"company\": \"e-commerce account 8\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_009\",\n \"company\": \"e-commerce account 9\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_010\",\n \"company\": \"e-commerce account 10\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_011\",\n \"company\": \"e-commerce account 11\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_012\",\n \"company\": \"e-commerce account 12\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n }\n ],\n \"sequence\": [\n {\n \"step\": 1,\n \"subject\": \"Quick question\",\n \"body\": \"Hi {{first_name}},\\n\\nI noticed {{company}} may care about Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 0\n },\n {\n \"step\": 2,\n \"subject\": \"Following up 2\",\n \"body\": \"Hi {{first_name}},\\n\\nSharing one more angle on Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 3\n },\n {\n \"step\": 3,\n \"subject\": \"Following up 3\",\n \"body\": \"Hi {{first_name}},\\n\\nSharing one more angle on Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 4\n }\n ],\n \"schedule\": {\n \"dailyLimit\": 4,\n \"senderEmails\": [\n \"founder@loop.test\"\n ],\n \"requiresApprovalBeforeSend\": true\n }\n}\n"},"id":"cf6f6f585b40bb148bb8d90162f39e2145fb39beac36227eea0c6b88de942d96","tenantId":"tenant_a","at":"2026-05-18T14:46:58.870Z","summary":"content_write touched 1 path(s)","objectHashes":["bfe31c88d0f29dfd14a45a238da6de1f5ea0e225bb1ac66a9d4b9e263311dacd"]}
4
- {"traceId":"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbl2iu","kind":"content_write","affected":["outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbl2iu.json"],"parent":null,"snapshot":{"outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbl2iu.json":"{\n \"id\": \"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbl2iu\",\n \"status\": \"draft\",\n \"icp\": {\n \"industries\": [\n \"e-commerce\",\n \"D2C\"\n ],\n \"companySize\": {\n \"min\": 50,\n \"max\": 500\n },\n \"titles\": [\n \"VP Marketing\",\n \"Head of Growth\",\n \"CMO\"\n ],\n \"geo\": [\n \"US\",\n \"EU\"\n ],\n \"techStack\": []\n },\n \"leads\": [\n {\n \"id\": \"lead_001\",\n \"company\": \"e-commerce account 1\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_002\",\n \"company\": \"e-commerce account 2\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_003\",\n \"company\": \"e-commerce account 3\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_004\",\n \"company\": \"e-commerce account 4\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_005\",\n \"company\": \"e-commerce account 5\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_006\",\n \"company\": \"e-commerce account 6\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_007\",\n \"company\": \"e-commerce account 7\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_008\",\n \"company\": \"e-commerce account 8\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_009\",\n \"company\": \"e-commerce account 9\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_010\",\n \"company\": \"e-commerce account 10\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_011\",\n \"company\": \"e-commerce account 11\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_012\",\n \"company\": \"e-commerce account 12\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n }\n ],\n \"sequence\": [\n {\n \"step\": 1,\n \"subject\": \"Quick question\",\n \"body\": \"Hi {{first_name}},\\n\\nI noticed {{company}} may care about Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 0\n },\n {\n \"step\": 2,\n \"subject\": \"Following up 2\",\n \"body\": \"Hi {{first_name}},\\n\\nSharing one more angle on Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 3\n },\n {\n \"step\": 3,\n \"subject\": \"Following up 3\",\n \"body\": \"Hi {{first_name}},\\n\\nSharing one more angle on Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 4\n }\n ],\n \"schedule\": {\n \"dailyLimit\": 4,\n \"senderEmails\": [\n \"founder@loop.test\"\n ],\n \"requiresApprovalBeforeSend\": true\n }\n}\n"},"id":"1f2fcfbaa0fc4032ea7c08005b9a3d34853b794da26f5b52cc00cbc5b1d47f47","tenantId":"tenant_a","at":"2026-05-18T14:49:15.279Z","summary":"content_write touched 1 path(s)","objectHashes":["79d7562b27f0d253dce2757cd17ae12297c555f86bd1f6d3c91191080e05bbe8"]}
5
- {"traceId":"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpc6vojg","kind":"content_write","affected":["outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpc6vojg.json"],"parent":null,"snapshot":{"outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpc6vojg.json":"{\n \"id\": \"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpc6vojg\",\n \"status\": \"draft\",\n \"icp\": {\n \"industries\": [\n \"e-commerce\",\n \"D2C\"\n ],\n \"companySize\": {\n \"min\": 50,\n \"max\": 500\n },\n \"titles\": [\n \"VP Marketing\",\n \"Head of Growth\",\n \"CMO\"\n ],\n \"geo\": [\n \"US\",\n \"EU\"\n ],\n \"techStack\": []\n },\n \"leads\": [\n {\n \"id\": \"lead_001\",\n \"company\": \"e-commerce account 1\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_002\",\n \"company\": \"e-commerce account 2\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_003\",\n \"company\": \"e-commerce account 3\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_004\",\n \"company\": \"e-commerce account 4\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_005\",\n \"company\": \"e-commerce account 5\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_006\",\n \"company\": \"e-commerce account 6\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_007\",\n \"company\": \"e-commerce account 7\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_008\",\n \"company\": \"e-commerce account 8\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_009\",\n \"company\": \"e-commerce account 9\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_010\",\n \"company\": \"e-commerce account 10\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_011\",\n \"company\": \"e-commerce account 11\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_012\",\n \"company\": \"e-commerce account 12\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n }\n ],\n \"sequence\": [\n {\n \"step\": 1,\n \"subject\": \"Quick question\",\n \"body\": \"Hi {{first_name}},\\n\\nI noticed {{company}} may care about Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 0\n },\n {\n \"step\": 2,\n \"subject\": \"Following up 2\",\n \"body\": \"Hi {{first_name}},\\n\\nSharing one more angle on Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 3\n },\n {\n \"step\": 3,\n \"subject\": \"Following up 3\",\n \"body\": \"Hi {{first_name}},\\n\\nSharing one more angle on Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 4\n }\n ],\n \"schedule\": {\n \"dailyLimit\": 4,\n \"senderEmails\": [\n \"founder@loop.test\"\n ],\n \"requiresApprovalBeforeSend\": true\n }\n}\n"},"id":"6f98ef2421c9ec84e2e641cd3bd1010e0404873f73542ab141899fb8ce9602b2","tenantId":"tenant_a","at":"2026-05-19T05:25:18.464Z","summary":"content_write touched 1 path(s)","objectHashes":["57c7bb029f92676ff8521e73c229890a2d33c1919c08c68d24a0752c594d9bc1"]}
6
- {"at":"2026-05-30T21:07:17.171Z","traceId":"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpsudfzc","kind":"content_write","affected":["outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpsudfzc.json"],"parent":null,"snapshot":{"outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpsudfzc.json":"{\n \"id\": \"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpsudfzc\",\n \"status\": \"draft\",\n \"icp\": {\n \"industries\": [\n \"e-commerce\",\n \"D2C\"\n ],\n \"companySize\": {\n \"min\": 50,\n \"max\": 500\n },\n \"titles\": [\n \"VP Marketing\",\n \"Head of Growth\",\n \"CMO\"\n ],\n \"geo\": [\n \"US\",\n \"EU\"\n ],\n \"techStack\": []\n },\n \"leads\": [\n {\n \"id\": \"lead_001\",\n \"company\": \"e-commerce account 1\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_002\",\n \"company\": \"e-commerce account 2\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_003\",\n \"company\": \"e-commerce account 3\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_004\",\n \"company\": \"e-commerce account 4\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_005\",\n \"company\": \"e-commerce account 5\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_006\",\n \"company\": \"e-commerce account 6\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_007\",\n \"company\": \"e-commerce account 7\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_008\",\n \"company\": \"e-commerce account 8\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_009\",\n \"company\": \"e-commerce account 9\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_010\",\n \"company\": \"e-commerce account 10\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_011\",\n \"company\": \"e-commerce account 11\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_012\",\n \"company\": \"e-commerce account 12\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n }\n ],\n \"sequence\": [\n {\n \"step\": 1,\n \"subject\": \"Quick question\",\n \"body\": \"Hi {{first_name}},\\n\\nI noticed {{company}} may care about Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 0\n },\n {\n \"step\": 2,\n \"subject\": \"Following up 2\",\n \"body\": \"Hi {{first_name}},\\n\\nSharing one more angle on Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 3\n },\n {\n \"step\": 3,\n \"subject\": \"Following up 3\",\n \"body\": \"Hi {{first_name}},\\n\\nSharing one more angle on Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 4\n }\n ],\n \"schedule\": {\n \"dailyLimit\": 4,\n \"senderEmails\": [\n \"founder@loop.test\"\n ],\n \"requiresApprovalBeforeSend\": true\n }\n}\n"},"id":"b8e27c2d51ce4e984aa4573ad59d3ff249c66473e4167d596660346b211c8467","tenantId":"tenant_a","summary":"content_write touched 1 path(s)","objectHashes":["75c4bab53cf63dc0d7e313833eecf2cd606886f3cf9bf7b9554c4529a8af81d3"]}
7
- {"at":"2026-07-01T01:40:46.887Z","traceId":"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mr1eskfc","kind":"content_write","affected":["outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mr1eskfc.json"],"parent":null,"snapshot":{"outreach/outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mr1eskfc.json":"{\n \"id\": \"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mr1eskfc\",\n \"status\": \"draft\",\n \"icp\": {\n \"industries\": [\n \"e-commerce\",\n \"D2C\"\n ],\n \"companySize\": {\n \"min\": 50,\n \"max\": 500\n },\n \"titles\": [\n \"VP Marketing\",\n \"Head of Growth\",\n \"CMO\"\n ],\n \"geo\": [\n \"US\",\n \"EU\"\n ],\n \"techStack\": []\n },\n \"leads\": [\n {\n \"id\": \"lead_001\",\n \"company\": \"e-commerce account 1\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_002\",\n \"company\": \"e-commerce account 2\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_003\",\n \"company\": \"e-commerce account 3\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_004\",\n \"company\": \"e-commerce account 4\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_005\",\n \"company\": \"e-commerce account 5\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_006\",\n \"company\": \"e-commerce account 6\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_007\",\n \"company\": \"e-commerce account 7\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_008\",\n \"company\": \"e-commerce account 8\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_009\",\n \"company\": \"e-commerce account 9\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_010\",\n \"company\": \"e-commerce account 10\",\n \"title\": \"VP Marketing\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_011\",\n \"company\": \"e-commerce account 11\",\n \"title\": \"Head of Growth\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n },\n {\n \"id\": \"lead_012\",\n \"company\": \"e-commerce account 12\",\n \"title\": \"CMO\",\n \"source\": \"local-plan\",\n \"confidence\": 0.72\n }\n ],\n \"sequence\": [\n {\n \"step\": 1,\n \"subject\": \"Quick question\",\n \"body\": \"Hi {{first_name}},\\n\\nI noticed {{company}} may care about Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 0\n },\n {\n \"step\": 2,\n \"subject\": \"Following up 2\",\n \"body\": \"Hi {{first_name}},\\n\\nSharing one more angle on Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 3\n },\n {\n \"step\": 3,\n \"subject\": \"Following up 3\",\n \"body\": \"Hi {{first_name}},\\n\\nSharing one more angle on Loop helps teams debug production issues.\\nTone: specific, useful, respectful.\\n\\nIf this is not useful, unsubscribe here: {{unsubscribe_url}}.\\n{{physical_address}}\",\n \"daysAfterPrevious\": 4\n }\n ],\n \"schedule\": {\n \"dailyLimit\": 4,\n \"senderEmails\": [\n \"founder@loop.test\"\n ],\n \"requiresApprovalBeforeSend\": true\n }\n}\n"},"id":"710d030c008ea6752a2ebc2dd959e35b3cb37b89a3cad5b996184f2aea4e7cc1","tenantId":"tenant_a","summary":"content_write touched 1 path(s)","objectHashes":["d62754881f76cbf2070fb344fa06adc8aead02260738c4443a017bba48c68995"]}
@@ -1,7 +0,0 @@
1
- {"at":"2026-05-18T14:42:47.517Z","type":"campaign_draft","tenantId":"tenant_a","campaignId":"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbcrbs","eventId":"780c782cada57106712f78d63b3eb8c75cf195dd1d972c5db165121df36a0546"}
2
- {"at":"2026-05-18T14:43:18.071Z","type":"campaign_draft","tenantId":"tenant_a","campaignId":"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbdewj","eventId":"74ed99cce7fb29095eaa2b1da62713eb0319ad8167d978d308ca9ba048f7d7d1"}
3
- {"at":"2026-05-18T14:46:58.872Z","type":"campaign_draft","tenantId":"tenant_a","campaignId":"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbi59p","eventId":"cf6f6f585b40bb148bb8d90162f39e2145fb39beac36227eea0c6b88de942d96"}
4
- {"at":"2026-05-18T14:49:15.281Z","type":"campaign_draft","tenantId":"tenant_a","campaignId":"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpbbl2iu","eventId":"1f2fcfbaa0fc4032ea7c08005b9a3d34853b794da26f5b52cc00cbc5b1d47f47"}
5
- {"at":"2026-05-19T05:25:18.465Z","type":"campaign_draft","tenantId":"tenant_a","campaignId":"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpc6vojg","eventId":"6f98ef2421c9ec84e2e641cd3bd1010e0404873f73542ab141899fb8ce9602b2"}
6
- {"at":"2026-05-30T21:07:17.174Z","type":"campaign_draft","tenantId":"tenant_a","campaignId":"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mpsudfzc","eventId":"b8e27c2d51ce4e984aa4573ad59d3ff249c66473e4167d596660346b211c8467"}
7
- {"at":"2026-07-01T01:40:46.900Z","type":"campaign_draft","tenantId":"tenant_a","campaignId":"outreach_campaign_decision_makers_at_mid_size_d2c_e_commer_mr1eskfc","eventId":"710d030c008ea6752a2ebc2dd959e35b3cb37b89a3cad5b996184f2aea4e7cc1"}
@@ -1,22 +0,0 @@
1
-
2
- > @nebutra/outreach-engine@0.1.3 build /Users/tseka_luk/Documents/Nebutra-SaaS-Lab/Nebutra-Sailor/packages/ai/outreach-engine
3
- > tsup
4
-
5
- CLI Building entry: src/cli.ts, src/index.ts
6
- CLI Using tsconfig: tsconfig.json
7
- CLI tsup v8.5.1
8
- CLI Using tsup config: /Users/tseka_luk/Documents/Nebutra-SaaS-Lab/Nebutra-Sailor/packages/ai/outreach-engine/tsup.config.ts
9
- CLI Target: es2022
10
- CLI Cleaning output folder
11
- ESM Build start
12
- ESM dist/cli.js 1.61 KB
13
- ESM dist/index.js 290.00 B
14
- ESM dist/chunk-XD3Y5BKC.js 6.75 KB
15
- ESM dist/cli.js.map 2.75 KB
16
- ESM dist/index.js.map 71.00 B
17
- ESM dist/chunk-XD3Y5BKC.js.map 15.03 KB
18
- ESM ⚡️ Build success in 43ms
19
- DTS Build start
20
- DTS ⚡️ Build success in 1523ms
21
- DTS dist/cli.d.ts 13.00 B
22
- DTS dist/index.d.ts 3.69 KB
@@ -1,16 +0,0 @@
1
-
2
- > @nebutra/outreach-engine@0.1.2 test /Users/tseka_luk/Documents/Nebutra-SaaS-Lab/Nebutra-Sailor/packages/ai/outreach-engine
3
- > vitest run
4
-
5
-
6
- RUN v4.1.4 /Users/tseka_luk/Documents/Nebutra-SaaS-Lab/Nebutra-Sailor/packages/ai/outreach-engine
7
-
8
- (node:57828) ExperimentalWarning: SQLite is an experimental feature and might change at any time
9
- (Use `node --trace-warnings ...` to show where the warning was created)
10
- ✓ src/index.test.ts (5 tests) 162ms
11
-
12
- Test Files 1 passed (1)
13
- Tests 5 passed (5)
14
- Start at 09:40:45
15
- Duration 1.21s (transform 372ms, setup 0ms, import 509ms, tests 162ms, environment 0ms)
16
-
@@ -1,4 +0,0 @@
1
-
2
- > @nebutra/outreach-engine@0.1.3 typecheck /Users/tseka_luk/Documents/Nebutra-SaaS-Lab/Nebutra-Sailor/packages/ai/outreach-engine
3
- > tsc --noEmit
4
-
@@ -1,18 +0,0 @@
1
- import { buildEmailSequence, checkEmailCompliance } from "../src/index";
2
-
3
- const sequence = buildEmailSequence({
4
- product: "Loop helps teams debug production issues",
5
- sequenceLength: 2,
6
- });
7
-
8
- process.stdout.write(
9
- `${JSON.stringify(
10
- checkEmailCompliance(sequence[0], {
11
- physicalAddress: "123 Market St",
12
- unsubscribeUrl: "https://loop.test/unsubscribe",
13
- gdprBasis: "legitimate_interest",
14
- }),
15
- null,
16
- 2,
17
- )}\n`,
18
- );
package/examples/icp.ts DELETED
@@ -1,9 +0,0 @@
1
- import { defineIcp } from "../src/index";
2
-
3
- process.stdout.write(
4
- `${JSON.stringify(
5
- defineIcp("decision makers at mid-size D2C e-commerce companies in the US"),
6
- null,
7
- 2,
8
- )}\n`,
9
- );
@@ -1,30 +0,0 @@
1
- import { OutreachEngine } from "../src/index";
2
-
3
- const engine = await OutreachEngine.open(".nebutra/outreach-engine-example", {
4
- tenantId: "local",
5
- });
6
-
7
- try {
8
- process.stdout.write(
9
- `${JSON.stringify(
10
- await engine.createCampaign({
11
- tenantId: "local",
12
- icpDescription: "decision makers at mid-size D2C e-commerce companies",
13
- targetCount: 10,
14
- product: "Loop helps teams debug production issues",
15
- sequenceLength: 3,
16
- sendPerDay: 5,
17
- senderEmails: ["founder@loop.test"],
18
- complianceProfile: {
19
- physicalAddress: "123 Market St",
20
- unsubscribeUrl: "https://loop.test/unsubscribe",
21
- gdprBasis: "legitimate_interest",
22
- },
23
- }),
24
- null,
25
- 2,
26
- )}\n`,
27
- );
28
- } finally {
29
- await engine.close();
30
- }
@@ -1,44 +0,0 @@
1
- ---
2
- name: outreach_campaign
3
- kind: play
4
- version: 1.0.0
5
- description: Create a compliance-gated founder-led outbound campaign draft
6
- inputs:
7
- icp_description: { type: string, max_length: 500 }
8
- target_count: { type: number }
9
- product: { type: string, max_length: 500 }
10
- sequence_length: { type: number }
11
- send_per_day: { type: number }
12
- outputs:
13
- campaign: { type: file, path: outreach/campaign.json, mime: application/json }
14
- budget:
15
- duration_s: 600
16
- cost_usd: 2.0
17
- required_skills:
18
- - content_store.write
19
- - research_agent.run
20
- - integration_vault.invoke
21
- sub_agents:
22
- - role: icp_strategist
23
- allowed_skills: [content_store.write]
24
- - role: lead_researcher
25
- allowed_skills: [research_agent.run]
26
- - role: compliance_reviewer
27
- allowed_skills: [content_store.write]
28
- depends_on_plays: []
29
- ---
30
-
31
- ## What this play does
32
-
33
- Creates a draft outbound campaign from an ICP description.
34
-
35
- The Play is draft-first. It may produce leads, enrichment notes, email variants,
36
- and a schedule, but actual sending requires explicit approval and a configured
37
- sender adapter.
38
-
39
- ## Rules
40
-
41
- - Never bypass unsubscribe, physical address, or consent basis checks.
42
- - Never send directly from the Play run.
43
- - Keep lead data tenant-scoped.
44
- - Write campaign artifacts through content-store.
package/src/cli.ts DELETED
@@ -1,49 +0,0 @@
1
- import { OutreachEngine, readOutreachEngineDebug } from "./index";
2
-
3
- const command = process.argv[2] ?? "doctor";
4
- const root = process.env.OUTREACH_ENGINE_ROOT ?? ".nebutra/outreach-engine";
5
- const tenantId = process.env.NEBUTRA_TENANT_ID ?? "local";
6
-
7
- if (command === "doctor") {
8
- const engine = await OutreachEngine.open(root, { tenantId });
9
- try {
10
- process.stdout.write(`${JSON.stringify(await engine.doctor(), null, 2)}\n`);
11
- } finally {
12
- await engine.close();
13
- }
14
- } else if (command === "quickstart") {
15
- const engine = await OutreachEngine.open(root, { tenantId });
16
- try {
17
- process.stdout.write(
18
- `${JSON.stringify(
19
- await engine.createCampaign({
20
- tenantId,
21
- icpDescription:
22
- process.argv.slice(3).join(" ") ||
23
- "decision makers at mid-size D2C e-commerce companies",
24
- targetCount: 10,
25
- product: "Loop helps teams debug production issues",
26
- sequenceLength: 3,
27
- sendPerDay: 5,
28
- senderEmails: ["founder@loop.test"],
29
- complianceProfile: {
30
- physicalAddress: "123 Market St, San Francisco, CA",
31
- unsubscribeUrl: "https://loop.test/unsubscribe",
32
- gdprBasis: "legitimate_interest",
33
- },
34
- }),
35
- null,
36
- 2,
37
- )}\n`,
38
- );
39
- } finally {
40
- await engine.close();
41
- }
42
- } else if (command === "debug") {
43
- process.stdout.write(
44
- `${JSON.stringify({ capability: "outreach-engine", entries: await readOutreachEngineDebug() }, null, 2)}\n`,
45
- );
46
- } else {
47
- process.stderr.write(`Unknown outreach-engine command: ${command}\n`);
48
- process.exitCode = 1;
49
- }
package/src/index.test.ts DELETED
@@ -1,120 +0,0 @@
1
- import { mkdtemp, readFile, rm } from "node:fs/promises";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
- import { parsePlayMarkdown } from "@nebutra/play-loader";
5
- import { afterEach, describe, expect, it } from "vitest";
6
- import {
7
- buildEmailSequence,
8
- checkEmailCompliance,
9
- defineIcp,
10
- OutreachEngine,
11
- readOutreachEngineDebug,
12
- } from "./index";
13
-
14
- let root: string | undefined;
15
- let engine: OutreachEngine | undefined;
16
-
17
- afterEach(async () => {
18
- if (engine) await engine.close();
19
- if (root) await rm(root, { recursive: true, force: true });
20
- root = undefined;
21
- engine = undefined;
22
- });
23
-
24
- async function open(): Promise<OutreachEngine> {
25
- root = await mkdtemp(join(tmpdir(), "outreach-engine-"));
26
- engine = await OutreachEngine.open(root, { tenantId: "tenant_a" });
27
- return engine;
28
- }
29
-
30
- describe("outreach-engine", () => {
31
- it("turns fuzzy ICP language into a structured targeting plan", () => {
32
- const icp = defineIcp("decision makers at mid-size D2C e-commerce companies in the US");
33
-
34
- expect(icp.industries).toContain("e-commerce");
35
- expect(icp.companySize).toEqual({ min: 50, max: 500 });
36
- expect(icp.titles).toContain("Head of Growth");
37
- expect(icp.geo).toContain("US");
38
- });
39
-
40
- it("builds compliance-gated email variants with unsubscribe requirements", () => {
41
- const sequence = buildEmailSequence({
42
- product: "Loop helps indie devs debug production issues",
43
- sequenceLength: 3,
44
- brandVoice: ["technical", "warm"],
45
- });
46
- const compliance = checkEmailCompliance(sequence[0], {
47
- physicalAddress: "123 Market St, San Francisco, CA",
48
- unsubscribeUrl: "https://loop.test/unsubscribe",
49
- gdprBasis: "legitimate_interest",
50
- });
51
-
52
- expect(sequence).toHaveLength(3);
53
- expect(sequence[0]?.body).toContain("unsubscribe");
54
- expect(compliance.ok).toBe(true);
55
- });
56
-
57
- it("runs outreach_campaign as a draft with leads, sequence, schedule, and event", async () => {
58
- const runtime = await open();
59
-
60
- const campaign = await runtime.createCampaign({
61
- tenantId: "tenant_a",
62
- icpDescription: "decision makers at mid-size D2C e-commerce companies",
63
- targetCount: 12,
64
- product: "Loop helps teams debug production issues",
65
- sequenceLength: 3,
66
- sendPerDay: 4,
67
- senderEmails: ["founder@loop.test"],
68
- complianceProfile: {
69
- physicalAddress: "123 Market St, San Francisco, CA",
70
- unsubscribeUrl: "https://loop.test/unsubscribe",
71
- gdprBasis: "legitimate_interest",
72
- },
73
- });
74
-
75
- expect(campaign.play).toBe("outreach_campaign");
76
- expect(campaign.status).toBe("draft");
77
- expect(campaign.leads).toHaveLength(12);
78
- expect(campaign.sequence).toHaveLength(3);
79
- expect(campaign.schedule.dailyLimit).toBe(4);
80
- expect(campaign.compliance.ok).toBe(true);
81
- expect(campaign.eventId).toEqual(expect.any(String));
82
- await expect(readOutreachEngineDebug(root)).resolves.toEqual(expect.any(Array));
83
- });
84
-
85
- it("rejects persistent campaign creation without tenant context", async () => {
86
- const runtime = await open();
87
-
88
- await expect(
89
- runtime.createCampaign({
90
- tenantId: "",
91
- icpDescription: "SaaS CTOs",
92
- targetCount: 5,
93
- product: "Loop",
94
- sequenceLength: 2,
95
- sendPerDay: 2,
96
- senderEmails: ["founder@loop.test"],
97
- complianceProfile: {
98
- physicalAddress: "123 Market St",
99
- unsubscribeUrl: "https://loop.test/unsubscribe",
100
- gdprBasis: "legitimate_interest",
101
- },
102
- }),
103
- ).rejects.toMatchObject({
104
- capability: "outreach-engine",
105
- suggestion: expect.stringContaining("tenantId"),
106
- });
107
- });
108
-
109
- it("keeps the outreach campaign as SKILL.md instead of a new workflow format", async () => {
110
- const skill = await readFile(
111
- join(process.cwd(), "plays", "outreach_campaign", "SKILL.md"),
112
- "utf8",
113
- );
114
- const play = parsePlayMarkdown(skill);
115
-
116
- expect(play.meta).toMatchObject({ name: "outreach_campaign", kind: "play" });
117
- expect(play.requiredSkills).toContain("content_store.write");
118
- expect(play.subAgents.map((agent) => agent.role)).toContain("lead_researcher");
119
- });
120
- });
package/src/index.ts DELETED
@@ -1,315 +0,0 @@
1
- import { mkdir } from "node:fs/promises";
2
- import { dirname, join } from "node:path";
3
- import { requireCapabilityTenant } from "@nebutra/capability-kit";
4
- import { appendCapabilityDebug, readCapabilityDebug } from "@nebutra/capability-kit/debug";
5
- import { ContentStore } from "@nebutra/content-store";
6
- import { CapabilityError } from "@nebutra/errors";
7
- import { EventLog } from "@nebutra/event-log";
8
- import { assetId } from "@nebutra/generation-context";
9
-
10
- export interface IcpDefinition {
11
- readonly industries: readonly string[];
12
- readonly companySize: { readonly min: number; readonly max: number };
13
- readonly titles: readonly string[];
14
- readonly geo: readonly string[];
15
- readonly techStack: readonly string[];
16
- }
17
-
18
- export interface ComplianceProfile {
19
- readonly physicalAddress: string;
20
- readonly unsubscribeUrl: string;
21
- readonly gdprBasis?: "legitimate_interest" | "consent" | "existing_customer";
22
- }
23
-
24
- export interface EmailVariant {
25
- readonly step: number;
26
- readonly subject: string;
27
- readonly body: string;
28
- readonly daysAfterPrevious: number;
29
- }
30
-
31
- export interface ComplianceReport {
32
- readonly ok: boolean;
33
- readonly checks: {
34
- readonly hasUnsubscribeLink: boolean;
35
- readonly hasPhysicalAddress: boolean;
36
- readonly hasClearSubject: boolean;
37
- readonly gdprBasisDocumented: boolean;
38
- };
39
- readonly suggestion?: string;
40
- }
41
-
42
- export interface CampaignInput {
43
- readonly tenantId?: string;
44
- readonly icpDescription: string;
45
- readonly targetCount: number;
46
- readonly product: string;
47
- readonly sequenceLength: number;
48
- readonly sendPerDay: number;
49
- readonly senderEmails: readonly string[];
50
- readonly complianceProfile: ComplianceProfile;
51
- }
52
-
53
- export interface Lead {
54
- readonly id: string;
55
- readonly company: string;
56
- readonly title: string;
57
- readonly source: "local-plan";
58
- readonly confidence: number;
59
- }
60
-
61
- export interface CampaignPackage {
62
- readonly tenantId: string;
63
- readonly play: "outreach_campaign";
64
- readonly id: string;
65
- readonly status: "draft";
66
- readonly icp: IcpDefinition;
67
- readonly leads: readonly Lead[];
68
- readonly sequence: readonly EmailVariant[];
69
- readonly compliance: ComplianceReport;
70
- readonly schedule: {
71
- readonly dailyLimit: number;
72
- readonly senderEmails: readonly string[];
73
- readonly requiresApprovalBeforeSend: true;
74
- };
75
- readonly artifactPath: string;
76
- readonly eventId: string;
77
- }
78
-
79
- export interface SequenceInput {
80
- readonly product: string;
81
- readonly sequenceLength: number;
82
- readonly brandVoice?: readonly string[];
83
- }
84
-
85
- export interface OutreachDoctorReport {
86
- readonly capability: "outreach-engine";
87
- readonly ok: boolean;
88
- readonly checkedAt: string;
89
- readonly plays: readonly string[];
90
- readonly sendMode: "draft-only";
91
- readonly adapters: readonly { readonly provider: string; readonly ok: boolean }[];
92
- }
93
-
94
- export interface OutreachEngineOptions {
95
- readonly tenantId?: string;
96
- readonly root?: string;
97
- readonly debugRoot?: string;
98
- readonly contentStore?: ContentStore;
99
- readonly eventLog?: EventLog;
100
- }
101
-
102
- function slug(value: string): string {
103
- return value
104
- .slice(0, 200)
105
- .toLowerCase()
106
- .replace(/[^a-z0-9]{1,200}/g, "_")
107
- .replace(/^_{1,200}|_{1,200}$/g, "")
108
- .slice(0, 48);
109
- }
110
-
111
- export function defineIcp(description: string): IcpDefinition {
112
- const text = description.toLowerCase();
113
- const industries =
114
- text.includes("e-commerce") || text.includes("d2c")
115
- ? ["e-commerce", "D2C"]
116
- : text.includes("saas")
117
- ? ["SaaS"]
118
- : ["startup"];
119
- const titles = text.includes("cto")
120
- ? ["CTO", "VP Engineering", "Head of Engineering"]
121
- : ["VP Marketing", "Head of Growth", "CMO"];
122
- const companySize =
123
- text.includes("mid-size") || text.includes("medium")
124
- ? { min: 50, max: 500 }
125
- : { min: 1, max: 50 };
126
- const geo = text.includes("eu") ? ["EU"] : text.includes("us") ? ["US"] : ["US", "EU"];
127
- const techStack = text.includes("shopify") ? ["Shopify"] : [];
128
- return { industries, companySize, titles, geo, techStack };
129
- }
130
-
131
- export function buildEmailSequence(input: SequenceInput): readonly EmailVariant[] {
132
- const length = Math.max(1, Math.min(5, input.sequenceLength));
133
- const voice = input.brandVoice?.join(", ") ?? "clear, useful";
134
- return Array.from({ length }, (_, index) => {
135
- const step = index + 1;
136
- return {
137
- step,
138
- subject: step === 1 ? "Quick question" : `Following up ${step}`,
139
- body: [
140
- `Hi {{first_name}},`,
141
- "",
142
- step === 1
143
- ? `I noticed {{company}} may care about ${input.product}.`
144
- : `Sharing one more angle on ${input.product}.`,
145
- `Tone: ${voice}.`,
146
- "",
147
- "If this is not useful, unsubscribe here: {{unsubscribe_url}}.",
148
- "{{physical_address}}",
149
- ].join("\n"),
150
- daysAfterPrevious: step === 1 ? 0 : step + 1,
151
- };
152
- });
153
- }
154
-
155
- export function checkEmailCompliance(
156
- email: EmailVariant | undefined,
157
- profile: ComplianceProfile,
158
- ): ComplianceReport {
159
- const body = email?.body ?? "";
160
- const checks = {
161
- hasUnsubscribeLink: body.includes("unsubscribe") && profile.unsubscribeUrl.startsWith("http"),
162
- hasPhysicalAddress: profile.physicalAddress.trim().length > 4,
163
- hasClearSubject: Boolean(email?.subject.trim()),
164
- gdprBasisDocumented: Boolean(profile.gdprBasis),
165
- };
166
- const ok = Object.values(checks).every(Boolean);
167
- return {
168
- ok,
169
- checks,
170
- ...(!ok
171
- ? {
172
- suggestion:
173
- "Add unsubscribe URL, physical address, clear subject, and GDPR basis before any send adapter can run.",
174
- }
175
- : {}),
176
- };
177
- }
178
-
179
- function plannedLeads(icp: IcpDefinition, count: number): readonly Lead[] {
180
- const size = Math.max(1, Math.min(250, count));
181
- return Array.from({ length: size }, (_, index) => ({
182
- id: `lead_${String(index + 1).padStart(3, "0")}`,
183
- company: `${icp.industries[0] ?? "startup"} account ${index + 1}`,
184
- title: icp.titles[index % icp.titles.length] ?? "Founder",
185
- source: "local-plan",
186
- confidence: 0.72,
187
- }));
188
- }
189
-
190
- export class OutreachEngine {
191
- readonly #tenantId: string | undefined;
192
- readonly #debugRoot: string;
193
- readonly #contentStore: ContentStore;
194
- readonly #eventLog: EventLog;
195
-
196
- private constructor(
197
- options: OutreachEngineOptions & { contentStore: ContentStore; eventLog: EventLog },
198
- ) {
199
- this.#tenantId = options.tenantId;
200
- this.#debugRoot = options.debugRoot ?? process.cwd();
201
- this.#contentStore = options.contentStore;
202
- this.#eventLog = options.eventLog;
203
- }
204
-
205
- static async open(
206
- root = ".nebutra/outreach-engine",
207
- options: Omit<OutreachEngineOptions, "root" | "contentStore" | "eventLog"> = {},
208
- ): Promise<OutreachEngine> {
209
- const tenantId = options.tenantId ?? "local";
210
- await mkdir(root, { recursive: true });
211
- const contentStore = await ContentStore.open(join(root, "content"), { tenantId });
212
- const eventLog = await EventLog.open(join(root, "event-log"), { tenantId });
213
- return new OutreachEngine({ ...options, tenantId, root, contentStore, eventLog });
214
- }
215
-
216
- async createCampaign(input: CampaignInput): Promise<CampaignPackage> {
217
- const tenantId = requireCapabilityTenant({
218
- explicit: input.tenantId,
219
- fallback: this.#tenantId,
220
- onMissing: () =>
221
- new CapabilityError("outreach-engine", "Outreach Engine requires tenant context", {
222
- suggestion: "Pass tenantId before creating or persisting a campaign.",
223
- statusCode: 400,
224
- }),
225
- });
226
- const icp = defineIcp(input.icpDescription);
227
- const sequence = buildEmailSequence({
228
- product: input.product,
229
- sequenceLength: input.sequenceLength,
230
- brandVoice: ["specific", "useful", "respectful"],
231
- });
232
- const compliance = checkEmailCompliance(sequence[0], input.complianceProfile);
233
- if (!compliance.ok) {
234
- throw new CapabilityError("outreach-engine", "Campaign failed compliance checks", {
235
- suggestion:
236
- compliance.suggestion ??
237
- "Add unsubscribe URL, physical address, clear subject, and GDPR basis.",
238
- statusCode: 400,
239
- metadata: compliance.checks,
240
- });
241
- }
242
- const id = assetId("outreach_campaign", slug(input.icpDescription));
243
- const leads = plannedLeads(icp, input.targetCount);
244
- const artifactPath = `outreach/${id}.json`;
245
- const draft = {
246
- id,
247
- status: "draft",
248
- icp,
249
- leads,
250
- sequence,
251
- schedule: {
252
- dailyLimit: Math.max(1, Math.min(30, input.sendPerDay)),
253
- senderEmails: input.senderEmails,
254
- requiresApprovalBeforeSend: true,
255
- } as const,
256
- };
257
- const content = `${JSON.stringify(draft, null, 2)}\n`;
258
- await this.#contentStore.write(artifactPath, content);
259
- const eventId = await this.#eventLog.commit({
260
- traceId: id,
261
- kind: "content_write",
262
- affected: [artifactPath],
263
- parent: null,
264
- snapshot: { [artifactPath]: content },
265
- });
266
- const campaign: CampaignPackage = {
267
- tenantId,
268
- play: "outreach_campaign",
269
- id,
270
- status: "draft",
271
- icp,
272
- leads,
273
- sequence,
274
- compliance,
275
- schedule: draft.schedule,
276
- artifactPath,
277
- eventId,
278
- };
279
- await this.#debug({ type: "campaign_draft", tenantId, campaignId: id, eventId });
280
- return campaign;
281
- }
282
-
283
- async doctor(): Promise<OutreachDoctorReport> {
284
- return {
285
- capability: "outreach-engine",
286
- ok: true,
287
- checkedAt: new Date().toISOString(),
288
- plays: ["outreach_campaign"],
289
- sendMode: "draft-only",
290
- adapters: [
291
- { provider: "local-plan", ok: true },
292
- { provider: "integration-vault-email", ok: false },
293
- { provider: "crm-sync", ok: false },
294
- ],
295
- };
296
- }
297
-
298
- async close(): Promise<void> {
299
- await this.#contentStore.close();
300
- }
301
-
302
- async #debug(entry: Record<string, unknown>): Promise<void> {
303
- await mkdir(dirname(join(this.#debugRoot, ".nebutra", "debug", "outreach-engine.jsonl")), {
304
- recursive: true,
305
- });
306
- await appendCapabilityDebug("outreach-engine", entry, { root: this.#debugRoot });
307
- }
308
- }
309
-
310
- export async function readOutreachEngineDebug(
311
- root = process.cwd(),
312
- limit = 20,
313
- ): Promise<unknown[]> {
314
- return readCapabilityDebug("outreach-engine", { root, limit });
315
- }
package/tsconfig.json DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "extends": "../../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "outDir": "dist",
5
- "rootDir": ".",
6
- "types": ["node", "vitest"]
7
- },
8
- "include": ["src/**/*.ts", "examples/**/*.ts"]
9
- }
package/tsup.config.ts DELETED
@@ -1,11 +0,0 @@
1
- import { defineConfig } from "tsup";
2
-
3
- export default defineConfig({
4
- entry: ["src/index.ts", "src/cli.ts"],
5
- format: ["esm"],
6
- sourcemap: true,
7
- dts: true,
8
- clean: true,
9
- target: "es2022",
10
- external: [/^@nebutra\//],
11
- });