@synap-core/workspace-templates 0.10.0 → 0.12.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/dist/index.js CHANGED
@@ -2,7 +2,11 @@
2
2
  var PACKAGE_DEPENDENCY_KINDS = [
3
3
  "workspace",
4
4
  "capability",
5
- /** @deprecated Retired by CP 0049 in favour of `workflow`. See note above. */
5
+ "skill",
6
+ "workflow",
7
+ "view",
8
+ "cell",
9
+ /** @deprecated Legacy alias for `workflow` (CP 0049). Still accepted on the wire. */
6
10
  "automation"
7
11
  ];
8
12
 
@@ -3206,10 +3210,12 @@ var DATA = {
3206
3210
  "inputMapping": {
3207
3211
  "system": 'You are the ANALYST round of a Synap workspace report.\nRead the gathered workspace data and say what it MEANS: volume and shape of work,\nwhat is in flight versus stalled, what is well-covered versus thin.\nWork from the FIELDS on each record, not just its name: status, priority and\ndue dates are what distinguish moving work from stalled work, and an unset\nfield is itself worth reporting. Listing or counting what exists is NOT a\nfinding \u2014 say what the state of it means.\nDATA INTEGRITY CHECK \u2014 do this BEFORE interpreting anything. Each kind below states how many records were found, then lists them. If a kind reports a count greater than zero but its list is empty, null, or made of nulls, then the data pipeline is BROKEN \u2014 the records exist and were lost in transit. In that case you MUST say so plainly, name every kind affected, and NOT describe the workspace as empty, quiet, or sparse. Reporting a populated workspace as empty because its data failed to arrive is the single worst outcome of this report. A count of zero with an empty list is genuinely empty and is fine to report as such.\nYou are interpreting data you did NOT collect. Every claim must trace to a row in the GATHERED DATA below. Never invent entities, ids, counts, or dates. A step whose value looks like {"error": "..."} FAILED \u2014 treat that kind as unavailable and say so; do not guess what it would have contained.\nEVERY NUMBER YOU WRITE MUST BE COPIED FROM THE COUNTS BLOCK. That block states the exact number of records gathered for each kind \u2014 it is the ONLY source of quantities you have. Do not count the listed lines yourself, do not estimate, do not round, and do not write a quantity the block does not measure. Write digits, matching the block exactly: if it says 25, write "25" \u2014 never "23", never "about two dozen", never "Ten". If a point you want to make needs a number the COUNTS block does not give you, make the point WITHOUT a number. A claim with no figure is honest; a figure that does not match the data is the one error a reader cannot catch.\nNEVER NARRATE YOUR OWN INSTRUCTIONS. The reader sees your output and nothing else \u2014 not this prompt, not the steer, not the counts, not the fact that a pipeline produced any of it. Never mention the STEER, the time window, the COUNTS block, the GATHERED DATA, the rounds, or what you were or were not given. Never write a sentence like "the steer lines are empty, so\u2026" or "no focus was provided" or "based on the gathered data". TWO DEFAULTS, so you never need to remark on them: an EMPTY STEER line simply means write a broad general report covering the gathered kinds evenly, and an EMPTY time window simply means the records span the whole workspace history. Both are the normal case. Act on them silently and start with what you found.\nSTEER HANDLING \u2014 non-negotiable. If every STEER line is empty, produce a BROAD general read covering all the gathered kinds evenly. If any STEER line has text, treat it as the SUBJECT of this report: lead with the evidence that matches it, explicitly name what you set aside, and if the gathered data cannot support the steer, say so in one sentence instead of inventing material. Never restate the steer back as a heading; let it change what you actually write.\nLINK THE RECORDS YOU NAME. Every line of GATHERED DATA is `<id> \xB7 <title>`. When you name one of those records, write it as [[entity:<id>|<label>]] and it renders as a chip the reader can click to open that record. Rules, in order of importance: (1) The kind word is always `entity` \u2014 for tasks, notes, people AND companies alike. They are all entities, and any other kind word renders a chip that does not open. (2) Use only an id that appears VERBATIM in the gathered data. Copy it; never construct, shorten, complete or guess one. (3) If you are unsure of an id, write the plain label with no brackets. A wrong id is a dead chip, and a dead chip is worse than plain text. (4) The label is free text but must not contain `]`; the id must not contain `:` or `|`. A marker breaking either rule renders as raw literal text. (5) EVERY record you name in prose MUST carry a chip on its FIRST mention \u2014 this is what makes a named record a live object the reader can open rather than a string. Link it once, on that first mention only; repeating the chip every time is decoration, not navigation.\nOutput PLAIN PROSE \u2014 short paragraphs and bullets, with [[entity:\u2026]] chips\ninline wherever you name a record. No markdown headings, no ::: directive\nblocks, no code fences. Under 300 words. Another round will format this.',
3208
3212
  "prompt": 'STEER:\n- Prompt: {{trigger.payload.prompt}}\n- Focus: {{trigger.payload.focus}}\n- Project lens id: {{trigger.payload.projectId}}\n\nCOUNTS \u2014 the exact number of records gathered for each kind. These figures\nare measured, not estimated, and they are the ONLY quantities available to\nyou. Each line also gives the cap the gather was limited to.\n- Tasks: {{steps.gather-tasks.output.count}} gathered (cap 25)\n- Notes: {{steps.gather-notes.output.count}} gathered (cap 15)\n- People: {{steps.gather-people.output.count}} gathered (cap 15)\n- Companies: {{steps.gather-companies.output.count}} gathered (cap 15)\nREADING A COUNT AGAINST ITS CAP: a count BELOW the cap means every record of\nthat kind is listed below \u2014 the set is COMPLETE and you may describe it as\nsuch. A count EQUAL to the cap means the gather stopped at the cap and more\nrecords exist that you cannot see \u2014 describe that kind as "at least N" and\nnever as complete, and never claim something does not exist merely because\nit is absent from the list.\n\nTime window: only records updated on or after {{trigger.payload.since}}\n\nGATHERED DATA \u2014 one line per record, MOST RECENTLY UPDATED first. Each line\nis `<id> \xB7 <title>` followed by ` \xB7 <field>=<value>` pairs carrying that\nrecord\'s real state. An EMPTY value means the field is not set on that\nrecord \u2014 that is a fact you may report (an unset status or a missing due\ndate is a finding), and never a value to guess at. Recent does not mean\nimportant.\nTasks \u2014 {{steps.gather-tasks.output.count}} found: {{steps.project-tasks.output.result}}\nNotes \u2014 {{steps.gather-notes.output.count}} found: {{steps.project-notes.output.result}}\nPeople \u2014 {{steps.gather-people.output.count}} found: {{steps.project-people.output.result}}\nCompanies \u2014 {{steps.gather-companies.output.count}} found: {{steps.project-companies.output.result}}',
3209
- "maxTokens": "700"
3213
+ "maxTokens": "2000"
3210
3214
  },
3211
3215
  "errorHandling": {
3212
- "continueOnError": true
3216
+ "continueOnError": true,
3217
+ "maxRetries": 1,
3218
+ "retryDelay": 5e3
3213
3219
  }
3214
3220
  }
3215
3221
  },
@@ -3227,10 +3233,12 @@ var DATA = {
3227
3233
  "inputMapping": {
3228
3234
  "system": 'You are the PATTERNS round of a Synap workspace report.\nYou receive the raw gathered data AND the analyst\'s read of it. Your job is what\nthe analyst did NOT do: surface RELATIONSHIPS and things worth attention \u2014\nclusters, repeated themes, people or companies that recur across kinds, gaps\nwhere a kind is conspicuously empty, and anything that looks like it needs a\ndecision. Prefer three sharp observations over ten shallow ones.\nYOUR SCOPE IS WHAT CONNECTS RECORDS, not what they individually are. Every\nobservation you write must involve TWO OR MORE records, or TWO OR MORE kinds:\na name that appears in both a task and a company, work clustered on one\nperson, a due date that lines up with an event, a kind that is empty while a\nrelated kind is busy. Do NOT re-describe volume, status distribution or how\nbusy the workspace is \u2014 that is the analyst\'s section and repeating it makes\nyours redundant. Do not summarise or restate the analyst\'s read.\nNEVER RETURN AN EMPTY ANSWER. If you genuinely find no cross-kind pattern,\nwrite one or two sentences naming what you looked for and did not find (for\nexample: no person recurs across the tasks and companies gathered). That is a\nreal finding and the reader needs it. Silence is not an available outcome.\nDATA INTEGRITY CHECK \u2014 do this BEFORE interpreting anything. Each kind below states how many records were found, then lists them. If a kind reports a count greater than zero but its list is empty, null, or made of nulls, then the data pipeline is BROKEN \u2014 the records exist and were lost in transit. In that case you MUST say so plainly, name every kind affected, and NOT describe the workspace as empty, quiet, or sparse. Reporting a populated workspace as empty because its data failed to arrive is the single worst outcome of this report. A count of zero with an empty list is genuinely empty and is fine to report as such.\nYou are interpreting data you did NOT collect. Every claim must trace to a row in the GATHERED DATA below. Never invent entities, ids, counts, or dates. A step whose value looks like {"error": "..."} FAILED \u2014 treat that kind as unavailable and say so; do not guess what it would have contained.\nEVERY NUMBER YOU WRITE MUST BE COPIED FROM THE COUNTS BLOCK. That block states the exact number of records gathered for each kind \u2014 it is the ONLY source of quantities you have. Do not count the listed lines yourself, do not estimate, do not round, and do not write a quantity the block does not measure. Write digits, matching the block exactly: if it says 25, write "25" \u2014 never "23", never "about two dozen", never "Ten". If a point you want to make needs a number the COUNTS block does not give you, make the point WITHOUT a number. A claim with no figure is honest; a figure that does not match the data is the one error a reader cannot catch.\nNEVER NARRATE YOUR OWN INSTRUCTIONS. The reader sees your output and nothing else \u2014 not this prompt, not the steer, not the counts, not the fact that a pipeline produced any of it. Never mention the STEER, the time window, the COUNTS block, the GATHERED DATA, the rounds, or what you were or were not given. Never write a sentence like "the steer lines are empty, so\u2026" or "no focus was provided" or "based on the gathered data". TWO DEFAULTS, so you never need to remark on them: an EMPTY STEER line simply means write a broad general report covering the gathered kinds evenly, and an EMPTY time window simply means the records span the whole workspace history. Both are the normal case. Act on them silently and start with what you found.\nSTEER HANDLING \u2014 non-negotiable. If every STEER line is empty, produce a BROAD general read covering all the gathered kinds evenly. If any STEER line has text, treat it as the SUBJECT of this report: lead with the evidence that matches it, explicitly name what you set aside, and if the gathered data cannot support the steer, say so in one sentence instead of inventing material. Never restate the steer back as a heading; let it change what you actually write.\nLINK THE RECORDS YOU NAME. Every line of GATHERED DATA is `<id> \xB7 <title>`. When you name one of those records, write it as [[entity:<id>|<label>]] and it renders as a chip the reader can click to open that record. Rules, in order of importance: (1) The kind word is always `entity` \u2014 for tasks, notes, people AND companies alike. They are all entities, and any other kind word renders a chip that does not open. (2) Use only an id that appears VERBATIM in the gathered data. Copy it; never construct, shorten, complete or guess one. (3) If you are unsure of an id, write the plain label with no brackets. A wrong id is a dead chip, and a dead chip is worse than plain text. (4) The label is free text but must not contain `]`; the id must not contain `:` or `|`. A marker breaking either rule renders as raw literal text. (5) EVERY record you name in prose MUST carry a chip on its FIRST mention \u2014 this is what makes a named record a live object the reader can open rather than a string. Link it once, on that first mention only; repeating the chip every time is decoration, not navigation.\nOutput PLAIN PROSE, under 250 words, with [[entity:\u2026]] chips inline. No\nheadings, no ::: directive blocks, no code fences.',
3229
3235
  "prompt": "STEER:\n- Prompt: {{trigger.payload.prompt}}\n- Focus: {{trigger.payload.focus}}\n- Project lens id: {{trigger.payload.projectId}}\n\nCOUNTS \u2014 the exact number of records gathered for each kind. These figures\nare measured, not estimated, and they are the ONLY quantities available to\nyou. Each line also gives the cap the gather was limited to.\n- Tasks: {{steps.gather-tasks.output.count}} gathered (cap 25)\n- Notes: {{steps.gather-notes.output.count}} gathered (cap 15)\n- People: {{steps.gather-people.output.count}} gathered (cap 15)\n- Companies: {{steps.gather-companies.output.count}} gathered (cap 15)\nREADING A COUNT AGAINST ITS CAP: a count BELOW the cap means every record of\nthat kind is listed below \u2014 the set is COMPLETE and you may describe it as\nsuch. A count EQUAL to the cap means the gather stopped at the cap and more\nrecords exist that you cannot see \u2014 describe that kind as \"at least N\" and\nnever as complete, and never claim something does not exist merely because\nit is absent from the list.\n\nTime window: only records updated on or after {{trigger.payload.since}}\n\nGATHERED DATA \u2014 one line per record, MOST RECENTLY UPDATED first. Each line\nis `<id> \xB7 <title>` followed by ` \xB7 <field>=<value>` pairs carrying that\nrecord's real state. An EMPTY value means the field is not set on that\nrecord \u2014 that is a fact you may report (an unset status or a missing due\ndate is a finding), and never a value to guess at. Recent does not mean\nimportant.\nTasks \u2014 {{steps.gather-tasks.output.count}} found: {{steps.project-tasks.output.result}}\nNotes \u2014 {{steps.gather-notes.output.count}} found: {{steps.project-notes.output.result}}\nPeople \u2014 {{steps.gather-people.output.count}} found: {{steps.project-people.output.result}}\nCompanies \u2014 {{steps.gather-companies.output.count}} found: {{steps.project-companies.output.result}}\n\nANALYST'S READ \u2014 already written and already in the report. Do NOT\nrestate, summarise or re-analyse it. It is here so you do not repeat it:\n{{steps.analyze.output}}\n\nYOUR TASK \u2014 cross-kind patterns ONLY. Look for what connects the lists\nabove: a person who recurs in tasks and companies, work clustered on one\nname, due dates that line up, a kind that is empty while a related kind\nis busy, a company with people but no tasks. Write only observations\nthat span TWO OR MORE records or kinds. If there are none, say what you\nchecked and did not find \u2014 never answer with nothing.",
3230
- "maxTokens": "700"
3236
+ "maxTokens": "2000"
3231
3237
  },
3232
3238
  "errorHandling": {
3233
- "continueOnError": true
3239
+ "continueOnError": true,
3240
+ "maxRetries": 1,
3241
+ "retryDelay": 5e3
3234
3242
  }
3235
3243
  }
3236
3244
  },
@@ -3407,6 +3415,10 @@ Be CONCISE \u2014 your entire output must fit in 2000 tokens. Emit ONLY the mark
3407
3415
  document. No preamble, no explanation, no code fences around the whole thing.`,
3408
3416
  "prompt": "STEER:\n- Prompt: {{trigger.payload.prompt}}\n- Focus: {{trigger.payload.focus}}\n- Project lens id: {{trigger.payload.projectId}}\n\nReport generated at: {{steps.now.output.result}}\n\nANALYZE ROUND MATERIAL:\n{{steps.analyze.output}}\n\nRELATE ROUND MATERIAL:\n{{steps.relate.output}}",
3409
3417
  "maxTokens": "2000"
3418
+ },
3419
+ "errorHandling": {
3420
+ "maxRetries": 1,
3421
+ "retryDelay": 5e3
3410
3422
  }
3411
3423
  }
3412
3424
  },
@@ -3425,6 +3437,10 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
3425
3437
  "system": 'Write ONE plain sentence, under 200 characters, stating what this report found.\nNo markdown, no directives, no quotes, no leading label. Just the sentence.\nIf the material is an error or empty, write exactly: "Report generated with incomplete data."',
3426
3438
  "prompt": "Material to summarize (may be an error object if the round failed):\n{{steps.analyze.output}}",
3427
3439
  "maxTokens": "500"
3440
+ },
3441
+ "errorHandling": {
3442
+ "maxRetries": 1,
3443
+ "retryDelay": 5e3
3428
3444
  }
3429
3445
  }
3430
3446
  },
@@ -3621,6 +3637,7 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
3621
3637
  "description": "A liquidity provider \u2014 makes markets and provides depth for a token.",
3622
3638
  "scope": "shared",
3623
3639
  "profileKind": "role",
3640
+ "roleCategory": "provider",
3624
3641
  "applicableKinds": [
3625
3642
  "company",
3626
3643
  "person"
@@ -3666,6 +3683,7 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
3666
3683
  "description": "A security firm or individual that audits smart contracts and protocols.",
3667
3684
  "scope": "shared",
3668
3685
  "profileKind": "role",
3686
+ "roleCategory": "provider",
3669
3687
  "applicableKinds": [
3670
3688
  "company",
3671
3689
  "person"
@@ -3711,6 +3729,7 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
3711
3729
  "description": "An outsourced engineering studio or build partner.",
3712
3730
  "scope": "shared",
3713
3731
  "profileKind": "role",
3732
+ "roleCategory": "provider",
3714
3733
  "applicableKinds": [
3715
3734
  "company",
3716
3735
  "person"
@@ -3756,6 +3775,7 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
3756
3775
  "description": "A brand, growth, or content marketing agency.",
3757
3776
  "scope": "shared",
3758
3777
  "profileKind": "role",
3778
+ "roleCategory": "provider",
3759
3779
  "applicableKinds": [
3760
3780
  "company",
3761
3781
  "person"
@@ -3801,6 +3821,7 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
3801
3821
  "description": "A performance / paid-media buying agency.",
3802
3822
  "scope": "shared",
3803
3823
  "profileKind": "role",
3824
+ "roleCategory": "provider",
3804
3825
  "applicableKinds": [
3805
3826
  "company",
3806
3827
  "person"
@@ -3846,6 +3867,7 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
3846
3867
  "description": "A key opinion leader or influencer who amplifies reach.",
3847
3868
  "scope": "shared",
3848
3869
  "profileKind": "role",
3870
+ "roleCategory": "provider",
3849
3871
  "applicableKinds": [
3850
3872
  "company",
3851
3873
  "person"
@@ -3882,6 +3904,100 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
3882
3904
  "inputType": "textarea"
3883
3905
  }
3884
3906
  ]
3907
+ },
3908
+ {
3909
+ "slug": "grant-program",
3910
+ "displayName": "Grant Program",
3911
+ "icon": "landmark",
3912
+ "color": "emerald",
3913
+ "description": "A per-chain funding program (e.g. Stellar SCF, Optimism RetroPGF) \u2014 the long-lived funder above a round.",
3914
+ "profileKind": "kind",
3915
+ "entityScope": "pod",
3916
+ "scope": "shared",
3917
+ "properties": [
3918
+ {
3919
+ "slug": "blockchain",
3920
+ "label": "Blockchain / Chain",
3921
+ "valueType": "string",
3922
+ "inputType": "text"
3923
+ },
3924
+ {
3925
+ "slug": "programName",
3926
+ "label": "Program Name",
3927
+ "valueType": "string",
3928
+ "inputType": "text"
3929
+ },
3930
+ {
3931
+ "slug": "programType",
3932
+ "label": "Program Type",
3933
+ "valueType": "string",
3934
+ "inputType": "select",
3935
+ "enumValues": [
3936
+ "direct",
3937
+ "retroactive",
3938
+ "quadratic",
3939
+ "rfp"
3940
+ ]
3941
+ },
3942
+ {
3943
+ "slug": "status",
3944
+ "label": "Status",
3945
+ "valueType": "string",
3946
+ "inputType": "select",
3947
+ "enumValues": [
3948
+ "active",
3949
+ "paused",
3950
+ "retired"
3951
+ ]
3952
+ },
3953
+ {
3954
+ "slug": "url",
3955
+ "label": "Program URL",
3956
+ "valueType": "string",
3957
+ "inputType": "url"
3958
+ },
3959
+ {
3960
+ "slug": "cadence",
3961
+ "label": "Cadence",
3962
+ "valueType": "string",
3963
+ "inputType": "text",
3964
+ "placeholder": "every 6 weeks"
3965
+ },
3966
+ {
3967
+ "slug": "nextDeadline",
3968
+ "label": "Next Deadline",
3969
+ "valueType": "date",
3970
+ "inputType": "date"
3971
+ },
3972
+ {
3973
+ "slug": "submissionTracks",
3974
+ "label": "Submission Tracks",
3975
+ "valueType": "array",
3976
+ "inputType": "text"
3977
+ },
3978
+ {
3979
+ "slug": "trancheModel",
3980
+ "label": "Tranche Model",
3981
+ "valueType": "string",
3982
+ "inputType": "text",
3983
+ "placeholder": "4 tranches / 90 days"
3984
+ },
3985
+ {
3986
+ "slug": "defaultPlaybook",
3987
+ "label": "Default Playbook",
3988
+ "valueType": "string",
3989
+ "inputType": "text",
3990
+ "constraints": {
3991
+ "defaultValue": "Grant Process"
3992
+ }
3993
+ },
3994
+ {
3995
+ "slug": "description",
3996
+ "label": "Description",
3997
+ "valueType": "string",
3998
+ "inputType": "textarea"
3999
+ }
4000
+ ]
3885
4001
  }
3886
4002
  ],
3887
4003
  "entityLinks": [
@@ -5220,7 +5336,8 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
5220
5336
  "builder.apps",
5221
5337
  "builder.deployments",
5222
5338
  "builder.agents",
5223
- "builder.packages"
5339
+ "builder.packages",
5340
+ "devplane.workspace"
5224
5341
  ]
5225
5342
  },
5226
5343
  "profiles": [
@@ -8772,6 +8889,640 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
8772
8889
  }
8773
8890
  ]
8774
8891
  },
8892
+ "business-model": {
8893
+ "meta": {
8894
+ "slug": "business-model",
8895
+ "domain": "strategy",
8896
+ "name": "Business Model",
8897
+ "description": "Interrogate a venture as a model that rests on things \u2014 components supported by evidence, bound by real conventions, and quantified by projections whose assumptions stay visible.",
8898
+ "icon": "layout-grid",
8899
+ "color": "#0EA5E9",
8900
+ "tags": [
8901
+ "strategy",
8902
+ "business-model",
8903
+ "grp",
8904
+ "ibis",
8905
+ "viability"
8906
+ ],
8907
+ "isPublic": true
8908
+ },
8909
+ "workspace": {
8910
+ "name": "Foundation",
8911
+ "description": "Adds business-model interrogation to the strategic substrate \u2014 what the model rests on, which conventions bind it, and which numbers assume what.",
8912
+ "subtype": "foundation"
8913
+ },
8914
+ "dependencies": [
8915
+ {
8916
+ "slug": "foundation",
8917
+ "relation": "compose",
8918
+ "reason": "The model's components ARE the foundation vocabulary \u2014 mission, audience, pain-point, positioning, offer, and the client/partner/porteur/funder roles. This pack interrogates them; it does not restate them."
8919
+ }
8920
+ ],
8921
+ "profiles": [
8922
+ {
8923
+ "slug": "question",
8924
+ "displayName": "Question",
8925
+ "icon": "help-circle",
8926
+ "profileKind": "kind",
8927
+ "properties": [
8928
+ {
8929
+ "slug": "questionStatus",
8930
+ "label": "Status",
8931
+ "valueType": "string",
8932
+ "inputType": "select",
8933
+ "enumValues": [
8934
+ "open",
8935
+ "exploring",
8936
+ "answered",
8937
+ "abandoned"
8938
+ ]
8939
+ }
8940
+ ]
8941
+ },
8942
+ {
8943
+ "slug": "decision",
8944
+ "displayName": "Decision",
8945
+ "icon": "gavel",
8946
+ "profileKind": "kind",
8947
+ "properties": [
8948
+ {
8949
+ "slug": "decisionStatus",
8950
+ "label": "Status",
8951
+ "valueType": "string",
8952
+ "inputType": "select",
8953
+ "enumValues": [
8954
+ "proposed",
8955
+ "accepted",
8956
+ "superseded",
8957
+ "rejected"
8958
+ ]
8959
+ }
8960
+ ]
8961
+ },
8962
+ {
8963
+ "slug": "convention",
8964
+ "displayName": "Convention",
8965
+ "icon": "scale",
8966
+ "color": "rose",
8967
+ "description": "A binding rule the model must satisfy and did not choose \u2014 an eligibility threshold, a professional duty, a contractual floor, a platform policy. Distinct from a decision (nobody decided it) and from a finding (it constrains rather than informs).",
8968
+ "profileKind": "kind",
8969
+ "properties": [
8970
+ {
8971
+ "slug": "rule",
8972
+ "label": "The Rule",
8973
+ "valueType": "string",
8974
+ "inputType": "textarea",
8975
+ "description": "State the constraint in the terms the issuer uses, not in a paraphrase. Paraphrase is where eligibility collisions hide."
8976
+ },
8977
+ {
8978
+ "slug": "issuer",
8979
+ "label": "Issued By",
8980
+ "valueType": "string",
8981
+ "inputType": "text",
8982
+ "description": "Who imposes it \u2014 a regulator, a funder, an ordre professionnel, a platform, a counterparty."
8983
+ },
8984
+ {
8985
+ "slug": "conventionType",
8986
+ "label": "Type",
8987
+ "valueType": "string",
8988
+ "inputType": "select",
8989
+ "enumValues": [
8990
+ "regulatory",
8991
+ "deontological",
8992
+ "eligibility",
8993
+ "contractual",
8994
+ "platform",
8995
+ "fiscal",
8996
+ "other"
8997
+ ]
8998
+ },
8999
+ {
9000
+ "slug": "bindingStatus",
9001
+ "label": "Binding Status",
9002
+ "valueType": "string",
9003
+ "inputType": "select",
9004
+ "enumValues": [
9005
+ "verified",
9006
+ "assumed",
9007
+ "contested",
9008
+ "expired"
9009
+ ],
9010
+ "description": "`assumed` is the dangerous default \u2014 it means nobody has read the source text yet."
9011
+ },
9012
+ {
9013
+ "slug": "sourceReference",
9014
+ "label": "Source Reference",
9015
+ "valueType": "string",
9016
+ "inputType": "text",
9017
+ "description": "The cahier des charges, article, or guide this comes from. A convention with no reference is an assumption wearing a rule's clothes."
9018
+ },
9019
+ {
9020
+ "slug": "expiresAt",
9021
+ "label": "Expires / Review By",
9022
+ "valueType": "date",
9023
+ "inputType": "date"
9024
+ },
9025
+ {
9026
+ "slug": "consequenceIfBreached",
9027
+ "label": "Consequence If Breached",
9028
+ "valueType": "string",
9029
+ "inputType": "textarea"
9030
+ }
9031
+ ]
9032
+ },
9033
+ {
9034
+ "slug": "projection",
9035
+ "displayName": "Projection",
9036
+ "icon": "trending-up",
9037
+ "color": "violet",
9038
+ "description": "A quantified scenario with its assumptions attached. The number is never the artifact \u2014 the assumptions are, because that is the only part anyone can argue with.",
9039
+ "profileKind": "kind",
9040
+ "properties": [
9041
+ {
9042
+ "slug": "scenario",
9043
+ "label": "Scenario",
9044
+ "valueType": "string",
9045
+ "inputType": "select",
9046
+ "enumValues": [
9047
+ "pessimistic",
9048
+ "base",
9049
+ "optimistic"
9050
+ ]
9051
+ },
9052
+ {
9053
+ "slug": "horizon",
9054
+ "label": "Horizon",
9055
+ "valueType": "string",
9056
+ "inputType": "select",
9057
+ "enumValues": [
9058
+ "month",
9059
+ "quarter",
9060
+ "year",
9061
+ "three-year"
9062
+ ]
9063
+ },
9064
+ {
9065
+ "slug": "assumptions",
9066
+ "label": "Assumptions",
9067
+ "valueType": "string",
9068
+ "inputType": "textarea",
9069
+ "description": "Every input this number needs to be true. When one changes, whatever rests on this projection goes stale."
9070
+ },
9071
+ {
9072
+ "slug": "revenueEstimate",
9073
+ "label": "Revenue Estimate",
9074
+ "valueType": "number",
9075
+ "inputType": "number"
9076
+ },
9077
+ {
9078
+ "slug": "costEstimate",
9079
+ "label": "Cost Estimate",
9080
+ "valueType": "number",
9081
+ "inputType": "number"
9082
+ },
9083
+ {
9084
+ "slug": "breakEvenUnits",
9085
+ "label": "Break-Even Units",
9086
+ "valueType": "number",
9087
+ "inputType": "number"
9088
+ },
9089
+ {
9090
+ "slug": "confidence",
9091
+ "label": "Confidence",
9092
+ "valueType": "string",
9093
+ "inputType": "select",
9094
+ "enumValues": [
9095
+ "low",
9096
+ "medium",
9097
+ "high"
9098
+ ]
9099
+ }
9100
+ ]
9101
+ }
9102
+ ],
9103
+ "relationDefs": [
9104
+ {
9105
+ "slug": "rests_on",
9106
+ "displayName": "Rests On",
9107
+ "description": "The source depends on the target for its validity \u2014 not for its scheduling. Cycles are LEGAL and meaningful here: a business model is mutually supporting by nature, and forcing it into an acyclic dependency graph destroys the information. When the target changes, everything resting on it is stale until re-checked.",
9108
+ "isDirectional": true,
9109
+ "uiHints": {
9110
+ "category": "reference",
9111
+ "inverseLabel": "Supports"
9112
+ }
9113
+ },
9114
+ {
9115
+ "slug": "refutes",
9116
+ "displayName": "Refutes",
9117
+ "description": "The source is evidence that the target is false. Kept as a first-class edge so a refuted component stays in the graph with its refutation attached, instead of being quietly deleted \u2014 the reason a road was not taken is worth more than the road.",
9118
+ "isDirectional": true,
9119
+ "uiHints": {
9120
+ "category": "reference",
9121
+ "inverseLabel": "Refuted By"
9122
+ }
9123
+ }
9124
+ ],
9125
+ "entityLinks": [
9126
+ {
9127
+ "sourceProfileSlug": "offer",
9128
+ "targetProfileSlug": "convention",
9129
+ "type": "rests_on",
9130
+ "label": "Rests on"
9131
+ },
9132
+ {
9133
+ "sourceProfileSlug": "offer",
9134
+ "targetProfileSlug": "audience",
9135
+ "type": "rests_on",
9136
+ "label": "Rests on"
9137
+ },
9138
+ {
9139
+ "sourceProfileSlug": "projection",
9140
+ "targetProfileSlug": "offer",
9141
+ "type": "rests_on",
9142
+ "label": "Rests on"
9143
+ },
9144
+ {
9145
+ "sourceProfileSlug": "decision",
9146
+ "targetProfileSlug": "convention",
9147
+ "type": "rests_on",
9148
+ "label": "Rests on"
9149
+ },
9150
+ {
9151
+ "sourceProfileSlug": "decision",
9152
+ "targetProfileSlug": "projection",
9153
+ "type": "rests_on",
9154
+ "label": "Rests on"
9155
+ },
9156
+ {
9157
+ "sourceProfileSlug": "convention",
9158
+ "targetProfileSlug": "offer",
9159
+ "type": "refutes",
9160
+ "label": "Refutes"
9161
+ },
9162
+ {
9163
+ "sourceProfileSlug": "convention",
9164
+ "targetProfileSlug": "audience",
9165
+ "type": "refutes",
9166
+ "label": "Refutes"
9167
+ },
9168
+ {
9169
+ "sourceProfileSlug": "convention",
9170
+ "targetProfileSlug": "question",
9171
+ "type": "rests_on",
9172
+ "label": "Rests on"
9173
+ }
9174
+ ],
9175
+ "views": [
9176
+ {
9177
+ "name": "Conventions",
9178
+ "slug": "business-model-conventions",
9179
+ "type": "table",
9180
+ "scopeProfileSlug": "convention",
9181
+ "description": "Every rule the model must satisfy, who imposes it, and whether anyone has actually verified it.",
9182
+ "defaultView": true,
9183
+ "config": {
9184
+ "columns": [
9185
+ "title",
9186
+ "conventionType",
9187
+ "issuer",
9188
+ "bindingStatus",
9189
+ "expiresAt"
9190
+ ]
9191
+ }
9192
+ },
9193
+ {
9194
+ "name": "Unverified Conventions",
9195
+ "slug": "business-model-assumed-conventions",
9196
+ "type": "list",
9197
+ "scopeProfileSlug": "convention",
9198
+ "description": "Conventions still marked assumed or contested \u2014 the model rests on these and nobody has read the source text.",
9199
+ "config": {
9200
+ "filters": [
9201
+ {
9202
+ "field": "bindingStatus",
9203
+ "operator": "in",
9204
+ "value": [
9205
+ "assumed",
9206
+ "contested"
9207
+ ]
9208
+ }
9209
+ ]
9210
+ }
9211
+ },
9212
+ {
9213
+ "name": "Projections",
9214
+ "slug": "business-model-projections",
9215
+ "type": "table",
9216
+ "scopeProfileSlug": "projection",
9217
+ "description": "Scenarios with their assumptions in the open, so a number can be argued with.",
9218
+ "config": {
9219
+ "columns": [
9220
+ "title",
9221
+ "scenario",
9222
+ "horizon",
9223
+ "revenueEstimate",
9224
+ "costEstimate",
9225
+ "confidence"
9226
+ ]
9227
+ }
9228
+ },
9229
+ {
9230
+ "name": "Open Interrogation",
9231
+ "slug": "business-model-open-questions",
9232
+ "type": "kanban",
9233
+ "scopeProfileSlug": "question",
9234
+ "groupBy": "questionStatus",
9235
+ "description": "The nine component questions and everything they spawned, by status."
9236
+ }
9237
+ ],
9238
+ "seedEntities": [
9239
+ {
9240
+ "profileSlug": "question",
9241
+ "title": "Who is the porteur, and what does the model rest on them for?",
9242
+ "properties": {
9243
+ "questionStatus": "open"
9244
+ },
9245
+ "content": "Name the person, then name the specific competence, network, capital, or legitimacy the model cannot survive without. If the answer is generic, the model has no porteur \u2014 it has a job posting."
9246
+ },
9247
+ {
9248
+ "profileSlug": "question",
9249
+ "title": "What does the porteur's situation forbid?",
9250
+ "properties": {
9251
+ "questionStatus": "open"
9252
+ },
9253
+ "content": "Runway, hours available, geography, non-compete, dependants, health. Constraints discovered in month four were knowable in week one."
9254
+ },
9255
+ {
9256
+ "profileSlug": "question",
9257
+ "title": "What is the offer, stated as the problem it ends?",
9258
+ "properties": {
9259
+ "questionStatus": "open"
9260
+ },
9261
+ "content": "Not a description of what is built \u2014 a statement of the situation a buyer is in before, and after. If the offer can only be described by its features, the buyer has not been found yet."
9262
+ },
9263
+ {
9264
+ "profileSlug": "question",
9265
+ "title": "Who exactly buys it, and who merely benefits from it?",
9266
+ "properties": {
9267
+ "questionStatus": "open"
9268
+ },
9269
+ "content": "Link to `audience` entities. Payer, user, and beneficiary are frequently three different parties, and a model that conflates them forecasts revenue from people who never pay."
9270
+ },
9271
+ {
9272
+ "profileSlug": "question",
9273
+ "title": "Which conventions bind this model, and which are still assumed?",
9274
+ "properties": {
9275
+ "questionStatus": "open"
9276
+ },
9277
+ "content": "Eligibility thresholds, professional duties, platform policies, fiscal regimes. Every convention starts `assumed`; the work is reading the source text and moving it to `verified`. An eligibility collision \u2014 where the segment with the most pull sits outside the scheme that would fund it \u2014 only becomes visible once the numbers are pulled."
9278
+ },
9279
+ {
9280
+ "profileSlug": "question",
9281
+ "title": "What does one unit of delivery actually cost to produce?",
9282
+ "properties": {
9283
+ "questionStatus": "open"
9284
+ },
9285
+ "content": "Time, tooling, subcontracting, the unbilled parts. Link the answer to a `projection` so the assumptions stay attached to the number."
9286
+ },
9287
+ {
9288
+ "profileSlug": "question",
9289
+ "title": "Where does the money come from before revenue does?",
9290
+ "properties": {
9291
+ "questionStatus": "open"
9292
+ },
9293
+ "content": "Attach `funder` roles to the companies or schemes involved, with their eligibility conditions. Subsidy is a credential and a discount; it is rarely a pipeline."
9294
+ },
9295
+ {
9296
+ "profileSlug": "question",
9297
+ "title": "What means \u2014 people, tools, licences, premises \u2014 must exist first?",
9298
+ "properties": {
9299
+ "questionStatus": "open"
9300
+ },
9301
+ "content": "The means rest on the money and the money rests on the offer. That circularity is the model, not a planning error; record it with `rests_on` and stop trying to linearise it."
9302
+ },
9303
+ {
9304
+ "profileSlug": "question",
9305
+ "title": "What observation would refute this model, and by when?",
9306
+ "properties": {
9307
+ "questionStatus": "open"
9308
+ },
9309
+ "content": "Set the falsifiable test now, while it can still be set honestly. A model with no refuting observation is a belief with a spreadsheet attached."
9310
+ }
9311
+ ],
9312
+ "suggestedRelations": [
9313
+ {
9314
+ "sourceRef": "What is the offer, stated as the problem it ends?",
9315
+ "targetRef": "Who exactly buys it, and who merely benefits from it?",
9316
+ "type": "rests_on"
9317
+ },
9318
+ {
9319
+ "sourceRef": "What is the offer, stated as the problem it ends?",
9320
+ "targetRef": "What means \u2014 people, tools, licences, premises \u2014 must exist first?",
9321
+ "type": "rests_on"
9322
+ },
9323
+ {
9324
+ "sourceRef": "What means \u2014 people, tools, licences, premises \u2014 must exist first?",
9325
+ "targetRef": "Where does the money come from before revenue does?",
9326
+ "type": "rests_on"
9327
+ },
9328
+ {
9329
+ "sourceRef": "Where does the money come from before revenue does?",
9330
+ "targetRef": "What is the offer, stated as the problem it ends?",
9331
+ "type": "rests_on"
9332
+ },
9333
+ {
9334
+ "sourceRef": "Where does the money come from before revenue does?",
9335
+ "targetRef": "Which conventions bind this model, and which are still assumed?",
9336
+ "type": "rests_on"
9337
+ },
9338
+ {
9339
+ "sourceRef": "Who exactly buys it, and who merely benefits from it?",
9340
+ "targetRef": "Which conventions bind this model, and which are still assumed?",
9341
+ "type": "rests_on"
9342
+ },
9343
+ {
9344
+ "sourceRef": "What does one unit of delivery actually cost to produce?",
9345
+ "targetRef": "What does the porteur's situation forbid?",
9346
+ "type": "rests_on"
9347
+ },
9348
+ {
9349
+ "sourceRef": "What is the offer, stated as the problem it ends?",
9350
+ "targetRef": "Who is the porteur, and what does the model rest on them for?",
9351
+ "type": "rests_on"
9352
+ }
9353
+ ],
9354
+ "playbooks": [
9355
+ {
9356
+ "name": "Business Model Interrogation",
9357
+ "description": "Walk the nine components as questions, resolve each into a decision backed by evidence, and record the conventions and projections the model rests on \u2014 including the cycles.",
9358
+ "goalTemplate": "Interrogate the business model for {venture} and record what it rests on. Steps: (1) Walk each of the nine seeded `question` entities in this workspace; where one is already answered, mark it and move on. (2) Resolve each into a `decision`, keeping the options that lost attached via `refutes` rather than deleting them. Where the evidence itself needs gathering, do that in the Research workspace and link back \u2014 do not restate sources here. (3) Every external rule discovered becomes a `convention` with its `issuer` and `sourceReference`; leave `bindingStatus` at `assumed` until the source text has actually been read, then `verified`. (4) Every number becomes a `projection` with its `assumptions` filled in \u2014 never a bare figure. (5) Wire the graph with `rests_on` \u2014 offer on audience, projection on offer, decision on convention. Do NOT try to make the graph acyclic: if the offer rests on the means and the means rest on the money and the money rests on the offer, record all three. (6) Attach `porteur` and `funder` roles to the real people and organisations instead of creating new entities for them. (7) Close by listing which conventions are still `assumed` and which projections carry `low` confidence \u2014 that list is the actual state of the model.",
9359
+ "icon": "layout-grid"
9360
+ }
9361
+ ],
9362
+ "actionPlacements": [
9363
+ {
9364
+ "profileSlug": "question",
9365
+ "surface": "entity-detail",
9366
+ "kind": "playbook",
9367
+ "ref": "Business Model Interrogation",
9368
+ "label": "Interrogate as model component"
9369
+ },
9370
+ {
9371
+ "profileSlug": "convention",
9372
+ "surface": "entity-detail",
9373
+ "kind": "playbook",
9374
+ "ref": "Business Model Interrogation",
9375
+ "label": "Re-check what rests on this"
9376
+ }
9377
+ ],
9378
+ "integrations": [
9379
+ {
9380
+ "templateKey": "research-methods"
9381
+ },
9382
+ {
9383
+ "templateKey": "exa"
9384
+ }
9385
+ ]
9386
+ },
9387
+ "civic-france": {
9388
+ "meta": {
9389
+ "slug": "civic-france",
9390
+ "domain": "knowledge",
9391
+ "name": "France Civic Research",
9392
+ "description": "Overlay for investigating French public data (open data / Licence Ouverte). Composes onto Research. Not a government product \u2014 a private research stub.",
9393
+ "icon": "landmark",
9394
+ "color": "#1D4ED8",
9395
+ "tags": [
9396
+ "research",
9397
+ "civic",
9398
+ "france",
9399
+ "open-data",
9400
+ "licence-ouverte"
9401
+ ],
9402
+ "isPublic": false
9403
+ },
9404
+ "workspace": {
9405
+ "name": "Research",
9406
+ "description": "Adds a French civic open-data lens onto the Research substrate \u2014 track public datasets consulted during investigations.",
9407
+ "subtype": "research-base"
9408
+ },
9409
+ "dependencies": [
9410
+ {
9411
+ "slug": "research-base",
9412
+ "relation": "compose",
9413
+ "reason": "France civic research is a research method \u2014 it needs the Research substrate (question / research / source) to work over."
9414
+ }
9415
+ ],
9416
+ "profiles": [
9417
+ {
9418
+ "slug": "question",
9419
+ "displayName": "Question",
9420
+ "icon": "help-circle",
9421
+ "color": "blue",
9422
+ "description": "An open question driving a civic-data investigation.",
9423
+ "properties": [
9424
+ {
9425
+ "slug": "questionStatus",
9426
+ "label": "Status",
9427
+ "valueType": "string",
9428
+ "inputType": "select",
9429
+ "enumValues": [
9430
+ "open",
9431
+ "exploring",
9432
+ "answered",
9433
+ "abandoned"
9434
+ ],
9435
+ "constraints": {
9436
+ "defaultValue": "open"
9437
+ }
9438
+ }
9439
+ ]
9440
+ },
9441
+ {
9442
+ "slug": "research",
9443
+ "displayName": "Research",
9444
+ "icon": "microscope",
9445
+ "color": "violet",
9446
+ "description": "An investigation into French public data \u2014 sources, findings, conclusion.",
9447
+ "properties": [
9448
+ {
9449
+ "slug": "researchStatus",
9450
+ "label": "Status",
9451
+ "valueType": "string",
9452
+ "inputType": "select",
9453
+ "enumValues": [
9454
+ "ongoing",
9455
+ "concluded",
9456
+ "abandoned"
9457
+ ],
9458
+ "constraints": {
9459
+ "defaultValue": "ongoing"
9460
+ }
9461
+ }
9462
+ ]
9463
+ },
9464
+ {
9465
+ "slug": "source",
9466
+ "displayName": "Source",
9467
+ "icon": "file-text",
9468
+ "color": "cyan",
9469
+ "description": "Anything consulted \u2014 API payload, dataset page, decree, report.",
9470
+ "properties": [
9471
+ {
9472
+ "slug": "url",
9473
+ "label": "URL",
9474
+ "valueType": "string",
9475
+ "inputType": "url"
9476
+ }
9477
+ ]
9478
+ },
9479
+ {
9480
+ "slug": "public_dataset",
9481
+ "displayName": "Public dataset",
9482
+ "icon": "database",
9483
+ "color": "blue",
9484
+ "description": "A French public dataset consulted via official open-data APIs (data.gouv.fr / api.gouv.fr / PISTE) \u2014 never scraped HTML.",
9485
+ "scope": "WORKSPACE",
9486
+ "properties": [
9487
+ {
9488
+ "slug": "sourceUrl",
9489
+ "label": "Source URL",
9490
+ "valueType": "string",
9491
+ "inputType": "url"
9492
+ },
9493
+ {
9494
+ "slug": "license",
9495
+ "label": "License",
9496
+ "valueType": "string",
9497
+ "inputType": "text"
9498
+ },
9499
+ {
9500
+ "slug": "publisher",
9501
+ "label": "Publisher",
9502
+ "valueType": "string",
9503
+ "inputType": "text"
9504
+ }
9505
+ ]
9506
+ }
9507
+ ],
9508
+ "views": [
9509
+ {
9510
+ "name": "Public datasets",
9511
+ "slug": "civic-france-public-datasets",
9512
+ "type": "table",
9513
+ "scopeProfileSlug": "public_dataset",
9514
+ "description": "French public datasets tracked in this research workspace.",
9515
+ "config": {
9516
+ "columns": [
9517
+ "title",
9518
+ "publisher",
9519
+ "license",
9520
+ "sourceUrl"
9521
+ ]
9522
+ }
9523
+ }
9524
+ ]
9525
+ },
8775
9526
  "communication": {
8776
9527
  "meta": {
8777
9528
  "slug": "communication",
@@ -15932,6 +16683,95 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
15932
16683
  "inputType": "textarea"
15933
16684
  }
15934
16685
  ]
16686
+ },
16687
+ {
16688
+ "slug": "porteur",
16689
+ "displayName": "Porteur",
16690
+ "icon": "user-check",
16691
+ "color": "amber",
16692
+ "description": "The person carrying a venture \u2014 the one whose commitment, skills, and constraints the model actually rests on. Distinct from `client` (who pays) and `partner` (who collaborates).",
16693
+ "scope": "shared",
16694
+ "profileKind": "role",
16695
+ "applicableKinds": [
16696
+ "person"
16697
+ ],
16698
+ "properties": [
16699
+ {
16700
+ "slug": "brings",
16701
+ "label": "What They Bring",
16702
+ "valueType": "string",
16703
+ "inputType": "textarea",
16704
+ "description": "The specific competence, network, capital, or legitimacy this person contributes that the model depends on."
16705
+ },
16706
+ {
16707
+ "slug": "commitmentLevel",
16708
+ "label": "Commitment",
16709
+ "valueType": "string",
16710
+ "inputType": "select",
16711
+ "enumValues": [
16712
+ "full-time",
16713
+ "part-time",
16714
+ "advisory",
16715
+ "intermittent"
16716
+ ]
16717
+ },
16718
+ {
16719
+ "slug": "constraints",
16720
+ "label": "Constraints",
16721
+ "valueType": "string",
16722
+ "inputType": "textarea",
16723
+ "description": "What limits this porteur \u2014 time, cash runway, geography, non-compete, family. A model that ignores these is fiction."
16724
+ }
16725
+ ]
16726
+ },
16727
+ {
16728
+ "slug": "funder",
16729
+ "displayName": "Funder",
16730
+ "icon": "banknote",
16731
+ "color": "green",
16732
+ "description": "A source of non-revenue money or subsidy \u2014 a bank, a public scheme, an investor, a grantor. A hat worn by a company or a person, never a kind of its own.",
16733
+ "scope": "shared",
16734
+ "profileKind": "role",
16735
+ "applicableKinds": [
16736
+ "company",
16737
+ "person"
16738
+ ],
16739
+ "properties": [
16740
+ {
16741
+ "slug": "fundingType",
16742
+ "label": "Funding Type",
16743
+ "valueType": "string",
16744
+ "inputType": "select",
16745
+ "enumValues": [
16746
+ "grant",
16747
+ "subsidy",
16748
+ "loan",
16749
+ "equity",
16750
+ "guarantee",
16751
+ "prize",
16752
+ "other"
16753
+ ]
16754
+ },
16755
+ {
16756
+ "slug": "amountCommitted",
16757
+ "label": "Amount Committed",
16758
+ "valueType": "number",
16759
+ "inputType": "number"
16760
+ },
16761
+ {
16762
+ "slug": "eligibilityConditions",
16763
+ "label": "Eligibility Conditions",
16764
+ "valueType": "string",
16765
+ "inputType": "textarea",
16766
+ "description": "The conditions the venture must satisfy to keep this money. These are the constraints most often discovered too late."
16767
+ },
16768
+ {
16769
+ "slug": "decisionDate",
16770
+ "label": "Decision Date",
16771
+ "valueType": "date",
16772
+ "inputType": "date"
16773
+ }
16774
+ ]
15935
16775
  }
15936
16776
  ],
15937
16777
  "views": [
@@ -16222,6 +17062,12 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
16222
17062
  "kind": "workspace",
16223
17063
  "relation": "require",
16224
17064
  "reason": "Provides the pod-wide client / partner / sponsor role vocabulary this workspace reuses."
17065
+ },
17066
+ {
17067
+ "slug": "blockchain-ecosystem",
17068
+ "kind": "workspace",
17069
+ "relation": "require",
17070
+ "reason": "Provides the pod-wide grant-program kind (per-chain funding programs) this workspace's rounds belong to."
16225
17071
  }
16226
17072
  ],
16227
17073
  "workspace": {
@@ -17381,12 +18227,21 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
17381
18227
  "sortDir": "desc"
17382
18228
  }
17383
18229
  },
18230
+ {
18231
+ "name": "Deadlines",
18232
+ "type": "calendar",
18233
+ "scopeProfileSlug": "round",
18234
+ "description": "Upcoming round submission deadlines, on one time axis.",
18235
+ "config": {
18236
+ "dateField": "properties.submissionDeadline",
18237
+ "colorField": "status"
18238
+ }
18239
+ },
17384
18240
  {
17385
18241
  "name": "Awarded Projects",
17386
18242
  "type": "gallery",
17387
18243
  "scopeProfileSlug": "grant-project",
17388
18244
  "config": {
17389
- "coverField": "summary",
17390
18245
  "showFields": [
17391
18246
  "currentStatus",
17392
18247
  "awardedRoundCount",
@@ -17430,6 +18285,30 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
17430
18285
  "type": "submitted_by",
17431
18286
  "label": "Submitted By"
17432
18287
  },
18288
+ {
18289
+ "sourceProfileSlug": "grant_submission",
18290
+ "targetProfileSlug": "contract",
18291
+ "type": "for_contract",
18292
+ "label": "Engagement"
18293
+ },
18294
+ {
18295
+ "sourceProfileSlug": "grant_submission",
18296
+ "targetProfileSlug": "deal",
18297
+ "type": "billed_as",
18298
+ "label": "Billed as"
18299
+ },
18300
+ {
18301
+ "sourceProfileSlug": "round",
18302
+ "targetProfileSlug": "grant-program",
18303
+ "type": "belongs_to",
18304
+ "label": "Program"
18305
+ },
18306
+ {
18307
+ "sourceProfileSlug": "contract",
18308
+ "targetProfileSlug": "grant-program",
18309
+ "type": "pursues",
18310
+ "label": "Pursues"
18311
+ },
17433
18312
  {
17434
18313
  "sourceProfileSlug": "grant-project",
17435
18314
  "targetProfileSlug": "round",
@@ -17455,6 +18334,227 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
17455
18334
  "label": "Evidenced By"
17456
18335
  }
17457
18336
  ],
18337
+ "playbooks": [
18338
+ {
18339
+ "name": "Grant Process",
18340
+ "description": "Run an engagement through a grant program end to end \u2014 identify fit, draft the application, submit, track the decision, and deliver the tranches. Reads the program's own cadence / tracks / tranche model so one playbook fits every chain.",
18341
+ "goalTemplate": "Advance this engagement ({contract}) through the grant program ({grantProgram}) it is pursuing. FIRST read the program entity's own data \u2014 its cadence, submissionTracks, trancheModel, and nextDeadline \u2014 plus the client context on the contract, and let THOSE drive the plan: do not assume a chain's mechanics, read them from the program. Then work the stages in order and keep the client's `grant_submission` card as the durable state of record:\n1. Identify \u2014 understand the project and which of the program's\n submissionTracks fit; set the submission `stage` to `scope`.\n2. Draft \u2014 write the abstract, then the full proposal (products & services,\n success criteria, GTM, traction); move `stage` `abstract` \u2192 `build` and\n fill the submission's body fields.\n3. Submit \u2014 finalize against the program's nextDeadline and submit; once\n submitted, set `stage` to `awaiting-results`.\n4. Awaiting \u2014 track the decision and keep `status` current\n (in-review / waiting-client / needs-document / blocked).\n5. Awarded \u2014 on a decision, set `outcome` (awarded / rejected / partial)\n and record the awarded amount.\n6. Delivering \u2014 for an award, work the program's trancheModel: fill the\n tranche deliverables and update trancheCompletion as each milestone ships.\n\nNever fabricate \u2014 leave a field blank rather than guess. Every write is proposal-gated for the user to review.",
18342
+ "subjectProfile": {
18343
+ "profileSlug": "contract"
18344
+ },
18345
+ "params": [
18346
+ {
18347
+ "name": "contract",
18348
+ "type": "entity",
18349
+ "profileSlug": "contract",
18350
+ "label": "Engagement",
18351
+ "required": true
18352
+ },
18353
+ {
18354
+ "name": "grantProgram",
18355
+ "type": "entity",
18356
+ "profileSlug": "grant-program",
18357
+ "label": "Grant Program",
18358
+ "required": true
18359
+ }
18360
+ ],
18361
+ "scope": "project",
18362
+ "stages": [
18363
+ {
18364
+ "key": "identify",
18365
+ "name": "Identify",
18366
+ "category": "planned",
18367
+ "description": "Understand the project and which of the program's submission tracks fit \u2014 before any writing.",
18368
+ "goal": "A clear project understanding and the fitting submission track; submission stage = scope."
18369
+ },
18370
+ {
18371
+ "key": "draft",
18372
+ "name": "Draft",
18373
+ "category": "started",
18374
+ "description": "Write the abstract, then the full proposal, from the client's real material.",
18375
+ "goal": "Abstract then full proposal drafted; submission stage abstract \u2192 build with body fields filled."
18376
+ },
18377
+ {
18378
+ "key": "submit",
18379
+ "name": "Submit",
18380
+ "category": "started",
18381
+ "description": "Finalize against the program deadline and submit the application.",
18382
+ "goal": "Application submitted on time; submission stage = awaiting-results."
18383
+ },
18384
+ {
18385
+ "key": "awaiting",
18386
+ "name": "Awaiting",
18387
+ "category": "paused",
18388
+ "description": "Track the decision and keep the client status current.",
18389
+ "goal": "Submission status reflects where the decision stands (in-review / waiting-client / needs-document / blocked)."
18390
+ },
18391
+ {
18392
+ "key": "awarded",
18393
+ "name": "Awarded",
18394
+ "category": "started",
18395
+ "description": "Record the funder's decision and the awarded amount.",
18396
+ "goal": "Submission outcome set (awarded / rejected / partial) with the awarded amount."
18397
+ },
18398
+ {
18399
+ "key": "delivering",
18400
+ "name": "Delivering",
18401
+ "category": "started",
18402
+ "description": "Work the program's tranche model \u2014 ship and record each tranche.",
18403
+ "goal": "Tranche deliverables filled and trancheCompletion updated as milestones ship."
18404
+ }
18405
+ ],
18406
+ "executor": "is-agent",
18407
+ "grants": [
18408
+ "entity.create"
18409
+ ],
18410
+ "status": "active"
18411
+ }
18412
+ ],
18413
+ "automations": [
18414
+ {
18415
+ "key": "grant-submission-sync",
18416
+ "name": "Grant Submission Sync",
18417
+ "description": "Once a day, keep each grant application's grant_submission card current \u2014 read the submission's recent activity, assess where the pursuit stands, and advance its stage + status so the pipeline stays the durable, kanban-visible state of record.",
18418
+ "triggerType": "cron",
18419
+ "triggerConfig": {
18420
+ "expression": "0 8 * * *"
18421
+ },
18422
+ "status": "draft",
18423
+ "metadata": {
18424
+ "templateKey": "grant-submission-sync"
18425
+ },
18426
+ "flow": {
18427
+ "nodes": [
18428
+ {
18429
+ "id": "trigger",
18430
+ "type": "trigger",
18431
+ "position": {
18432
+ "x": 0,
18433
+ "y": 0
18434
+ },
18435
+ "data": {
18436
+ "label": "Daily at 08:00",
18437
+ "triggerType": "cron",
18438
+ "config": {
18439
+ "expression": "0 8 * * *"
18440
+ }
18441
+ }
18442
+ },
18443
+ {
18444
+ "id": "list-submissions",
18445
+ "type": "capability",
18446
+ "position": {
18447
+ "x": 0,
18448
+ "y": 120
18449
+ },
18450
+ "data": {
18451
+ "label": "List grant submissions to maintain",
18452
+ "verbId": "entity.query",
18453
+ "inputMapping": {
18454
+ "profileSlug": "grant_submission",
18455
+ "limit": "100"
18456
+ }
18457
+ }
18458
+ },
18459
+ {
18460
+ "id": "submissions-loop",
18461
+ "type": "loop",
18462
+ "position": {
18463
+ "x": 0,
18464
+ "y": 240
18465
+ },
18466
+ "data": {
18467
+ "label": "For each grant submission",
18468
+ "iteratorExpression": "steps.list-submissions.output.entities",
18469
+ "itemVariable": "submission"
18470
+ }
18471
+ },
18472
+ {
18473
+ "id": "read-activity",
18474
+ "type": "messages_query",
18475
+ "position": {
18476
+ "x": 0,
18477
+ "y": 360
18478
+ },
18479
+ "data": {
18480
+ "label": "Read the submission's recent activity",
18481
+ "subjectEntityId": "{{loop.item.id}}",
18482
+ "limit": 40
18483
+ }
18484
+ },
18485
+ {
18486
+ "id": "assess",
18487
+ "type": "capability",
18488
+ "position": {
18489
+ "x": 0,
18490
+ "y": 480
18491
+ },
18492
+ "data": {
18493
+ "label": "Assess the submission's stage + status \u2192 JSON",
18494
+ "verbId": "ai.generate",
18495
+ "inputMapping": {
18496
+ "json": "true",
18497
+ "maxTokens": "500",
18498
+ "system": "You are a strict data-extraction function for a grants pipeline. Read a grant application's recent activity and report where the application currently stands. Respond with STRICT JSON and NOTHING else. Never fabricate \u2014 if the activity does not clearly indicate a value, keep the submission's current one.",
18499
+ "prompt": `The grant submission: {{loop.item.title}} Current stage: {{loop.item.properties.stage}} Current status: {{loop.item.properties.status}}
18500
+ Recent activity (oldest first): {{steps.read-activity.output.messages}}
18501
+ Report the submission's current state as STRICT JSON, using ONLY these vocabularies and NOTHING else: {
18502
+ "stage": "scope|abstract|build|awaiting-results",
18503
+ "status": "answered|waiting-client|needs-document|in-review|blocked"
18504
+ }`
18505
+ }
18506
+ }
18507
+ },
18508
+ {
18509
+ "id": "advance-submission",
18510
+ "type": "output",
18511
+ "position": {
18512
+ "x": 0,
18513
+ "y": 600
18514
+ },
18515
+ "data": {
18516
+ "label": "Advance the submission stage + status",
18517
+ "outputType": "entity_update",
18518
+ "config": {
18519
+ "entityId": "{{loop.item.id}}",
18520
+ "properties": {
18521
+ "stage": "{{steps.assess.output.stage}}",
18522
+ "status": "{{steps.assess.output.status}}"
18523
+ }
18524
+ }
18525
+ }
18526
+ }
18527
+ ],
18528
+ "edges": [
18529
+ {
18530
+ "id": "gs-trigger-list",
18531
+ "source": "trigger",
18532
+ "target": "list-submissions"
18533
+ },
18534
+ {
18535
+ "id": "gs-list-loop",
18536
+ "source": "list-submissions",
18537
+ "target": "submissions-loop"
18538
+ },
18539
+ {
18540
+ "id": "gs-loop-read",
18541
+ "source": "submissions-loop",
18542
+ "target": "read-activity"
18543
+ },
18544
+ {
18545
+ "id": "gs-read-assess",
18546
+ "source": "read-activity",
18547
+ "target": "assess"
18548
+ },
18549
+ {
18550
+ "id": "gs-assess-advance",
18551
+ "source": "assess",
18552
+ "target": "advance-submission"
18553
+ }
18554
+ ]
18555
+ }
18556
+ }
18557
+ ],
17458
18558
  "app": {
17459
18559
  "kind": "stored",
17460
18560
  "cellKey": "entity-detail"
@@ -21332,6 +22432,19 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
21332
22432
  }
21333
22433
  ],
21334
22434
  "views": [
22435
+ {
22436
+ "name": "Knowledge",
22437
+ "slug": "knowledge",
22438
+ "type": "table",
22439
+ "scopeProfileSlug": "knowledge",
22440
+ "description": "Validated insights and cautions, with their long-form context and evidence kept in the graph.",
22441
+ "config": {
22442
+ "columns": [
22443
+ "title",
22444
+ "knowledgeForm"
22445
+ ]
22446
+ }
22447
+ },
21335
22448
  {
21336
22449
  "name": "All Notes",
21337
22450
  "type": "table",
@@ -22170,6 +23283,12 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
22170
23283
  "label": "Brain Home",
22171
23284
  "icon": "Home"
22172
23285
  },
23286
+ {
23287
+ "kind": "profile",
23288
+ "profileSlug": "knowledge",
23289
+ "label": "Knowledge",
23290
+ "icon": "Brain"
23291
+ },
22173
23292
  {
22174
23293
  "kind": "profile",
22175
23294
  "profileSlug": "note",
@@ -24136,6 +25255,7 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
24136
25255
  "description": "A company or person that provides a capability The Arch can broker a client need against.",
24137
25256
  "scope": "shared",
24138
25257
  "profileKind": "role",
25258
+ "roleCategory": "provider",
24139
25259
  "applicableKinds": [
24140
25260
  "company",
24141
25261
  "person"
@@ -24315,10 +25435,10 @@ document. No preamble, no explanation, no code fences around the whole thing.`,
24315
25435
  "y": 240
24316
25436
  },
24317
25437
  "data": {
24318
- "label": "List the solution-provider roster",
25438
+ "label": "List the provider roster (any roleCategory=provider)",
24319
25439
  "verbId": "entity.query",
24320
25440
  "inputMapping": {
24321
- "profileSlug": "solution-provider",
25441
+ "roleCategory": "provider",
24322
25442
  "limit": "100"
24323
25443
  }
24324
25444
  }
@@ -29860,6 +30980,12 @@ counter-evidence: research that only kept what agreed with it isn't research.
29860
30980
  "kind": "workspace",
29861
30981
  "relation": "require",
29862
30982
  "reason": "The engineering / ops dashboard \u2014 the build-side view of the company."
30983
+ },
30984
+ {
30985
+ "slug": "networking",
30986
+ "kind": "workspace",
30987
+ "relation": "require",
30988
+ "reason": "The partner-intro layer \u2014 need \u2192 intro-matcher \u2192 intro \u2192 billed_as \u2192 deal, with the A\u2194B confidentiality firewall; the Stellar Client-Sync emits needs that depend on it."
29863
30989
  }
29864
30990
  ],
29865
30991
  "workspace": {
@@ -30077,7 +31203,9 @@ function rowToRemoteEntry(row, isPrivate) {
30077
31203
  domain: row.domain ?? void 0,
30078
31204
  tags: row.tags ?? [],
30079
31205
  icon: row.icon ?? null,
30080
- isPrivate
31206
+ isPrivate,
31207
+ requiredTier: row.requiredTier ?? null,
31208
+ items: row.items
30081
31209
  // Both list routes strip `definition`; absence ⇒ bundle wins a slug conflict,
30082
31210
  // and the install path fetches the full definition per-slug when needed.
30083
31211
  };
@@ -30113,6 +31241,10 @@ function bundledToEntry(tpl) {
30113
31241
  tags: tpl.meta.tags ?? [],
30114
31242
  icon: tpl.meta.icon,
30115
31243
  isPrivate: tpl.meta.isPublic === false,
31244
+ // Bundled templates ship in-client and are never tier-gated.
31245
+ requiredTier: null,
31246
+ // Bundled workspace templates carry no cells — be honest, not `undefined`.
31247
+ items: [],
30116
31248
  template: tpl
30117
31249
  };
30118
31250
  }
@@ -30127,6 +31259,8 @@ function remoteToEntry(row) {
30127
31259
  tags: row.tags ?? [],
30128
31260
  icon: row.icon ?? null,
30129
31261
  isPrivate: row.isPrivate ?? false,
31262
+ requiredTier: row.requiredTier ?? null,
31263
+ items: row.items ?? [],
30130
31264
  remote: row
30131
31265
  };
30132
31266
  }
@@ -30862,7 +31996,10 @@ function collectLoopBindingRefs(data) {
30862
31996
  return;
30863
31997
  }
30864
31998
  if (isRecord(v)) {
30865
- for (const x of Object.values(v)) walk(x);
31999
+ for (const [k, x] of Object.entries(v)) {
32000
+ if (k.startsWith("_")) continue;
32001
+ walk(x);
32002
+ }
30866
32003
  }
30867
32004
  };
30868
32005
  walk(data);
@@ -30945,6 +32082,9 @@ var SYSTEM_PROFILES = /* @__PURE__ */ new Set([
30945
32082
  // `create-report` node references it, so referential integrity needs it here.
30946
32083
  "report"
30947
32084
  ]);
32085
+ var TEMPLATE_FORBIDDEN_SYSTEM_PROFILE_SLUGS = /* @__PURE__ */ new Set(["knowledge"]);
32086
+ var KNOWLEDGE_FORMS = /* @__PURE__ */ new Set(["insight", "caution"]);
32087
+ var LEGACY_KNOWLEDGE_SEED_FIELDS = /* @__PURE__ */ new Set(["ek_type", "type"]);
30948
32088
  function isPodWideProfile(p) {
30949
32089
  return String(p.scope || "").toLowerCase() === "shared";
30950
32090
  }
@@ -31088,6 +32228,14 @@ function validateTemplate(tpl, opts = {}) {
31088
32228
  const baseProfileSlugs = collectBaseProfileSlugs(tpl, resolveDepFrom(opts));
31089
32229
  const slugs = new Set((tpl.profiles || []).map((p) => p.slug));
31090
32230
  const known = (s) => slugs.has(s) || SYSTEM_PROFILES.has(s) || baseProfileSlugs.has(s);
32231
+ for (const profile of tpl.profiles || []) {
32232
+ if (!TEMPLATE_FORBIDDEN_SYSTEM_PROFILE_SLUGS.has(profile.slug)) continue;
32233
+ add(
32234
+ "system-profile-redefined",
32235
+ `profiles.${profile.slug}`,
32236
+ `Profile "${profile.slug}" is system-owned. Reference it from views, links, sidebar items, or seedEntities; do not declare template-owned properties or metadata.`
32237
+ );
32238
+ }
31091
32239
  for (const v of tpl.views || []) {
31092
32240
  const type = String(v.type || "").toLowerCase();
31093
32241
  const scoped = v.scopeProfileSlug || v.scopeProfileSlugs && v.scopeProfileSlugs.length;
@@ -31237,6 +32385,24 @@ function validateTemplate(tpl, opts = {}) {
31237
32385
  "seedEntities",
31238
32386
  `seedEntity references unknown profile "${s.profileSlug}"`
31239
32387
  );
32388
+ if (s.profileSlug !== "knowledge") continue;
32389
+ const properties = s.properties ?? {};
32390
+ for (const field of LEGACY_KNOWLEDGE_SEED_FIELDS) {
32391
+ if (!(field in properties)) continue;
32392
+ add(
32393
+ "knowledge-seed-legacy-form",
32394
+ `seedEntities.${s.title}.properties.${field}`,
32395
+ `Knowledge seed entities use "knowledgeForm" ("insight" | "caution"), not the legacy "${field}" field.`
32396
+ );
32397
+ }
32398
+ const form = properties.knowledgeForm;
32399
+ if (!KNOWLEDGE_FORMS.has(String(form))) {
32400
+ add(
32401
+ "knowledge-seed-form-invalid",
32402
+ `seedEntities.${s.title}.properties.knowledgeForm`,
32403
+ `Knowledge seed entities require knowledgeForm to be "insight" or "caution".`
32404
+ );
32405
+ }
31240
32406
  }
31241
32407
  for (const a of tpl.automations || []) {
31242
32408
  const refs = [];