@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
package/README.md ADDED
@@ -0,0 +1,509 @@
1
+ # The Synap catalog
2
+
3
+ ONE home for every official installable template: workspaces, capabilities, skills,
4
+ packs, automations and views. The team sees, edits, validates and publishes them all from
5
+ this folder, through one lib and one CLI. The live catalog is the Control Plane's
6
+ `synap_packages` table, and it has one write door: `POST /api/packages` →
7
+ `publishPackageCore`.
8
+
9
+ > **Name today:** `synap-app/packages/workspace-templates/`, npm
10
+ > `@synap-core/workspace-templates`. **Planned, not done:** a rename to
11
+ > `packages/catalog/`, `@synap-core/catalog`, with the old name kept as a re-export
12
+ > shim for one release. See [Coordinated rename](#5-coordinated-rename-planned).
13
+
14
+ How installs, reconciles and tiers work is in the `synap-market` skill
15
+ (`synap-backend/skills/synap-market/`), which is also the agent door.
16
+
17
+ ---
18
+
19
+ ## 1. What lives here, by kind
20
+
21
+ | Dir | Kind | Format | Published today? |
22
+ |---|---|---|---|
23
+ | `src/*.yaml` | `workspace` (and `pack`, for a suite) | Legacy workspace YAML (`meta:` plus body). A thin adapter reads it as `{kind: workspace, meta, spec}` | Yes. 31 entries, CI on every push to main |
24
+ | `capabilities/<key>.capability.json` | `capability` | Manifest (below). `meta` carries the listing and visibility; `spec` is the CapabilityDefinition | Yes, by hand. CI also publishes it once `SYNAP_CATALOG_LIVE_KINDS` includes `capability` (§3) |
25
+ | `skills/<slug>/` | `skill` | Either a manifest `<slug>.skill.json` (`creative-director`), or an Agent-Skills folder (`SKILL.md` plus references) with a header `skills/<slug>.catalog.json` beside it | The manifest: yes. A folder: only with its header, and only when it holds no reference files (a skill package carries no documents). Today one folder has a header (`designing-with-real-components`); the five moved folders have none and are **staged** |
26
+ | `views/<slug>.view.json` | `view` | Manifest; `spec.views` in the canonical shape the CP stores (`{slug, displayName, type, config, scopeProfileSlugs}`) | Category `view`. Three today (`bookmark-views-pack`, `event-views-pack`, `task-views-pack`), moved from the old CP pack fragments on 2026-11-05. CI writes them once `SYNAP_CATALOG_LIVE_KINDS` includes `view` |
27
+ | `automations/<slug>.automation.json` | `automation` | bridge-setup `flowDefinition` form, plus a header `automations/<slug>.catalog.json` beside it | Only with its header, and only without apply-time placeholders. Today none has a header, so all three are **staged** (`mail-feed` also carries two placeholders bridge-setup fills) |
28
+ | `schema/` | | Zod manifest schema: `header.ts`, plus one body per kind (`workspace`, `capability`, `skill`, `automation`, `playbook`) | |
29
+ | `standards/*.standard.yaml` | | Quality standard per workspace (`pnpm eval`) | |
30
+ | `scripts/catalog-lib.mjs` | | **The ONE lib**: `loadCatalog` → `validateCatalog` → `diffCatalog` → `publishCatalog` | |
31
+ | `src/*.ts` | | The typed bundle (`dist/`) that clients ship as the zero-network fallback | |
32
+
33
+ A staged file is read, validated and counted, and the problem list carries a
34
+ `staged` warning for it. It cannot reach `POST /api/packages`. On 2026-11-05 the
35
+ whole-catalog validate printed `✓ 93 catalog entries validated (selected: 27
36
+ workspace · 44 capability · 18 skill · 0 pack · 0 automation · 3 view) + 13 retired`.
37
+
38
+ **No CP pack fragment.** The old CP `templates/packs/*.json` shape (a JSON with a
39
+ top-level `_meta`) is a load error. Its three view packs are `kind: view`
40
+ manifests in `views/`. Its ten profile packs and the misfiled `deep-research`
41
+ playbook are in `retired-sources/packs/` (never loaded or published): the CP
42
+ retired the `profile-pack` category in its migration 0049, and the playbook never
43
+ reached the CP.
44
+
45
+ **What stays elsewhere:**
46
+ - **System skills** (`system/*`) stay in `synap-backend/skills/`. They are the pod's
47
+ teaching substrate, seeded at boot, and are not marketplace items. Catalog files
48
+ may reference `system/*` slugs; the validator checks those exist when the
49
+ sibling repo is checked out, and says it skipped when it is not.
50
+ - **CLI runtime skills** (`authoring-*`, `coordinating-*`) stay in `synap-cli/templates/skills/`.
51
+
52
+ ## 2. The one manifest shape
53
+
54
+ ```jsonc
55
+ {
56
+ "apiVersion": "synap/v1",
57
+ "kind": "capability", // workspace | capability | skill | pack | automation | view
58
+ "meta": { // the header: same limits as the CP publishSchema
59
+ "slug": "apify", // kebab-case; dots only for a capability whose slug === spec.key
60
+ "name": "Apify — Web Scraping",
61
+ "description": "Find and run any Apify actor to collect data from public web pages and social posts. …",
62
+ "tags": ["capability"], "isPublic": true, "syncByDefault": true
63
+ // also: icon, color, domain, requiredTier, version?, owner ("template-owner" ⇔ private)
64
+ },
65
+ "spec": { "key": "apify", "skills": [ … ] }, // the per-kind body
66
+ "dependencies": [] // { kind, slug } — what an install pulls in
67
+ }
68
+ ```
69
+
70
+ One pure compiler, `toPublishBody(manifest)`, turns a manifest into today's
71
+ `POST /api/packages` body. The CP door and its `PACKAGE_TYPES` are unchanged. A
72
+ workspace publishes as category `workspace`, a capability as `capability`, a skill
73
+ as `skill`, an automation as `workflow`, a view as `view`.
74
+
75
+ Playbook goals use `{name}` placeholders. `@{arg:}` is refused at authoring; the
76
+ runtime still reads it.
77
+
78
+ ## 3. Add or update, per kind
79
+
80
+ **Workspace.** Edit or add `src/<slug>.yaml`, along with its `*.template.test.ts`
81
+ when the template has one. Then run `pnpm --filter @synap-core/workspace-templates build`.
82
+ That regenerates `src/templates.ts` and `dist/`. The publish refuses a stale
83
+ `dist/`. **Bump `package.json` `version` whenever content changes**: the official
84
+ publish stamps `definition.sourcePackage.version`, and clients let a remote row win
85
+ only when it is strictly newer than their bundle.
86
+
87
+ **Capability.** Edit `capabilities/<key>.capability.json`. The listing and
88
+ visibility go in `meta`; the definition goes in `spec`.
89
+ - **Transition:** an **existing** capability also has a CP copy,
90
+ `synap-control-plane-api/src/seeds/capability-templates/<key>.capability.json`,
91
+ whose content must equal `spec`. Its header lives in `capability-listings.ts` and
92
+ `CAPABILITY_VISIBILITY` in the seeder, and must equal `meta`. Change both sides.
93
+ The CP tripwire `catalog-mirror.tripwire.test.ts` turns red otherwise.
94
+ - A **new** capability is authored here only: catalog-only files are allowed.
95
+ - **A reader** is an ordinary verb that reads one link: `intent: "read_webpage"`, `metadata.readOnly: true`,
96
+ a required `url` parameter, and `urls: [...]` declaring the links it handles (`host[/path]`, `*.host`,
97
+ or `"*"`; the grammar lives in `@synap-core/types/url-read`). The pod's one read door routes by those
98
+ patterns; nothing else names a vendor. It returns a `UrlRead` (`status`, `text`, `media`, ...), saves
99
+ nothing, and an account-billed one runs only on the person's tap. Reference: `apify`'s
100
+ `capture_social_post`. `synap catalog validate` enforces it (`skill-urls`). The agents' own door to
101
+ reading a link is the pod's built-in `web.read` verb (Synap Core), not a catalog capability: the old
102
+ `web.read` pack is retired.
103
+
104
+ **Skill.** Either a manifest `skills/<slug>/<slug>.skill.json` (`kind: skill`,
105
+ `spec` = the CP's `definition.skill`), or an Agent-Skills folder
106
+ `skills/<slug>/SKILL.md`. A folder stays in the shape `synap bridge-setup` reads; to
107
+ publish it, add a header BESIDE it (never inside: bridge-setup imports every file in
108
+ the folder as a document):
109
+
110
+ ```jsonc
111
+ // skills/<slug>.catalog.json — a manifest without spec
112
+ { "apiVersion": "synap/v1", "kind": "skill",
113
+ "meta": { "slug": "<slug>", "name": "Display name", "description": "listing copy", "tags": [], "isPublic": true },
114
+ "dependencies": [] }
115
+ ```
116
+
117
+ It compiles to `definition.skill = { slug: <frontmatter name>, name: meta.name,
118
+ description: <frontmatter description>, kind: "instruction", scope: "pod", body }`,
119
+ the same slug/description/body bridge-setup imports. Refused: reference files in the
120
+ folder (`skill-documents`), `metadata.auto_load: true` (`skill-auto-load`), a
121
+ frontmatter name that is not `meta.slug` (`skill-slug`). Without a header the folder
122
+ is staged. Deciding which folders get a header (their listing and visibility) is a
123
+ content decision; `reading-client-progress` and `stellar-scf-grants-advisor` are
124
+ client-specific.
125
+ - **Transition:** the five moved folders (`bookmark-enrichment`,
126
+ `mapping-the-server`, `reading-client-progress`, `routing-to-channels`,
127
+ `stellar-scf-grants-advisor`) must stay byte-identical to
128
+ `synap-cli/templates/skills/<slug>/`, because `bridge-setup` still reads them
129
+ there. The guard is the CLI's `test/catalog-mirror.tripwire.test.ts`.
130
+
131
+ **View.** Add or edit `views/<slug>.view.json`:
132
+
133
+ ```jsonc
134
+ { "apiVersion": "synap/v1", "kind": "view",
135
+ "meta": { "slug": "task-views-pack", "name": "Task Views", "description": "listing copy", "icon": "layout-grid", "color": "#3B82F6", "tags": ["tasks"], "isPublic": true },
136
+ "spec": { "views": [ { "slug": "task-board", "displayName": "Task Board", "type": "kanban", "config": { "groupByField": "status" }, "scopeProfileSlugs": ["task"] } ] },
137
+ "dependencies": [] }
138
+ ```
139
+
140
+ It publishes as category `view` with `definition = { profiles: [], views, description:
141
+ meta.description, icon, color }`, the shape the seeded view rows carry. Only the
142
+ canonical view shape is accepted (the CP's `name` / singular `scopeProfileSlug`
143
+ shorthand is refused), and view slugs are unique within the file.
144
+
145
+ **Pack.** A `pack` is a workspace suite (`src/*.yaml` with the `suite` tag): it
146
+ publishes as category `workspace` and owns no space.
147
+
148
+ **Automation.** Either a manifest (`kind: automation`, `spec` in the authoring
149
+ `flow` form), or a raw `automations/<slug>.automation.json` in the `flowDefinition`
150
+ form bridge-setup reads, published once a header `automations/<slug>.catalog.json`
151
+ (`kind: "automation"`, no `spec`) sits beside it. It publishes as category
152
+ `workflow`: `definition = { profiles: [], automations: [{ key: <slug>, name,
153
+ description?, triggerType, triggerConfig, flowDefinition, status }] }`, i.e. the raw
154
+ file minus its `metadata` notes. Refused: an apply-time placeholder
155
+ (`apply-time-placeholder`: an empty or `<…>` connection id, a `<…>` output channel,
156
+ a skill node without `skillId`) and any raw key a package cannot carry (`state`).
157
+ Transition: the three raw files must stay byte-identical to
158
+ `synap-cli/templates/automations/` (CLI tripwire).
159
+
160
+ **Every kind.** Run the gate before you push:
161
+
162
+ ```bash
163
+ cd synap-app
164
+ node_modules/.bin/vitest run packages/workspace-templates # schema, parity, lifecycle, goal grammar
165
+ pnpm --filter @synap-core/workspace-templates type-check:catalog # schema/ + scripts/
166
+ synap catalog validate # the whole corpus, offline
167
+ ```
168
+
169
+ The lib needs Node ≥ 22.18, because it imports `schema/*.ts` through native type
170
+ stripping. An older Node refuses with `unsupported-runtime`.
171
+
172
+ ## Retiring a template
173
+
174
+ A template that leaves the catalog is **not** just deleted: it gets a tombstone in
175
+ `retired.yaml` (schema `schema/retired.ts`), so a pod can tell "retired, replaced by
176
+ X" from "never heard of it" and offer the person a safe move to X.
177
+
178
+ 1. Delete the file (`src/<slug>.yaml`, `capabilities/<key>.capability.json`, …).
179
+ 2. Add an entry to `retired.yaml`:
180
+ ```yaml
181
+ - slug: radar
182
+ kind: workspace # default; capability · skill · pack · automation · view
183
+ replacedBy: ecosystem # a LIVE slug of the same kind, or omit when nothing replaces it
184
+ reason: Radar was merged into Ecosystem, which tracks competitors and trends in one place.
185
+ since: "2026-07-16"
186
+ ```
187
+ 3. `synap catalog validate`: `replacedBy` must be live and not retired, no slug may be
188
+ both live and retired **in the same category** (the CP keys rows on slug + category,
189
+ so a retired workspace `posthog-analytics` beside a live capability of that slug is
190
+ fine), and the reason must be one plain sentence a person reads.
191
+ 4. Publish as usual. `publishCatalog` sends each tombstone of the selected kinds to
192
+ `POST /api/packages/retire` through the catalog door, **after** the live publishes
193
+ (a replacement published in the same run exists by then; a tombstone whose
194
+ replacement failed is not sent). The preview prints `retire radar → ecosystem` with
195
+ its status: `new` (no CP row, a tombstone row is created), `changed` (the live row is
196
+ retired, or its retirement updated), `unchanged` (not sent). A CP without the endpoint
197
+ is reported as such, never skipped silently.
198
+
199
+ Removing an entry from `retired.yaml` does not un-retire the CP row. The evidence
200
+ behind each seeded entry is in the pod file `00c1b2fe-ef98-41fa-86cf-801dfab12cd1` ("Template lifecycle: decisions wave + lane catalog").
201
+
202
+ ## Removing a kind from a live template
203
+
204
+ `retired.yaml` tombstones a whole template, not a kind inside one. There is no
205
+ kind-level tombstone: remove the `profiles:` entry and everything that names it
206
+ (views, relations, entity bento, onboarding `collect`, standards), bump the
207
+ `package.json` version (minor for a removed kind), and republish. A pod that already
208
+ installed the template keeps its profile and entities (profiles are never removed from
209
+ an installed pod); only new installs lose the kind. The kinds removed this way are
210
+ listed in `src/retired-goal-kinds.test.ts`, which fails if a template declares one again
211
+ (Life OS `goal`, Enterprise OS `objective`, Project Management `okr`: "Goal" is the
212
+ pod's track, decision D2, 2026-10-23).
213
+
214
+ ## Writing a process (a playbook that follows a kind's lifecycle)
215
+
216
+ The status belongs to the **kind or role**, never to a playbook. Its profile declares the lifecycle ONCE, in its
217
+ template:
218
+
219
+ ```yaml
220
+ lifecycle:
221
+ property: post-status
222
+ options:
223
+ - { key: Idea, category: open }
224
+ - { key: Published, category: done }
225
+ - { key: Archived, category: lost, humanOnly: true }
226
+ ```
227
+
228
+ Every option has one category (`open · active · paused · done · lost`); rules read the category, names stay free.
229
+ `humanOnly` marks an option no agent sets; an agent's move into `done` or `lost` proposes. Every move goes through
230
+ the one status door (`moveStatus`; an agent sends `update_entity` with `expectedStatus`).
231
+
232
+ A step that can still move may also say when it is late and what it waits on, by the pod's own rules
233
+ (`lifecycleOptionWaitsProblems` in `src/validate.ts`; never on a done or lost option):
234
+
235
+ ```yaml
236
+ - key: sent
237
+ category: active
238
+ dateBinding: dueDate # late once this date passes while it stands here
239
+ waits: { on: external, waitKind: payment, refFrom: clientId, dateBinding: dueDate }
240
+ ```
241
+
242
+ `dateBinding` and `waits.refFrom` / `waits.dateBinding` are property slugs. `waits.on` is a hold's `on` (person ·
243
+ agent · external · thing · decision · date · nobody); `waitKind` one of the pod's `WAIT_KINDS`.
244
+
245
+ A new lifecycle should adopt one of the ten bases (`src/lifecycle-presets.ts`: work-item, run, decision, asset,
246
+ publication, agreement, pipeline, relationship, offering, initiative) and say only how it differs:
247
+
248
+ ```yaml
249
+ lifecycle:
250
+ property: reference-status
251
+ adopts: asset
252
+ rename: { in-review: studied, deprecated: archived } # base key → this kind's key
253
+ drop: [] # base keys this kind does not use
254
+ add: [] # { key, category, after | before }
255
+ humanOnly: {} # per step; false removes a base's mark
256
+ stuckAfterDays: {} # per step
257
+ dateBinding: {} # per step: { sent: dueDate }
258
+ waits: {} # per step: { sent: { on: external } }
259
+ ```
260
+
261
+ The build compiles it into the flat `options` above and writes the select's `enumValues` when the YAML leaves them
262
+ out; nothing new reaches the pod. A lifecycle whose order the bases cannot express stays flat.
263
+
264
+ A playbook that works that lifecycle is a **process**: it FOLLOWS it. Its stages name options of it, its workers
265
+ start on it, and a person decides at the moments that commit the business. It never keeps a second status field.
266
+ The reference is Content OS "Produce Content" (`synap-app/packages/workspace-templates/src/content-os.yaml`).
267
+
268
+ **Official vs pod-local.** An official template or capability lives ONLY in the catalog
269
+ (`synap-app/packages/workspace-templates/`, by kind) and is published with
270
+ `synap catalog publish --official` (CI on main). A playbook, kind or automation an agent creates on a pod
271
+ (`synap_create_playbook`, `synap_define_kind`, …) is **pod-local**: it never reaches the catalog. To make it
272
+ official, write it into the catalog file and publish.
273
+
274
+ | Field | Where | Rule |
275
+ |---|---|---|
276
+ | `subjectProfile.profileSlug` | playbook | The kind or role the process works. |
277
+ | `subjectProfile.statusProperty` | playbook | Omit it: the pod follows the profile's declared lifecycle. If you name it, name that same property. A status worker on a role with no declared lifecycle is refused. |
278
+ | `stages[].subjectStatus` | stage | Entering the stage moves the subject to this option, through the door. Must be an **existing option** of the lifecycle — never invent one. |
279
+ | `stages[].gate` | stage | `{kind: human}` at every commitment: send to a client, sign, pay, publish, won/lost, anything irreversible. `{kind: check}` only where the stage's own criteria can be verified. A gated stage writes its status only when the gate passes. A check gate judges the stage being LEFT, so never use it to guard an irreversible status. |
280
+ | `stages[].onFail` | stage | `{toStage: <key>}` — where a rejected gate sends the run (rework loop). |
281
+ | `stages[].criteria` | stage | 2–5 binary statements; `check.kind` evidence (cheapest) · capability · judge · human. |
282
+ | `expectedOutputs[]` | stage or playbook | What the step must produce: `kind` + `label` + `relationToSubject` (an existing relation slug, or `none`). The UI shows what was produced from this. |
283
+ | `activators[]` (workers) | playbook | `on`: `created` · `enters_status` (+ `status`) · `count` (+ `status`, `min` ≥ 2) · `schedule` (+ `cron`, UTC) · `manual`. `size`: `per_thing` (default) · `per_moment` (count and schedule always are). `mode`: `propose` (default) · `run` only when cheap and safe. `maxPendingApprovals` (default 20) throttles. Compiled to a governed rule the owner can pause; it fires once per thing per transition. |
284
+ | `humanOnlyStatuses` | playbook | Legacy: the options no stage owns. Mark a person-only option `humanOnly` on the lifecycle instead; while `statusProperty` is set, `synap catalog validate` still checks that stages and this list cover every option. |
285
+ | `goalTemplate` | playbook | Placeholders are `{paramName}`. Never `@{arg:…}` (read-only legacy). |
286
+ | `params` | playbook | The subject is a `type: entity` param. A required param left unanswered becomes a question owed by the person, not an empty string. |
287
+
288
+ Human moments use an `ask` on an owed slot: `confirm` / `choose` (one `recommended`) / `form` / `act` / `provide`
289
+ (connection, file or secret through the vault). Never ask for a secret in a form.
290
+
291
+ Validation: `synap catalog validate` (process contract, goal grammar, lifecycle coverage ratchet — the count of
292
+ lifecycle kinds with no process may only go down).
293
+
294
+ ## Intent: what a space produces
295
+
296
+ A space is named by its PURPOSE first ("Product · Dev", "Sales · CRM") and is read through the THINGS it makes.
297
+ The template that owns the space says both, in `meta.intent`:
298
+
299
+ ```yaml
300
+ meta:
301
+ intent:
302
+ label: Product # the purpose word, ≤ 24 characters
303
+ produces: # ordered; kinds or roles
304
+ - profile: devplane_feature
305
+ - profile: devplane_story
306
+ - profile: ui-design
307
+ ```
308
+
309
+ - **Several kinds, never one only.** List what a person would come to the space to see move, in the order a home
310
+ shows them.
311
+ - **No `produces` (or `[]`) = a library.** Brand, Strategy, Ecosystem, Knowledge… are read, not moved: they carry
312
+ a label only.
313
+ - **Each produced profile declares a lifecycle** — a home counts things by lifecycle category, so a kind without
314
+ one cannot be counted (`intent-no-lifecycle`, naming it). Declare the lifecycle first (see "Writing a process").
315
+ - **Each produced profile is the template's own or one it depends on** (`require`/`compose` closure), e.g. CRM
316
+ produces the `lead` and `client` roles whose lifecycles `foundation` declares (`intent-profile-unknown`).
317
+ - **Only a template that owns a space declares it.** An overlay (`compose`) layers onto its base's space and a
318
+ pack (`suite`) owns none, so neither carries an intent (`intent-no-workspace`); `base` carries none either
319
+ (it is seeded into every space).
320
+ - **On the pod.** Both install doors forward it as a top-level `intent` (never in `_meta`, which the CP rebuilds
321
+ on serve); the pod keeps it in `workspaces.settings.intent`. A space with no declared intent gets one inferred at
322
+ read time (the profiles there that declare a lifecycle and hold things), never stored.
323
+
324
+ ## 4. The ONE command set
325
+
326
+ ```bash
327
+ synap catalog validate [--kind k] [slug...] # offline: per-kind schema, cross-kind refs, goal grammar, duplicates
328
+ synap catalog diff [--kind k] [slug...] # vs the live CP: new / changed / unchanged (+ warnings)
329
+ synap catalog publish --official [--kind k] [slug...] [--dry-run] [--yes] [--json]
330
+ synap market publish --official [slug...] [--dry-run] # alias of: catalog publish --official --kind workspace
331
+ ```
332
+
333
+ - `publish` requires `--official` and a `synap login` session that owns the
334
+ `synap-official` vendor. The CLI checks the publisher (`checkPublisher`) **before**
335
+ it shows the diff. A non-official account is refused up front. A failed read is
336
+ reported as `cp-unreachable`, never as "not official". `diff` warns instead of
337
+ refusing.
338
+ - `publish` validates the **whole corpus** and stops on any error. It then shows the
339
+ diff, asks y/N, and writes only after you confirm. `--dry-run` stops after the
340
+ preview. Warnings never block.
341
+ - A selection (`--kind`, slugs) narrows what gets planned and published. Validation
342
+ always covers the whole corpus, so a workspace's `dependencies` still resolve.
343
+ - The CLI finds the checkout by package name (`@synap-core/catalog` first, then
344
+ `@synap-core/workspace-templates`), or by `--catalog-dir`. Every error code maps
345
+ to a single next step (`hint` in `--json`).
346
+
347
+ **CI** (`synap-app/.github/workflows/publish-official-templates.yml`, through the
348
+ wrapper `scripts/publish-official.mjs`, which uses the same lib):
349
+
350
+ | Event | What runs |
351
+ |---|---|
352
+ | PR touching the catalog | Job `validate` only: build, validate every kind, print the **offline** preview (each entry and the version the CP will derive, where knowable offline). It holds **no secret and no `id-token`**: a PR runs its own lockfile and scripts. Guarded by `scripts/publish-workflow.guard.test.ts`. |
353
+ | Push to `main` (or manual) | `validate`, then job `publish` (environment `catalog-publish`): a read-only preview against the live CP, then publish live `--kind ${SYNAP_CATALOG_LIVE_KINDS:-workspace}`, then npm publish, only if the `package.json` version is new on npm. |
354
+
355
+ `SYNAP_CATALOG_LIVE_KINDS` is a repository **variable**. While it is unset, main
356
+ publishes workspaces only: every kind is still validated and previewed, but only
357
+ workspaces are written. Set it to `workspace,capability,skill,pack,automation,view`
358
+ only after runbook §5 A. Secrets: `SYNAP_CP_URL`, `SYNAP_CP_PUBLISH_TOKEN`
359
+ (a CP PAT of the `synap-official` owner; humans use `synap login`), `NPM_TOKEN`.
360
+
361
+ **One-time setup of the `catalog-publish` environment** (GitHub → synap-app →
362
+ Settings → Environments):
363
+ 1. Create the environment `catalog-publish`.
364
+ 2. Deployment branches and tags: **Selected branches → `main`** only.
365
+ 3. Add the environment secrets `SYNAP_CP_PUBLISH_TOKEN` and `SYNAP_CP_URL`.
366
+ 4. **Delete** the repository-level `SYNAP_CP_PUBLISH_TOKEN` (and `SYNAP_CP_URL`)
367
+ secrets, so no other job, and no workflow a branch pusher writes, can read them.
368
+ `NPM_TOKEN` may stay a repository secret (it is read only by the same job).
369
+ Until step 3 is done, the `publish` job has no token: it validates and leaves a
370
+ `::warning::`, it never publishes.
371
+
372
+ **The CP never reseeds on deploy.** `deploy.sh`, `update.sh` and ops `apply` no
373
+ longer run `seed:capabilities` or `seed:templates`. Both seeders are **insert-only
374
+ bootstraps** for an empty CP, run by hand: they skip any slug that already has a
375
+ row. A tripwire (`no-template-reseed-on-deploy-tripwire.test.ts`) guards this.
376
+ **Official capability keys are reserved:** a non-official publish of an official
377
+ key gets 409 `OFFICIAL_CAPABILITY_KEY_RESERVED`, and the CP serves the official row
378
+ first for a key.
379
+
380
+ **Transition mirrors** (each retires in the same change that deletes its copies; see §5).
381
+ These guards are **local-only**: each skips when the sibling repo is not checked out,
382
+ and every repo's CI checks out itself alone, so CI does not enforce them. Run them
383
+ on a full monorepo checkout before merging a change to either side. The same holds
384
+ for `schema/header.mirror.tripwire.test.ts` (header limits ↔ the CP `publishSchema`)
385
+ and `scripts/catalog-lib.columns.tripwire.test.ts` (the preview's columns and
386
+ adoption rule ↔ the CP publish core); their CI-safe halves are snapshots.
387
+
388
+ | Copy | Guard | Retires when |
389
+ |---|---|---|
390
+ | ~~CP `src/seeds/capability-templates/`, `templates/packs/`~~ | | **Retired 2026-11-05** (founder: one source). The CP seeders read the installed package; its tripwire `no-catalog-copy.tripwire.test.ts` fails on any copy |
391
+ | CLI `templates/skills/<5 moved>/`, `templates/automations/*.automation.json` | CLI `test/catalog-mirror.tripwire.test.ts` (byte-equal, both directions) | the CLI's pin admits a package release that ships them: `bridge-setup` already reads the installed package first, and the CLI's retirement test fails while both exist |
392
+
393
+ ## 5. Founder runbook: deploy, publish, retire the copies
394
+
395
+ Do these in order. The runbook only names the commands; it does not run anything.
396
+
397
+ ### A. Turn on catalog-published capabilities
398
+
399
+ 1. **Pre-flight on the prod CP DB.** Both queries must return 0 rows. If either
400
+ does not, resolve the duplicates first.
401
+ ```sql
402
+ SELECT lower(definition->'capability'->>'key') k, count(*)
403
+ FROM packages WHERE category = 'capability' GROUP BY 1 HAVING count(*) > 1;
404
+ SELECT slug, count(*)
405
+ FROM packages WHERE category = 'capability' GROUP BY 1 HAVING count(*) > 1;
406
+ ```
407
+ 2. **Deploy the backend first:** `26638d5e` ("an unanswered optional declared param
408
+ renders empty") must be live on the pods before any playbook goal written as
409
+ `{name}` reaches them; otherwise a literal `{programName}` lands in agent prompts.
410
+ Order: **backend → CP → dry run → publish.**
411
+ 3. **Deploy the CP** with all of these commits in that one deploy:
412
+ - `b669f90a`: posthog listing.
413
+ - `7ff44bf9`: capabilities publish onto their seeded row (official adoption, `syncByDefault`, dotted slug, description up to 10,000, full-column compare).
414
+ - `dac1da23`: reserved official keys, official-first read.
415
+ - `fe56bdf6`: reseed retired, seeder is insert-only.
416
+ - `d7a3f401`: ops drift is a human step.
417
+ - `0b0be3c8`: a capability key's owner is resolved before visibility; a key is a string equal to its slug.
418
+ - `a1401509`: an official publish adopts by the adoption rule, never a row of another kind.
419
+ - `6417b9f9`: `GET /api/packages/:slug?category=` serves the row a publish writes (the preview reads it).
420
+
421
+ Never ship `fe56bdf6` without `7ff44bf9` and `dac1da23`: on the old door, a catalog
422
+ publish forks every seeded row. This deploy no longer reseeds, so the rows stay
423
+ as the last reseed left them.
424
+ 4. **Dry run**, signed in as the official publisher (a private row is invisible to
425
+ an anonymous read): `synap catalog publish --official --kind capability --dry-run`.
426
+ The preview compares each body with the row the publish WRITES (the CP's adoption
427
+ rule) on the content version AND every column the CP writes, and prints a
428
+ content change as `~ definition: new content version` and each changed column
429
+ as `~ column: before → after`.
430
+ 5. **Read the diff.** Expected, and NOT a reason to stop:
431
+ - The **seeded capabilities** each show `CHANGED` with the same `h-` version and
432
+ only `~ source: "file-seed" → "api"`: the first publish writes each row once.
433
+ - **arch-client-intelligence** and **proton** show `CHANGED` with a new version (3 playbooks: Propose Grant Submission, Call Prep Brief, Draft Reply):
434
+ their playbook goals moved to the `{name}` grammar (`84363910`), which the
435
+ retired reseed never shipped.
436
+ - **posthog-analytics** shows `CHANGED` on its listing columns (`b669f90a`).
437
+ - **canva, dropbox, notion, slack, vercel** show `CHANGED` with a new version:
438
+ they have been official rows since 2026-10-01 (published from the old root
439
+ copies), and the catalog copy is newer (a derived `provides`, `72dd8d66`, and
440
+ reconciled descriptions). Their `~ tags` line shows only the AUTHORED tags
441
+ (`["capability"]`): the CP appends the search tokens it derives from the
442
+ definition, so the row keeps its search words and gains `capability` first.
443
+ - **content-idea-to-production** shows `CHANGED` on its definition and
444
+ description: the "Retired" listing the reseed never shipped.
445
+ - **claude-code-routines** is `NEW`. Publish it early: until an official row
446
+ exists, its key can be claimed by anyone.
447
+ - Any other `changed` row, or a warning that the CP ignores `?category=` (an
448
+ older CP): **STOP** and look.
449
+ 6. **Publish:** `synap catalog publish --official --kind capability`. Confirm at the
450
+ prompt.
451
+ 7. **Views** (`views/`, 2026-11-05): `synap catalog diff bookmark-views-pack
452
+ event-views-pack task-views-pack` shows each `CHANGED`: a new content version
453
+ (the new listing description inside the definition), `displayName` and
454
+ `description` (the catalog's copy, which never reached the CP), `source:
455
+ "file-seed" → "api"` and `vendorId: null → synap-official` (the publish adopts
456
+ the unowned seeded row). The views themselves are byte-equal to the live rows.
457
+ Then publish the same three slugs with `synap catalog publish --official`.
458
+ 8. **Widen CI:** set the repo variable
459
+ `SYNAP_CATALOG_LIVE_KINDS=workspace,capability,skill,automation,view`. A skill
460
+ folder or raw automation publishes only once it has a header.
461
+ 9. On a **brand-new, empty** CP only: run
462
+ `docker compose -f docker-compose.prod.yml run --rm control-plane pnpm seed:capabilities`
463
+ (and `seed:templates`) once, then step 6 and step 7. `seed:templates` seeds
464
+ workspaces only: views reach an empty CP through the publish.
465
+
466
+ ### B. Publish the package and retire the mirrors
467
+
468
+ 1. **Publish the package to npm.** Merge a version bump to main, and CI publishes
469
+ it. Local is `0.13.0` and npm has `0.12.0`, so `check-publish-freshness` is red
470
+ until then. Never run `npm publish` by hand.
471
+ 2. **Bump the pins** and refresh each repo's own lockfile:
472
+ - **CP:** `^0.12.0` → `>=0.13.0 <1.0.0`. The caret excludes 0.13. Do this only
473
+ once the CP `pnpm-lock.yaml` is no longer peer-dirty.
474
+ - **CLI:** `>=0.12.0 <1.0.0`, which already admits 0.13. Refresh with
475
+ `pnpm install --lockfile-only --ignore-workspace` so the root lockfile is not
476
+ touched.
477
+ - **Backend:** `packages/api` **and** `apps/api` (`>=0.11.0 <1.0.0`). Move the
478
+ floor up only if a consumer needs the new content.
479
+ 3. **Point the readers at the package:**
480
+ - the CP seeder and capability resolver (`capability-template-dir.ts`) read
481
+ `node_modules/@synap-core/workspace-templates/capabilities/` (done 2026-11-05;
482
+ `seed-templates.ts` no longer seeds packs: views publish through the door);
483
+ - `synap bridge-setup` installs the published skill and automation entries
484
+ through the pod instead of reading `templates/`.
485
+ 4. **Delete the copies and their tripwires in the same change:**
486
+ - CP: done 2026-11-05 (copies, listing and visibility literals, and both
487
+ tripwires deleted);
488
+ - CLI: the five moved skill folders, `templates/automations/`, and
489
+ `test/catalog-mirror.tripwire.test.ts`.
490
+
491
+ ### C. Coordinated rename (planned)
492
+
493
+ Rename `packages/workspace-templates` to `packages/catalog` (`@synap-core/catalog`)
494
+ in one change, at a quiet moment, because every tree's `node_modules` links move:
495
+
496
+ 1. `git mv synap-app/packages/workspace-templates synap-app/packages/catalog`.
497
+ 2. Update **both** workspace files: the root `pnpm-workspace.yaml`
498
+ (`synap-app/packages/workspace-templates`) and `synap-app/pnpm-workspace.yaml`
499
+ (`packages/workspace-templates`).
500
+ 3. Change the `package.json` `name` to `@synap-core/catalog`. Ship a thin
501
+ `@synap-core/workspace-templates` shim that re-exports it for one release. The
502
+ backend pins `>=0.11 <1`, the CP `^0.12`, the CLI `>=0.12 <1`, and the
503
+ synap-app/browser consumers use `workspace:*`.
504
+ 4. Update the workflow paths and `--filter` in `publish-official-templates.yml`,
505
+ and the `ci.yml` freshness step.
506
+ 5. Run `pnpm install` in each tree: the monorepo root, `synap-app/`, and each
507
+ sibling that installs on its own. Then run every consumer's typecheck.
508
+ 6. The CLI and both tripwires already resolve `packages/catalog` first. Remove the
509
+ `workspace-templates` fallback once the shim is retired.