@synap-core/workspace-templates 0.7.3 → 0.8.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synap-core/workspace-templates",
3
- "version": "0.7.3",
3
+ "version": "0.8.0",
4
4
  "type": "module",
5
5
  "packageManager": "pnpm@9.15.4",
6
6
  "description": "Canonical workspace definitions — YAML source + typed exports for browser, backend, CLI, and marketplace",
package/src/crm.yaml CHANGED
@@ -108,6 +108,11 @@ profiles:
108
108
  description: An organisation being qualified or sold to.
109
109
  scope: WORKSPACE
110
110
  properties:
111
+ - slug: contextSummary
112
+ label: Context
113
+ valueType: string
114
+ inputType: textarea
115
+ placeholder: The AI-maintained one-paragraph summary of who this client is and where they stand.
111
116
  - slug: website
112
117
  label: Website
113
118
  valueType: string
@@ -178,6 +183,17 @@ profiles:
178
183
  - won
179
184
  - lost
180
185
  - inactive
186
+ - slug: commercialStage
187
+ label: Commercial stage
188
+ valueType: string
189
+ inputType: select
190
+ enumValues:
191
+ - draft
192
+ - proposed
193
+ - negotiating
194
+ - won
195
+ - lost
196
+ constraints: { defaultValue: draft }
181
197
  - slug: valueType
182
198
  label: Value type
183
199
  valueType: string
@@ -48,6 +48,10 @@ dependencies:
48
48
  kind: workspace
49
49
  relation: require
50
50
  reason: "The pipeline — contacts, leads, clients, and deals."
51
+ - slug: business-developer
52
+ kind: workspace
53
+ relation: require
54
+ reason: "The lead-first sales motion (crm-lead/crm-client roles, commercial proposals, commission handoff) that the CRM app runs on. Composes onto the CRM workspace above — without it the CRM lens is provisioned with pod-wide lead/client only and the app's pipeline is empty."
51
55
  - slug: content-os
52
56
  kind: workspace
53
57
  relation: require
@@ -0,0 +1,597 @@
1
+ # Networking — the BD-middleman overlay on the CRM workspace.
2
+ # =========================================================================
3
+ # The Arch sits between clients: client A has a NEED, client B has a
4
+ # CAPABILITY (a `solution-provider` role), and The Arch brokers the INTRO and
5
+ # bills the match as a deal. This is an ADDITIVE overlay on the CRM workspace —
6
+ # it reuses CRM's `company`/`deal`/`client` vocabulary and layers three things:
7
+ #
8
+ # • need — KIND: the client's stated ask (the demand side).
9
+ # • intro — KIND: the brokerage artifact (the match + its fee).
10
+ # • solution-provider — FACET (role on company/person): the supply side.
11
+ #
12
+ # KIND vs FACET rationale (applied rigorously):
13
+ # - `need` is a KIND: it is a thing with its own independent life — a status
14
+ # that moves (open → matching → intro-made → satisfied), a requester, an
15
+ # evidence trail. It is NOT a hat a company wears; it is authored, tracked,
16
+ # and retired on its own timeline. So it is a primary kind, never a facet.
17
+ # - `intro` is a KIND for the same reason `deal` is: it is a relationship-thing
18
+ # (requester × provider × need × stage × fee) with its own life and its own
19
+ # board. It cannot be a facet of any single entity — it spans two companies.
20
+ # - `solution-provider` is a FACET (profileKind: role): "being a provider of
21
+ # X" is a HAT an existing company or person wears. The Arch must NOT spin up
22
+ # a second entity for a firm it already knows as a company/client — it
23
+ # resolves identity first, then attaches this role. It carries no independent
24
+ # identity, it cascades with the parent company, and graph edges link the
25
+ # PARENT company (introduced_provider), not the facet. Mirrors the web3 role
26
+ # facets in blockchain-ecosystem.yaml (market-maker / security-auditor / …).
27
+ #
28
+ # SHARED-ROLE SSOT: `solution-provider` is a networking-specific role with a
29
+ # single consumer (this template). Following the blockchain-ecosystem precedent
30
+ # — where market-maker / security-auditor / dev-shop are `scope: shared` roles
31
+ # OWNED by their domain template, not foundation — it is declared ONCE here as
32
+ # `scope: shared`, `profileKind: role`. foundation.yaml is the SSOT only for the
33
+ # CROSS-CUTTING roles that many templates reuse (client / partner / lead /
34
+ # churned / sponsor); a single-consumer domain role belongs with its domain, and
35
+ # a single declaration cannot drift, so it is NOT added to foundation and NOT
36
+ # re-declared anywhere else. (The shared-role-ssot tripwire polices rows (b)/(c)
37
+ # per profile slug and rule (d) applicableKinds — a lone consistent declaration
38
+ # passes all of them.)
39
+
40
+ meta:
41
+ slug: networking
42
+ domain: revenue
43
+ name: Networking
44
+ description: "The BD-middleman layer over your CRM — capture client needs, keep a roster of solution providers, and broker the intros that connect demand to supply."
45
+ icon: waypoints
46
+ color: "#6366F1"
47
+ tags: [networking, business-development, matchmaking, intros, middleman]
48
+ isPublic: true
49
+
50
+ # OVERLAY on CRM — composes additively onto the CRM workspace (no separate
51
+ # workspace is created); subtype MATCHES the compose base (`crm`, a no-op on the
52
+ # additive reconcile) and visibility is OMITTED so the base CRM keeps its own
53
+ # identity. `require foundation` (deps-first) guarantees the pod-wide role
54
+ # vocabulary CRM reuses is seeded before this overlay lands — mirroring
55
+ # grants.yaml's compose-base + require-foundation dependency shape.
56
+ dependencies:
57
+ - slug: crm
58
+ kind: workspace
59
+ relation: compose
60
+ reason: "Adds a needs → intros brokerage workflow onto your CRM workspace."
61
+ - slug: foundation
62
+ kind: workspace
63
+ relation: require
64
+ reason: "Provides the pod-wide client/partner role vocabulary the CRM base reuses."
65
+
66
+ workspace:
67
+ name: Networking
68
+ description: "A brokerage workspace layered on your CRM — client needs, a provider roster, and the intros that connect them."
69
+ proposalId: networking-v1
70
+ subtype: crm
71
+
72
+ profiles:
73
+ # ── Need (KIND) — the demand side: a client's stated ask ───────────────────
74
+ - slug: need
75
+ displayName: Need
76
+ icon: target
77
+ color: amber
78
+ description: A client's stated ask — the demand The Arch brokers a provider against.
79
+ scope: WORKSPACE
80
+ properties:
81
+ - slug: needStatus
82
+ label: Status
83
+ valueType: string
84
+ inputType: select
85
+ enumValues: [open, matching, intro-made, satisfied, dropped]
86
+ constraints: { defaultValue: open }
87
+ - slug: domain
88
+ label: Domain
89
+ valueType: string
90
+ inputType: text
91
+ placeholder: The area of the ask — e.g. market-making, audit, design.
92
+ - slug: urgency
93
+ label: Urgency
94
+ valueType: string
95
+ inputType: text
96
+ - slug: budgetRange
97
+ label: Budget Range
98
+ valueType: string
99
+ inputType: text
100
+ - slug: requesterCompanyId
101
+ label: Requester
102
+ valueType: entity_id
103
+ inputType: entity_select
104
+ targetProfileSlug: company
105
+ # The A↔B FIREWALL control. `confidential` (the default) keeps a need OUT
106
+ # of the match roster entirely — only `shareable` needs may be surfaced to
107
+ # a provider match. Defaulting to confidential means a need is private
108
+ # until a human explicitly opens it up.
109
+ - slug: confidentiality
110
+ label: Confidentiality
111
+ valueType: string
112
+ inputType: select
113
+ enumValues: [shareable, confidential]
114
+ constraints: { defaultValue: confidential }
115
+ - slug: evidenceQuote
116
+ label: Evidence Quote
117
+ valueType: string
118
+ inputType: textarea
119
+ placeholder: The client's own words that captured this need.
120
+ - slug: sourceMessageId
121
+ label: Source Message ID
122
+ valueType: string
123
+ inputType: text
124
+ - slug: notes
125
+ label: Notes
126
+ valueType: string
127
+ inputType: textarea
128
+
129
+ # ── Intro (KIND) — the brokerage artifact: the match + how it bills ────────
130
+ - slug: intro
131
+ displayName: Intro
132
+ icon: waypoints
133
+ color: violet
134
+ description: The middleman brokerage artifact — connects a requester to a provider for a need, and bills the match as a deal.
135
+ scope: WORKSPACE
136
+ properties:
137
+ - slug: introStage
138
+ label: Stage
139
+ valueType: string
140
+ inputType: select
141
+ enumValues: [identified, proposed, approved, introduced, in-discussion, signed, dead]
142
+ constraints: { defaultValue: identified }
143
+ - slug: requesterCompanyId
144
+ label: Requester
145
+ valueType: entity_id
146
+ inputType: entity_select
147
+ targetProfileSlug: company
148
+ - slug: providerCompanyId
149
+ label: Provider
150
+ valueType: entity_id
151
+ inputType: entity_select
152
+ targetProfileSlug: company
153
+ - slug: needId
154
+ label: Need
155
+ valueType: entity_id
156
+ inputType: entity_select
157
+ targetProfileSlug: need
158
+ # ── Fee vocabulary — REUSED VERBATIM from business-developer.yaml's `deal`
159
+ # commercial contract, so an intro bills exactly like a CRM deal does. ──
160
+ - slug: synapFeeModel
161
+ label: Synap fee model
162
+ valueType: string
163
+ inputType: select
164
+ enumValues: [fixed, success_fee]
165
+ - slug: synapSuccessFeeRate
166
+ label: Synap success fee rate
167
+ valueType: number
168
+ inputType: number
169
+ - slug: synapFixedFee
170
+ label: Synap fixed fee
171
+ valueType: number
172
+ inputType: number
173
+ - slug: expectedClientGain
174
+ label: Expected client gain
175
+ valueType: number
176
+ inputType: number
177
+ - slug: synapFeeAmount
178
+ label: Synap fee amount
179
+ valueType: number
180
+ inputType: number
181
+ - slug: sourcedByUserId
182
+ label: Sourced by user ID
183
+ valueType: string
184
+ inputType: text
185
+ - slug: commissionStatus
186
+ label: Commission status
187
+ valueType: string
188
+ inputType: select
189
+ enumValues: [estimated, earned, paid, requires_review, void]
190
+ - slug: introducedAt
191
+ label: Introduced at
192
+ valueType: date
193
+ inputType: date
194
+ - slug: outcome
195
+ label: Outcome
196
+ valueType: string
197
+ inputType: textarea
198
+ - slug: deadReason
199
+ label: Dead reason
200
+ valueType: string
201
+ inputType: textarea
202
+
203
+ # ── Solution Provider (FACET) — the supply side: a role on company/person ──
204
+ # `scope: shared`, `profileKind: role` — the ONE pod-wide row for "is a
205
+ # provider of some capability". Attached to the EXISTING company/person via
206
+ # FacetRepository; never a second entity. Mirrors blockchain-ecosystem's role
207
+ # facets. applicableKinds is required (rule (d) of the shared-role tripwire).
208
+ - slug: solution-provider
209
+ displayName: Solution Provider
210
+ icon: handshake
211
+ color: teal
212
+ description: A company or person that provides a capability The Arch can broker a client need against.
213
+ scope: shared
214
+ profileKind: role
215
+ applicableKinds:
216
+ - company
217
+ - person
218
+ properties:
219
+ - slug: status
220
+ label: Status
221
+ valueType: string
222
+ inputType: select
223
+ enumValues: [prospect, active, paused, churned]
224
+ - slug: domains
225
+ label: Domains
226
+ valueType: array
227
+ inputType: text
228
+ placeholder: The capability areas this provider covers.
229
+ - slug: capacity
230
+ label: Capacity
231
+ valueType: string
232
+ inputType: text
233
+ - slug: pricingNotes
234
+ label: Pricing Notes
235
+ valueType: string
236
+ inputType: textarea
237
+ - slug: geography
238
+ label: Geography
239
+ valueType: string
240
+ inputType: text
241
+ - slug: notes
242
+ label: Notes
243
+ valueType: string
244
+ inputType: textarea
245
+
246
+ # Relations. `company`/`deal` resolve from the CRM compose base (not redeclared);
247
+ # `need`/`intro` are this overlay's own kinds. The graph links the PARENT company
248
+ # on both sides of an intro — a facet is never a link endpoint.
249
+ entityLinks:
250
+ - sourceProfileSlug: need
251
+ targetProfileSlug: company
252
+ type: needed_by
253
+ label: Needed by
254
+ - sourceProfileSlug: intro
255
+ targetProfileSlug: need
256
+ type: resolves
257
+ label: Resolves
258
+ - sourceProfileSlug: intro
259
+ targetProfileSlug: company
260
+ type: introduced_requester
261
+ label: Requester
262
+ - sourceProfileSlug: intro
263
+ targetProfileSlug: company
264
+ type: introduced_provider
265
+ label: Provider
266
+ - sourceProfileSlug: intro
267
+ targetProfileSlug: deal
268
+ type: billed_as
269
+ label: Billed as
270
+
271
+ # Curated views — the two boards of the brokerage motion plus the provider roster.
272
+ views:
273
+ - name: Needs
274
+ slug: needs
275
+ type: kanban
276
+ scopeProfileSlug: need
277
+ description: Client needs on a board by status — open demand waiting for a match.
278
+ config:
279
+ groupByField: needStatus
280
+ - name: Intros
281
+ slug: intros
282
+ type: kanban
283
+ scopeProfileSlug: intro
284
+ description: Brokered intros on a board by stage — from identified match to signed.
285
+ config:
286
+ groupByField: introStage
287
+ - name: Providers
288
+ slug: providers
289
+ type: table
290
+ scopeProfileSlug: solution-provider
291
+ description: The solution-provider roster — companies wearing the provider role, by status.
292
+ config:
293
+ columns: [title, status, domains, geography, capacity]
294
+
295
+ # ============================================================================
296
+ # Intro Matcher automation — the daily demand↔supply match.
297
+ #
298
+ # WHAT: once a day, enumerate the SHAREABLE open needs, and for each one match
299
+ # it against the solution-provider roster with ONE batched AI call, propose a
300
+ # governed `intro`, and post a match brief to The Arch's INTERNAL team channel.
301
+ #
302
+ # A↔B FIREWALL (never bend):
303
+ # • Only `confidentiality: shareable` needs enter the roster — the query
304
+ # filters on it, so a confidential need is never even read into a match.
305
+ # • The brief posts to a `team`-purpose channel (branchPurpose: team) — The
306
+ # Arch's INTERNAL artifact channel — resolved from the REQUESTER COMPANY
307
+ # (client A, the need's owner), which owns a team channel bound at onboarding.
308
+ # That is The Arch's internal thread for client A, NOT a client-comms channel
309
+ # and NEVER client B's (the provider's) channel. It does not land in any
310
+ # client-facing channel. (It cannot resolve from the just-proposed intro
311
+ # entity: channel.resolve is a read-only FIND and the intro has no channel
312
+ # bound to it yet, so that returned null and the brief never posted.)
313
+ # • The matcher prompt forbids drafting anything for a client's own channel
314
+ # and forbids revealing one client's need to another client.
315
+ #
316
+ # GOVERNANCE: the two read builtins (`entity.query`, `channel.resolve`) and the
317
+ # `ai.generate` digest are READ-ONLY and auto-run; the single WRITE is an
318
+ # `output/entity_create` (returns `proposed`, never throws; `entity.create` is
319
+ # auto-approved for an owner/agent run) — mirrors operations.yaml's daily
320
+ # briefing exactly.
321
+ #
322
+ # NOTE on the query lens: `entity.query`'s DEFAULT lens already reads pod-wide ∪
323
+ # workspace, so needs (workspace-scoped) and providers (pod-wide shared role)
324
+ # both resolve WITHOUT a `scope: pod` opt-in. `need` is this template's own
325
+ # profile, so `assertKnownProfileSlug` cannot fail the first node.
326
+ # ============================================================================
327
+ automations:
328
+ - key: networking-intro-matcher
329
+ name: Intro Matcher
330
+ description: >-
331
+ Once a day, match each shareable open client need against the
332
+ solution-provider roster, propose an intro for the best fit, and post a
333
+ match brief to The Arch's internal team channel — never to a client's own
334
+ channel.
335
+ triggerType: cron
336
+ triggerConfig:
337
+ expression: "0 9 * * *"
338
+ status: active
339
+ metadata:
340
+ templateKey: networking-intro-matcher
341
+ flow:
342
+ nodes:
343
+ - id: trigger
344
+ type: trigger
345
+ position: { x: 0, y: 0 }
346
+ data:
347
+ label: Daily at 09:00
348
+ triggerType: cron
349
+ config:
350
+ expression: "0 9 * * *"
351
+
352
+ # READ-ONLY builtin. Enumerates ONLY shareable open needs — the firewall
353
+ # filter lives here, so a confidential need is never read into a match.
354
+ - id: list-needs
355
+ type: capability
356
+ position: { x: 0, y: 120 }
357
+ data:
358
+ label: List shareable open needs (FIREWALL filter)
359
+ verbId: entity.query
360
+ inputMapping:
361
+ profileSlug: need
362
+ filter:
363
+ needStatus: open
364
+ confidentiality: shareable
365
+ limit: "100"
366
+
367
+ # READ-ONLY builtin. The provider roster to match against — companies /
368
+ # people wearing the pod-wide `solution-provider` role.
369
+ - id: list-providers
370
+ type: capability
371
+ position: { x: 0, y: 240 }
372
+ data:
373
+ label: List the solution-provider roster
374
+ verbId: entity.query
375
+ inputMapping:
376
+ profileSlug: solution-provider
377
+ limit: "100"
378
+
379
+ - id: needs-loop
380
+ type: loop
381
+ position: { x: 0, y: 360 }
382
+ data:
383
+ label: For each shareable open need
384
+ iteratorExpression: steps.list-needs.output.entities
385
+ itemVariable: need
386
+
387
+ # READ-ONLY builtin (pure compute — auto-runs). ONE batched match call
388
+ # per need against the whole roster. Returns STRICT JSON naming the best
389
+ # provider (by entity id) or none.
390
+ - id: match
391
+ type: capability
392
+ position: { x: 0, y: 480 }
393
+ data:
394
+ label: Match this need to the roster → JSON
395
+ verbId: ai.generate
396
+ inputMapping:
397
+ json: "true"
398
+ maxTokens: "800"
399
+ system: >-
400
+ You are The Arch's business-development matchmaker. You connect a
401
+ CLIENT'S NEED to the single best SOLUTION PROVIDER from a roster.
402
+
403
+ FIREWALL (never break): your output is a brief for The Arch's
404
+ INTERNAL team channel ONLY. NEVER draft anything to be sent into a
405
+ client's own channel, and NEVER reveal one client's need to
406
+ another client. Do not name the requesting client in any text
407
+ intended for the provider.
408
+ prompt: >-
409
+ The client need:
410
+ title: {{loop.item.title}}
411
+ domain: {{loop.item.properties.domain}}
412
+ urgency: {{loop.item.properties.urgency}}
413
+ budget: {{loop.item.properties.budgetRange}}
414
+ detail: {{loop.item.properties.notes}}
415
+
416
+ The solution-provider roster (JSON — each has an id, title, and
417
+ properties incl. domains/geography/capacity):
418
+ {{steps.list-providers.output.entities}}
419
+
420
+ Pick the SINGLE best provider for this need, or none if nothing
421
+ fits well. Respond with STRICT JSON and NOTHING else:
422
+ {
423
+ "hasMatch": "true" or "false" (a STRING),
424
+ "providerEntityId": "<the matched provider's entity id, or empty string>",
425
+ "providerName": "<the matched provider's name, or empty string>",
426
+ "rationale": "<one or two sentences on why this provider fits, for the internal team>",
427
+ "brief": "<a short internal match brief for the team, markdown>"
428
+ }
429
+ Set hasMatch to "false" when no provider is a genuine fit.
430
+
431
+ # PER-ITEM gate (continue-semantics). Skip the rest of THIS need's body
432
+ # when no provider fit — no intro, no post. A `condition` (not `switch`)
433
+ # keeps the loop body a contiguous chain.
434
+ - id: match-gate
435
+ type: condition
436
+ position: { x: 0, y: 600 }
437
+ data:
438
+ label: Only continue when there is a real match
439
+ expression: "steps.match.output.hasMatch === true"
440
+
441
+ # GOVERNED WRITE via `output/entity_create` (returns `proposed`, never
442
+ # throws; `entity.create` is auto-approved for an owner/agent run).
443
+ # Proposes the intro linking this need's requester to the matched provider.
444
+ - id: create-intro
445
+ type: output
446
+ position: { x: 0, y: 720 }
447
+ data:
448
+ label: Propose the intro
449
+ outputType: entity_create
450
+ config:
451
+ profileSlug: intro
452
+ title: "Intro — {{loop.item.title}} → {{steps.match.output.providerName}}"
453
+ properties:
454
+ introStage: identified
455
+ needId: "{{loop.item.id}}"
456
+ requesterCompanyId: "{{loop.item.properties.requesterCompanyId}}"
457
+ providerCompanyId: "{{steps.match.output.providerEntityId}}"
458
+
459
+ # READ-ONLY builtin. Resolves the REQUESTER COMPANY's team-side channel
460
+ # (The Arch's internal artifact channel for that client) — NOT a company
461
+ # client-comms channel, NEVER the provider's. This is the firewall
462
+ # boundary: the brief posts internally, never client-facing.
463
+ - id: resolve-team
464
+ type: capability
465
+ position: { x: 0, y: 840 }
466
+ data:
467
+ label: Resolve The Arch's internal team channel for the requester (FIREWALL)
468
+ _note: >-
469
+ Resolves from the REQUESTER COMPANY, not the intro entity.
470
+ channel.resolve is a read-only FIND — it never creates. A
471
+ just-proposed `intro` has no channel bound to it, so resolving from
472
+ {{steps.create-intro.output.entityId}} returned channelId: null and
473
+ the brief silently never posted. The requester company is a stable
474
+ entity that already owns a `team`-purpose channel (bound at
475
+ onboarding), so we resolve from it instead. Firewall-safe: this is
476
+ The Arch's INTERNAL team thread for client A (the need's owner), NOT
477
+ client B's (the provider's) channel and NOT any client-comms channel.
478
+ verbId: channel.resolve
479
+ inputMapping:
480
+ contextObjectType: entity
481
+ contextObjectId: "{{loop.item.properties.requesterCompanyId}}"
482
+ branchPurpose: team
483
+
484
+ # UNGOVERNED direct insert to the EXPLICIT resolved internal channelId.
485
+ # Posts the match brief to The Arch's team channel ONLY.
486
+ - id: post-brief
487
+ type: output
488
+ position: { x: 0, y: 960 }
489
+ data:
490
+ label: Post the match brief to the INTERNAL team channel (FIREWALL)
491
+ outputType: channel_message
492
+ config:
493
+ channelId: "{{steps.resolve-team.output.channelId}}"
494
+ content: >-
495
+ **Match found — {{loop.item.title}} → {{steps.match.output.providerName}}**
496
+
497
+ {{steps.match.output.rationale}}
498
+
499
+ {{steps.match.output.brief}}
500
+ metadata:
501
+ automationMessage: true
502
+ kind: intro-match
503
+ edges:
504
+ - { id: e-trigger-needs, source: trigger, target: list-needs }
505
+ - { id: e-needs-providers, source: list-needs, target: list-providers }
506
+ - { id: e-providers-loop, source: list-providers, target: needs-loop }
507
+ - { id: e-loop-match, source: needs-loop, target: match }
508
+ - { id: e-match-gate, source: match, target: match-gate }
509
+ - { id: e-gate-intro, source: match-gate, target: create-intro }
510
+ - { id: e-intro-resolve, source: create-intro, target: resolve-team }
511
+ - { id: e-resolve-post, source: resolve-team, target: post-brief }
512
+
513
+ app:
514
+ kind: stored
515
+ cellKey: entity-detail
516
+
517
+ layout:
518
+ defaultView: Needs
519
+ defaultApp: null
520
+ pinnedApps: [dashboard, data]
521
+ sidebarItems:
522
+ - kind: view
523
+ viewName: Needs
524
+ label: Needs
525
+ icon: target
526
+ - kind: view
527
+ viewName: Intros
528
+ label: Intros
529
+ icon: waypoints
530
+ - kind: view
531
+ viewName: Providers
532
+ label: Providers
533
+ icon: handshake
534
+
535
+ bento:
536
+ viewName: Needs
537
+ blocks:
538
+ - kind: view
539
+ viewName: Needs
540
+ pos: { x: 0, y: 0, w: 6, h: 5 }
541
+ - kind: view
542
+ viewName: Intros
543
+ pos: { x: 6, y: 0, w: 6, h: 5 }
544
+
545
+ onboarding:
546
+ goal: >
547
+ Capture the two sides of the brokerage — the live client NEEDS and the
548
+ SOLUTION-PROVIDER roster — so the matcher has real demand and real supply to
549
+ connect, and every intro traces back to a stated need and a named provider.
550
+ framing: |
551
+ THE BD MIDDLEMAN: Act as a sharp business-development broker who lives
552
+ between clients. One client has a need; another has the capability to meet
553
+ it; your value is the introduction and the fee on the match. Push for the
554
+ concrete: whose need is this, how confidential is it, and which real provider
555
+ can serve it. Tag the provider role onto the REAL company you already know —
556
+ never a second entity for the same firm.
557
+ expertise:
558
+ starters:
559
+ - >
560
+ A need has an owner and a confidentiality. Default every need to
561
+ confidential — it only enters the match roster once a human marks it
562
+ shareable. Capture whose need it is (the requester company) and, where
563
+ you can, the client's own words as the evidence quote.
564
+ - >
565
+ The provider is a HAT, not a new entity. Attach the solution-provider
566
+ role to the real company/person you already track (match on domain /
567
+ name first) — a market of providers is a graph of roles on known
568
+ companies, not a parallel directory.
569
+ blindSpots:
570
+ - >
571
+ A need with no provider and no status is a wish, not a pipeline. Force
572
+ the status (open / matching / intro-made) and, once a match exists,
573
+ broker the intro rather than letting the need sit open.
574
+ - >
575
+ The firewall is the product. Never let one client's confidential need
576
+ leak to another client. If a need is sensitive, keep it confidential —
577
+ an intro is proposed to the internal team first, never straight to a
578
+ client's channel.
579
+ bar: >
580
+ A workspace with real client needs (each with a requester and a
581
+ confidentiality), a roster of solution providers tagged onto real
582
+ companies, and the first intros brokered between them — so a glance shows
583
+ what demand is open and which providers can serve it.
584
+ collect:
585
+ - profileSlug: need
586
+ what: The live client needs you could broker a provider against.
587
+ cardinality: several
588
+ keyFields: [needStatus, domain, requesterCompanyId, confidentiality]
589
+ - profileSlug: solution-provider
590
+ what: The solution providers you can connect clients to, tagged onto the real company.
591
+ cardinality: several
592
+ keyFields: [status, domains, geography]
593
+ openingQuestions:
594
+ - "Which client needs are open right now, and whose needs are they?"
595
+ - "Which of those needs are shareable, and which must stay confidential?"
596
+ - "Which solution providers can you connect clients to, and what do they cover?"
597
+ doneWhen: A few client needs captured with a requester and a confidentiality, a handful of solution providers tagged onto real companies, and at least one intro brokered between them.
@@ -355,9 +355,13 @@ automations:
355
355
  - key: operations-daily-client-briefing
356
356
  name: Daily client briefing
357
357
  description: >-
358
- Each morning, for every client, distil their recent comms into one
359
- batched digest, save it as a durable client-briefing, and post the recap
360
- to the client's internal TEAM channel (never the client-facing channel).
358
+ Operations-native daily client briefing. Writes a durable, dated
359
+ client-briefing ENTITY per client (queryable history, linked to the
360
+ client) from their recent comms, and posts the recap to the client's
361
+ internal TEAM channel (never the client-facing channel). Knowledge-building
362
+ and entity-first — the delivery OS's structured memory of each client. For
363
+ a lighter, portable message-only digest installable on any pod, use the
364
+ client-comms-report capability.
361
365
  triggerType: cron
362
366
  triggerConfig:
363
367
  expression: "0 8 * * *"