@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,467 @@
1
+ {
2
+ "apiVersion": "synap/v1",
3
+ "kind": "capability",
4
+ "meta": {
5
+ "slug": "postiz",
6
+ "name": "Post to social networks",
7
+ "description": "Drafts, schedules, or publishes a post through your Postiz account. You approve every send. The social accounts stay in Postiz. Needs a Postiz API key.",
8
+ "tags": [
9
+ "capability",
10
+ "publish_post"
11
+ ],
12
+ "isPublic": true,
13
+ "syncByDefault": true
14
+ },
15
+ "spec": {
16
+ "key": "postiz",
17
+ "name": "Post to social networks",
18
+ "description": "List the user's Postiz channels and posts, and draft, schedule or publish posts with media through their Postiz (cloud or self-hosted). Tokens stay in Postiz.",
19
+ "params": [
20
+ {
21
+ "name": "postizApiKey",
22
+ "label": "Postiz API key",
23
+ "type": "text",
24
+ "required": true,
25
+ "description": "API key from the user's Postiz (Settings → API Keys). Sent as the Authorization header value. Stored server-encrypted in the vault; never persisted in the template."
26
+ },
27
+ {
28
+ "name": "postizBaseUrl",
29
+ "label": "Postiz API origin",
30
+ "type": "text",
31
+ "required": false,
32
+ "default": "https://api.postiz.com",
33
+ "description": "Where your Postiz public API lives, without /public/v1. Postiz Cloud: https://api.postiz.com (the default). Self-hosted: your Postiz address followed by /api, e.g. https://postiz.example.com/api, because a self-hosted Postiz serves its public API at /api/public/v1. Not a shared Synap broker. Docs: https://docs.postiz.com/public-api/introduction"
34
+ }
35
+ ],
36
+ "vault": [
37
+ {
38
+ "ref": "postizApiKeySecret",
39
+ "name": "{{name}} Postiz API key",
40
+ "value": "{{postizApiKey}}",
41
+ "type": "api_key",
42
+ "description": "Postiz API key for the postiz connector. The applier remaps this template-local ref to vault://<id>."
43
+ }
44
+ ],
45
+ "tools": [
46
+ {
47
+ "name": "postiz",
48
+ "kind": "api",
49
+ "description": "Authenticated HTTP access to the user's Postiz public API. baseUrl is {{postizBaseUrl}}. Authorization is the raw API key with an empty prefix — Postiz does not use the Bearer scheme (https://docs.postiz.com/public-api/introduction). credentialRef is remapped to vault://<id> at apply.",
50
+ "credentialRef": "postizApiKeySecret",
51
+ "executor": "is-agent",
52
+ "config": {
53
+ "baseUrl": "{{postizBaseUrl}}",
54
+ "auth": {
55
+ "in": "header",
56
+ "name": "Authorization",
57
+ "prefix": ""
58
+ }
59
+ }
60
+ }
61
+ ],
62
+ "skills": [
63
+ {
64
+ "name": "postiz_draft",
65
+ "intent": "publish_post",
66
+ "kind": "declarative",
67
+ "scope": "pod",
68
+ "description": "Creates a Postiz draft (type \"draft\") on one connected channel. Write: POST /public/v1/posts. Does not publish. Body matches https://docs.postiz.com/public-api/posts/create — type, date, shortLink, tags, and posts[{integration.id, value[].content, settings.__type}]. Args: { content: string, integrationId: string, provider: string (settings.__type, e.g. x or linkedin), date?: ISO-8601 (defaults to now; drafts ignore publish time) }. Text only, and only for a channel whose Postiz settings need nothing but the provider (LinkedIn, Facebook, Threads, Bluesky, Mastodon, Telegram…). With media, or on X, Instagram, YouTube, TikTok, Pinterest, Reddit and the other channels whose settings require more, use postiz_schedule_post.",
69
+ "requires": [
70
+ "postiz"
71
+ ],
72
+ "executionMode": "sync",
73
+ "timeoutSeconds": 60,
74
+ "metadata": {
75
+ "verbType": "write"
76
+ },
77
+ "parameters": {
78
+ "content": "string",
79
+ "integrationId": "string",
80
+ "provider": "string",
81
+ "date": "string?"
82
+ },
83
+ "providerSpec": {
84
+ "tool": "postiz",
85
+ "method": "POST",
86
+ "pathTemplate": "/public/v1/posts",
87
+ "body": {
88
+ "type": "draft",
89
+ "date": "{{date}}",
90
+ "shortLink": false,
91
+ "tags": [],
92
+ "posts": [
93
+ {
94
+ "integration": {
95
+ "id": "{{integrationId}}"
96
+ },
97
+ "value": [
98
+ {
99
+ "content": "{{content}}",
100
+ "image": []
101
+ }
102
+ ],
103
+ "settings": {
104
+ "__type": "{{provider}}"
105
+ }
106
+ }
107
+ ]
108
+ },
109
+ "paramMapping": {
110
+ "content": {
111
+ "required": true
112
+ },
113
+ "integrationId": {
114
+ "required": true
115
+ },
116
+ "provider": {
117
+ "required": true
118
+ },
119
+ "date": {
120
+ "default": "@now"
121
+ }
122
+ },
123
+ "responseShape": {
124
+ "collectionPath": "",
125
+ "collectionAs": "posts",
126
+ "item": {
127
+ "postId": "postId",
128
+ "integration": "integration"
129
+ }
130
+ }
131
+ }
132
+ },
133
+ {
134
+ "name": "postiz_schedule",
135
+ "intent": "publish_post",
136
+ "kind": "declarative",
137
+ "scope": "pod",
138
+ "description": "Schedules a Postiz post (type \"schedule\") on one connected channel. Write: POST /public/v1/posts. Body matches https://docs.postiz.com/public-api/posts/create. Args: { content: string, integrationId: string, provider: string (settings.__type), date: ISO-8601 publish time }. Text only, and only for a channel whose Postiz settings need nothing but the provider (LinkedIn, Facebook, Threads, Bluesky, Mastodon, Telegram…). With media, or on X, Instagram, YouTube, TikTok, Pinterest, Reddit and the other channels whose settings require more, use postiz_schedule_post.",
139
+ "requires": [
140
+ "postiz"
141
+ ],
142
+ "executionMode": "sync",
143
+ "timeoutSeconds": 60,
144
+ "metadata": {
145
+ "verbType": "write"
146
+ },
147
+ "parameters": {
148
+ "content": "string",
149
+ "integrationId": "string",
150
+ "provider": "string",
151
+ "date": "string"
152
+ },
153
+ "inputMap": {
154
+ "params": {
155
+ "content": "$.text",
156
+ "date": "$.when",
157
+ "integrationId": "$account.id",
158
+ "provider": "$account.provider"
159
+ },
160
+ "accounts": {
161
+ "verb": "postiz_list_integrations",
162
+ "id": "id",
163
+ "label": "name",
164
+ "provider": "provider"
165
+ }
166
+ },
167
+ "providerSpec": {
168
+ "tool": "postiz",
169
+ "method": "POST",
170
+ "pathTemplate": "/public/v1/posts",
171
+ "body": {
172
+ "type": "schedule",
173
+ "date": "{{date}}",
174
+ "shortLink": false,
175
+ "tags": [],
176
+ "posts": [
177
+ {
178
+ "integration": {
179
+ "id": "{{integrationId}}"
180
+ },
181
+ "value": [
182
+ {
183
+ "content": "{{content}}",
184
+ "image": []
185
+ }
186
+ ],
187
+ "settings": {
188
+ "__type": "{{provider}}"
189
+ }
190
+ }
191
+ ]
192
+ },
193
+ "paramMapping": {
194
+ "content": {
195
+ "required": true
196
+ },
197
+ "integrationId": {
198
+ "required": true
199
+ },
200
+ "provider": {
201
+ "required": true
202
+ },
203
+ "date": {
204
+ "required": true
205
+ }
206
+ },
207
+ "responseShape": {
208
+ "collectionPath": "",
209
+ "collectionAs": "posts",
210
+ "item": {
211
+ "postId": "postId",
212
+ "integration": "integration"
213
+ }
214
+ }
215
+ }
216
+ },
217
+ {
218
+ "name": "postiz_publish",
219
+ "intent": "publish_post",
220
+ "kind": "declarative",
221
+ "scope": "pod",
222
+ "description": "Publishes a Postiz post immediately (type \"now\"; the API has no type \"publish\"). Write: POST /public/v1/posts. Body matches https://docs.postiz.com/public-api/posts/create. Args: { content: string, integrationId: string, provider: string (settings.__type), date?: ISO-8601 (required by the API, ignored for type now, defaults to now) }. Text only, and only for a channel whose Postiz settings need nothing but the provider (LinkedIn, Facebook, Threads, Bluesky, Mastodon, Telegram…). With media, or on X, Instagram, YouTube, TikTok, Pinterest, Reddit and the other channels whose settings require more, use postiz_schedule_post.",
223
+ "requires": [
224
+ "postiz"
225
+ ],
226
+ "executionMode": "sync",
227
+ "timeoutSeconds": 60,
228
+ "metadata": {
229
+ "verbType": "write"
230
+ },
231
+ "parameters": {
232
+ "content": "string",
233
+ "integrationId": "string",
234
+ "provider": "string",
235
+ "date": "string?"
236
+ },
237
+ "inputMap": {
238
+ "params": {
239
+ "content": "$.text",
240
+ "integrationId": "$account.id",
241
+ "provider": "$account.provider"
242
+ },
243
+ "accounts": {
244
+ "verb": "postiz_list_integrations",
245
+ "id": "id",
246
+ "label": "name",
247
+ "provider": "provider"
248
+ }
249
+ },
250
+ "providerSpec": {
251
+ "tool": "postiz",
252
+ "method": "POST",
253
+ "pathTemplate": "/public/v1/posts",
254
+ "body": {
255
+ "type": "now",
256
+ "date": "{{date}}",
257
+ "shortLink": false,
258
+ "tags": [],
259
+ "posts": [
260
+ {
261
+ "integration": {
262
+ "id": "{{integrationId}}"
263
+ },
264
+ "value": [
265
+ {
266
+ "content": "{{content}}",
267
+ "image": []
268
+ }
269
+ ],
270
+ "settings": {
271
+ "__type": "{{provider}}"
272
+ }
273
+ }
274
+ ]
275
+ },
276
+ "paramMapping": {
277
+ "content": {
278
+ "required": true
279
+ },
280
+ "integrationId": {
281
+ "required": true
282
+ },
283
+ "provider": {
284
+ "required": true
285
+ },
286
+ "date": {
287
+ "default": "@now"
288
+ }
289
+ },
290
+ "responseShape": {
291
+ "collectionPath": "",
292
+ "collectionAs": "posts",
293
+ "item": {
294
+ "postId": "postId",
295
+ "integration": "integration"
296
+ }
297
+ }
298
+ }
299
+ },
300
+ {
301
+ "name": "postiz_list_integrations",
302
+ "intent": "list_records",
303
+ "kind": "declarative",
304
+ "scope": "pod",
305
+ "description": "Lists the social channels connected in Postiz: id (the integrationId every post needs), name, provider (the identifier a post's settings use: x, linkedin, instagram, …), profile handle, picture, disabled, and the Postiz customer it belongs to. Read-only. GET /public/v1/integrations. Store id and provider on the matching Synap platform as postiz-integration-id and postiz-provider. Args: none.",
306
+ "requires": [
307
+ "postiz"
308
+ ],
309
+ "executionMode": "sync",
310
+ "timeoutSeconds": 30,
311
+ "metadata": {
312
+ "readOnly": true
313
+ },
314
+ "parameters": {},
315
+ "providerSpec": {
316
+ "tool": "postiz",
317
+ "method": "GET",
318
+ "pathTemplate": "/public/v1/integrations",
319
+ "responseShape": {
320
+ "collectionPath": "",
321
+ "collectionAs": "channels",
322
+ "item": {
323
+ "id": "id",
324
+ "name": "name",
325
+ "provider": "identifier",
326
+ "profile": "profile",
327
+ "picture": "picture",
328
+ "disabled": "disabled",
329
+ "customerId": "customer.id",
330
+ "customerName": "customer.name"
331
+ }
332
+ }
333
+ }
334
+ },
335
+ {
336
+ "name": "postiz_list_posts",
337
+ "intent": "list_records",
338
+ "kind": "declarative",
339
+ "scope": "pod",
340
+ "description": "Lists the Postiz posts in a date range: id, content, publishDate, state (QUEUE, PUBLISHED, ERROR, DRAFT), releaseURL once live, the platform's error when it failed, and the channel (integrationId, provider, channelName). Read-only. GET /public/v1/posts. Args: { endDate: ISO-8601, startDate?: ISO-8601 (defaults to now), customer?: Postiz customer id }.",
341
+ "requires": [
342
+ "postiz"
343
+ ],
344
+ "executionMode": "sync",
345
+ "timeoutSeconds": 30,
346
+ "metadata": {
347
+ "readOnly": true
348
+ },
349
+ "parameters": {
350
+ "startDate": "string?",
351
+ "endDate": "string",
352
+ "customer": "string?"
353
+ },
354
+ "providerSpec": {
355
+ "tool": "postiz",
356
+ "method": "GET",
357
+ "pathTemplate": "/public/v1/posts",
358
+ "query": {
359
+ "startDate": "{{startDate}}",
360
+ "endDate": "{{endDate}}",
361
+ "customer": "{{customer}}"
362
+ },
363
+ "paramMapping": {
364
+ "startDate": {
365
+ "default": "@now"
366
+ },
367
+ "endDate": {
368
+ "required": true
369
+ }
370
+ },
371
+ "responseShape": {
372
+ "collectionPath": "posts",
373
+ "collectionAs": "posts",
374
+ "item": {
375
+ "id": "id",
376
+ "content": "content",
377
+ "publishDate": "publishDate",
378
+ "state": "state",
379
+ "releaseURL": "releaseURL",
380
+ "error": "error",
381
+ "integrationId": "integration.id",
382
+ "provider": "integration.providerIdentifier",
383
+ "channelName": "integration.name"
384
+ }
385
+ }
386
+ }
387
+ },
388
+ {
389
+ "name": "postiz_upload_from_url",
390
+ "intent": "manage_file",
391
+ "kind": "declarative",
392
+ "scope": "pod",
393
+ "description": "Stores one file in the Postiz media library from a link Postiz downloads itself (an https URL, e.g. a signed link to a pod file). Returns { id, path, name }: a post's media is [{id, path}]. Writes to Postiz but publishes nothing. POST /public/v1/upload-from-url. postiz_schedule_post already uploads its mediaUrls; use this to stage a file on its own. Args: { url: string }.",
394
+ "requires": [
395
+ "postiz"
396
+ ],
397
+ "executionMode": "sync",
398
+ "timeoutSeconds": 120,
399
+ "metadata": {
400
+ "verbType": "write"
401
+ },
402
+ "parameters": {
403
+ "url": "string"
404
+ },
405
+ "providerSpec": {
406
+ "tool": "postiz",
407
+ "method": "POST",
408
+ "pathTemplate": "/public/v1/upload-from-url",
409
+ "body": {
410
+ "url": "{{url}}"
411
+ },
412
+ "paramMapping": {
413
+ "url": {
414
+ "required": true
415
+ }
416
+ },
417
+ "responseShape": {
418
+ "scalar": {
419
+ "id": "id",
420
+ "path": "path",
421
+ "name": "name"
422
+ }
423
+ }
424
+ }
425
+ },
426
+ {
427
+ "name": "postiz_schedule_post",
428
+ "intent": "publish_post",
429
+ "kind": "code",
430
+ "scope": "pod",
431
+ "description": "Queues one post on one Postiz channel, with media. Uploads each mediaUrls link to Postiz (POST /public/v1/upload-from-url), then creates the post (POST /public/v1/posts) with its media as image:[{id, path}]. type draft saves it in Postiz without sending, schedule sends it at date, now sends it at once. Publishes, so an agent's run is always a proposal a person approves. Returns { postId, integrationId, provider, type, date, media, postEntityId }: with postEntityId set, the pod records postId on that post as postiz-post-id once the run succeeds (metadata.writeBack). Args: { content: string, integrationId: string and provider: string (a channel's id and provider from postiz_list_integrations, or the post's account: postiz-integration-id and postiz-provider), type?: draft | schedule | now (default schedule), date?: ISO-8601 (required to schedule), mediaUrls?: string[] (https links Postiz can download, in order), settings?: object (provider settings, e.g. YouTube title and type; X and Instagram get defaults), postEntityId?: string (the Synap post, echoed back) }.",
432
+ "requires": [
433
+ "postiz"
434
+ ],
435
+ "executionMode": "sync",
436
+ "timeoutSeconds": 300,
437
+ "metadata": {
438
+ "verbType": "write",
439
+ "writeBack": {
440
+ "entityParam": "postEntityId",
441
+ "kind": "post",
442
+ "properties": {
443
+ "postiz-post-id": "postId"
444
+ }
445
+ }
446
+ },
447
+ "parameters": {
448
+ "content": "string",
449
+ "integrationId": "string",
450
+ "provider": "string",
451
+ "type": "string?",
452
+ "date": "string?",
453
+ "mediaUrls": "array?",
454
+ "settings": "object?",
455
+ "postEntityId": "string?"
456
+ },
457
+ "code": "// Executor wraps this body as (async (args, context) => { <code> }); use args\n// directly and `return`. Every call goes to the postiz tool (the user's Postiz\n// public API; the raw API key is the Authorization header). Code, not a\n// declarative verb: the create-post body nests arrays (posts[].value[].image[])\n// and a per-provider settings object, which string interpolation cannot build.\nconst postiz = async (method, path, body) => {\n const res = await callProvider('postiz', method, path, body);\n if (res && res.proposed === true) return { proposed: true, proposalId: res.proposalId || null };\n return res ? res.body : null;\n};\nconst str = (v) => String(v ?? '').trim();\nconst content = str(args?.content);\nconst integrationId = str(args?.integrationId);\nconst provider = str(args?.provider);\nif (!content) throw new Error('content is required: the text of the post');\nif (!integrationId) throw new Error('integrationId is required: a channel id from postiz_list_integrations');\nif (!provider) throw new Error('provider is required: the channel identifier from postiz_list_integrations (x, linkedin, instagram, ...)');\nconst type = str(args?.type) || 'schedule';\nif (!['draft', 'schedule', 'now'].includes(type)) throw new Error('type must be draft, schedule or now');\nlet date = str(args?.date);\nif (type === 'schedule' && !date) throw new Error('date is required to schedule: an ISO-8601 time, e.g. 2026-11-02T09:00:00.000Z');\nif (!date) date = new Date().toISOString();\nif (Number.isNaN(Date.parse(date))) throw new Error(`date is not an ISO-8601 time: ${date}`);\ndate = new Date(date).toISOString();\nconst rawUrls = Array.isArray(args?.mediaUrls) ? args.mediaUrls : args?.mediaUrls ? [args.mediaUrls] : [];\nconst mediaUrls = rawUrls.map(str).filter(Boolean);\nfor (const url of mediaUrls) {\n if (!/^https:\\/\\//i.test(url)) throw new Error(`mediaUrls must be https links Postiz can download: ${url}`);\n}\n// settings.__type is the provider. Postiz requires more for some providers\n// (openapi: X who_can_reply_post, Instagram post_type); those two get a\n// default, and whatever the caller passes in `settings` wins over it.\nconst DEFAULT_SETTINGS = {\n x: { who_can_reply_post: 'everyone' },\n instagram: { post_type: 'post' },\n 'instagram-standalone': { post_type: 'post' },\n};\nconst extra = args?.settings && typeof args.settings === 'object' && !Array.isArray(args.settings) ? args.settings : {};\nconst settings = { ...(DEFAULT_SETTINGS[provider] || {}), ...extra, __type: provider };\nconst image = [];\nfor (const url of mediaUrls) {\n const up = await postiz('POST', '/public/v1/upload-from-url', { url });\n if (up && up.proposed) return { proposed: true, proposalId: up.proposalId, step: 'upload', url };\n if (!up || !up.id || !up.path) throw new Error(`Postiz did not store ${url}`);\n image.push({ id: String(up.id), path: String(up.path) });\n}\nconst created = await postiz('POST', '/public/v1/posts', {\n type,\n date,\n shortLink: false,\n tags: [],\n posts: [{ integration: { id: integrationId }, value: [{ content, image }], settings }],\n});\nif (created && created.proposed) return { proposed: true, proposalId: created.proposalId };\nconst first = Array.isArray(created) ? created[0] : null;\nconst postId = first && first.postId ? String(first.postId) : null;\nif (!postId) throw new Error('Postiz created no post: the response carried no postId');\nreturn { postId, integrationId, provider, type, date, media: image, postEntityId: str(args?.postEntityId) || null };\n"
458
+ }
459
+ ],
460
+ "provides": [
461
+ "publish_post",
462
+ "list_records",
463
+ "manage_file"
464
+ ]
465
+ },
466
+ "dependencies": []
467
+ }
@@ -0,0 +1,190 @@
1
+ {
2
+ "apiVersion": "synap/v1",
3
+ "kind": "capability",
4
+ "meta": {
5
+ "slug": "proactive-digest",
6
+ "name": "Daily Workspace Digest",
7
+ "description": "Each morning, checks the workspace for open tasks and recent captures and, if there is anything to report, posts a short written digest to the workspace's feed channel.",
8
+ "tags": [
9
+ "capability"
10
+ ],
11
+ "isPublic": true,
12
+ "syncByDefault": true
13
+ },
14
+ "spec": {
15
+ "key": "proactive-digest",
16
+ "name": "Proactive Digest",
17
+ "description": "Config-first per-workspace daily digest: each morning, gather what needs attention in the workspace (open tasks, recent captures), and if there's anything, post an AI-written digest to the workspace's proactive feed channel. This REPLACES the dead feed-proactive-executor worker (packages/jobs/src/workers/feed-proactive-executor.ts had zero enqueuers after its proactive-scheduler was removed). It is per-workspace / one-owner, which fits the automation model directly (unlike a per-user fan-out). EXPRESSIBILITY: tasksDue + recentCaptures are expressed as `query` nodes; two of the original aggregator's five sources are NOT expressible as config today and are omitted — pendingProposals (proposals are not entities, so the `query` node cannot read them) and recentEntities-across-all-profiles + activitySummary counts (the `query` node requires a single profileSlug, so 'any recent entity' / COUNT(*) have no node). The AI merges the two available sources in-prompt (there is no array-concat/merge pipe).",
18
+ "params": [],
19
+ "vault": [],
20
+ "tools": [],
21
+ "skills": [],
22
+ "provides": [],
23
+ "playbooks": [],
24
+ "automations": [
25
+ {
26
+ "name": "Proactive Digest — Daily",
27
+ "description": "Every morning: query open tasks + recent captures, skip if both are empty, else AI-write a short digest and post it to the workspace's proactive feed. Seeded ACTIVE so the cron schedules (a draft never gets a nextRunAt).",
28
+ "triggerType": "cron",
29
+ "triggerConfig": {
30
+ "expression": "0 9 * * *"
31
+ },
32
+ "status": "active",
33
+ "metadata": {
34
+ "replaces": "feed-proactive-executor",
35
+ "kind": "proactive-digest"
36
+ },
37
+ "flowDefinition": {
38
+ "nodes": [
39
+ {
40
+ "id": "trigger",
41
+ "type": "trigger",
42
+ "position": {
43
+ "x": 0,
44
+ "y": 0
45
+ },
46
+ "data": {
47
+ "triggerType": "cron",
48
+ "label": "Every morning at 09:00",
49
+ "config": {
50
+ "expression": "0 9 * * *"
51
+ }
52
+ }
53
+ },
54
+ {
55
+ "id": "query-tasks",
56
+ "type": "query",
57
+ "position": {
58
+ "x": -150,
59
+ "y": 120
60
+ },
61
+ "data": {
62
+ "label": "Open tasks",
63
+ "profileSlug": "task",
64
+ "filter": "",
65
+ "limit": 25,
66
+ "_note": "Ports the aggregator's tasksDue source. Due-date windowing is not expressed — the `query` filter is JSONB equality only (no range), so the AI reasons over the recent task set instead."
67
+ }
68
+ },
69
+ {
70
+ "id": "query-captures",
71
+ "type": "query",
72
+ "position": {
73
+ "x": 150,
74
+ "y": 120
75
+ },
76
+ "data": {
77
+ "label": "Recent captures",
78
+ "profileSlug": "capture",
79
+ "filter": "",
80
+ "limit": 25
81
+ }
82
+ },
83
+ {
84
+ "id": "count",
85
+ "type": "compute",
86
+ "position": {
87
+ "x": 0,
88
+ "y": 240
89
+ },
90
+ "data": {
91
+ "label": "Total items found",
92
+ "operation": "add",
93
+ "left": "{{steps.query-tasks.output.count}}",
94
+ "right": "{{steps.query-captures.output.count}}"
95
+ }
96
+ },
97
+ {
98
+ "id": "guard",
99
+ "type": "condition",
100
+ "position": {
101
+ "x": 0,
102
+ "y": 360
103
+ },
104
+ "data": {
105
+ "label": "Anything to report?",
106
+ "expression": "steps.count.output.result > 0",
107
+ "_note": "Empty-guard: ports the worker's `hasContent` skip. compute `add` of the two counts + a numeric condition stands in for an OR across sources (a condition is a single comparison; the counts summed give a non-empty test)."
108
+ }
109
+ },
110
+ {
111
+ "id": "digest",
112
+ "type": "capability",
113
+ "position": {
114
+ "x": 0,
115
+ "y": 480
116
+ },
117
+ "data": {
118
+ "label": "AI-write the digest",
119
+ "verbId": "ai.generate",
120
+ "inputMapping": {
121
+ "prompt": "You are writing a short daily workspace digest for the owner. Lead with what needs attention, group by theme, keep it skimmable, and omit noise. Open tasks (JSON): {{steps.query-tasks.output.entities}} . Recent captures (JSON): {{steps.query-captures.output.entities}} . Respond with STRICT JSON and nothing else: { \"digest\": \"<a short markdown digest>\" }.",
122
+ "json": "true"
123
+ }
124
+ }
125
+ },
126
+ {
127
+ "id": "post",
128
+ "type": "output",
129
+ "position": {
130
+ "x": 0,
131
+ "y": 600
132
+ },
133
+ "data": {
134
+ "label": "Post to the workspace proactive feed",
135
+ "outputType": "channel_message",
136
+ "config": {
137
+ "channelType": "proactive",
138
+ "content": "{{steps.digest.output.digest}}",
139
+ "metadata": {
140
+ "automationMessage": true,
141
+ "kind": "proactive-digest"
142
+ }
143
+ }
144
+ }
145
+ }
146
+ ],
147
+ "edges": [
148
+ {
149
+ "id": "e-tasks",
150
+ "source": "trigger",
151
+ "target": "query-tasks"
152
+ },
153
+ {
154
+ "id": "e-captures",
155
+ "source": "trigger",
156
+ "target": "query-captures"
157
+ },
158
+ {
159
+ "id": "e-count-t",
160
+ "source": "query-tasks",
161
+ "target": "count"
162
+ },
163
+ {
164
+ "id": "e-count-c",
165
+ "source": "query-captures",
166
+ "target": "count"
167
+ },
168
+ {
169
+ "id": "e-guard",
170
+ "source": "count",
171
+ "target": "guard"
172
+ },
173
+ {
174
+ "id": "e-digest",
175
+ "source": "guard",
176
+ "target": "digest",
177
+ "sourceHandle": "yes"
178
+ },
179
+ {
180
+ "id": "e-post",
181
+ "source": "digest",
182
+ "target": "post"
183
+ }
184
+ ]
185
+ }
186
+ }
187
+ ]
188
+ },
189
+ "dependencies": []
190
+ }