@synap-core/workspace-templates 0.12.0 → 0.24.0

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