@synap-core/workspace-templates 0.11.0 → 0.23.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 (249) hide show
  1. package/README.md +483 -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 +420 -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 +471 -0
  54. package/capabilities/vercel.capability.json +424 -0
  55. package/dist/define-CPS0n8BV.d.ts +1331 -0
  56. package/dist/index.d.ts +189 -900
  57. package/dist/index.js +24654 -21639
  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 +41 -27
  63. package/packs/bookmark-views-pack.json +33 -0
  64. package/packs/crm-pack.json +76 -0
  65. package/packs/customer-profile.json +28 -0
  66. package/packs/deep-research.playbook.json +30 -0
  67. package/packs/event-views-pack.json +33 -0
  68. package/packs/habit-profile.json +27 -0
  69. package/packs/hr-pack.json +54 -0
  70. package/packs/invoice-profile.json +28 -0
  71. package/packs/knowledge-base-pack.json +56 -0
  72. package/packs/meeting-profile.json +29 -0
  73. package/packs/product-profile.json +30 -0
  74. package/packs/project-management-pack.json +49 -0
  75. package/packs/recipe-profile.json +29 -0
  76. package/packs/task-views-pack.json +39 -0
  77. package/retired.yaml +136 -0
  78. package/skills/app-factory-build-slice/SKILL.md +70 -0
  79. package/skills/app-factory-build-slice.catalog.json +17 -0
  80. package/skills/app-factory-design-canvas/SKILL.md +96 -0
  81. package/skills/app-factory-design-canvas.catalog.json +17 -0
  82. package/skills/app-factory-design-review/SKILL.md +99 -0
  83. package/skills/app-factory-design-review.catalog.json +18 -0
  84. package/skills/app-factory-research/SKILL.md +123 -0
  85. package/skills/app-factory-research.catalog.json +17 -0
  86. package/skills/bookmark-enrichment/SKILL.md +40 -0
  87. package/skills/carousel-format/carousel-format.skill.json +18 -0
  88. package/skills/collage-broll/collage-broll.skill.json +20 -0
  89. package/skills/content-taste/content-taste.skill.json +18 -0
  90. package/skills/creative-director/creative-director.skill.json +18 -0
  91. package/skills/design-critique/SKILL.md +135 -0
  92. package/skills/design-critique.catalog.json +12 -0
  93. package/skills/designing-with-real-components/SKILL.md +140 -0
  94. package/skills/designing-with-real-components.catalog.json +12 -0
  95. package/skills/edit-loop/edit-loop.skill.json +25 -0
  96. package/skills/facecam-edit/facecam-edit.skill.json +24 -0
  97. package/skills/mapping-the-server/SKILL.md +54 -0
  98. package/skills/math-explainer-manimgx/math-explainer-manimgx.skill.json +20 -0
  99. package/skills/motion-quality-gates/motion-quality-gates.skill.json +20 -0
  100. package/skills/open-design-edit/open-design-edit.skill.json +24 -0
  101. package/skills/reading-client-progress/SKILL.md +65 -0
  102. package/skills/routing-to-channels/SKILL.md +54 -0
  103. package/skills/stellar-scf-grants-advisor/ASSOCIATE-CHEATSHEET.md +133 -0
  104. package/skills/stellar-scf-grants-advisor/ASSOCIATE-ONBOARDING-GUIDE.md +761 -0
  105. package/skills/stellar-scf-grants-advisor/CLIENT-FAQ.md +181 -0
  106. package/skills/stellar-scf-grants-advisor/PARTNER-HANDOVER.md +130 -0
  107. package/skills/stellar-scf-grants-advisor/SKILL.md +102 -0
  108. package/skills/stellar-scf-grants-advisor/examples/README.md +43 -0
  109. package/skills/stellar-scf-grants-advisor/examples/chat-summary-templates.md +158 -0
  110. package/skills/stellar-scf-grants-advisor/examples/corpus-comparable-rows.md +136 -0
  111. package/skills/stellar-scf-grants-advisor/examples/q10-team-rewrites.md +109 -0
  112. package/skills/stellar-scf-grants-advisor/examples/q2-description-rewrites.md +88 -0
  113. package/skills/stellar-scf-grants-advisor/examples/q6-integration-rewrites.md +107 -0
  114. package/skills/stellar-scf-grants-advisor/examples/tranche-structures.md +176 -0
  115. package/skills/stellar-scf-grants-advisor/reference/01-methodology.md +96 -0
  116. package/skills/stellar-scf-grants-advisor/reference/02-scoring-framework.md +199 -0
  117. package/skills/stellar-scf-grants-advisor/reference/03-rejection-patterns.md +241 -0
  118. package/skills/stellar-scf-grants-advisor/reference/04-winner-patterns.md +120 -0
  119. package/skills/stellar-scf-grants-advisor/reference/05-comeback-patterns.md +92 -0
  120. package/skills/stellar-scf-grants-advisor/reference/06-budget-benchmarks.md +125 -0
  121. package/skills/stellar-scf-grants-advisor/reference/07-integration-list.md +147 -0
  122. package/skills/stellar-scf-grants-advisor/reference/08-abstract-fields.md +258 -0
  123. package/skills/stellar-scf-grants-advisor/reference/09-build-fields.md +259 -0
  124. package/skills/stellar-scf-grants-advisor/reference/10-corpus-winners.md +135 -0
  125. package/skills/stellar-scf-grants-advisor/reference/11-corpus-rejects.md +267 -0
  126. package/skills/stellar-scf-grants-advisor/reference/12-client-communication.md +131 -0
  127. package/skills/stellar-scf-grants-advisor/reference/13-excel-output-spec.md +199 -0
  128. package/skills/stellar-scf-grants-advisor/reference/14-worked-examples.md +160 -0
  129. package/skills/stellar-scf-grants-advisor/templates/abstract-review-builder.py +253 -0
  130. package/skills/stellar-scf-grants-advisor/templates/build-review-builder.py +213 -0
  131. package/skills/video-direction/video-direction.skill.json +20 -0
  132. package/skills/video-style-vocabulary/video-style-vocabulary.skill.json +20 -0
  133. package/skills/video-toolbox/video-toolbox.skill.json +20 -0
  134. package/src/__fixtures__/lifecycle-presets.flat-before.json +205 -0
  135. package/src/agency-os.yaml +122 -0
  136. package/src/agent-os-skill-slugs.test.ts +65 -0
  137. package/src/apify-social-reader.test.ts +317 -0
  138. package/src/base.template.test.ts +25 -19
  139. package/src/base.yaml +95 -39
  140. package/src/blockchain-ecosystem.yaml +1 -0
  141. package/src/brand-library.yaml +525 -14
  142. package/src/builder-dev-fold.template.test.ts +113 -0
  143. package/src/builder.yaml +798 -92
  144. package/src/business-model-catalog-description.test.ts +47 -0
  145. package/src/business-model-grp.template.test.ts +214 -0
  146. package/src/business-model.yaml +598 -0
  147. package/src/catalog-safety.test.ts +198 -0
  148. package/src/catalog.template-items.test.ts +75 -0
  149. package/src/catalog.ts +85 -2
  150. package/src/civic-france.yaml +102 -0
  151. package/src/concept-guard.test.ts +28 -8
  152. package/src/concept-guard.ts +2 -2
  153. package/src/content-creation.template.test.ts +52 -0
  154. package/src/content-creation.yaml +192 -0
  155. package/src/content-os.edit-loop.template.test.ts +210 -0
  156. package/src/content-os.publish-due-posts.template.test.ts +261 -0
  157. package/src/content-os.template.test.ts +322 -0
  158. package/src/content-os.video-takes.template.test.ts +338 -0
  159. package/src/content-os.work-a-take.template.test.ts +125 -0
  160. package/src/content-os.yaml +1830 -39
  161. package/src/content-studio-retired.template.test.ts +82 -0
  162. package/src/corpus-flow-validity.test.ts +4 -5
  163. package/src/crm-absorbs-outreach.template.test.ts +117 -0
  164. package/src/crm-build-plan.template.test.ts +128 -0
  165. package/src/crm-lists.template.test.ts +96 -0
  166. package/src/crm-messages-cadence.template.test.ts +164 -0
  167. package/src/crm-one-send-door.template.test.ts +65 -0
  168. package/src/crm.yaml +1456 -181
  169. package/src/decisions-wave.template.test.ts +186 -0
  170. package/src/define.ts +130 -17
  171. package/src/design-to-implementation.template.test.ts +94 -0
  172. package/src/dist-freshness.test.ts +97 -0
  173. package/src/domain-template-type.test.ts +75 -0
  174. package/src/ecosystem.yaml +27 -66
  175. package/src/enterprise-os.yaml +10 -134
  176. package/src/facecam-edit.audio-studio.test.ts +188 -0
  177. package/src/fal-generate-image.test.ts +200 -0
  178. package/src/fal-media-lab-pod-files.test.ts +180 -0
  179. package/src/finance.yaml +254 -1
  180. package/src/foundation.yaml +130 -28
  181. package/src/frame-host-modules.d.mts +6 -0
  182. package/src/frame-host-modules.mjs +58 -0
  183. package/src/generate.mjs +9 -3
  184. package/src/github-merge.test.ts +210 -0
  185. package/src/grants.yaml +57 -17
  186. package/src/hr.yaml +39 -6
  187. package/src/index.ts +36 -1
  188. package/src/intent.test.ts +161 -0
  189. package/src/internal-runbook.yaml +19 -1
  190. package/src/jev.test.ts +356 -0
  191. package/src/legal.yaml +33 -1
  192. package/src/life-os.yaml +65 -240
  193. package/src/lifecycle-coverage.test.ts +124 -0
  194. package/src/lifecycle-declarations.test.ts +252 -0
  195. package/src/lifecycle-presets.test.ts +468 -0
  196. package/src/lifecycle-presets.ts +494 -0
  197. package/src/lifecycle-stuck.test.ts +46 -0
  198. package/src/lifecycle-waits.parity.test.ts +319 -0
  199. package/src/marketing.yaml +108 -4
  200. package/src/meetings-knowledge.yaml +18 -0
  201. package/src/networking.yaml +23 -2
  202. package/src/operations.yaml +304 -4
  203. package/src/pipeline-views.template.test.ts +88 -0
  204. package/src/playbook-goal-placeholders.test.ts +57 -0
  205. package/src/postiz-contract.test.ts +134 -0
  206. package/src/presentation-declarations.test.ts +174 -0
  207. package/src/process-contract.validate.test.ts +352 -0
  208. package/src/project-management.yaml +39 -740
  209. package/src/publish-body.d.mts +29 -0
  210. package/src/publish-body.mjs +74 -0
  211. package/src/publish-body.test.ts +74 -0
  212. package/src/publish-official-lib.test.ts +176 -0
  213. package/src/replicate-rvm.test.ts +504 -0
  214. package/src/research-base.yaml +119 -20
  215. package/src/research-decision.yaml +60 -3
  216. package/src/reserved-profile-slugs.test.ts +83 -0
  217. package/src/retired-goal-kinds.test.ts +58 -0
  218. package/src/role-reference-and-step-domain.test.ts +192 -0
  219. package/src/seed-obligation.test.ts +176 -0
  220. package/src/send-message-maps.test.ts +227 -0
  221. package/src/shared-role-ssot.test.ts +42 -1
  222. package/src/ship-a-change.template.test.ts +177 -0
  223. package/src/skills.test.ts +170 -0
  224. package/src/social.yaml +85 -27
  225. package/src/space-packages.freshness.test.ts +97 -0
  226. package/src/space-packages.generated.ts +40 -0
  227. package/src/space-packages.test.ts +125 -0
  228. package/src/space-packages.ts +73 -0
  229. package/src/start.test.ts +188 -0
  230. package/src/task-intents.test.ts +293 -0
  231. package/src/templates.ts +21639 -21522
  232. package/src/types.ts +443 -60
  233. package/src/unipile-publish-post.test.ts +162 -0
  234. package/src/validate-flow.drift.test.ts +2 -3
  235. package/src/validate-flow.ts +32 -2
  236. package/src/validate-onboarding.test.ts +59 -0
  237. package/src/validate.test.ts +156 -3
  238. package/src/validate.ts +1384 -7
  239. package/src/wire-core.ts +231 -0
  240. package/src/wire.test.ts +159 -0
  241. package/src/wire.ts +107 -0
  242. package/src/__fixtures__/report-automation-flow.json +0 -393
  243. package/src/agent-fleet.yaml +0 -1645
  244. package/src/business-developer.template.test.ts +0 -351
  245. package/src/business-developer.yaml +0 -860
  246. package/src/content-studio.yaml +0 -361
  247. package/src/dev-dashboard.yaml +0 -990
  248. package/src/outreach-comms.yaml +0 -486
  249. package/src/the-arch.yaml +0 -201
@@ -1,860 +0,0 @@
1
- # Business Developer — a composable, lead-first CRM operating model.
2
- #
3
- # This is an ADDITIVE overlay on the CRM workspace, not a second CRM and not a
4
- # rewrite of shared identity profiles. It REUSES the pod-wide `lead` and
5
- # `client` roles from Foundation (`scope: shared`, `profileKind: role`) and adds
6
- # its business-development properties to them as WORKSPACE OVERLAYS — the
7
- # documented extension mechanism (`getEffectiveProperties`, and rule (b) of
8
- # `shared-role-ssot.test.ts`). It used to fork them into workspace-scoped
9
- # `crm-lead` / `crm-client`; that was a vocabulary fork of one real-world
10
- # concept: the same company was a "lead" under one spelling and not under the
11
- # other, so pod-wide surfaces, the Operations handoff, and the CRM app
12
- # disagreed about who was a client. One concept, one slug, workspace-specific
13
- # FIELDS.
14
- #
15
- # Lifecycle:
16
- # person / company + lead → optional deal(s) → won deal → client
17
- #
18
- # Deals are commercial proposals attached through CRM's existing
19
- # `linked_to_deal` relation. The CRM requires one counterparty before a deal
20
- # can be won, but a counterparty can have more than one proposal over time. A
21
- # client facet is only added when a deal is won; post-sale delivery belongs to
22
- # another application.
23
-
24
- meta:
25
- slug: business-developer
26
- domain: revenue
27
- name: Business Developer
28
- description: "A lead-first sales motion for a CRM workspace: qualify leads, work commercial proposals, and hand won clients to the next system."
29
- icon: target
30
- color: "#D97706"
31
- tags: [crm, sales, lead-management, business-development]
32
- isPublic: true
33
-
34
- # Compose onto an existing CRM workspace. The resolver installs CRM first, then
35
- # applies these profiles and relations to that same workspace.
36
- dependencies:
37
- - slug: crm
38
- kind: workspace
39
- relation: compose
40
- reason: "Adds a lead-first business-development workflow to your CRM workspace."
41
-
42
- workspace:
43
- name: CRM
44
- description: A focused pre-sale workspace for lead qualification and commercial proposals.
45
- subtype: crm
46
- capabilities:
47
- - crm.business-development
48
-
49
- profiles:
50
- # ── Lead (reused shared role — SSOT is foundation.yaml) ───────────────────
51
- # NOT a workspace-local copy: this RE-DECLARES foundation's pod-wide `lead`
52
- # role so the CRM workspace receives the grant (shared profiles are
53
- # grant-gated — a workspace only sees a shared role if it references the
54
- # slug), and ADDS the business-development properties below.
55
- #
56
- # Row-level fields (displayName/icon/color/description/applicableKinds) are
57
- # restated VERBATIM from foundation, exactly as crm.yaml does: there is ONE
58
- # pod-wide row and no overlay mechanism for row-level fields, so a divergent
59
- # value here would be silently false on every pod depending on apply order
60
- # (shared-role-ssot rule (c)).
61
- #
62
- # The properties are EXTRAS ONLY. Foundation's own `leadStage` / `notes` are
63
- # deliberately NOT restated — omitting is "no claim", and restating with a
64
- # different definition is the base-drift rule (b) forbids. Extras land as
65
- # WORKSPACE OVERLAYS via getEffectiveProperties, so this workspace's members
66
- # see lifecycle/ownership fields that other workspaces don't.
67
- - slug: lead
68
- displayName: Lead
69
- icon: user-plus
70
- color: yellow
71
- description: An early-pipeline prospect — not yet a client, being qualified or nurtured.
72
- scope: shared
73
- profileKind: role
74
- applicableKinds:
75
- - company
76
- - person
77
- properties:
78
- - slug: lifecycleStage
79
- label: Lifecycle stage
80
- valueType: string
81
- inputType: select
82
- enumValues:
83
- [
84
- new,
85
- researching,
86
- outreach,
87
- engaged,
88
- qualified,
89
- nurturing,
90
- disqualified,
91
- converted,
92
- ]
93
- constraints: { defaultValue: new }
94
- - slug: assignedUserId
95
- label: Assigned user ID
96
- valueType: string
97
- inputType: text
98
- placeholder: Workspace member ID
99
- - slug: source
100
- label: Source
101
- valueType: string
102
- inputType: select
103
- enumValues:
104
- [
105
- cold-outreach,
106
- linkedin,
107
- twitter,
108
- landing-page,
109
- inbound-call,
110
- referral,
111
- event,
112
- other,
113
- ]
114
- - slug: icpScore
115
- label: ICP score
116
- valueType: number
117
- inputType: number
118
- - slug: outreachChannels
119
- label: Outreach channels
120
- valueType: array
121
- inputType: text
122
- placeholder: linkedin, email, phone
123
- - slug: lastContactedAt
124
- label: Last contacted at
125
- valueType: date
126
- inputType: date
127
- - slug: nextActionAt
128
- label: Next action at
129
- valueType: date
130
- inputType: date
131
- - slug: nextAction
132
- label: Next action
133
- valueType: string
134
- inputType: textarea
135
- - slug: qualificationNotes
136
- label: Qualification notes
137
- valueType: string
138
- inputType: textarea
139
- - slug: disqualificationReason
140
- label: Disqualification reason
141
- valueType: string
142
- inputType: textarea
143
- - slug: convertedAt
144
- label: Converted at
145
- valueType: date
146
- inputType: date
147
-
148
- # ── Client (reused shared role — SSOT is foundation.yaml) ─────────────────
149
- # Same pattern as `lead` above: foundation's pod-wide `client` role, restated
150
- # verbatim at row level, EXTENDED with the handoff context this pre-sale
151
- # addon owns. Client delivery, renewal, and service health belong to
152
- # operations.yaml, which reads the SAME `client` role pod-wide — that shared
153
- # slug is what makes the CRM → Operations handoff possible at all.
154
- - slug: client
155
- displayName: Client
156
- icon: briefcase
157
- color: emerald
158
- description: An active commercial relationship — created when a deal is won.
159
- scope: shared
160
- profileKind: role
161
- applicableKinds:
162
- - company
163
- - person
164
- properties:
165
- - slug: becameClientAt
166
- label: Became client at
167
- valueType: date
168
- inputType: date
169
- - slug: handoffStatus
170
- label: Handoff status
171
- valueType: string
172
- inputType: select
173
- enumValues: [pending, ready, handed_off]
174
- constraints: { defaultValue: pending }
175
- - slug: handoffDestination
176
- label: Handoff destination
177
- valueType: string
178
- inputType: text
179
- - slug: handoffNotes
180
- label: Handoff notes
181
- valueType: string
182
- inputType: textarea
183
-
184
- # CRM's original deal profile remains the generic compatibility layer. These
185
- # fields are the additive commercial contract used by this addon; applications
186
- # that opt into Business Developer read them rather than treating a deal board
187
- # as the lead pipeline.
188
- - slug: deal
189
- displayName: Deal
190
- icon: git-branch
191
- color: violet
192
- properties:
193
- - slug: commercialStage
194
- label: Commercial stage
195
- valueType: string
196
- inputType: select
197
- enumValues: [draft, proposed, negotiating, won, lost]
198
- constraints: { defaultValue: draft }
199
- - slug: synapFeeModel
200
- label: Synap fee model
201
- valueType: string
202
- inputType: select
203
- enumValues: [fixed, success_fee]
204
- - slug: synapFixedFee
205
- label: Synap fixed fee
206
- valueType: number
207
- inputType: number
208
- - slug: expectedClientGain
209
- label: Expected client gain
210
- valueType: number
211
- inputType: number
212
- - slug: synapSuccessFeeRate
213
- label: Synap success fee rate
214
- valueType: number
215
- inputType: number
216
- - slug: sourcedByUserId
217
- label: Sourced by user ID
218
- valueType: string
219
- inputType: text
220
- - slug: synapFeeAmount
221
- label: Synap fee amount
222
- valueType: number
223
- inputType: number
224
- - slug: commissionEntitlementId
225
- label: Commission entitlement
226
- valueType: entity_id
227
- targetProfileSlug: crm-commission-entitlement
228
- inputType: entity_select
229
- - slug: commissionStatus
230
- label: Commission status
231
- valueType: string
232
- inputType: select
233
- enumValues: [estimated, earned, paid, requires_review, void]
234
- - slug: wonAt
235
- label: Won at
236
- valueType: date
237
- inputType: date
238
- - slug: lostReason
239
- label: Lost reason
240
- valueType: string
241
- inputType: textarea
242
-
243
- # Immutable-at-creation commission records make first- and repeat-deal
244
- # commissions auditable. The CRM creates one on a win: 20% of Synap's fee for
245
- # the counterparty's first won deal, then 10% for later won deals.
246
- - slug: crm-commission-entitlement
247
- displayName: Commission Entitlement
248
- icon: receipt-text
249
- color: green
250
- description: An auditable business-developer commission created from a won deal.
251
- scope: WORKSPACE
252
- properties:
253
- # Correlates this record with its originating deal. The configured
254
- # handoff automation uses it as its idempotency key, so a resumed run
255
- # cannot create a second entitlement after a partial write.
256
- - slug: sourceDealId
257
- label: Source deal ID
258
- valueType: entity_id
259
- targetProfileSlug: deal
260
- inputType: entity_select
261
- - slug: sourcedByUserId
262
- label: Sourced by user ID
263
- valueType: string
264
- inputType: text
265
- - slug: sequence
266
- label: Deal sequence
267
- valueType: string
268
- inputType: select
269
- enumValues: [first, subsequent]
270
- - slug: rateBps
271
- label: Commission rate (basis points)
272
- valueType: number
273
- inputType: number
274
- - slug: feeBasisAmount
275
- label: Synap fee basis amount
276
- valueType: number
277
- inputType: number
278
- - slug: estimatedAmount
279
- label: Estimated commission amount
280
- valueType: number
281
- inputType: number
282
- - slug: status
283
- label: Status
284
- valueType: string
285
- inputType: select
286
- enumValues: [estimated, earned, paid, void]
287
- constraints: { defaultValue: estimated }
288
- - slug: earnedAt
289
- label: Earned at
290
- valueType: date
291
- inputType: date
292
- - slug: paidAt
293
- label: Paid at
294
- valueType: date
295
- inputType: date
296
- - slug: voidReason
297
- label: Void reason
298
- valueType: string
299
- inputType: textarea
300
-
301
- # ── Campaign (reused kind — SSOT is marketing.yaml) ───────────────────────
302
- # NOT a new kind and NOT a CRM fork of one: this RE-DECLARES the
303
- # marketing-campaign template's `campaign` so the CRM can attach people and
304
- # companies to the campaigns that sourced them (`member_of`, below). Keeping
305
- # `semanticSlug: marketing.campaign` is what makes it the SAME concept rather
306
- # than a third one — the concept guard only errors when two DIFFERENT slugs
307
- # claim one semanticSlug. `content-os.yaml` re-declares it exactly this way;
308
- # this follows that precedent.
309
- #
310
- # It must live in THIS file, not in `crm.yaml` or `marketing.yaml`:
311
- # `toWorkspaceDefinition` does NOT flatten dependencies, so only
312
- # business-developer's OWN profiles/entityLinks reach an existing CRM
313
- # workspace through `reconcileFromDefinition`. It is also what lets the
314
- # `member_of` links below resolve — an entityLink endpoint must be an own
315
- # profile, a SYSTEM_PROFILE, or dependency vocab, and `campaign` is none of
316
- # the latter two.
317
- #
318
- # Scope is OMITTED (= workspace) to MATCH marketing's own declaration: the
319
- # promotion to pod-wide is the resolver's job (resolve-profile-for-apply.ts
320
- # same-actor workspace→shared branch), not ours to assert. Body kept verbatim
321
- # so no property drift.
322
- - slug: campaign
323
- displayName: Campaign
324
- icon: megaphone
325
- color: pink
326
- description: "A marketing campaign — email, social, event, content, or partnership"
327
- semanticSlug: marketing.campaign
328
- properties:
329
- - slug: campaign-status
330
- label: Status
331
- valueType: string
332
- inputType: select
333
- enumValues: [planning, active, paused, completed, cancelled]
334
- constraints: { defaultValue: planning }
335
- - slug: campaign-channel
336
- label: Channel
337
- valueType: string
338
- inputType: select
339
- enumValues:
340
- [email, social, event, content, partnership, paid, organic, other]
341
- - slug: campaign-goal
342
- label: Goal
343
- valueType: string
344
- inputType: textarea
345
- - slug: campaign-target-audience
346
- label: Target Audience
347
- valueType: string
348
- inputType: textarea
349
- - slug: campaign-start-date
350
- label: Start Date
351
- valueType: date
352
- inputType: date
353
- - slug: campaign-end-date
354
- label: End Date
355
- valueType: date
356
- inputType: date
357
- - slug: campaign-budget
358
- label: Budget
359
- valueType: number
360
- inputType: number
361
- - slug: campaign-lead-count
362
- label: Lead Count
363
- valueType: number
364
- inputType: number
365
- - slug: campaign-conversion-rate
366
- label: Conversion Rate (%)
367
- valueType: number
368
- inputType: number
369
- - slug: campaign-notes
370
- label: Notes
371
- valueType: string
372
- inputType: textarea
373
- # `campaign-type` is the campaign's NATURE/phase, orthogonal to
374
- # `campaign-channel` (the delivery medium). scoping/outreach/live have no
375
- # channel equivalent, so folding them into `campaign-channel` would lose
376
- # them — they get their own def. Kept verbatim across the three campaign
377
- # declarations (marketing / content-os / here) so there is no drift.
378
- - slug: campaign-type
379
- label: Type
380
- valueType: string
381
- inputType: select
382
- enumValues:
383
- [scoping, outreach, live, partnership, event, other]
384
- constraints: { defaultValue: outreach }
385
- # `campaign-color` backs the per-campaign colour the CRM surfaces render.
386
- # Stored as a palette NAME (see apps/crm/lib/campaignColors.ts), not a hex.
387
- - slug: campaign-color
388
- label: Color
389
- valueType: string
390
- inputType: select
391
- enumValues: [indigo, violet, amber, cyan, pink, teal]
392
-
393
- entityLinks:
394
- # The existing generic `linked_to_deal` relation remains the deal ↔
395
- # counterparty connection. This overlay adds only the new auditable
396
- # commission relation, avoiding a parallel relationship model.
397
- - sourceProfileSlug: deal
398
- targetProfileSlug: crm-commission-entitlement
399
- type: crm_commission_for_deal
400
- label: Commission entitlement
401
- # Campaign membership — the sourcing edge between a counterparty and the
402
- # campaign it came from. Same predicate for both endpoint kinds, mirroring
403
- # CRM's own `linked_to_deal` person/company pair.
404
- - sourceProfileSlug: person
405
- targetProfileSlug: campaign
406
- type: member_of
407
- label: Member of
408
- - sourceProfileSlug: company
409
- targetProfileSlug: campaign
410
- type: member_of
411
- label: Member of
412
-
413
- # These are guided, proposal-first sessions — not background automations. They
414
- # never create a deal merely because a lead exists, and never convert a lead to
415
- # a client until a human-confirmed deal win is proposed and applied.
416
- playbooks:
417
- - name: Qualify a CRM lead
418
- description: Research and qualify one CRM lead, then make the next action explicit without creating a commercial proposal automatically.
419
- goalTemplate: >-
420
- Work on CRM lead ({lead}). Verify and enrich only factual information that
421
- can be supported, assess fit, and update its CRM lifecycle stage, ICP score,
422
- qualification notes, outreach channels, and next action. Do not create a
423
- deal simply because the lead is qualified. If a commercial proposal is
424
- warranted, explain why and ask for or propose that next step separately.
425
- subjectProfile:
426
- profileSlug: lead
427
- params:
428
- - { name: lead, type: entity, label: CRM lead, required: true }
429
- executor: is-agent
430
- status: active
431
-
432
- - name: Advance a commercial proposal
433
- description: Help progress a linked deal without confusing commercial state with the lead pipeline or client conversion.
434
- goalTemplate: >-
435
- Work on commercial proposal ({deal}). Confirm its primary counterparty,
436
- current commercial stage, fee model, expected fee, and next blocker. Propose
437
- the single next action needed to advance it. Never mark the counterparty as
438
- a CRM client unless the deal is genuinely won; a win must preserve the
439
- sourced business developer and create the appropriate commission entitlement
440
- (20% of Synap's fee for the first won deal with that counterparty, 10% later).
441
- subjectProfile:
442
- profileSlug: deal
443
- params:
444
- - { name: deal, type: entity, label: Commercial proposal, required: true }
445
- executor: is-agent
446
- status: active
447
-
448
- # The deterministic counterpart to the guided playbooks above. This runs only
449
- # after a human explicitly confirms the commercial win. It remains entirely
450
- # domain-configured: generic workflow nodes read, validate, calculate, and
451
- # write through the Pod's governed facet/relation/entity doors.
452
- automations:
453
- - key: crm-win-and-handoff
454
- name: Win and hand off
455
- description: Convert one qualified CRM lead after its proposal is won, record its commission entitlement, and leave a resumable handoff trail.
456
- triggerType: manual
457
- triggerConfig: {}
458
- status: active
459
- flow:
460
- nodes:
461
- - id: trigger
462
- type: trigger
463
- position: { x: 0, y: 0 }
464
- data:
465
- label: Mark won and hand off
466
- triggerType: manual
467
- config: {}
468
-
469
- - id: read-deal
470
- type: entity_read
471
- position: { x: 240, y: 0 }
472
- data:
473
- label: Read proposal
474
- entityId: "{{trigger.payload.entityId}}"
475
-
476
- - id: guard-deal
477
- type: guard
478
- position: { x: 480, y: 0 }
479
- data:
480
- label: Confirm proposal is ready
481
- checks:
482
- - path: steps.read-deal.output.entity.type
483
- equals: deal
484
- message: This action is only available for a commercial proposal.
485
- - path: steps.read-deal.output.entity.properties.commercialStage
486
- anyOf:
487
- - {
488
- path: steps.read-deal.output.entity.properties.commercialStage,
489
- equals: won,
490
- }
491
- - {
492
- path: steps.read-deal.output.entity.properties.dealStage,
493
- equals: won,
494
- }
495
- message: Mark the proposal as won before handing it off.
496
- - path: steps.read-deal.output.entity.properties.handoffStatus
497
- notEquals: handed_off
498
- message: This proposal has already been handed off.
499
- # minLength, NOT exists: `exists` is a null check, so an empty
500
- # string satisfies it and the handoff would proceed with no
501
- # sourcer actually set. The intent here is "has a value".
502
- - path: steps.read-deal.output.entity.properties.sourcedByUserId
503
- minLength: 1
504
- message: Set the business developer who sourced this proposal before handing it off.
505
- - path: steps.read-deal.output.entity.properties.synapFeeAmount
506
- numberGte: 0
507
- message: Set the confirmed Synap fee before handing this proposal off.
508
-
509
- - id: find-party
510
- type: related_entities
511
- position: { x: 720, y: 0 }
512
- data:
513
- label: Find proposal counterparty
514
- entityId: "{{trigger.payload.entityId}}"
515
- direction: inbound
516
- relationTypes: [linked_to_deal]
517
- limit: 2
518
-
519
- - id: guard-party
520
- type: guard
521
- position: { x: 960, y: 0 }
522
- data:
523
- label: Confirm one qualified counterparty
524
- checks:
525
- - path: steps.find-party.output.entities
526
- lengthEquals: 1
527
- message: A proposal must have exactly one commercial counterparty before it can be handed off.
528
-
529
- - id: read-party
530
- type: entity_read
531
- position: { x: 1200, y: 0 }
532
- data:
533
- label: Read CRM lead
534
- entityId: "{{steps.find-party.output.entities.0.id}}"
535
-
536
- - id: guard-lead
537
- type: guard
538
- position: { x: 1440, y: 0 }
539
- data:
540
- label: Confirm qualified CRM lead
541
- checks:
542
- - path: steps.read-party.output.entity.facetSlugs
543
- arrayIncludes: lead
544
- message: The commercial counterparty must still be a CRM lead before it becomes a CRM client.
545
-
546
- # Source-deal claim is the durable idempotency boundary for the whole
547
- # financial handoff. It must happen before the first-deal decision so
548
- # duplicate clicks cannot reserve different commission policies.
549
- - id: claim-commission-entitlement
550
- type: claim
551
- position: { x: 1680, y: 0 }
552
- data:
553
- label: Reserve commission entitlement
554
- namespace: crm-commission-entitlement
555
- key: "{{trigger.payload.entityId}}"
556
-
557
- - id: guard-commission-claim
558
- type: guard
559
- position: { x: 1920, y: 0 }
560
- data:
561
- label: Confirm this run owns the commission write
562
- checks:
563
- - path: steps.claim-commission-entitlement.output.claimed
564
- equals: true
565
- message: This proposal handoff is already being handled by another workflow run.
566
-
567
- # A durable generic claim serializes the one-time policy decision. It
568
- # prevents two concurrent wins for the same counterparty from both
569
- # receiving the first-deal rate, while retries of the winning run keep
570
- # their original decision.
571
- - id: claim-first-client-deal
572
- type: claim
573
- position: { x: 2160, y: 0 }
574
- data:
575
- label: Reserve first-client commission rate
576
- namespace: crm-commission-first-deal
577
- key: "{{steps.read-party.output.entity.id}}"
578
-
579
- # Existing pods may already have won work from before this add-on. Read
580
- # that history before applying the claim policy, including the legacy
581
- # `dealStage` field until old CRM records are migrated.
582
- - id: prior-won-deals
583
- type: related_entities
584
- position: { x: 2400, y: 0 }
585
- data:
586
- label: Find earlier won proposals
587
- entityId: "{{steps.read-party.output.entity.id}}"
588
- direction: outbound
589
- relationTypes: [linked_to_deal]
590
- excludeEntityId: "{{trigger.payload.entityId}}"
591
- propertyAnyEquals:
592
- commercialStage: [won]
593
- dealStage: [won]
594
- limit: 100
595
-
596
- - id: has-no-prior-won-deals
597
- type: condition
598
- position: { x: 2640, y: 0 }
599
- data:
600
- label: Is this the first historical win?
601
- expression: steps.prior-won-deals.output.count === 0
602
-
603
- - id: is-first-client-deal
604
- type: compute
605
- position: { x: 2880, y: 120 }
606
- data:
607
- label: Confirm first-client commission
608
- operation: multiply
609
- left: "{{steps.claim-first-client-deal.output.claimed}}"
610
- right: "{{steps.has-no-prior-won-deals.output.result}}"
611
-
612
- # 1,000 bps for every deal, plus 1,000 bps for the winning first-deal claim.
613
- # Number(true) is deliberately supported by the generic compute node,
614
- # keeping the first/subsequent policy in config rather than application code.
615
- - id: first-deal-bonus-bps
616
- type: compute
617
- position: { x: 2880, y: 0 }
618
- data:
619
- label: Calculate first-deal bonus
620
- operation: multiply
621
- left: 1000
622
- right: "{{steps.is-first-client-deal.output.result}}"
623
-
624
- - id: commission-sequence
625
- type: select
626
- position: { x: 3120, y: 0 }
627
- data:
628
- label: Label commission sequence
629
- when: "{{steps.is-first-client-deal.output.result}}"
630
- ifTrue: first
631
- ifFalse: subsequent
632
-
633
- - id: commission-rate-bps
634
- type: compute
635
- position: { x: 3360, y: 0 }
636
- data:
637
- label: Calculate commission rate
638
- operation: add
639
- left: 1000
640
- right: "{{steps.first-deal-bonus-bps.output.result}}"
641
-
642
- - id: commission-product
643
- type: compute
644
- position: { x: 3600, y: 0 }
645
- data:
646
- label: Calculate commission basis points
647
- operation: multiply
648
- left: "{{steps.read-deal.output.entity.properties.synapFeeAmount}}"
649
- right: "{{steps.commission-rate-bps.output.result}}"
650
-
651
- - id: commission-amount
652
- type: compute
653
- position: { x: 3840, y: 0 }
654
- data:
655
- label: Calculate commission amount
656
- operation: divide
657
- left: "{{steps.commission-product.output.result}}"
658
- right: 10000
659
-
660
- - id: handoff-time
661
- type: compute
662
- position: { x: 4080, y: 0 }
663
- data:
664
- label: Record handoff time
665
- operation: now
666
-
667
- - id: create-commission
668
- type: output
669
- position: { x: 4320, y: 0 }
670
- data:
671
- label: Record commission entitlement
672
- outputType: entity_create
673
- config:
674
- profileSlug: crm-commission-entitlement
675
- title: "Commission · {{steps.read-deal.output.entity.title}}"
676
- # The durable claim above serializes creators; this lookup heals a
677
- # crash after the entity write but before its step ledger update.
678
- dedupeBy: sourceDealId
679
- properties:
680
- sourceDealId: "{{trigger.payload.entityId}}"
681
- sourcedByUserId: "{{steps.read-deal.output.entity.properties.sourcedByUserId}}"
682
- sequence: "{{steps.commission-sequence.output.value}}"
683
- rateBps: "{{steps.commission-rate-bps.output.result}}"
684
- feeBasisAmount: "{{steps.read-deal.output.entity.properties.synapFeeAmount}}"
685
- estimatedAmount: "{{steps.commission-amount.output.result}}"
686
- status: estimated
687
- earnedAt: "{{steps.handoff-time.output.result}}"
688
-
689
- - id: link-commission
690
- type: output
691
- position: { x: 4560, y: 0 }
692
- data:
693
- label: Link proposal and commission
694
- outputType: relation_create
695
- config:
696
- fromEntityId: "{{trigger.payload.entityId}}"
697
- toEntityId: "{{steps.create-commission.output.entityId}}"
698
- relationType: crm_commission_for_deal
699
- dedupe: true
700
-
701
- - id: mark-deal-won
702
- type: output
703
- position: { x: 4800, y: 0 }
704
- data:
705
- label: Mark proposal won
706
- outputType: entity_update
707
- config:
708
- entityId: "{{trigger.payload.entityId}}"
709
- properties:
710
- commercialStage: won
711
- wonAt: "{{steps.handoff-time.output.result}}"
712
- handoffStatus: handed_off
713
- commissionEntitlementId: "{{steps.create-commission.output.entityId}}"
714
- commissionStatus: estimated
715
-
716
- - id: attach-client
717
- type: output
718
- position: { x: 5040, y: 0 }
719
- data:
720
- label: Attach CRM client role
721
- outputType: facet_attach
722
- config:
723
- entityId: "{{steps.read-party.output.entity.id}}"
724
- facetSlug: client
725
- properties:
726
- becameClientAt: "{{steps.handoff-time.output.result}}"
727
- handoffStatus: handed_off
728
-
729
- - id: convert-lead
730
- type: output
731
- position: { x: 5280, y: 0 }
732
- data:
733
- label: Complete CRM lead lifecycle
734
- outputType: facet_update
735
- config:
736
- entityId: "{{steps.read-party.output.entity.id}}"
737
- facetSlug: lead
738
- properties:
739
- lifecycleStage: converted
740
- convertedAt: "{{steps.handoff-time.output.result}}"
741
-
742
- edges:
743
- - { id: trigger-read, source: trigger, target: read-deal }
744
- - { id: read-guard, source: read-deal, target: guard-deal }
745
- - { id: guard-party-search, source: guard-deal, target: find-party }
746
- - { id: party-search-guard, source: find-party, target: guard-party }
747
- - { id: party-guard-read, source: guard-party, target: read-party }
748
- - { id: party-read-guard, source: read-party, target: guard-lead }
749
- - {
750
- id: lead-guard-commission-claim,
751
- source: guard-lead,
752
- target: claim-commission-entitlement,
753
- }
754
- - {
755
- id: commission-claim-guard,
756
- source: claim-commission-entitlement,
757
- target: guard-commission-claim,
758
- }
759
- - {
760
- id: commission-guard-first-claim,
761
- source: guard-commission-claim,
762
- target: claim-first-client-deal,
763
- }
764
- - {
765
- id: first-claim-history,
766
- source: claim-first-client-deal,
767
- target: prior-won-deals,
768
- }
769
- - {
770
- id: history-condition,
771
- source: prior-won-deals,
772
- target: has-no-prior-won-deals,
773
- }
774
- - {
775
- id: first-confirm-bonus,
776
- source: is-first-client-deal,
777
- target: first-deal-bonus-bps,
778
- }
779
- - {
780
- id: first-history-confirm,
781
- source: has-no-prior-won-deals,
782
- target: is-first-client-deal,
783
- }
784
- - {
785
- id: first-confirm-sequence,
786
- source: is-first-client-deal,
787
- target: commission-sequence,
788
- }
789
- - {
790
- id: bonus-rate,
791
- source: first-deal-bonus-bps,
792
- target: commission-rate-bps,
793
- }
794
- - {
795
- id: rate-product,
796
- source: commission-rate-bps,
797
- target: commission-product,
798
- }
799
- - {
800
- id: product-amount,
801
- source: commission-product,
802
- target: commission-amount,
803
- }
804
- - { id: amount-time, source: commission-amount, target: handoff-time }
805
- - {
806
- id: time-commission,
807
- source: handoff-time,
808
- target: create-commission,
809
- }
810
- - {
811
- id: sequence-commission,
812
- source: commission-sequence,
813
- target: create-commission,
814
- }
815
- - {
816
- id: commission-link,
817
- source: create-commission,
818
- target: link-commission,
819
- }
820
- - { id: link-deal, source: link-commission, target: mark-deal-won }
821
- - { id: deal-client, source: mark-deal-won, target: attach-client }
822
- - { id: client-lead, source: attach-client, target: convert-lead }
823
-
824
- # Rendered by both CRM and Browser through the shared entity-action runner.
825
- # The lead facet requirement keeps the qualification playbook out of general
826
- # person/company records; the commercial action is explicitly confirmed because
827
- # it writes a client handoff and commission record.
828
- actionPlacements:
829
- - profileSlug: person
830
- surface: entity-detail
831
- kind: playbook
832
- ref: Qualify a CRM lead
833
- label: Qualify lead
834
- when: { requiredFacetSlugs: [lead] }
835
-
836
- - profileSlug: company
837
- surface: entity-detail
838
- kind: playbook
839
- ref: Qualify a CRM lead
840
- label: Qualify lead
841
- when: { requiredFacetSlugs: [lead] }
842
-
843
- - profileSlug: deal
844
- surface: entity-detail
845
- kind: playbook
846
- ref: Advance a commercial proposal
847
- label: Advance proposal
848
-
849
- - profileSlug: deal
850
- surface: entity-detail
851
- kind: automation
852
- ref: Win and hand off
853
- label: Hand off won proposal
854
- when:
855
- propertyAnyEquals: { commercialStage: [won], dealStage: [won] }
856
- propertyNotEquals: { handoffStatus: handed_off }
857
- confirmation:
858
- title: Hand off this won proposal?
859
- description: This converts its qualified CRM lead counterparty and records the business developer commission.
860
- confirmLabel: Hand off proposal