@synap-core/workspace-templates 0.12.0 → 0.24.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 (237) hide show
  1. package/README.md +509 -0
  2. package/automations/bookmark-enrichment.automation.json +321 -0
  3. package/automations/github-pr-events.automation.json +505 -0
  4. package/automations/mail-feed.automation.json +86 -0
  5. package/automations/ship-a-change-checks-green.automation.json +106 -0
  6. package/automations/ship-a-change-checks-red.automation.json +106 -0
  7. package/automations/ship-a-change-deployed.automation.json +56 -0
  8. package/automations/ship-a-change-pr-merged.automation.json +110 -0
  9. package/automations/ship-a-change-pr-opened.automation.json +104 -0
  10. package/automations/url-bookmark-capture.automation.json +132 -0
  11. package/capabilities/agency-skills.capability.json +157 -0
  12. package/capabilities/apify.capability.json +265 -0
  13. package/capabilities/apollo.capability.json +120 -0
  14. package/capabilities/arch-backend.capability.json +97 -0
  15. package/capabilities/arch-client-intelligence.capability.json +401 -0
  16. package/capabilities/backblaze-b2.capability.json +205 -0
  17. package/capabilities/cal-com.capability.json +266 -0
  18. package/capabilities/canva.capability.json +274 -0
  19. package/capabilities/claude-code-routines.capability.json +172 -0
  20. package/capabilities/claude-managed-agents.capability.json +215 -0
  21. package/capabilities/client-comms-report.capability.json +246 -0
  22. package/capabilities/content-idea-to-production.capability.json +29 -0
  23. package/capabilities/datagouv.capability.json +315 -0
  24. package/capabilities/discord-bot.capability.json +157 -0
  25. package/capabilities/dropbox.capability.json +281 -0
  26. package/capabilities/exa.capability.json +109 -0
  27. package/capabilities/fal-ai.capability.json +83 -0
  28. package/capabilities/fal-media-lab.capability.json +158 -0
  29. package/capabilities/fireflies.capability.json +191 -0
  30. package/capabilities/freellmapi.capability.json +114 -0
  31. package/capabilities/generic-apikey.capability.json +92 -0
  32. package/capabilities/github-merge.capability.json +99 -0
  33. package/capabilities/github-read.capability.json +325 -0
  34. package/capabilities/governance-tighten-recommender.capability.json +81 -0
  35. package/capabilities/jev.capability.json +226 -0
  36. package/capabilities/lead-conversion-enrollment.capability.json +246 -0
  37. package/capabilities/mail-feed.capability.json +277 -0
  38. package/capabilities/mailgun.capability.json +52 -0
  39. package/capabilities/nango-google.capability.json +639 -0
  40. package/capabilities/notion.capability.json +417 -0
  41. package/capabilities/omniroute.capability.json +137 -0
  42. package/capabilities/posthog-analytics.capability.json +258 -0
  43. package/capabilities/postiz.capability.json +467 -0
  44. package/capabilities/proactive-digest.capability.json +190 -0
  45. package/capabilities/proton.capability.json +288 -0
  46. package/capabilities/replicate-rvm.capability.json +97 -0
  47. package/capabilities/research-methods.capability.json +57 -0
  48. package/capabilities/shopify.capability.json +395 -0
  49. package/capabilities/slack.capability.json +369 -0
  50. package/capabilities/stripe.capability.json +1496 -0
  51. package/capabilities/telegram-bridge.capability.json +56 -0
  52. package/capabilities/treg.capability.json +102 -0
  53. package/capabilities/unipile-linkedin.capability.json +494 -0
  54. package/capabilities/vercel.capability.json +424 -0
  55. package/dist/define-DqoItRiR.d.ts +1370 -0
  56. package/dist/index.d.ts +174 -900
  57. package/dist/index.js +26447 -24075
  58. package/dist/index.js.map +1 -1
  59. package/dist/wire.d.ts +222 -0
  60. package/dist/wire.js +77 -0
  61. package/dist/wire.js.map +1 -0
  62. package/package.json +27 -4
  63. package/retired.yaml +136 -0
  64. package/skills/app-factory-build-slice/SKILL.md +70 -0
  65. package/skills/app-factory-build-slice.catalog.json +17 -0
  66. package/skills/app-factory-design-canvas/SKILL.md +96 -0
  67. package/skills/app-factory-design-canvas.catalog.json +17 -0
  68. package/skills/app-factory-design-review/SKILL.md +105 -0
  69. package/skills/app-factory-design-review.catalog.json +18 -0
  70. package/skills/app-factory-research/SKILL.md +123 -0
  71. package/skills/app-factory-research.catalog.json +17 -0
  72. package/skills/bookmark-enrichment/SKILL.md +40 -0
  73. package/skills/carousel-format/carousel-format.skill.json +18 -0
  74. package/skills/collage-broll/collage-broll.skill.json +20 -0
  75. package/skills/content-taste/content-taste.skill.json +18 -0
  76. package/skills/creative-director/creative-director.skill.json +18 -0
  77. package/skills/design-critique/SKILL.md +138 -0
  78. package/skills/design-critique.catalog.json +12 -0
  79. package/skills/designing-with-real-components/SKILL.md +140 -0
  80. package/skills/designing-with-real-components.catalog.json +12 -0
  81. package/skills/edit-loop/edit-loop.skill.json +25 -0
  82. package/skills/facecam-edit/facecam-edit.skill.json +24 -0
  83. package/skills/mapping-the-server/SKILL.md +54 -0
  84. package/skills/math-explainer-manimgx/math-explainer-manimgx.skill.json +20 -0
  85. package/skills/motion-quality-gates/motion-quality-gates.skill.json +20 -0
  86. package/skills/open-design-edit/open-design-edit.skill.json +24 -0
  87. package/skills/reading-client-progress/SKILL.md +65 -0
  88. package/skills/routing-to-channels/SKILL.md +54 -0
  89. package/skills/stellar-scf-grants-advisor/ASSOCIATE-CHEATSHEET.md +133 -0
  90. package/skills/stellar-scf-grants-advisor/ASSOCIATE-ONBOARDING-GUIDE.md +761 -0
  91. package/skills/stellar-scf-grants-advisor/CLIENT-FAQ.md +181 -0
  92. package/skills/stellar-scf-grants-advisor/PARTNER-HANDOVER.md +130 -0
  93. package/skills/stellar-scf-grants-advisor/SKILL.md +102 -0
  94. package/skills/stellar-scf-grants-advisor/examples/README.md +43 -0
  95. package/skills/stellar-scf-grants-advisor/examples/chat-summary-templates.md +158 -0
  96. package/skills/stellar-scf-grants-advisor/examples/corpus-comparable-rows.md +136 -0
  97. package/skills/stellar-scf-grants-advisor/examples/q10-team-rewrites.md +109 -0
  98. package/skills/stellar-scf-grants-advisor/examples/q2-description-rewrites.md +88 -0
  99. package/skills/stellar-scf-grants-advisor/examples/q6-integration-rewrites.md +107 -0
  100. package/skills/stellar-scf-grants-advisor/examples/tranche-structures.md +176 -0
  101. package/skills/stellar-scf-grants-advisor/reference/01-methodology.md +96 -0
  102. package/skills/stellar-scf-grants-advisor/reference/02-scoring-framework.md +199 -0
  103. package/skills/stellar-scf-grants-advisor/reference/03-rejection-patterns.md +241 -0
  104. package/skills/stellar-scf-grants-advisor/reference/04-winner-patterns.md +120 -0
  105. package/skills/stellar-scf-grants-advisor/reference/05-comeback-patterns.md +92 -0
  106. package/skills/stellar-scf-grants-advisor/reference/06-budget-benchmarks.md +125 -0
  107. package/skills/stellar-scf-grants-advisor/reference/07-integration-list.md +147 -0
  108. package/skills/stellar-scf-grants-advisor/reference/08-abstract-fields.md +258 -0
  109. package/skills/stellar-scf-grants-advisor/reference/09-build-fields.md +259 -0
  110. package/skills/stellar-scf-grants-advisor/reference/10-corpus-winners.md +135 -0
  111. package/skills/stellar-scf-grants-advisor/reference/11-corpus-rejects.md +267 -0
  112. package/skills/stellar-scf-grants-advisor/reference/12-client-communication.md +131 -0
  113. package/skills/stellar-scf-grants-advisor/reference/13-excel-output-spec.md +199 -0
  114. package/skills/stellar-scf-grants-advisor/reference/14-worked-examples.md +160 -0
  115. package/skills/stellar-scf-grants-advisor/templates/abstract-review-builder.py +253 -0
  116. package/skills/stellar-scf-grants-advisor/templates/build-review-builder.py +213 -0
  117. package/skills/video-direction/video-direction.skill.json +20 -0
  118. package/skills/video-style-vocabulary/video-style-vocabulary.skill.json +20 -0
  119. package/skills/video-toolbox/video-toolbox.skill.json +20 -0
  120. package/src/__fixtures__/lifecycle-presets.flat-before.json +205 -0
  121. package/src/agency-os.yaml +122 -0
  122. package/src/agent-os-skill-slugs.test.ts +65 -0
  123. package/src/apify-social-reader.test.ts +317 -0
  124. package/src/base.yaml +85 -39
  125. package/src/blockchain-ecosystem.yaml +1 -0
  126. package/src/brand-library.yaml +525 -14
  127. package/src/builder-dev-fold.template.test.ts +113 -0
  128. package/src/builder.yaml +779 -91
  129. package/src/business-model-catalog-description.test.ts +47 -0
  130. package/src/business-model-grp.template.test.ts +214 -0
  131. package/src/business-model.yaml +296 -49
  132. package/src/catalog-safety.test.ts +198 -0
  133. package/src/catalog.template-items.test.ts +75 -0
  134. package/src/catalog.ts +66 -2
  135. package/src/concept-guard.test.ts +28 -8
  136. package/src/concept-guard.ts +2 -2
  137. package/src/content-creation.template.test.ts +52 -0
  138. package/src/content-creation.yaml +192 -0
  139. package/src/content-os.edit-loop.template.test.ts +210 -0
  140. package/src/content-os.publish-due-posts.template.test.ts +261 -0
  141. package/src/content-os.template.test.ts +349 -0
  142. package/src/content-os.video-takes.template.test.ts +338 -0
  143. package/src/content-os.work-a-take.template.test.ts +125 -0
  144. package/src/content-os.yaml +1873 -39
  145. package/src/content-studio-retired.template.test.ts +82 -0
  146. package/src/corpus-flow-validity.test.ts +4 -5
  147. package/src/crm-absorbs-outreach.template.test.ts +117 -0
  148. package/src/crm-build-plan.template.test.ts +128 -0
  149. package/src/crm-lists.template.test.ts +96 -0
  150. package/src/crm-messages-cadence.template.test.ts +246 -0
  151. package/src/crm-one-send-door.template.test.ts +65 -0
  152. package/src/crm.yaml +1563 -181
  153. package/src/decisions-wave.template.test.ts +186 -0
  154. package/src/define.ts +146 -17
  155. package/src/design-to-implementation.template.test.ts +94 -0
  156. package/src/domain-template-type.test.ts +75 -0
  157. package/src/ecosystem.yaml +27 -66
  158. package/src/enterprise-os.yaml +10 -134
  159. package/src/facecam-edit.audio-studio.test.ts +188 -0
  160. package/src/fal-generate-image.test.ts +200 -0
  161. package/src/fal-media-lab-pod-files.test.ts +180 -0
  162. package/src/finance.yaml +254 -1
  163. package/src/foundation.yaml +78 -38
  164. package/src/frame-host-modules.d.mts +6 -0
  165. package/src/frame-host-modules.mjs +58 -0
  166. package/src/generate.mjs +9 -3
  167. package/src/github-merge.test.ts +210 -0
  168. package/src/grants.yaml +46 -17
  169. package/src/hr.yaml +39 -6
  170. package/src/index.ts +36 -1
  171. package/src/intent.test.ts +161 -0
  172. package/src/internal-runbook.yaml +19 -1
  173. package/src/jev.test.ts +356 -0
  174. package/src/legal.yaml +33 -1
  175. package/src/life-os.yaml +51 -240
  176. package/src/lifecycle-coverage.test.ts +124 -0
  177. package/src/lifecycle-declarations.test.ts +252 -0
  178. package/src/lifecycle-presets.test.ts +468 -0
  179. package/src/lifecycle-presets.ts +494 -0
  180. package/src/lifecycle-stuck.test.ts +46 -0
  181. package/src/lifecycle-waits.parity.test.ts +319 -0
  182. package/src/marketing.yaml +108 -4
  183. package/src/meetings-knowledge.yaml +18 -0
  184. package/src/networking.yaml +23 -2
  185. package/src/operations.yaml +304 -4
  186. package/src/pipeline-views.template.test.ts +88 -0
  187. package/src/playbook-goal-placeholders.test.ts +57 -0
  188. package/src/postiz-contract.test.ts +134 -0
  189. package/src/presentation-declarations.test.ts +174 -0
  190. package/src/process-contract.validate.test.ts +352 -0
  191. package/src/project-management.yaml +39 -740
  192. package/src/publish-body.d.mts +29 -0
  193. package/src/publish-body.mjs +74 -0
  194. package/src/publish-body.test.ts +74 -0
  195. package/src/publish-official-lib.test.ts +176 -0
  196. package/src/replicate-rvm.test.ts +504 -0
  197. package/src/research-base.yaml +119 -20
  198. package/src/research-decision.yaml +60 -3
  199. package/src/reserved-profile-slugs.test.ts +81 -0
  200. package/src/retired-goal-kinds.test.ts +52 -0
  201. package/src/role-reference-and-step-domain.test.ts +192 -0
  202. package/src/seed-obligation.test.ts +1 -6
  203. package/src/send-message-maps.test.ts +227 -0
  204. package/src/shared-role-ssot.test.ts +40 -2
  205. package/src/ship-a-change.template.test.ts +177 -0
  206. package/src/skills.test.ts +170 -0
  207. package/src/social.yaml +85 -27
  208. package/src/space-packages.freshness.test.ts +97 -0
  209. package/src/space-packages.generated.ts +40 -0
  210. package/src/space-packages.test.ts +125 -0
  211. package/src/space-packages.ts +73 -0
  212. package/src/start.test.ts +188 -0
  213. package/src/stripe-capability.test.ts +192 -0
  214. package/src/task-intents.test.ts +293 -0
  215. package/src/template-documents.test.ts +158 -0
  216. package/src/templates.ts +20907 -21464
  217. package/src/types.ts +475 -61
  218. package/src/unipile-linkedin-find-profile.test.ts +183 -0
  219. package/src/unipile-publish-post.test.ts +162 -0
  220. package/src/validate-flow.drift.test.ts +2 -3
  221. package/src/validate-flow.ts +22 -2
  222. package/src/validate-onboarding.test.ts +59 -0
  223. package/src/validate.test.ts +71 -4
  224. package/src/validate.ts +1416 -7
  225. package/src/wire-core.ts +231 -0
  226. package/src/wire.test.ts +159 -0
  227. package/src/wire.ts +107 -0
  228. package/views/bookmark-views-pack.view.json +39 -0
  229. package/views/event-views-pack.view.json +45 -0
  230. package/views/task-views-pack.view.json +53 -0
  231. package/src/agent-fleet.yaml +0 -1645
  232. package/src/business-developer.template.test.ts +0 -351
  233. package/src/business-developer.yaml +0 -860
  234. package/src/content-studio.yaml +0 -361
  235. package/src/dev-dashboard.yaml +0 -990
  236. package/src/outreach-comms.yaml +0 -486
  237. package/src/the-arch.yaml +0 -201
@@ -0,0 +1,277 @@
1
+ {
2
+ "apiVersion": "synap/v1",
3
+ "kind": "capability",
4
+ "meta": {
5
+ "slug": "mail-feed",
6
+ "name": "Mail Feed — Gmail Triage",
7
+ "description": "Every two hours, checks recent Gmail, skips blocked senders, sorts the rest and posts one line per relevant email to its own channel. Needs the Google Workspace connector.",
8
+ "tags": [
9
+ "capability"
10
+ ],
11
+ "isPublic": true,
12
+ "syncByDefault": true
13
+ },
14
+ "spec": {
15
+ "key": "mail-feed",
16
+ "name": "Mail Feed",
17
+ "description": "Config-first mail feed: every 2 hours, search recent Gmail, drop denied senders, triage the rest with AI, and post one line per relevant email into the automation's own run channel. This is the SHADOW form of the bespoke run-mail-feed worker (packages/api/src/services/mail-feed/run-mail-feed.ts) — same verb pipeline (gmail_search -> ai.triage -> post), expressed purely as an automation flow so it can be dogfooded for parity BEFORE the live worker is retired. Because the output channel_message is TARGETLESS it posts to this automation's run channel, so it never collides with the live worker's Discord-bound feed channel. POST-SIGNOFF CUTOVER (do NOT do now): retarget the `post` node to the real team channel via a `channel.resolve` -> channel_message pair (see client-comms-report.capability.json) and delete run-mail-feed.ts + its mail-feed-cron shim.",
18
+ "params": [],
19
+ "vault": [],
20
+ "tools": [],
21
+ "skills": [],
22
+ "provides": [],
23
+ "playbooks": [],
24
+ "automations": [
25
+ {
26
+ "name": "Mail Feed — Shadow",
27
+ "description": "Every 2h: gmail_search -> deny-gate (not-in) -> ai.triage -> keep relevant -> post one line each into this automation's OWN run channel (shadow-separated from the live worker). Advances a watermark cursor and nudges if the Google connector is dead. Seeded ACTIVE so the cron actually schedules (a draft never gets a nextRunAt). CUTOVER: retarget `post` to the team channel + delete run-mail-feed once parity is confirmed.",
28
+ "triggerType": "cron",
29
+ "triggerConfig": {
30
+ "expression": "0 */2 * * *"
31
+ },
32
+ "status": "active",
33
+ "state": {
34
+ "gmailQuery": "newer_than:2h",
35
+ "senderDeny": [],
36
+ "mutedCategories": [],
37
+ "lastProcessedMs": 0
38
+ },
39
+ "metadata": {
40
+ "shadowOf": "run-mail-feed",
41
+ "kind": "mail-feed"
42
+ },
43
+ "flowDefinition": {
44
+ "nodes": [
45
+ {
46
+ "id": "trigger",
47
+ "type": "trigger",
48
+ "position": {
49
+ "x": 0,
50
+ "y": 0
51
+ },
52
+ "data": {
53
+ "triggerType": "cron",
54
+ "label": "Every 2 hours",
55
+ "config": {
56
+ "expression": "0 */2 * * *"
57
+ }
58
+ }
59
+ },
60
+ {
61
+ "id": "gmail-search",
62
+ "type": "capability",
63
+ "position": {
64
+ "x": 0,
65
+ "y": 120
66
+ },
67
+ "data": {
68
+ "label": "Search recent Gmail",
69
+ "verbId": "gmail_search",
70
+ "inputMapping": {
71
+ "query": "{{automation.state.gmailQuery}}",
72
+ "maxResults": "25"
73
+ },
74
+ "_note": "The `newer_than:2h` query window IS the config-expressible dedup for a 2-hourly cron — run-mail-feed's per-email isNewerThanWatermark filter is NOT expressible as a single transform node today (resolveTemplate has no pipe support, the transform `|` split collides inside a filter predicate, gmail_search results carry no `dateMs`, and there is no per-item field-merge pipe). continueOnError so a dead token still reaches the connector health check below instead of aborting the run.",
75
+ "errorHandling": {
76
+ "continueOnError": true
77
+ }
78
+ }
79
+ },
80
+ {
81
+ "id": "deny-gate",
82
+ "type": "transform",
83
+ "position": {
84
+ "x": 0,
85
+ "y": 240
86
+ },
87
+ "data": {
88
+ "label": "Drop denied senders (deny-wins)",
89
+ "expression": "{{steps.gmail-search.output.results}} | filter:item.from not-in automation.state.senderDeny",
90
+ "_note": "Ports passesSenderFilters' deny half via the `not-in` membership operator: keep an email when its `from` is NOT in the seeded senderDeny list. The ALLOW half (`senderAllow` = if non-empty, keep only matches) is NOT ported — an `in` filter against an EMPTY allow-list would drop every email, and the conditional 'only when non-empty' is not expressible as one predicate."
91
+ }
92
+ },
93
+ {
94
+ "id": "triage",
95
+ "type": "capability",
96
+ "position": {
97
+ "x": 0,
98
+ "y": 360
99
+ },
100
+ "data": {
101
+ "label": "AI triage (relevance + category + summary)",
102
+ "verbId": "ai.triage",
103
+ "inputMapping": {
104
+ "emails": "{{steps.deny-gate.output.result}}",
105
+ "mutedCategories": "{{automation.state.mutedCategories}}"
106
+ },
107
+ "errorHandling": {
108
+ "continueOnError": true
109
+ }
110
+ }
111
+ },
112
+ {
113
+ "id": "relevant-only",
114
+ "type": "transform",
115
+ "position": {
116
+ "x": 0,
117
+ "y": 480
118
+ },
119
+ "data": {
120
+ "label": "Keep only relevant emails",
121
+ "expression": "{{steps.triage.output.results}} | filter:item.relevant == 'true'"
122
+ }
123
+ },
124
+ {
125
+ "id": "mail-loop",
126
+ "type": "loop",
127
+ "position": {
128
+ "x": 0,
129
+ "y": 600
130
+ },
131
+ "data": {
132
+ "label": "For each relevant email",
133
+ "iteratorExpression": "steps.relevant-only.output.result",
134
+ "itemVariable": "email"
135
+ }
136
+ },
137
+ {
138
+ "id": "post",
139
+ "type": "output",
140
+ "position": {
141
+ "x": 200,
142
+ "y": 720
143
+ },
144
+ "data": {
145
+ "label": "Post one line into the run channel (TARGETLESS = shadow-separated)",
146
+ "outputType": "channel_message",
147
+ "config": {
148
+ "content": "**{{loop.item.category}}** — {{loop.item.summary}}\n{{loop.item.suggestedAction}}",
149
+ "metadata": {
150
+ "automationMessage": true,
151
+ "kind": "mail-feed"
152
+ }
153
+ },
154
+ "_note": "TARGETLESS on purpose: no channelId/channelType, so the executor posts to this automation's OWN run channel — automatic separation from the live worker's Discord-bound feed. Subject/from/gmail-link enrichment (run-mail-feed's buildMailMessage) is NOT ported: it needs a join from the triage result back to the original email by id, which is not expressible in-flow; the triage summary line stands in.",
155
+ "errorHandling": {
156
+ "continueOnError": true
157
+ }
158
+ }
159
+ },
160
+ {
161
+ "id": "compute-now",
162
+ "type": "compute",
163
+ "position": {
164
+ "x": -200,
165
+ "y": 720
166
+ },
167
+ "data": {
168
+ "label": "Run timestamp",
169
+ "operation": "now"
170
+ }
171
+ },
172
+ {
173
+ "id": "watermark-ms",
174
+ "type": "transform",
175
+ "position": {
176
+ "x": -200,
177
+ "y": 840
178
+ },
179
+ "data": {
180
+ "label": "Run timestamp -> epoch ms",
181
+ "expression": "{{steps.compute-now.output.result}} | to_ms"
182
+ }
183
+ },
184
+ {
185
+ "id": "set-watermark",
186
+ "type": "output",
187
+ "position": {
188
+ "x": -200,
189
+ "y": 960
190
+ },
191
+ "data": {
192
+ "label": "Advance the watermark cursor (runs even when all filtered)",
193
+ "outputType": "set_state",
194
+ "config": {
195
+ "lastProcessedMs": "{{steps.watermark-ms.output.result}}"
196
+ },
197
+ "_note": "Ports the atomic single-leaf watermark advance (one key merged via set_state's `state || patch` jsonb). Placed on the main spine (not in the loop) so it advances once per run regardless of how many emails survived — mirroring run-mail-feed advancing past an all-filtered batch. The cursor is recorded for auditability + forward-compat; it is not yet consumed by the query (see gmail-search _note)."
198
+ }
199
+ },
200
+ {
201
+ "id": "health-check",
202
+ "type": "capability",
203
+ "position": {
204
+ "x": -200,
205
+ "y": 1080
206
+ },
207
+ "data": {
208
+ "label": "Nudge if the Google connector is dead",
209
+ "verbId": "connector.health_check",
210
+ "inputMapping": {
211
+ "provider": "google",
212
+ "connectorName": "Google Workspace",
213
+ "reconnectHint": "Reconnect it in the app (Settings -> Connectors) or run `/connect provider:google` in Discord.",
214
+ "probeVerbId": "gmail_search"
215
+ },
216
+ "_note": "Ports the connector-health nudge: probes gmail_search and, on an auth error, nudges the operator once per cooldown (deduped on the pod's discord tool) instead of the feed going silently dead."
217
+ }
218
+ }
219
+ ],
220
+ "edges": [
221
+ {
222
+ "id": "e-trigger",
223
+ "source": "trigger",
224
+ "target": "gmail-search"
225
+ },
226
+ {
227
+ "id": "e-search",
228
+ "source": "gmail-search",
229
+ "target": "deny-gate"
230
+ },
231
+ {
232
+ "id": "e-deny",
233
+ "source": "deny-gate",
234
+ "target": "triage"
235
+ },
236
+ {
237
+ "id": "e-triage",
238
+ "source": "triage",
239
+ "target": "relevant-only"
240
+ },
241
+ {
242
+ "id": "e-loop",
243
+ "source": "relevant-only",
244
+ "target": "mail-loop"
245
+ },
246
+ {
247
+ "id": "e-post",
248
+ "source": "mail-loop",
249
+ "target": "post"
250
+ },
251
+ {
252
+ "id": "e-now",
253
+ "source": "relevant-only",
254
+ "target": "compute-now"
255
+ },
256
+ {
257
+ "id": "e-ms",
258
+ "source": "compute-now",
259
+ "target": "watermark-ms"
260
+ },
261
+ {
262
+ "id": "e-set",
263
+ "source": "watermark-ms",
264
+ "target": "set-watermark"
265
+ },
266
+ {
267
+ "id": "e-health",
268
+ "source": "set-watermark",
269
+ "target": "health-check"
270
+ }
271
+ ]
272
+ }
273
+ }
274
+ ]
275
+ },
276
+ "dependencies": []
277
+ }
@@ -0,0 +1,52 @@
1
+ {
2
+ "apiVersion": "synap/v1",
3
+ "kind": "capability",
4
+ "meta": {
5
+ "slug": "mailgun",
6
+ "name": "Mailgun Inbound Email",
7
+ "description": "Brings client emails into Synap: Mailgun forwards incoming mail to your pod, which verifies it and files each message under the matching client. Also works for Proton Mail via auto-forward. Inbound only. Needs a Mailgun inbound route and webhook signing key.",
8
+ "tags": [
9
+ "capability"
10
+ ],
11
+ "isPublic": true,
12
+ "syncByDefault": true
13
+ },
14
+ "spec": {
15
+ "key": "mailgun",
16
+ "name": "Mailgun Inbound Email",
17
+ "description": "Client emails land in the pod's channel/message substrate, queryable by the AI (The Arch Wave 5). Registers a Mailgun HTTP webhook-signing key in the vault (NOT an SMTP send credential — v1 is inbound-only) plus a minimal `mailgun` tool row so an outbound send-as capability can be layered on later without a second connector. The actual ingestion is a BESPOKE pod route (POST /api/webhooks/mailgun/:token, not a generic skill) because it has to parse Mailgun's multipart 'Parsed' inbound payload and verify Mailgun's own timestamp+token HMAC scheme before landing the email as a channel message via recordInboundMessage. ALSO COVERS PROTON MAIL: a Proton user sets an auto-forward rule from their Proton inbox to the Mailgun-provisioned catch-all inbound address, so a Proton client's email reaches the same pipeline as a native Mailgun route address. PRECONDITION: a Mailgun account with an inbound Route configured to forward to POST https://<pod>/api/webhooks/mailgun/<token>, and the account's HTTP webhook signing key (Sending -> Webhooks -> HTTP webhook signing key, shared across all webhook types). Pass it as `mailgunSigningKey`. INBOUND WEBHOOK: Mailgun POSTs multipart/form-data per delivered message (sender, recipient, subject, body-plain, stripped-text, Message-Id, From, Reply-To); the pod verifies `signature == hex(HMAC-SHA256(key=signingKey, msg=timestamp+token))` fail-closed, dedups on Message-Id, resolves the sender's email via strong-signal identity resolution to an existing client entity (one channel PER CLIENT, not per thread) — falling back to the sender email itself (unlinked review-queue channel) when unresolved — and lands the message via recordInboundMessage. FORWARDING LIMITATION: a Proton forward normally preserves the `From` header even though the envelope `sender` is rewritten to the forwarding relay, so the mapper prefers From > Reply-To > envelope sender; a forward that also rewrites From (e.g. SRS/'resend as new') cannot be attributed and lands unlinked. The webhook config is provisioned at install/config time (NOT template-seeded) under `tools.metadata.mailgun.webhook = { token, secretVaultRef, workspaceId?, ownerUserId?, seen:{} }`; the `:token` selects+authorizes the config (unknown -> 404, no enumeration leak).",
18
+ "params": [
19
+ {
20
+ "name": "mailgunSigningKey",
21
+ "label": "Mailgun HTTP webhook signing key",
22
+ "type": "text",
23
+ "required": true,
24
+ "description": "The Mailgun account's HTTP webhook signing key (Sending -> Webhooks -> HTTP webhook signing key). Used to verify inbound webhook signatures; NOT an API key. Stored server-encrypted in the vault; never persisted in the template."
25
+ }
26
+ ],
27
+ "vault": [
28
+ {
29
+ "ref": "mailgunSigningKeySecret",
30
+ "name": "{{name}} Mailgun webhook signing key",
31
+ "value": "{{mailgunSigningKey}}",
32
+ "type": "api_key",
33
+ "description": "Mailgun HTTP webhook signing key used to verify inbound-route webhook signatures for the mailgun connector."
34
+ }
35
+ ],
36
+ "tools": [
37
+ {
38
+ "name": "mailgun",
39
+ "kind": "api",
40
+ "description": "Mailgun connector. v1 is INBOUND-ONLY: `credentialRef` holds the webhook SIGNING key, consumed directly by the pod's /api/webhooks/mailgun/:token route to verify inbound signatures — it is NOT used for outbound HTTP auth (no skill calls this tool yet). `config.baseUrl` is recorded only as a placeholder for a future outbound send-as skill (Mailgun Messages API, region-specific: https://api.mailgun.net/v3 US or https://api.eu.mailgun.net/v3 EU). GOTCHA for that future skill: Mailgun's outbound API auth is HTTP Basic with username `api` and password = a separate Mailgun API KEY (Settings -> API Keys) — NOT this signing key and NOT wired here; it would need its own vault secret + credentialRef.",
41
+ "credentialRef": "mailgunSigningKeySecret",
42
+ "executor": "is-agent",
43
+ "config": {
44
+ "baseUrl": "https://api.mailgun.net/v3"
45
+ }
46
+ }
47
+ ],
48
+ "skills": [],
49
+ "provides": []
50
+ },
51
+ "dependencies": []
52
+ }