@synap-core/workspace-templates 0.30.0 → 0.32.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 (45) hide show
  1. package/README.md +13 -5
  2. package/agents/hermes.agent.yaml +3 -0
  3. package/dist/{define-DqoItRiR.d.ts → define-DHDi8C33.d.ts} +19 -18
  4. package/dist/index.d.ts +2 -2
  5. package/dist/index.js +428 -239
  6. package/dist/index.js.map +1 -1
  7. package/dist/wire.d.ts +1 -1
  8. package/package.json +1 -1
  9. package/src/brand-library.yaml +0 -6
  10. package/src/builder-dev-fold.template.test.ts +2 -3
  11. package/src/builder-dev-playbooks.template.test.ts +7 -5
  12. package/src/builder.yaml +60 -42
  13. package/src/business-model.yaml +20 -1
  14. package/src/civic-france.yaml +9 -0
  15. package/src/content-creation.yaml +1 -1
  16. package/src/content-os.yaml +22 -18
  17. package/src/crm-absorbs-outreach.template.test.ts +1 -1
  18. package/src/crm-build-plan.template.test.ts +1 -1
  19. package/src/crm.yaml +5 -14
  20. package/src/decisions-wave.template.test.ts +7 -5
  21. package/src/define.primary-surface.test.ts +9 -0
  22. package/src/define.ts +4 -1
  23. package/src/finance.yaml +10 -6
  24. package/src/foundation.yaml +1 -2
  25. package/src/hr.yaml +3 -2
  26. package/src/intent.test.ts +43 -2
  27. package/src/internal-runbook.yaml +0 -1
  28. package/src/kanban-grouping.test.ts +72 -0
  29. package/src/legal.yaml +4 -4
  30. package/src/lifecycle-coverage.test.ts +7 -64
  31. package/src/lifecycle-declarations.test.ts +70 -74
  32. package/src/marketing.yaml +4 -3
  33. package/src/meetings-knowledge.yaml +1 -2
  34. package/src/operations.yaml +13 -9
  35. package/src/process-contract.validate.test.ts +40 -55
  36. package/src/project-management.yaml +2 -2
  37. package/src/publish-official-lib.test.ts +3 -2
  38. package/src/research-base.yaml +12 -5
  39. package/src/research-decision.yaml +18 -2
  40. package/src/ship-a-change.template.test.ts +3 -2
  41. package/src/social.yaml +4 -1
  42. package/src/start.test.ts +22 -0
  43. package/src/templates.ts +324 -183
  44. package/src/types.ts +28 -18
  45. package/src/validate.ts +143 -77
package/README.md CHANGED
@@ -25,7 +25,7 @@ How installs, reconciles and tiers work is in the `synap-market` skill
25
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). Headers decided by the founder on 2026-11-05: `bookmark-enrichment` and `routing-to-channels` public, `mapping-the-server` unlisted (private to the official owner); `reading-client-progress` and the parked `stellar-scf-grants-advisor` stay **staged** |
26
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 on every push to main |
27
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. Headers decided by the founder on 2026-11-05: `bookmark-enrichment` public; `url-bookmark-capture`, `github-pr-events` and the five `ship-a-change-*` unlisted. `mail-feed` stays **staged**: it carries two placeholders bridge-setup fills |
28
- | `agents/<slug>.agent.yaml` | `agent` | Manifest. `spec` (`schema/agent.ts`) is what the pod reads as `definition.agent`: `harness` (the `agent_type` join key), `aliases`, `worker`, `tried`, `detect`, `wake` (data: `program` + `args` + `params`, never a shell line; required for a worker only), `practices.skills`, `mcp` (where its program reads MCP servers: `config` under ~/, `format` yaml/json, `key` dot path, `entry`; the CLI writes the pod's server there on `synap agents add`, the pod ignores it). One per program of the backend harness registry, plus `hermes`. CP category `agent`, official vendor only, left out of browse lists (the catalog installs every official agent on every pod, founder decision D8) | Yes, on every push to main, like every other kind (the first publish was the founder's, by hand, on 2026-11-07; `FIRST_PUBLISH_BY_HAND` is empty since) |
28
+ | `agents/<slug>.agent.yaml` | `agent` | Manifest. `spec` (`schema/agent.ts`) is what the pod reads as `definition.agent`: `harness` (the `agent_type` join key), `aliases`, `worker`, `tried`, `detect`, `wake` (data: `program` + `args` + `params`, never a shell line; required for a worker only), `practices.skills`, `mcp` (where its program reads MCP servers: `config` under ~/, `format` yaml/json, `key` dot path, `entry`; the CLI writes the pod's server there on `synap agents add`, the pod ignores it), `toolProfile` (`entry` / `builder`) + `toolGroups` (only with `entry`): the MCP tools an agent's first key lists, read by the pod (backend#900). One per program of the backend harness registry, plus `hermes`. CP category `agent`, official vendor only, left out of browse lists (the catalog installs every official agent on every pod, founder decision D8) | Yes, on every push to main, like every other kind (the first publish was the founder's, by hand, on 2026-11-07; `FIRST_PUBLISH_BY_HAND` is empty since) |
29
29
  | `schema/` | | Zod manifest schema: `header.ts`, plus one body per kind (`workspace`, `capability`, `skill`, `automation`, `view`, `agent`, `playbook`) | |
30
30
  | `standards/*.standard.yaml` | | Quality standard per workspace (`pnpm eval`) | |
31
31
  | `scripts/catalog-lib.mjs` | | **The ONE lib**: `loadCatalog` → `validateCatalog` → `diffCatalog` → `publishCatalog` | |
@@ -270,23 +270,26 @@ proposal; the review is the catalog commit.
270
270
  | Field | Where | Rule |
271
271
  |---|---|---|
272
272
  | `subjectProfile.profileSlug` | playbook | The kind or role the process works. |
273
- | `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. |
273
+ | (no status field) | playbook | The process FOLLOWS the kind's declared lifecycle: every `subjectStatus` and worker `status` is an option of it. `statusProperty`, `onEnd` and `humanOnlyStatuses` are retired (One model decision 4, `playbook-field-retired`): a person-only option is `humanOnly` on the lifecycle, a status no stage owns is derived by the pod, and a session that ends early moves nothing. |
274
274
  | `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. |
275
275
  | `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. |
276
276
  | `stages[].onFail` | stage | `{toStage: <key>}` — where a rejected gate sends the run (rework loop). |
277
277
  | `stages[].criteria` | stage | 2–5 binary statements; `check.kind` evidence (cheapest) · capability · judge · human. |
278
278
  | `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. |
279
279
  | `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. |
280
- | `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. |
281
280
  | `goalTemplate` | playbook | Placeholders are `{paramName}`. Never `@{arg:…}` (read-only legacy). |
282
281
  | `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. |
283
282
 
284
283
  Human moments use an `ask` on an owed slot: `confirm` / `choose` (one `recommended`) / `form` / `act` / `provide`
285
284
  (connection, file or secret through the vault). Never ask for a secret in a form.
286
285
 
287
- Validation: `synap catalog validate` (process contract, goal grammar, lifecycle coverage ratchet — the count of
286
+ Validation: `synap catalog validate` (process contract, goal grammar, lifecycle ratchet — the count of
288
287
  lifecycle kinds with no process may only go down).
289
288
 
289
+ **Boards.** A kanban names its columns in `config.groupByField` (the one key the board reads); grouped on the
290
+ kind's lifecycle property it is the flow board, where a drag is the governed status move. A `groupBy` (top-level
291
+ or in `config`) is never read and is refused (`view-kanban-group-*`).
292
+
290
293
  ## Intent: what a space produces
291
294
 
292
295
  A space is named by its PURPOSE first ("Product · Dev", "Sales · CRM") and is read through the THINGS it makes.
@@ -296,6 +299,7 @@ The template that owns the space says both, in `meta.intent`:
296
299
  meta:
297
300
  intent:
298
301
  label: Product # the purpose word, ≤ 24 characters
302
+ primary: devplane_feature # the ONE output the main flow produces; one of produces
299
303
  produces: # ordered; kinds or roles
300
304
  - profile: devplane_feature
301
305
  - profile: devplane_story
@@ -304,8 +308,12 @@ meta:
304
308
 
305
309
  - **Several kinds, never one only.** List what a person would come to the space to see move, in the order a home
306
310
  shows them.
311
+ - **One `primary` output** (One model decision 3): the kind or role the space's main flow produces, the one its
312
+ home leads with. Required when the space produces anything, and one of `produces`; the rest are its operational
313
+ kinds (`intent-primary-missing`, `intent-primary-not-produced`). `meta.start.profile` defaults to it: omit it
314
+ unless the start is about another kind (`start-profile-redundant`).
307
315
  - **No `produces` (or `[]`) = a library.** Brand, Strategy, Ecosystem, Knowledge… are read, not moved: they carry
308
- a label only.
316
+ a label only, and no `primary` (`intent-primary-library`).
309
317
  - **Each produced profile declares a lifecycle** — a home counts things by lifecycle category, so a kind without
310
318
  one cannot be counted (`intent-no-lifecycle`, naming it). Declare the lifecycle first (see "Writing a process").
311
319
  - **Each produced profile is the template's own or one it depends on** (`require`/`compose` closure), e.g. CRM
@@ -24,5 +24,8 @@ spec:
24
24
  format: yaml
25
25
  key: mcp_servers
26
26
  entry: url-headers
27
+ # Its first key lists the essential tools plus the read group (backend#900).
28
+ toolProfile: entry
29
+ toolGroups: [read]
27
30
  practices:
28
31
  skills: [synap]
@@ -459,12 +459,11 @@ interface TemplatePlaybook {
459
459
  * `playbooks.matchForEntity` (filters `subject_profile->>'profileSlug'`), so a
460
460
  * captured entity of this kind can auto-launch the playbook as a session.
461
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.
462
+ * The process FOLLOWS the kind's declared lifecycle (`profiles[].lifecycle`):
463
+ * that property is what `stages[].subjectStatus` and activator `status` are
464
+ * values of (`validate.ts`). A playbook never names it again — the
465
+ * `statusProperty`, `onEnd` and `humanOnlyStatuses` fields are retired from
466
+ * the catalog (One model decision 4; rule `playbook-field-retired`).
468
467
  */
469
468
  subjectProfile?: {
470
469
  profileSlug: string;
@@ -476,7 +475,6 @@ interface TemplatePlaybook {
476
475
  * fan-out is refused, so the schedule would silently never be created.
477
476
  */
478
477
  filter?: string;
479
- statusProperty?: string;
480
478
  };
481
479
  /**
482
480
  * Playbook-level slots: what a run of this process is expected to produce.
@@ -497,14 +495,6 @@ interface TemplatePlaybook {
497
495
  * `automations:`. Public templates default to `mode: propose`.
498
496
  */
499
497
  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
498
  status?: "draft" | "active" | "paused";
509
499
  /**
510
500
  * `project` = a TRACK template (a method a project runs over its `stages`);
@@ -546,7 +536,7 @@ interface TemplatePlaybookStage {
546
536
  proposalType?: "playbook.stage_gate";
547
537
  };
548
538
  /**
549
- * The value of the playbook's `subjectProfile.statusProperty` this stage
539
+ * The value of the subject kind's lifecycle property this stage
550
540
  * corresponds to. Advancing INTO the stage writes it to the subject
551
541
  * (governed); the subject ENTERING it advances an open run to the stage.
552
542
  */
@@ -829,8 +819,12 @@ interface TemplateStart {
829
819
  promise: string;
830
820
  /** Identity ids this start is suggested for; each id belongs to one start. */
831
821
  suggestFor: string[];
832
- /** The produced kind the views and the first session are about. */
833
- profile: string;
822
+ /**
823
+ * The kind the views and the first session are about. Omit it: it defaults
824
+ * to `meta.intent.primary` (one source; `define.ts` fills it on the wire).
825
+ * Name it only when the start is about another kind than the primary.
826
+ */
827
+ profile?: string;
834
828
  /** 1-3 slugs of THIS template's views, scoped to `profile`; first = default. */
835
829
  views: string[];
836
830
  /** Preview rows, never written. `values` keys are properties of `profile`. */
@@ -851,6 +845,13 @@ declare const INTENT_LABEL_MAX = 24;
851
845
  interface TemplateIntent {
852
846
  /** ≤ {@link INTENT_LABEL_MAX} chars. */
853
847
  label: string;
848
+ /**
849
+ * The space's ONE primary output (One model decision 3): the kind or role
850
+ * its main flow produces, the one its home leads with. Required when the
851
+ * space produces anything, and one of `produces` (the rest of `produces` are
852
+ * its operational kinds). A library (no `produces`) names none.
853
+ */
854
+ primary?: string;
854
855
  produces?: Array<{
855
856
  profile: string;
856
857
  }>;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { W as WorkspaceYaml, T as TemplateDependency, a as TemplateLifecycleOption, b as TemplateLifecycleOptionWaits } from './define-DqoItRiR.js';
2
- export { B as BentoViewBlockWire, c as BentoWidgetBlockWire, d as BuiltSpacePackage, e as BuiltSpacePackageCell, I as INTENT_LABEL_MAX, P as PACKAGE_DEPENDENCY_KINDS, f as PackageAutomationWire, g as PackageDefinitionOutput, h as PackageDependencyKind, S as START_EXAMPLE_RANGE, i as START_STARTERS_RANGE, j as START_VIEWS_MAX, k as SpacePackageCellWire, l as SplitBentoBlocks, m as TemplateActionPlacement, n as TemplateAppKind, o as TemplateAppRef, p as TemplateAutomation, q as TemplateBentoBlock, r as TemplateDefaultSource, s as TemplateDisplayTemplate, t as TemplateEntityLink, u as TemplateExtendsRef, v as TemplateIntegration, w as TemplateIntent, x as TemplateLayoutConfig, y as TemplateMeta, z as TemplateOnboarding, A as TemplateOnboardingCollectTarget, C as TemplatePlaybook, D as TemplatePlaybookParam, E as TemplatePrimarySurface, F as TemplateProfile, G as TemplateProfileEntityBentoTemplates, H as TemplateProperty, J as TemplateSeedEntity, K as TemplateSidebarItem, L as TemplateSidebarSurface, M as TemplateSourceRole, N as TemplateSpacePackage, O as TemplateSpacePackageCell, Q as TemplateStart, R as TemplateSuggestedRelation, U as TemplateView, V as ToDefinitionResult, X as WorkspaceDefinitionInput, Y as WorkspaceJsonValue, Z as WorkspacePrimarySurface, _ as WorkspacePrimarySurfaceViewReference, $ as normalizeTemplateLayout, a0 as spacePackageCells, a1 as splitBentoBlocks, a2 as toAutomationWire, a3 as toPackageDefinition, a4 as toWorkspaceDefinition } from './define-DqoItRiR.js';
1
+ import { W as WorkspaceYaml, T as TemplateDependency, a as TemplateLifecycleOption, b as TemplateLifecycleOptionWaits } from './define-DHDi8C33.js';
2
+ export { B as BentoViewBlockWire, c as BentoWidgetBlockWire, d as BuiltSpacePackage, e as BuiltSpacePackageCell, I as INTENT_LABEL_MAX, P as PACKAGE_DEPENDENCY_KINDS, f as PackageAutomationWire, g as PackageDefinitionOutput, h as PackageDependencyKind, S as START_EXAMPLE_RANGE, i as START_STARTERS_RANGE, j as START_VIEWS_MAX, k as SpacePackageCellWire, l as SplitBentoBlocks, m as TemplateActionPlacement, n as TemplateAppKind, o as TemplateAppRef, p as TemplateAutomation, q as TemplateBentoBlock, r as TemplateDefaultSource, s as TemplateDisplayTemplate, t as TemplateEntityLink, u as TemplateExtendsRef, v as TemplateIntegration, w as TemplateIntent, x as TemplateLayoutConfig, y as TemplateMeta, z as TemplateOnboarding, A as TemplateOnboardingCollectTarget, C as TemplatePlaybook, D as TemplatePlaybookParam, E as TemplatePrimarySurface, F as TemplateProfile, G as TemplateProfileEntityBentoTemplates, H as TemplateProperty, J as TemplateSeedEntity, K as TemplateSidebarItem, L as TemplateSidebarSurface, M as TemplateSourceRole, N as TemplateSpacePackage, O as TemplateSpacePackageCell, Q as TemplateStart, R as TemplateSuggestedRelation, U as TemplateView, V as ToDefinitionResult, X as WorkspaceDefinitionInput, Y as WorkspaceJsonValue, Z as WorkspacePrimarySurface, _ as WorkspacePrimarySurfaceViewReference, $ as normalizeTemplateLayout, a0 as spacePackageCells, a1 as splitBentoBlocks, a2 as toAutomationWire, a3 as toPackageDefinition, a4 as toWorkspaceDefinition } from './define-DHDi8C33.js';
3
3
  import '@synap-core/types/presentation';
4
4
  import '@synap-core/types/space-brief';
5
5
  import '@synap-core/types/capability-intents';