@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
@@ -0,0 +1,1331 @@
1
+ import { ProfilePresentation } from '@synap-core/types/presentation';
2
+ import { SpaceBrief, SpaceTemplateRule, SpaceTemplateSkill, SpaceBriefCollectTarget } from '@synap-core/types/space-brief';
3
+ import { CapabilityIntentSlug } from '@synap-core/types/capability-intents';
4
+
5
+ /**
6
+ * @synap-core/workspace-templates — Types
7
+ *
8
+ * Canonical shape of a workspace template.
9
+ * YAML source files validate against these types.
10
+ * Every consumer (browser, backend, CLI, marketplace) imports from here.
11
+ */
12
+ type TemplateAppKind = "native" | "stored" | "url";
13
+ interface TemplateAppRef {
14
+ kind: TemplateAppKind;
15
+ /** For kind='native': the appId registered in the browser manifest */
16
+ appId?: string;
17
+ /** For kind='native': how the platform renders the app */
18
+ rendererType?: "native" | "external" | "iframe-srcdoc";
19
+ /** For kind='stored': the cell key registered in the cell registry */
20
+ cellKey?: string;
21
+ /** For kind='stored': default props passed to the cell */
22
+ props?: Record<string, WorkspaceJsonValue>;
23
+ /** For kind='url': external URL to open */
24
+ url?: string;
25
+ /** Human label */
26
+ title?: string;
27
+ }
28
+ type WorkspaceJsonValue = string | number | boolean | null | WorkspaceJsonValue[] | {
29
+ [key: string]: WorkspaceJsonValue;
30
+ };
31
+ type WorkspacePrimarySurface = {
32
+ kind: "app";
33
+ appId: string;
34
+ rendererType: "native";
35
+ title?: string;
36
+ props?: Record<string, WorkspaceJsonValue>;
37
+ } | {
38
+ kind: "app";
39
+ appId: string;
40
+ rendererType: "external";
41
+ url: string;
42
+ title?: string;
43
+ props?: Record<string, WorkspaceJsonValue>;
44
+ } | {
45
+ kind: "cell";
46
+ cellKey: string;
47
+ title?: string;
48
+ props?: Record<string, WorkspaceJsonValue>;
49
+ } | {
50
+ /**
51
+ * Ordinary website. Unlike an external `app`, this has no trusted app
52
+ * identity and is always opened through the Browser's unprivileged URL
53
+ * surface.
54
+ */
55
+ kind: "url";
56
+ url: string;
57
+ title?: string;
58
+ /**
59
+ * The pod app this website is (spec 17 §7.1): its Client ID Metadata
60
+ * Document URL. A launch hint only: the Browser opens the site with the
61
+ * space's pod `iss` so the app starts that pod's OAuth flow. It grants
62
+ * no identity, bridge or credential; the site stays an unprivileged URL.
63
+ * Mirrors the pod's `WorkspacePrimarySurface` (@synap/database).
64
+ */
65
+ podApp?: {
66
+ clientId: string;
67
+ };
68
+ } | {
69
+ kind: "view";
70
+ viewId: string;
71
+ title?: string;
72
+ };
73
+ /**
74
+ * Authoring-time view reference. View IDs do not exist until provisioning, so
75
+ * templates and packages address a view by its stable authored name and/or
76
+ * slug. The pod resolves this to `WorkspacePrimarySurface` before persistence.
77
+ */
78
+ type WorkspacePrimarySurfaceViewReference = {
79
+ kind: "view";
80
+ viewName: string;
81
+ viewSlug?: string;
82
+ title?: string;
83
+ } | {
84
+ kind: "view";
85
+ viewName?: string;
86
+ viewSlug: string;
87
+ title?: string;
88
+ };
89
+ type TemplatePrimarySurface = WorkspacePrimarySurface | WorkspacePrimarySurfaceViewReference;
90
+ interface TemplateProperty {
91
+ slug: string;
92
+ label: string;
93
+ valueType: string;
94
+ inputType?: string;
95
+ placeholder?: string;
96
+ enumValues?: string[];
97
+ constraints?: Record<string, unknown>;
98
+ targetProfileSlug?: string;
99
+ }
100
+ interface TemplateProfile {
101
+ slug: string;
102
+ displayName: string;
103
+ icon?: string;
104
+ color?: string;
105
+ description?: string;
106
+ /**
107
+ * Visibility of the profile DEFINITION — who can USE this vocabulary.
108
+ * `system` = pod-wide; `shared` = ONE row reachable from other workspaces via
109
+ * a `profile_workspace_access` grant; omit or `workspace` = this workspace
110
+ * only. Orthogonal to `entityScope` below — do not conflate the two axes. */
111
+ scope?: string;
112
+ /**
113
+ * Placement of the profile's ENTITY ROWS — where the data LANDS.
114
+ * `pod` → entities are created with `workspace_id = NULL` and are therefore
115
+ * visible in every workspace; `workspace` (the backend default when omitted)
116
+ * → entities belong to the workspace that created them.
117
+ *
118
+ * Independent of `scope`: a `shared` profile can still mint workspace-scoped
119
+ * rows, and a `workspace`-scoped profile could in principle mint pod-wide
120
+ * ones. Both provisioning doors thread this verbatim into
121
+ * `ProfileRepository.create` (`create-workspace-from-definition.ts:1149`,
122
+ * `reconcile-workspace-from-definition.ts:319`) — omitting it inherits the
123
+ * repo default (`workspace`), which is the unchanged behaviour for templates
124
+ * that do not declare it. Applied on CREATE only: neither door flips the
125
+ * `entity_scope` of an existing profile (a divergence is reported as an
126
+ * advisory `scopeConflict` and the live row is left alone).
127
+ */
128
+ entityScope?: "pod" | "workspace";
129
+ /** Semantic slug for system profiles. */
130
+ semanticSlug?: string;
131
+ /** Kind vs role profile. Omit for default ('kind'). */
132
+ profileKind?: "kind" | "role";
133
+ /** For profileKind='role': which base-kind profile slugs this role can attach to. */
134
+ applicableKinds?: string[];
135
+ properties: TemplateProperty[];
136
+ /**
137
+ * The kind's / role's ONE lifecycle (work model L1): which select property it
138
+ * is, and a category for each of its options. The pod folds the options onto
139
+ * that property and declares it (`declareLifecycle`); boards, pipelines and
140
+ * governance then read the category, never the option name.
141
+ * `validate.ts` (`lifecycle-*` rules) requires the option keys to be the
142
+ * property's `enumValues`, same order, and every template that declares this
143
+ * profile to declare the same lifecycle.
144
+ *
145
+ * This is the COMPILED shape. The YAML may instead adopt one of the ten base
146
+ * lifecycles (`TemplateLifecycleAdoption`, `lifecycle-presets.ts`) and may
147
+ * omit the select's `enumValues`; `resolveLifecyclePresets` compiles both
148
+ * into this shape before validation, generation and publish.
149
+ */
150
+ lifecycle?: TemplateLifecycle;
151
+ /**
152
+ * How entities of this kind PRESENT themselves (entity rendering, decision
153
+ * 8): the family (media · document · link · record · work), where its media
154
+ * lives, and optional per-altitude fields. Stored on the pod as
155
+ * `uiHints.presentation` and converged on every apply. Parsed by the ONE
156
+ * parser, `parseProfilePresentation` (`@synap-core/types/presentation`);
157
+ * `validate.ts` (`presentation-*` rules) also requires every named property
158
+ * to exist on this profile and every declaration of the slug to agree.
159
+ */
160
+ presentation?: ProfilePresentation;
161
+ }
162
+ /** Fixed categories (`@synap-core/types/lifecycle` LIFECYCLE_CATEGORIES). */
163
+ type TemplateLifecycleCategory = "open" | "active" | "paused" | "done" | "lost";
164
+ interface TemplateLifecycleOption {
165
+ /** The stored value — one of the property's `enumValues`. */
166
+ key: string;
167
+ label?: string;
168
+ category: TemplateLifecycleCategory;
169
+ /** A `UnitTone` token; absent ⇒ the category's default tone. */
170
+ tone?: string;
171
+ /** Only a person may move a thing INTO this option. */
172
+ humanOnly?: boolean;
173
+ /**
174
+ * Days a thing may sit in this option before it is STUCK (an intent
175
+ * surface's Stuck count). Whole days, 1–3650; open/active/paused only.
176
+ */
177
+ stuckAfterDays?: number;
178
+ /**
179
+ * The date property this step is bound to (an invoice's `dueDate` while
180
+ * `sent`): the thing is LATE once that date passes while it stands here.
181
+ * A property slug; open/active/paused only.
182
+ */
183
+ dateBinding?: string;
184
+ /**
185
+ * The wait this step declares: an ACTIVE step such as "sent" waits on
186
+ * someone without being a pause. Open/active/paused only.
187
+ */
188
+ waits?: TemplateLifecycleOptionWaits;
189
+ }
190
+ /** A step's declared wait (the pod's `LifecycleOptionWaits`). */
191
+ interface TemplateLifecycleOptionWaits {
192
+ /** A hold's `on`, never `unspecified`: person · agent · external · thing · decision · date · nobody. */
193
+ on: "person" | "agent" | "external" | "thing" | "decision" | "date" | "nobody";
194
+ /** The finer kind (`WAIT_KINDS`: "signature", "payment"…); absent ⇒ derived from `on`. */
195
+ waitKind?: string;
196
+ /** The property or relation naming WHO or WHAT is waited on (a deal's `contactId`). */
197
+ refFrom?: string;
198
+ /** The date property that ends the wait (a lead's `nextActionAt`). */
199
+ dateBinding?: string;
200
+ }
201
+ interface TemplateLifecycle {
202
+ /** The lifecycle property's slug (a select of this profile). */
203
+ property: string;
204
+ options: TemplateLifecycleOption[];
205
+ }
206
+ interface TemplateView {
207
+ name: string;
208
+ slug?: string;
209
+ type: string;
210
+ scopeProfileSlug?: string;
211
+ scopeProfileSlugs?: string[];
212
+ config?: Record<string, unknown>;
213
+ /** If true, this view auto-selected as the default view for this workspace */
214
+ defaultView?: boolean;
215
+ description?: string;
216
+ groupBy?: string;
217
+ }
218
+ interface TemplateEntityLink {
219
+ sourceProfileSlug: string;
220
+ targetProfileSlug: string;
221
+ type: string;
222
+ label?: string;
223
+ /**
224
+ * Every record of the source kind should carry this link (an edge of `type`
225
+ * to the target kind). Several rows of one source kind and one `type` are ONE
226
+ * rule, met by an edge to any of their targets. The pod's template reconcile
227
+ * stores it on `profile_relations.metadata` (`required`, `requiredBy`); its
228
+ * create doors warn when a new record leaves it out (never refuse yet) and
229
+ * template health lists the records missing it. Omitted = says nothing (a
230
+ * mark another template set stays); `false` clears the mark.
231
+ */
232
+ required?: boolean;
233
+ }
234
+ /**
235
+ * A domain-level relation TYPE definition — a `relation_defs` row, the workspace's
236
+ * relation vocabulary. Distinct from {@link TemplateEntityLink}, which is a
237
+ * profile→profile EDGE (and only carries `type` + `label`). A relation def stands
238
+ * alone: it has no source/target profile pairing and it carries the rich metadata
239
+ * (`description`, `isDirectional`, `uiHints`) that the entity-link path drops.
240
+ *
241
+ * Mirrors `DefaultRelationDef` in synap-backend
242
+ * `packages/database/src/utils/default-relation-defs.ts` VERBATIM — the door
243
+ * find-or-creates a `relation_defs` row from each entry (idempotent by
244
+ * `slug` within the workspace), which is `ensureDefaultRelationDefs`'s body.
245
+ */
246
+ interface TemplateRelationDef {
247
+ slug: string;
248
+ displayName: string;
249
+ description?: string;
250
+ isDirectional?: boolean;
251
+ uiHints?: {
252
+ category?: "workflow" | "social" | "reference" | "hierarchy";
253
+ inverseLabel?: string;
254
+ };
255
+ }
256
+ interface TemplateSeedEntity {
257
+ profileSlug: string;
258
+ title: string;
259
+ properties?: Record<string, unknown>;
260
+ content?: string;
261
+ }
262
+ /**
263
+ * Relations between seed entities, created on provisioning. `sourceRef`/
264
+ * `targetRef` reference seed-entity titles (or refs) defined in `seedEntities`.
265
+ * Mirrors `suggestedRelations` in synap-backend `create-workspace-from-definition.ts`.
266
+ */
267
+ interface TemplateSuggestedRelation {
268
+ sourceRef: string;
269
+ targetRef: string;
270
+ type: string;
271
+ metadata?: Record<string, unknown>;
272
+ }
273
+ /**
274
+ * Entity-card display templates. Mirrors `displayTemplates` in synap-backend
275
+ * `create-workspace-from-definition.ts`.
276
+ */
277
+ interface TemplateDisplayTemplate {
278
+ name: string;
279
+ description?: string;
280
+ entityType?: string;
281
+ targetType?: string;
282
+ isDefault?: boolean;
283
+ config: Record<string, unknown>;
284
+ }
285
+ interface TemplateSidebarSurface {
286
+ kind: "cell" | "view" | "entity" | "document" | "channel" | "app" | "url";
287
+ cellKey?: string;
288
+ viewId?: string;
289
+ viewName?: string;
290
+ appId?: string;
291
+ url?: string;
292
+ rendererType?: "native" | "external" | "iframe-srcdoc";
293
+ placement?: "main" | "side" | "floating" | "modal" | "popover" | "embed";
294
+ displayMode?: "compact" | "medium" | "full";
295
+ props?: Record<string, unknown>;
296
+ title?: string;
297
+ meta?: Record<string, unknown>;
298
+ }
299
+ interface TemplateSidebarItem {
300
+ kind: "app" | "view" | "profile" | "external" | "cell";
301
+ appId?: string;
302
+ viewName?: string;
303
+ viewId?: string;
304
+ profileSlug?: string;
305
+ url?: string;
306
+ cellKey?: string;
307
+ cellProps?: Record<string, unknown>;
308
+ /** When present, bypasses kind-based dispatch — full surface control */
309
+ surface?: TemplateSidebarSurface;
310
+ label?: string;
311
+ icon?: string;
312
+ section?: string;
313
+ matchUrls?: string[];
314
+ }
315
+ interface TemplateLayoutConfig {
316
+ pinnedApps?: string[];
317
+ defaultView?: string;
318
+ /**
319
+ * Canonical first screen for this workspace.
320
+ *
321
+ * `undefined` means the template has no opinion during reconciliation,
322
+ * `null` explicitly returns the workspace to its home surface, and a
323
+ * descriptor replaces the current primary surface. */
324
+ primarySurface?: TemplatePrimarySurface | null;
325
+ /** Compatibility input only. New templates should use `app:` or `primarySurface`. */
326
+ defaultApp?: string | null;
327
+ theme?: string;
328
+ sidebarItems?: TemplateSidebarItem[];
329
+ }
330
+ interface TemplateBentoBlock {
331
+ kind: "view" | "widget";
332
+ viewName?: string;
333
+ widgetType?: string;
334
+ pos: {
335
+ x: number;
336
+ y: number;
337
+ w: number;
338
+ h: number;
339
+ };
340
+ config?: Record<string, unknown>;
341
+ overrides?: Record<string, unknown>;
342
+ }
343
+ interface TemplateProfileEntityBentoTemplates {
344
+ [profileSlug: string]: {
345
+ blocks: Array<Record<string, unknown>>;
346
+ };
347
+ }
348
+ /** Mirrors `WorkspaceSourceRole` in synap-backend `schema/workspaces.ts`. */
349
+ type TemplateSourceRole = "provider" | "consumer" | "provider-consumer";
350
+ /** Mirrors `WorkspaceDefaultSource` in synap-backend `schema/workspaces.ts`. */
351
+ interface TemplateDefaultSource {
352
+ /** The workspace id that supplies this capability domain. */
353
+ workspaceId: string;
354
+ /** The capability domain this source satisfies (e.g. "brand", "strategy"). */
355
+ capability?: string;
356
+ /** Optional profile slug the source resolves to. */
357
+ profileSlug?: string;
358
+ /** Human label for the source. */
359
+ label?: string;
360
+ }
361
+ type TemplateOnboardingCollectTarget = SpaceBriefCollectTarget;
362
+ /**
363
+ * A template's brief. `rules` is NOT authored here — a template declares its
364
+ * rules at the top level (`rules:`); the pod stores only refs to them.
365
+ */
366
+ type TemplateOnboarding = Omit<SpaceBrief, "rules">;
367
+ /**
368
+ * A rule a template installs in its space — applied through the pod's ONE rule
369
+ * door, stamped so a later template update never overwrites a rule the user
370
+ * edited. `key` is its stable identity across template versions.
371
+ */
372
+ type TemplateRule = SpaceTemplateRule;
373
+ /**
374
+ * A SKILL a template declares for its space (`skills:`). Same shape as a rule —
375
+ * the template declares, the pod LINKS the skill to the space at install and
376
+ * keeps a ref in the brief. `mode: "always"` is prepended to every session or
377
+ * run started in the space; `on-demand` is surfaced and ranked first instead.
378
+ * Validation (`validateSpaceSkillDeclaration`) is shared with the pod's applier.
379
+ */
380
+ type TemplateSkill = SpaceTemplateSkill;
381
+ interface TemplatePlaybookParam {
382
+ name: string;
383
+ type: "text" | "number" | "entity" | "choice" | "boolean";
384
+ label?: string;
385
+ required?: boolean;
386
+ defaultValue?: unknown;
387
+ }
388
+ interface TemplatePlaybook {
389
+ name: string;
390
+ description?: string;
391
+ goalTemplate: string;
392
+ params?: TemplatePlaybookParam[];
393
+ executor?: "is-agent" | "external-agent" | "hybrid";
394
+ /**
395
+ * Legacy fan-out modes stay strings. `pinned` is an object: first eligible
396
+ * pin, then `fallback`. Entity ids are not part of this shape.
397
+ */
398
+ inputStrategy?: "none" | "static" | "rotating" | "query" | {
399
+ kind: "pinned";
400
+ fallback?: {
401
+ filter?: Record<string, unknown>;
402
+ orderBy?: string;
403
+ orderDir?: "asc" | "desc";
404
+ };
405
+ };
406
+ channelSpec?: {
407
+ type: "GROUP" | "AGENT_COLLAB" | "THREAD";
408
+ members?: string[];
409
+ aiReactionMode?: "on_mention" | "always" | "never";
410
+ };
411
+ /**
412
+ * A cron schedule that maintains ONE backing cron automation (a single
413
+ * `playbook_run` node) which the pod's `automation-cron-scheduler` fires.
414
+ * `enabled` is read STRICTLY (`materializePlaybookCronAutomation` requires
415
+ * `enabled === true`) — omit it and the backing cron is NEVER created, so the
416
+ * playbook silently never fires. Always set it explicitly.
417
+ */
418
+ schedule?: {
419
+ cron: string;
420
+ enabled: boolean;
421
+ } | null;
422
+ /** tool/skill keys this playbook grants. */
423
+ grants?: string[];
424
+ /**
425
+ * Free-form playbook metadata → `playbooks.metadata`. Carries the propose-only
426
+ * governance marker for unattended maintenance playbooks:
427
+ * `{ governance: { forceProposeWrites: true } }` — every agent write in the
428
+ * playbook's scheduled sessions then routes to a reviewable proposal.
429
+ * `lineage` is a CONVENTION (no reader enforces it): where the process comes
430
+ * from (an APQC PCF id, a named method, O*NET task ids).
431
+ */
432
+ metadata?: Record<string, unknown> & {
433
+ lineage?: TemplatePlaybookLineage;
434
+ };
435
+ /**
436
+ * The entity kind this playbook operates over, persisted to
437
+ * `playbooks.subject_profile`. Makes the playbook matchable by
438
+ * `playbooks.matchForEntity` (filters `subject_profile->>'profileSlug'`), so a
439
+ * captured entity of this kind can auto-launch the playbook as a session.
440
+ *
441
+ * `statusProperty` names the subject kind's SELECT property that holds its
442
+ * lifecycle (e.g. `post-status`). It is what ties `stages[].subjectStatus`
443
+ * to the subject: advancing into a stage writes that value (governed), and
444
+ * the subject entering the value advances an open run to the stage.
445
+ * `validate.ts` checks it is a select property of the kind, and that every
446
+ * `subjectStatus` / activator `status` is one of its enum values.
447
+ */
448
+ subjectProfile?: {
449
+ profileSlug: string;
450
+ /**
451
+ * Narrows a kind-bound SCHEDULE's fan-out: a JSON string of
452
+ * `{ "properties.<key>": value }`. A STRING, because the pod's cron door
453
+ * keeps only a string (`readSubjectProfile`, synap-backend
454
+ * cron-automation.ts) — an object would be dropped, and an unfiltered AI
455
+ * fan-out is refused, so the schedule would silently never be created.
456
+ */
457
+ filter?: string;
458
+ statusProperty?: string;
459
+ };
460
+ /**
461
+ * Playbook-level slots: what a run of this process is expected to produce.
462
+ * Instantiated as the session's owed slots (`sanitizeDeclaredOutputs`).
463
+ */
464
+ expectedOutputs?: TemplateExpectedOutput[];
465
+ /** Binary acceptance criteria every run is graded against (pod `sessionCriteriaSchema`). */
466
+ criteria?: TemplateCriterion[];
467
+ /**
468
+ * The abstract intents the process needs the pod to be able to do — the
469
+ * closed `capability_intents` vocabulary (`@synap-core/types/capability-intents`).
470
+ */
471
+ requiredIntents?: string[];
472
+ /**
473
+ * DECLARATIONS of when the process starts. Compiled at install/apply into
474
+ * governed rules through the pod's ONE rule door and linked in
475
+ * `playbook_automations` (role `activator`) — never hand-written template
476
+ * `automations:`. Public templates default to `mode: propose`.
477
+ */
478
+ activators?: TemplatePlaybookActivator[];
479
+ /**
480
+ * TEMPLATE-AUTHORING ONLY. Values of `subjectProfile.statusProperty` that no
481
+ * stage owns because a PERSON sets them (e.g. Idea, Archived). The lifecycle
482
+ * coverage ratchet (`lifecycle-coverage.test.ts`) requires every enum value
483
+ * of the status property to be either a stage's `subjectStatus` or listed
484
+ * here, so a lifecycle state can never be silently orphaned by a process.
485
+ */
486
+ humanOnlyStatuses?: string[];
487
+ status?: "draft" | "active" | "paused";
488
+ /**
489
+ * `project` = a TRACK template (a method a project runs over its `stages`);
490
+ * `session` / omitted = a work template. The kind is DERIVED from this, never
491
+ * declared elsewhere (concepts.md).
492
+ */
493
+ scope?: "session" | "project";
494
+ /** Ordered steps. Validated at the pod door by `playbookStageSchema`. */
495
+ stages?: TemplatePlaybookStage[];
496
+ }
497
+ /**
498
+ * One step of a playbook. Mirrors the pod's `PlaybookStage` (@synap/playbooks)
499
+ * for the fields templates author; the pod schema stays the authority.
500
+ */
501
+ interface TemplatePlaybookStage {
502
+ key: string;
503
+ name: string;
504
+ category: "backlog" | "planned" | "started" | "paused" | "completed" | "canceled";
505
+ description?: string;
506
+ goal?: string;
507
+ suggestedTasks?: string[];
508
+ indefinite?: boolean;
509
+ /**
510
+ * The DOMAIN the step is worked in: a workspace TEMPLATE slug that becomes a
511
+ * workspace's `package_slug` (e.g. `foundation`, `finance`) — never an
512
+ * overlay's slug (an overlay never owns a workspace), a workspace id or a
513
+ * display name. `validate.ts` rule `stage-domain-*` enforces it.
514
+ */
515
+ domain?: string;
516
+ expectedOutputs?: TemplateExpectedOutput[];
517
+ /** Binary acceptance criteria of THIS stage (a `check` gate evaluates them). */
518
+ criteria?: TemplateCriterion[];
519
+ /**
520
+ * Entry gate. `human` files a review; `check` evaluates the criteria of the
521
+ * stage being LEFT before the run may continue (pod `stage-gate.ts`).
522
+ */
523
+ gate?: {
524
+ kind: "human" | "check";
525
+ proposalType?: "playbook.stage_gate";
526
+ };
527
+ /**
528
+ * The value of the playbook's `subjectProfile.statusProperty` this stage
529
+ * corresponds to. Advancing INTO the stage writes it to the subject
530
+ * (governed); the subject ENTERING it advances an open run to the stage.
531
+ */
532
+ subjectStatus?: string;
533
+ /** Where a rejected human gate / failed check sends the run back (a stage key or name). */
534
+ onFail?: {
535
+ toStage: string;
536
+ };
537
+ [key: string]: unknown;
538
+ }
539
+ /**
540
+ * One declared output slot (playbook- or stage-level). Mirrors the pod's
541
+ * `ExpectedOutput` (@synap/playbooks) for the fields templates author.
542
+ */
543
+ interface TemplateExpectedOutput {
544
+ /** The output's kind — a profile slug for entities. */
545
+ kind: string;
546
+ label: string;
547
+ icon?: string;
548
+ owner?: "human" | "agent";
549
+ key?: string;
550
+ /**
551
+ * Relation type written output → subject when the slot is satisfied (e.g.
552
+ * `made_for`, `derived_from`). Must resolve to a relation the corpus defines
553
+ * (`entityLinks[].type` / `relationDefs[].slug`). `none` = deliberately no
554
+ * edge (a playbook with no subject, whose outputs stand alone).
555
+ */
556
+ relationToSubject?: string;
557
+ /**
558
+ * `true` = nobody owes this slot (synap-backend 30a9ab85): no needs-you row,
559
+ * never an unmet outcome at a gate or at completion; filled, it counts like
560
+ * any slot. Absent = required. Read STRICTLY — only a boolean `true`
561
+ * (validate.ts `output-optional-not-boolean`). A BIRTH declaration: a change
562
+ * reaches new runs and new stage entries only.
563
+ */
564
+ optional?: boolean;
565
+ [key: string]: unknown;
566
+ }
567
+ /** A binary acceptance criterion — mirrors the pod's strict `sessionCriterionSchema`. */
568
+ interface TemplateCriterion {
569
+ /** Lowercase slug, unique within the list. */
570
+ key: string;
571
+ statement: string;
572
+ required?: boolean;
573
+ check: {
574
+ kind: "evidence" | "capability" | "judge" | "human";
575
+ capability?: string;
576
+ evidenceKey?: string;
577
+ hint?: string;
578
+ };
579
+ stageKey?: string;
580
+ }
581
+ /** A declared process activator (compiled to a governed rule at install). */
582
+ interface TemplatePlaybookActivator {
583
+ /**
584
+ * `created` / `enters_status` per thing; `count` (≥ `min` things in
585
+ * `status`) and `schedule` (on `cron`) over the whole set; `manual` a
586
+ * button that compiles no rule. The pod's grammar (`ACTIVATOR_ON`).
587
+ */
588
+ on: "created" | "enters_status" | "count" | "schedule" | "manual";
589
+ /** Required for `enters_status` / `count`, optional for `schedule`: a value of the status property. */
590
+ status?: string;
591
+ /** Required for `schedule` (UTC). */
592
+ cron?: string;
593
+ /** Required for `count`. */
594
+ min?: number;
595
+ /** `per_thing` (default) or `per_moment`; count/schedule are per_moment. */
596
+ size?: "per_thing" | "per_moment";
597
+ mode: "run" | "propose";
598
+ /** Pending approvals before the worker stops starting runs (default 20). */
599
+ maxPendingApprovals?: number;
600
+ /** Per-thing `created` / `enters_status` only: leave out a thing that carries this property. */
601
+ unless?: {
602
+ property: string;
603
+ present: true;
604
+ };
605
+ }
606
+ /** Where a process comes from — convention only, read by nobody yet. */
607
+ interface TemplatePlaybookLineage {
608
+ apqc?: string;
609
+ method?: string;
610
+ onet?: string[];
611
+ }
612
+ interface TemplateAutomation {
613
+ /** Stable local key (unused on the wire today — reserved for dedup/refs). */
614
+ key?: string;
615
+ name: string;
616
+ description?: string;
617
+ triggerType: "event" | "cron" | "webhook" | "manual";
618
+ triggerConfig?: Record<string, unknown>;
619
+ flow: {
620
+ nodes: unknown[];
621
+ edges: unknown[];
622
+ precondition?: string;
623
+ };
624
+ status?: "draft" | "active" | "paused";
625
+ }
626
+ interface TemplateCommandDerivedInput {
627
+ name: string;
628
+ label?: string;
629
+ /** Mirrors `DerivedInput.type` (text | number | entity | view | choice). */
630
+ type?: string;
631
+ }
632
+ interface TemplateCommand {
633
+ title: string;
634
+ promptTemplate: string;
635
+ derivedInputs?: TemplateCommandDerivedInput[];
636
+ /** text | proposal | view */
637
+ outputMode?: string;
638
+ canCreateViews?: boolean;
639
+ /** read_only | propose_writes */
640
+ permissionsProfile?: string;
641
+ }
642
+ interface TemplateActionPlacement {
643
+ /** Entity kind whose detail surface this action appears on. */
644
+ profileSlug: string;
645
+ /** Where the action renders. Only "entity-detail" is consumed today. */
646
+ surface: "entity-detail" | string;
647
+ /** What the action does when clicked. */
648
+ kind: "capability" | "playbook" | "automation";
649
+ /**
650
+ * Reference to the thing to run: a capability verb key, or a playbook /
651
+ * automation NAME (resolved to a row id at apply time).
652
+ */
653
+ ref: string;
654
+ /** Human label shown on the action button. */
655
+ label: string;
656
+ /** Additional entity-state requirements, evaluated by the rendering surface. */
657
+ when?: {
658
+ /** All listed workspace facets must be present on the entity. */
659
+ requiredFacetSlugs?: string[];
660
+ /** Entity property values that must equal their configured literal values. */
661
+ propertyEquals?: Record<string, unknown>;
662
+ /** Any configured property/value match makes the action applicable. */
663
+ propertyAnyEquals?: Record<string, unknown[]>;
664
+ /** Entity property values that must not equal their configured literal values. */
665
+ propertyNotEquals?: Record<string, unknown>;
666
+ };
667
+ /** Explicit intent required before a consequential action is launched. */
668
+ confirmation?: {
669
+ title: string;
670
+ description?: string;
671
+ confirmLabel?: string;
672
+ };
673
+ }
674
+ interface TemplateIntegration {
675
+ /** Capability template key to install (matches a capability template). */
676
+ templateKey: string;
677
+ /** Override default params with {{var}} interpolation. */
678
+ params?: Record<string, string>;
679
+ /** "apply" (create+update) or "install" (create only). */
680
+ mode?: "apply" | "install";
681
+ }
682
+ interface TemplateExtendsRef {
683
+ source: string;
684
+ import?: {
685
+ profiles?: string[];
686
+ views?: string[];
687
+ };
688
+ }
689
+ /**
690
+ * A dependency this template declares on ANOTHER template/package. The install
691
+ * resolver (backend `POST /api/hub/packages/apply`) reads these to build the
692
+ * pod's template graph: every dependency is ensured present before this
693
+ * template is applied — missing ones install first (topologically) — and a
694
+ * `compose` dependency LAYERS this template's schema additively onto the
695
+ * dependency's workspace instead of creating a second workspace.
696
+ *
697
+ * This is the general composition primitive: a BASE template carries the
698
+ * agnostic data model; an OVERLAY template `compose`s onto it and adds the
699
+ * use-case-specific data (e.g. `blockchain-ecosystem` → `ecosystem`,
700
+ * `grants` → `operations`). Distinct from `extends` (which imports from a live
701
+ * workspace, tRPC-only) — `dependencies` is template→template.
702
+ */
703
+ /**
704
+ * PACKAGE_DEPENDENCY_KINDS — the dependency-kind vocabulary, declared ONCE.
705
+ *
706
+ * This tuple exists so consumers can IMPORT the vocabulary instead of
707
+ * hand-copying it. `TemplateDependency` is mirrored by hand in several other
708
+ * places — a comment cannot fail a build, an import can, but these mirrors live
709
+ * in repos this package does not own, so they must match this list EXACTLY:
710
+ *
711
+ * - marketplace `features/marketplace/src/types.ts`
712
+ * - onboarding `features/onboarding/src/templates/workspace-templates.ts`
713
+ * - browser `InstallPackageDialog.tsx`
714
+ * - synap-backend `package-definition.ts` (`PackageDependencyKind`)
715
+ * - hub-protocol REST `rest/packages.ts` (zod enum)
716
+ * - control-plane-api `db/schema/packages.ts` (`TemplateDependency` type)
717
+ * + `routes/packages.ts` (`DEPENDENCY_KINDS` zod enum)
718
+ *
719
+ * These are the 7 literals the wire accepts, in lockstep with the CP publish
720
+ * enum (`DEPENDENCY_KINDS = [...PACKAGE_TYPES, "automation"]`, CP
721
+ * `routes/packages.ts`), the hub install enum (`rest/packages.ts`), and the
722
+ * backend resolver's `PackageDependencyKind` (`@synap/database`).
723
+ *
724
+ * Resolver behaviour (backend `package-dependency-resolver.ts`):
725
+ * - `workspace` → resolve+install; the ONLY kind that may `compose`.
726
+ * - `capability` / `cell` → resolve+install, always `require`d (presence).
727
+ * - `skill` / `workflow` / `view` / `automation` → ACCEPTED and `require`d
728
+ * present, surfaced as `required-absent` (non-fatal) — no standalone by-slug
729
+ * applier on the pod yet; when one grows, give the kind its own branch.
730
+ *
731
+ * `'automation'` is legacy vocabulary: CP migration `0049_package_vocabulary`
732
+ * renamed the `automation` package category → `workflow` (which absorbs
733
+ * automation + playbook, `PACKAGE_TYPES` in CP `db/schema/packages.ts`). It
734
+ * stays accepted on the wire — and therefore in this tuple — for back-compat
735
+ * with dependencies published before the rename.
736
+ */
737
+ declare const PACKAGE_DEPENDENCY_KINDS: readonly ["workspace", "capability", "skill", "workflow", "view", "cell", "automation"];
738
+ /** What a `TemplateDependency` points at. Derived — never re-declare the list. */
739
+ type PackageDependencyKind = (typeof PACKAGE_DEPENDENCY_KINDS)[number];
740
+ interface TemplateDependency {
741
+ /** Slug of the template/package this one depends on. */
742
+ slug: string;
743
+ /**
744
+ * What the dependency is. Default `'workspace'`. Only `'workspace'`
745
+ * dependencies can be `compose`d; every other kind is always `require`d
746
+ * present without merging.
747
+ */
748
+ kind?: PackageDependencyKind;
749
+ /**
750
+ * How this template relates to the dependency:
751
+ * - `'compose'`: this template is an OVERLAY on the dependency's workspace.
752
+ * The base is installed first if absent, then this template's profiles /
753
+ * roles / relations / views are applied ADDITIVELY onto the base workspace
754
+ * — no separate workspace is created for this template.
755
+ * - `'require'` (default): the dependency must be present on the pod as its
756
+ * own artifact, but this template does not merge into it.
757
+ */
758
+ relation?: "compose" | "require";
759
+ /**
760
+ * Short human reason shown in the install-time "this also installs…" prompt.
761
+ */
762
+ reason?: string;
763
+ }
764
+ interface TemplateMeta {
765
+ slug: string;
766
+ name: string;
767
+ description: string;
768
+ icon: string;
769
+ color: string;
770
+ tags?: string[];
771
+ isPublic?: boolean;
772
+ /**
773
+ * Human-facing subject area used to SECTION the marketplace (CLI `market
774
+ * list`, browser New Space + catalog). Authored here so grouping is a
775
+ * property of the template, read by every surface — never re-derived from a
776
+ * hardcoded slug→group map in a consumer. NOT `category` (that is the
777
+ * PACKAGE TYPE — `workspace`/`capability`/…). Optional and open: an unknown
778
+ * or missing value is grouped, never dropped — see `./domains.ts`.
779
+ */
780
+ domain?: string;
781
+ /**
782
+ * WHAT THE SPACE PRODUCES — the purpose word shown first ("Product · Dev")
783
+ * and the kinds/roles it makes, in order. An empty `produces` (or none) makes
784
+ * the space a LIBRARY. Every produced profile is the template's own or one
785
+ * it depends on, and declares a lifecycle (`validate.ts` `intent-*` rules).
786
+ * Forwarded to the pod (top-level `intent` on both doors), which projects it into
787
+ * `workspaces.settings.intent`.
788
+ */
789
+ intent?: TemplateIntent;
790
+ /**
791
+ * An ONBOARDING START: this space offers itself as a first thing to run
792
+ * ("What should Synap run first?"). Declared once here, read by the pod, the
793
+ * CP and the landing. Rules: `validate.ts` `start-*`. Forwarded as top-level
794
+ * `start` on the package door, never in `_meta`.
795
+ */
796
+ start?: TemplateStart;
797
+ }
798
+ /** `meta.start.label` reuses {@link INTENT_LABEL_MAX}; these bound the lists. */
799
+ declare const START_VIEWS_MAX = 3;
800
+ declare const START_EXAMPLE_RANGE: readonly [4, 6];
801
+ declare const START_STARTERS_RANGE: readonly [3, 6];
802
+ /** `meta.start` — see {@link TemplateMeta.start}. */
803
+ interface TemplateStart {
804
+ /** Card order; unique across the catalog's starts. */
805
+ order: number;
806
+ /** ≤ {@link INTENT_LABEL_MAX} chars. */
807
+ label: string;
808
+ promise: string;
809
+ /** Identity ids this start is suggested for; each id belongs to one start. */
810
+ suggestFor: string[];
811
+ /** The produced kind the views and the first session are about. */
812
+ profile: string;
813
+ /** 1-3 slugs of THIS template's views, scoped to `profile`; first = default. */
814
+ views: string[];
815
+ /** Preview rows, never written. `values` keys are properties of `profile`. */
816
+ example: Array<{
817
+ title: string;
818
+ values?: Record<string, unknown>;
819
+ }>;
820
+ firstSession: {
821
+ title: string;
822
+ goal: string;
823
+ };
824
+ /** "Build it with me" chips. */
825
+ starters: string[];
826
+ }
827
+ /** `meta.intent.label` max — the purpose word must fit before " · <name>". */
828
+ declare const INTENT_LABEL_MAX = 24;
829
+ /** `meta.intent` — see {@link TemplateMeta.intent}. */
830
+ interface TemplateIntent {
831
+ /** ≤ {@link INTENT_LABEL_MAX} chars. */
832
+ label: string;
833
+ produces?: Array<{
834
+ profile: string;
835
+ }>;
836
+ }
837
+ interface WorkspaceYaml {
838
+ /** Template metadata — not sent to backend, used for listing/UI */
839
+ meta: TemplateMeta;
840
+ /**
841
+ * THE WORKSPACE'S TASK REQUIREMENTS — the specific intents (closed
842
+ * vocabulary, `@synap-core/types/capability-intents`) this workspace needs to
843
+ * function. The SSOT for WHAT THE SPACE REQUIRES, as distinct from
844
+ * `workspace.capabilities`, which names what it PROVIDES to others.
845
+ *
846
+ * Every value is validated against the closed vocabulary by
847
+ * `validateTemplate` (`task-intent-unknown`), so a typo fails at authoring
848
+ * time rather than installing a capability axis nobody can route.
849
+ *
850
+ * Deliberately NOT forwarded by either converter yet: the backend has no
851
+ * `taskIntents` sink on `createFromDefinition` (see `WorkspaceDefinitionDropped`
852
+ * in `define.ts`, which records that). Phase 1 is the declaration + its
853
+ * guard; wiring it to a sink is a follow-up that must edit that ledger.
854
+ */
855
+ taskIntents?: CapabilityIntentSlug[];
856
+ /** The workspace definition sent to createFromDefinition */
857
+ workspace: {
858
+ name: string;
859
+ description: string;
860
+ proposalId?: string;
861
+ subtype?: string;
862
+ /**
863
+ * Workspace classifier — consumed by createFromDefinition (settings.workspaceType,
864
+ * creator-role + agent-workspace behavior). Mirrors the backend union.
865
+ */
866
+ workspaceType?: "personal" | "agent" | "project" | "operational";
867
+ visibility?: string;
868
+ /** Capabilities this workspace provides (e.g. "brand.library", "content.pipeline") */
869
+ capabilities?: string[];
870
+ /**
871
+ * Cross-workspace dependency roles.
872
+ * E.g. { brand: "consumer", content: "provider" }
873
+ * "consumer" = this workspace reads from another workspace of that capability
874
+ * "provider" = this workspace provides that capability to others
875
+ */
876
+ sourceRoles?: Record<string, TemplateSourceRole>;
877
+ /**
878
+ * Pins which workspace supplies each capability domain for this workspace.
879
+ * E.g. { brand: { workspaceId: "..." } } — read by the IS source resolver
880
+ * (resolveBrandWorkspaceId / resolveFoundationWorkspaceId) before falling
881
+ * back to provider role. Usually set at runtime, not in a template, but
882
+ * carried here so it round-trips through the canonical seam.
883
+ */
884
+ defaultSources?: Record<string, TemplateDefaultSource>;
885
+ };
886
+ /** Entity profiles — the data schema */
887
+ profiles: TemplateProfile[];
888
+ /** Curated views — only the ones that add value */
889
+ views?: TemplateView[];
890
+ /** Schema-level links between entity types */
891
+ entityLinks?: TemplateEntityLink[];
892
+ /**
893
+ * Domain-level relation TYPE vocabulary seeded into the workspace's
894
+ * `relation_defs`. Distinct from `entityLinks` (profile→profile edges): a
895
+ * relation def stands alone and carries `description`/`isDirectional`/`uiHints`.
896
+ * The `base` template carries the universal defaults. See {@link TemplateRelationDef}.
897
+ */
898
+ relationDefs?: TemplateRelationDef[];
899
+ /**
900
+ * Workspace-scoped intelligence commands (prompt-template "Default Command
901
+ * Pack") seeded with the workspace. The `base` template carries the universal
902
+ * pack. See {@link TemplateCommand}.
903
+ */
904
+ commands?: TemplateCommand[];
905
+ /** Initial data to seed on workspace creation */
906
+ seedEntities?: TemplateSeedEntity[];
907
+ /** Relations between seed entities, created on provisioning */
908
+ suggestedRelations?: TemplateSuggestedRelation[];
909
+ /** Entity-card display templates */
910
+ displayTemplates?: TemplateDisplayTemplate[];
911
+ /** App reference — what opens as first screen */
912
+ app?: TemplateAppRef;
913
+ /** Browser sidebar + layout config */
914
+ layout?: TemplateLayoutConfig;
915
+ /** Bento dashboard */
916
+ bento?: {
917
+ viewName?: string;
918
+ blocks?: TemplateBentoBlock[];
919
+ };
920
+ /** Per-profile entity bento layouts */
921
+ profileEntityBentoTemplates?: TemplateProfileEntityBentoTemplates;
922
+ /** Playbooks (session templates) seeded with the workspace */
923
+ playbooks?: TemplatePlaybook[];
924
+ /**
925
+ * Flow-based automations (WHEN→THEN triggers) seeded with the workspace.
926
+ * Applier-only — see {@link TemplateAutomation}.
927
+ */
928
+ automations?: TemplateAutomation[];
929
+ /**
930
+ * Entity-detail action placements seeded into `settings.actionPlacements`.
931
+ * See {@link TemplateActionPlacement}.
932
+ */
933
+ actionPlacements?: TemplateActionPlacement[];
934
+ /** Capability templates (tools/connectors) to install on provisioning */
935
+ integrations?: TemplateIntegration[];
936
+ /**
937
+ * Per-workspace onboarding context. Written to workspace.settings.onboarding
938
+ * and read by the shared `onboard` skill to run a domain-specific adaptive
939
+ * interview — no per-domain skill file needed.
940
+ */
941
+ onboarding?: TemplateOnboarding;
942
+ /**
943
+ * Rules this template installs in its space (package `rules[]`). See
944
+ * {@link TemplateRule}.
945
+ */
946
+ rules?: TemplateRule[];
947
+ /**
948
+ * Skills this template declares for its space (package `skills[]`). The pod
949
+ * links each to the new space at install, approved skills only, so every AI
950
+ * working there is told them. See {@link TemplateSkill}.
951
+ */
952
+ skills?: TemplateSkill[];
953
+ /**
954
+ * The space's own experience as CODE: the modules this template builds into
955
+ * sandboxed frame cells and installs in its space (package `cells[]`, typeKey
956
+ * `cell:<meta.slug>:<key>`). The template's `app: {kind: stored, cellKey}`
957
+ * opens one of them. See {@link TemplateSpacePackage}.
958
+ */
959
+ spacePackage?: TemplateSpacePackage;
960
+ /** Inherit profiles/views from other workspaces */
961
+ extends?: TemplateExtendsRef[];
962
+ /**
963
+ * Template-composition dependencies — other templates this one needs. The
964
+ * install resolver installs missing dependencies first and, for a `compose`
965
+ * dependency, layers this template additively onto the dependency's
966
+ * workspace. See {@link TemplateDependency}.
967
+ */
968
+ dependencies?: TemplateDependency[];
969
+ }
970
+ /**
971
+ * One module of a space package. `source` is the entry file, relative to the
972
+ * synap-app repo root and under `packages/web/src/space-packages/`, so the
973
+ * package is built from the SAME shared components every surface uses, never
974
+ * from a copy. `scripts/build-space-packages.mjs` bundles it (React external,
975
+ * host-inlined in the frame; its CSS injected by the module) into
976
+ * `src/space-packages.generated.ts`, and `toPackageDefinition` carries it as a
977
+ * `frame` cell.
978
+ */
979
+ interface TemplateSpacePackageCell {
980
+ /** Cell key inside the package: the installed typeKey is `cell:<meta.slug>:<key>`. */
981
+ key: string;
982
+ /** Display name of the installed cell. */
983
+ name: string;
984
+ /** Entry module, repo-relative (`packages/web/src/space-packages/<pkg>/<file>.tsx`). */
985
+ source: string;
986
+ }
987
+ /** The space package a template installs (base layer; the person's overlay comes later). */
988
+ interface TemplateSpacePackage {
989
+ cells: TemplateSpacePackageCell[];
990
+ }
991
+
992
+ /**
993
+ * Space packages: the built code a template installs in its space.
994
+ *
995
+ * `scripts/build-space-packages.mjs` bundles each template's
996
+ * `spacePackage.cells[]` into `space-packages.generated.ts` (committed, like
997
+ * `templates.ts`, so every consumer of `toPackageDefinition` gets the same
998
+ * cells without a bundler). This module reads that output for the converter.
999
+ */
1000
+
1001
+ /** One built module: the declared cell plus its bundled ES module source. */
1002
+ interface BuiltSpacePackageCell {
1003
+ key: string;
1004
+ name: string;
1005
+ source: string;
1006
+ /** The ES module the frame runs (default export = a React component). */
1007
+ code: string;
1008
+ /**
1009
+ * Every name the module imports from the host's `@synap/kit` frame module:
1010
+ * the kit contract it was built against (the build refused any name the kit
1011
+ * did not export).
1012
+ */
1013
+ kitImports: string[];
1014
+ }
1015
+ /**
1016
+ * A template's built space package. It bundles only its own modules
1017
+ * (`packages/web/src/space-packages/`): the shared layers come from the host's
1018
+ * kit, whose own build record is `FRAME_HOST_MODULES_BUILD`
1019
+ * (`@synap-core/web` cell-runtime).
1020
+ */
1021
+ interface BuiltSpacePackage {
1022
+ cells: BuiltSpacePackageCell[];
1023
+ /** sha256 of every synap-app file the bundles read (repo-relative path → hex). */
1024
+ inputs: Record<string, string>;
1025
+ }
1026
+ /**
1027
+ * A space package cell on the package wire (`PackageDefinition.cells[]`, the
1028
+ * pod's `PackageCellDef`): a sandboxed `frame` cell. No `externalHosts`: a
1029
+ * space package is network-contained; its only data path is the host bridge.
1030
+ */
1031
+ interface SpacePackageCellWire {
1032
+ key: string;
1033
+ name: string;
1034
+ code: string;
1035
+ rendererType: 'frame';
1036
+ }
1037
+ /**
1038
+ * The cells a template's space package installs, or `undefined` when it has
1039
+ * none. Throws when a declared cell was never built (or was built from another
1040
+ * source): a template must never ship an entry that opens "Unknown cell".
1041
+ */
1042
+ declare function spacePackageCells(tpl: WorkspaceYaml, built?: Record<string, BuiltSpacePackage>): SpacePackageCellWire[] | undefined;
1043
+
1044
+ /**
1045
+ * @synap-core/workspace-templates — Definition adapter
1046
+ *
1047
+ * Converts a YAML template (WorkspaceYaml) into the flat payload shape that
1048
+ * the backend `workspaces.createFromDefinition` mutation + Hub REST
1049
+ * `/workspaces/from-definition` endpoint expect.
1050
+ *
1051
+ * This is the single canonical seam: every consumer (browser app, onboarding,
1052
+ * CLI, marketplace) provisions a workspace through this function so the wire
1053
+ * shape never drifts per call-site.
1054
+ */
1055
+
1056
+ /**
1057
+ * A `TemplateAutomation` as the apply door expects it: `flowDefinition`, not
1058
+ * the authored `flow` (mirrors `PackagePostWorkspaceBody['automations'][number]`
1059
+ * / the Hub `POST /packages/apply` `AutomationSchema`).
1060
+ */
1061
+ interface PackageAutomationWire {
1062
+ /** Stable template identity; names may be edited without orphaning the flow. */
1063
+ key?: string;
1064
+ name: string;
1065
+ description?: string;
1066
+ triggerType: TemplateAutomation['triggerType'];
1067
+ triggerConfig?: Record<string, unknown>;
1068
+ flowDefinition?: {
1069
+ nodes: unknown[];
1070
+ edges: unknown[];
1071
+ precondition?: string;
1072
+ };
1073
+ status?: TemplateAutomation['status'];
1074
+ }
1075
+ /** The ONE automation projection (authored `flow` → wire `flowDefinition`), shared by workspaces and standalone automation packages. */
1076
+ declare function toAutomationWire(automations: TemplateAutomation[] | undefined): PackageAutomationWire[] | undefined;
1077
+ /** A widget block as the wire expects it: `bentoLayout[]`, keyed by `widgetType`. */
1078
+ interface BentoWidgetBlockWire {
1079
+ widgetType: string;
1080
+ pos: TemplateBentoBlock['pos'];
1081
+ config?: Record<string, unknown>;
1082
+ }
1083
+ /** A view block as the wire expects it: `bentoViewBlocks[]`, keyed by `viewName`. */
1084
+ interface BentoViewBlockWire {
1085
+ kind: 'view';
1086
+ viewName: string;
1087
+ pos: TemplateBentoBlock['pos'];
1088
+ overrides?: Record<string, unknown>;
1089
+ }
1090
+ interface SplitBentoBlocks {
1091
+ bentoLayout: BentoWidgetBlockWire[];
1092
+ bentoViewBlocks: BentoViewBlockWire[];
1093
+ }
1094
+ /**
1095
+ * Produce the canonical persisted layout. A template may author either the
1096
+ * top-level `app:` shorthand or an explicit `layout.primarySurface`, never both.
1097
+ * Legacy `defaultApp` is the final compatibility fallback. Keeping the property
1098
+ * absent preserves a live workspace value during reconciliation; an authored
1099
+ * null is retained as an explicit clear.
1100
+ */
1101
+ declare function normalizeTemplateLayout(layout: TemplateLayoutConfig | undefined, app: TemplateAppRef | undefined): TemplateLayoutConfig | undefined;
1102
+ declare function splitBentoBlocks(blocks: TemplateBentoBlock[] | undefined): SplitBentoBlocks;
1103
+ /** The flat definition object accepted by createFromDefinition. */
1104
+ interface WorkspaceDefinitionInput {
1105
+ workspaceName: string;
1106
+ description: string;
1107
+ proposalId?: string;
1108
+ profiles: WorkspaceYaml['profiles'];
1109
+ views: NonNullable<WorkspaceYaml['views']>;
1110
+ entityLinks: NonNullable<WorkspaceYaml['entityLinks']>;
1111
+ seedEntities: NonNullable<WorkspaceYaml['seedEntities']>;
1112
+ suggestedRelations?: WorkspaceYaml['suggestedRelations'];
1113
+ displayTemplates?: WorkspaceYaml['displayTemplates'];
1114
+ /**
1115
+ * Domain-level relation TYPE vocabulary — the door find-or-creates a
1116
+ * `relation_defs` row per entry (idempotent by slug within the workspace). NOT
1117
+ * `entityLinks` (those are profile→profile edges and drop the rich metadata).
1118
+ * Carried verbatim; the authored form IS the wire form.
1119
+ */
1120
+ relationDefs?: WorkspaceYaml['relationDefs'];
1121
+ /**
1122
+ * Workspace intelligence commands — the door find-or-creates an
1123
+ * `intelligence_commands` row per entry (idempotent by title). Carried
1124
+ * verbatim; the authored form IS the wire form.
1125
+ */
1126
+ commands?: WorkspaceYaml['commands'];
1127
+ layoutConfig: WorkspaceYaml['layout'] | undefined;
1128
+ bentoViewName?: string;
1129
+ /**
1130
+ * WIDGET half of the authored bento union. The door declares this field
1131
+ * (`workspaces.createFromDefinition` zod) and the pod maps it as widgets via
1132
+ * `widget.widgetType`. It was missing from this interface entirely, which is
1133
+ * why `toWorkspaceDefinition` had nowhere to put widgets and dumped the whole
1134
+ * union into `bentoViewBlocks` — where every widget was silently filtered out.
1135
+ */
1136
+ bentoLayout?: BentoWidgetBlockWire[];
1137
+ /** VIEW half of the authored bento union — resolved against the viewMap. */
1138
+ bentoViewBlocks?: BentoViewBlockWire[];
1139
+ profileEntityBentoTemplates?: WorkspaceYaml['profileEntityBentoTemplates'];
1140
+ /**
1141
+ * Capability integrations (→ tools + skills + vault + capability-embedded
1142
+ * automations/playbooks). Emitted from the template's `integrations:` list —
1143
+ * IDENTICAL to what `toPackageDefinition` puts in its `capabilities` field. The
1144
+ * tRPC door (`workspaces.createFromDefinition`) now declares `capabilities` in
1145
+ * its zod input and installs them via the SHARED `applyPackagePostWorkspace`
1146
+ * door (same as Hub `/packages/apply`). It was missing from this interface, so
1147
+ * `toWorkspaceDefinition` had nowhere to put integrations and the browser
1148
+ * BUNDLED install path carried NO capabilities — every capability's
1149
+ * tools/skills/automations silently dropped on that door.
1150
+ */
1151
+ capabilities?: WorkspaceYaml['integrations'];
1152
+ /** Playbooks normalized to the workspace-create input contract. */
1153
+ playbooks?: Array<Record<string, unknown>>;
1154
+ /**
1155
+ * Entity-detail action placements — forwarded verbatim to
1156
+ * `applyPackagePostWorkspace`, which merges them into
1157
+ * `settings.actionPlacements`. The tRPC door (`createFromDefinition`)
1158
+ * declares `actionPlacements` in its zod input and carries them through the
1159
+ * shared apply door. No shape transform: the authored form IS the wire form.
1160
+ */
1161
+ actionPlacements?: WorkspaceYaml['actionPlacements'];
1162
+ /**
1163
+ * Graph-based automations. Deliberately distinct from the legacy
1164
+ * `automations` loop/playbook-trigger wire shape accepted by this door.
1165
+ */
1166
+ flowAutomations?: PackageAutomationWire[];
1167
+ workspaceSubtype?: string;
1168
+ workspaceType?: NonNullable<WorkspaceYaml['workspace']>['workspaceType'];
1169
+ workspaceVisibility?: string;
1170
+ workspaceCapabilities?: string[];
1171
+ /**
1172
+ * THE DECLARED INTENT SINK (Phase 3). `taskIntents` is authored at the TOP
1173
+ * level of the template, not inside `workspace`, and is forwarded verbatim to
1174
+ * `workspaces.createFromDefinition`, which persists it to
1175
+ * `settings.taskIntents` — where the intent resolver joins it against what is
1176
+ * actually installed. No shape transform: the authored form IS the wire form.
1177
+ */
1178
+ taskIntents?: WorkspaceYaml['taskIntents'];
1179
+ /**
1180
+ * What the space PRODUCES (`meta.intent`), forwarded verbatim; the pod
1181
+ * projects it into `settings.intent`. Same top-level field on the package
1182
+ * door.
1183
+ */
1184
+ intent?: WorkspaceYaml['meta']['intent'];
1185
+ sourceRoles?: NonNullable<WorkspaceYaml['workspace']>['sourceRoles'];
1186
+ defaultSources?: NonNullable<WorkspaceYaml['workspace']>['defaultSources'];
1187
+ /** Per-workspace onboarding context — written to settings.onboarding. */
1188
+ onboarding?: WorkspaceYaml['onboarding'];
1189
+ /**
1190
+ * Template-composition dependencies. MUST be forwarded: the backend resolves
1191
+ * these BEFORE materializing this workspace (`workspaces.createFromDefinition`
1192
+ * → `materializeWorkspaceCore` Step 0 → `resolvePackageDependencies`), which
1193
+ * is what installs a `require`d base FIRST and makes shared-profile base
1194
+ * seeding deterministic. Dropping this field silently de-orders provisioning
1195
+ * on the tRPC/UI door — see the note in `toWorkspaceDefinition`.
1196
+ */
1197
+ dependencies?: WorkspaceYaml['dependencies'];
1198
+ }
1199
+ interface ToDefinitionResult {
1200
+ definition: WorkspaceDefinitionInput;
1201
+ /** Stable idempotency key — the template's proposalId or slug. */
1202
+ proposalId: string;
1203
+ /** Display name for the new workspace. */
1204
+ workspaceName: string;
1205
+ /** Template id for telemetry / dedup. */
1206
+ templateId: string;
1207
+ }
1208
+ /**
1209
+ * Resolve a template (by slug or YAML object) into the createFromDefinition
1210
+ * payload. Pass `nameOverride` to rename the workspace at creation time.
1211
+ */
1212
+ declare function toWorkspaceDefinition(slugOrYaml: string | WorkspaceYaml, nameOverride?: string): ToDefinitionResult;
1213
+ /**
1214
+ * The unified `PackageDefinition` shape consumed by `POST /api/hub/packages/apply`
1215
+ * (CLI `synap launch`) and the CP package registry seeder. It composes the
1216
+ * workspace definition with the capability/playbook/onboarding layers. Mirrors
1217
+ * `PackageDefinition` in synap-backend `package-definition.ts`. Typed loosely on
1218
+ * the layered fields to avoid a backend import; the wire validation lives in the
1219
+ * apply endpoint.
1220
+ */
1221
+ interface PackageDefinitionOutput {
1222
+ _meta: {
1223
+ slug: string;
1224
+ /** The PACKAGE's own name (meta.name). For an overlay this differs from
1225
+ * `workspaceName`, which names the workspace it composes onto. */
1226
+ name?: string;
1227
+ /** The PACKAGE's own description (meta.description) — what the catalog
1228
+ * lists. Top-level `description` stays the workspace's (install copy). */
1229
+ description?: string;
1230
+ icon?: string;
1231
+ color?: string;
1232
+ domain?: string;
1233
+ tags?: string[];
1234
+ isPublic?: boolean;
1235
+ requiredTier?: string | null;
1236
+ };
1237
+ workspaceName: string;
1238
+ description: string;
1239
+ workspaceType?: WorkspaceYaml['workspace']['workspaceType'];
1240
+ workspaceSubtype?: string;
1241
+ workspaceVisibility?: string;
1242
+ workspaceCapabilities?: string[];
1243
+ /**
1244
+ * The DECLARED intents, carried to the marketplace/CLI install path too.
1245
+ * Without it here, a workspace installed from the marketplace would LOSE its
1246
+ * declaration while a bundled one kept it — the same field behaving
1247
+ * differently per install route, which is precisely the fork this package
1248
+ * exists to prevent.
1249
+ */
1250
+ taskIntents?: WorkspaceYaml['taskIntents'];
1251
+ /**
1252
+ * What the space PRODUCES (`meta.intent`), TOP-LEVEL like `taskIntents` —
1253
+ * never in `_meta`, which the CP rebuilds from its row columns on serve
1254
+ * (`normalizePublishedDefinition`), so a key there never reaches a pod.
1255
+ */
1256
+ intent?: WorkspaceYaml['meta']['intent'];
1257
+ /**
1258
+ * The onboarding start (`meta.start`), TOP-LEVEL for the same reason as
1259
+ * `intent`. Package door only: the pod and the CP read starts off the package.
1260
+ */
1261
+ start?: WorkspaceYaml['meta']['start'];
1262
+ sourceRoles?: WorkspaceYaml['workspace']['sourceRoles'];
1263
+ defaultSources?: WorkspaceYaml['workspace']['defaultSources'];
1264
+ profiles: WorkspaceYaml['profiles'];
1265
+ views: NonNullable<WorkspaceYaml['views']>;
1266
+ suggestedEntities: NonNullable<WorkspaceYaml['seedEntities']>;
1267
+ suggestedRelations?: WorkspaceYaml['suggestedRelations'];
1268
+ displayTemplates?: WorkspaceYaml['displayTemplates'];
1269
+ entityLinks?: WorkspaceYaml['entityLinks'];
1270
+ /** Relation-type vocabulary — carried verbatim (authored form IS the wire form). */
1271
+ relationDefs?: WorkspaceYaml['relationDefs'];
1272
+ /** Intelligence commands — carried verbatim (authored form IS the wire form). */
1273
+ commands?: WorkspaceYaml['commands'];
1274
+ /** WIDGET half of the authored bento union — mapped by the pod via `widgetType`. */
1275
+ bentoLayout?: BentoWidgetBlockWire[];
1276
+ /**
1277
+ * VIEW half of the authored bento union. Widgets go to `bentoLayout`, views
1278
+ * here — the pod splits by field (create-workspace-from-definition.ts:1373
1279
+ * reads `bentoViewBlocks`), so both wire fields must be carried. The apply
1280
+ * door's `PackageApplySchema` now declares this field (it is a plain
1281
+ * `z.object`, so an undeclared field would be silently stripped) — the inbound
1282
+ * seam is closed to match this outbound emit.
1283
+ */
1284
+ bentoViewBlocks?: BentoViewBlockWire[];
1285
+ bentoViewName?: string;
1286
+ profileEntityBentoTemplates?: WorkspaceYaml['profileEntityBentoTemplates'];
1287
+ layoutConfig?: WorkspaceYaml['layout'];
1288
+ capabilities?: WorkspaceYaml['integrations'];
1289
+ playbooks?: WorkspaceYaml['playbooks'];
1290
+ /** Flow-based automations — mapped to the apply door's `flowDefinition` field. */
1291
+ automations?: PackageAutomationWire[];
1292
+ /**
1293
+ * Entity-detail action placements — carried verbatim (authored form IS the
1294
+ * wire form). The Hub `PackageApplySchema` (synap-backend
1295
+ * `hub-protocol/rest/packages.ts`) now declares `actionPlacements`
1296
+ * (`z.array(ActionPlacementSchema).optional()`), so BOTH the tRPC
1297
+ * `createFromDefinition` door and the CLI/Hub install path carry it through to
1298
+ * `applyPackagePostWorkspace` — the parity is closed.
1299
+ */
1300
+ actionPlacements?: WorkspaceYaml['actionPlacements'];
1301
+ onboarding?: WorkspaceYaml['onboarding'];
1302
+ /**
1303
+ * Rules the template installs in its space — applied by the pod's
1304
+ * `applyPackagePostWorkspace` through the ONE rule door and converged by the
1305
+ * template-rule reconcile (three-way stamp on `metadata.rule.seed`).
1306
+ */
1307
+ rules?: WorkspaceYaml['rules'];
1308
+ /**
1309
+ * Skills the template declares for its space — linked to the new space by the
1310
+ * pod's `applyPackagePostWorkspace` (approved skills only), which is why they
1311
+ * travel on the PACKAGE definition and not the workspace door's input.
1312
+ */
1313
+ skills?: WorkspaceYaml['skills'];
1314
+ /**
1315
+ * The space package's built modules (`spacePackage` → `space-packages.ts`),
1316
+ * installed by the pod's `applyPackagePostWorkspace` as sandboxed frame cells
1317
+ * `cell:<_meta.slug>:<key>` — what the template's `app: {kind: stored}` opens.
1318
+ */
1319
+ cells?: SpacePackageCellWire[];
1320
+ /** Template-composition dependencies — resolved by the apply endpoint. */
1321
+ dependencies?: WorkspaceYaml['dependencies'];
1322
+ }
1323
+ /**
1324
+ * Resolve a template (by slug or YAML object) into the full `PackageDefinition`
1325
+ * accepted by `POST /api/hub/packages/apply` and the CP registry seeder. This is
1326
+ * the single seam the CLI and control-plane use so they read from the canonical
1327
+ * package instead of disk-stored JSON.
1328
+ */
1329
+ declare function toPackageDefinition(slugOrYaml: string | WorkspaceYaml): PackageDefinitionOutput;
1330
+
1331
+ export { normalizeTemplateLayout as $, type TemplateOnboardingCollectTarget as A, type BentoViewBlockWire as B, type TemplatePlaybook as C, type TemplatePlaybookParam as D, type TemplatePrimarySurface as E, type TemplateProfile as F, type TemplateProfileEntityBentoTemplates as G, type TemplateProperty as H, INTENT_LABEL_MAX as I, type TemplateSeedEntity as J, type TemplateSidebarItem as K, type TemplateSidebarSurface as L, type TemplateSourceRole as M, type TemplateSpacePackage as N, type TemplateSpacePackageCell as O, PACKAGE_DEPENDENCY_KINDS as P, type TemplateStart as Q, type TemplateSuggestedRelation as R, START_EXAMPLE_RANGE as S, type TemplateDependency as T, type TemplateView as U, type ToDefinitionResult as V, type WorkspaceYaml as W, type WorkspaceDefinitionInput as X, type WorkspaceJsonValue as Y, type WorkspacePrimarySurface as Z, type WorkspacePrimarySurfaceViewReference as _, type TemplateLifecycleOption as a, spacePackageCells as a0, splitBentoBlocks as a1, toAutomationWire as a2, toPackageDefinition as a3, toWorkspaceDefinition as a4, type TemplateLifecycleOptionWaits as b, type BentoWidgetBlockWire as c, type BuiltSpacePackage as d, type BuiltSpacePackageCell as e, type PackageAutomationWire as f, type PackageDefinitionOutput as g, type PackageDependencyKind as h, START_STARTERS_RANGE as i, START_VIEWS_MAX as j, type SpacePackageCellWire as k, type SplitBentoBlocks as l, type TemplateActionPlacement as m, type TemplateAppKind as n, type TemplateAppRef as o, type TemplateAutomation as p, type TemplateBentoBlock as q, type TemplateDefaultSource as r, type TemplateDisplayTemplate as s, type TemplateEntityLink as t, type TemplateExtendsRef as u, type TemplateIntegration as v, type TemplateIntent as w, type TemplateLayoutConfig as x, type TemplateMeta as y, type TemplateOnboarding as z };