naive-framework 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/AGENTS.md +2 -1
  2. package/docs/decisions/decisions.json +27 -0
  3. package/docs/reference/ROUTES.md +36 -37
  4. package/governance/layer.json +2 -1
  5. package/governance/venture-template/roles/venture-roles.json +62 -0
  6. package/interface/acting.mjs +83 -0
  7. package/interface/adapters/claude-code.json +16 -0
  8. package/interface/adapters/codex.json +14 -0
  9. package/interface/adapters/cursor.json +16 -0
  10. package/interface/adapters.mjs +182 -0
  11. package/interface/api/server.mjs +4 -2
  12. package/interface/boundaries.mjs +218 -0
  13. package/interface/brand.mjs +214 -0
  14. package/interface/cli/freshness.mjs +59 -0
  15. package/interface/cli/guard.mjs +6 -0
  16. package/interface/cli/mentura.mjs +78 -8
  17. package/interface/cli/naive.mjs +33 -8
  18. package/interface/context.mjs +524 -0
  19. package/interface/demo/board.mjs +1 -1
  20. package/interface/dev/setup.mjs +84 -0
  21. package/interface/gate-hooks.mjs +36 -0
  22. package/interface/harness/evals.mjs +3 -3
  23. package/interface/harness/run.mjs +4 -4
  24. package/interface/instrumentation.mjs +86 -0
  25. package/interface/kit-boundary.mjs +73 -0
  26. package/interface/layer.json +8 -2
  27. package/interface/mcp/server.mjs +47 -7
  28. package/interface/package-routes.mjs +196 -0
  29. package/interface/provenance.mjs +24 -1
  30. package/interface/reads.mjs +173 -0
  31. package/interface/release-card.mjs +42 -0
  32. package/interface/router.mjs +101 -28
  33. package/interface/skills/naive-setup/SKILL.md +71 -0
  34. package/interface/skills/naive-setup/artifact.html +83 -0
  35. package/interface/vitals.mjs +115 -0
  36. package/interface/writes.mjs +190 -0
  37. package/knowledge/freshness.json +85 -0
  38. package/knowledge/layer.json +11 -3
  39. package/knowledge/templates/glossary.md +23 -0
  40. package/operations/layer.json +10 -3
  41. package/operations/templates/marketing-brand.md +46 -0
  42. package/operations/templates/public-assets.md +39 -0
  43. package/package.json +3 -1
  44. package/packages/catalog.json +8 -0
  45. package/packages/customers/package.json +21 -1
  46. package/packages/deals/package.json +27 -0
  47. package/packages/decisions/package.json +12 -1
  48. package/packages/finance/frames/fund-without-ceding-control.frame.json +177 -0
  49. package/packages/foundation/package.json +8 -1
  50. package/packages/fund/package.json +48 -0
  51. package/packages/marketing/package.json +10 -4
  52. package/packages/money/package.json +24 -3
  53. package/packages/validation/package.json +13 -0
  54. package/platform/README.md +6 -0
  55. package/platform/adapter.json +15 -0
  56. package/platform/integrations/remote-image.mjs +79 -0
  57. package/platform/integrations/rho.mjs +7 -6
  58. package/platform/kits/README.md +8 -1
  59. package/platform/kits/agent-upgrade/kit.json +15 -0
  60. package/platform/kits/agent-upgrade/run.mjs +82 -0
  61. package/platform/kits/agent-upgrade/stand-in-agent.mjs +32 -0
  62. package/platform/kits/validation-kickoff/kit.json +29 -0
  63. package/platform/webhooks/server.mjs +70 -0
  64. package/purpose/frameworks/idea-map/ideamap.mjs +4 -2
  65. package/schema/README.md +1 -0
  66. package/schema/access.mjs +57 -0
  67. package/schema/adapter.schema.json +33 -0
  68. package/schema/assets.mjs +212 -0
  69. package/schema/brand.mjs +373 -0
  70. package/schema/build-release.mjs +61 -0
  71. package/schema/caching.mjs +505 -0
  72. package/schema/check-assets.mjs +24 -0
  73. package/schema/check-brand.mjs +24 -0
  74. package/schema/check-config.mjs +110 -0
  75. package/schema/check-nextjs-status.mjs +3 -1
  76. package/schema/check-people.mjs +70 -0
  77. package/schema/check-sources.mjs +9 -1
  78. package/schema/data-model.json +334 -8
  79. package/schema/deal.schema.json +80 -0
  80. package/schema/decisions.mjs +7 -1
  81. package/schema/examples/frames/judge.mjs +10 -0
  82. package/schema/examples/venture-type/jev.mjs +12 -0
  83. package/schema/examples/workspace/ventures/acme-labs/AGENTS.md +17 -0
  84. package/schema/examples/workspace/ventures/acme-labs/accounts/.gitkeep +0 -0
  85. package/schema/examples/workspace/ventures/acme-labs/decisions/discovery-goal.decision.json +23 -0
  86. package/schema/examples/workspace/ventures/acme-labs/decisions/statement-icp.decision.json +22 -0
  87. package/schema/examples/workspace/ventures/acme-labs/decisions/statement-problem.decision.json +22 -0
  88. package/schema/examples/workspace/ventures/acme-labs/decisions/venture.team.decision.json +37 -0
  89. package/schema/examples/workspace/ventures/acme-labs/knowledge/README.md +3 -0
  90. package/schema/examples/workspace/ventures/acme-labs/knowledge/sources.json +46 -0
  91. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000001.json +12 -0
  92. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000002.json +12 -0
  93. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000003.json +12 -0
  94. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000004.json +12 -0
  95. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000005.json +12 -0
  96. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000006.json +12 -0
  97. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000007.json +12 -0
  98. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000008.json +12 -0
  99. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000009.json +12 -0
  100. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000010.json +12 -0
  101. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000011.json +12 -0
  102. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000012.json +12 -0
  103. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000013.json +12 -0
  104. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000014.json +12 -0
  105. package/schema/examples/workspace/ventures/acme-labs/money/_streams/transactions/stream.json +5 -0
  106. package/schema/examples/workspace/ventures/acme-labs/money/_summary.json +30 -0
  107. package/schema/examples/workspace/ventures/acme-labs/operations/departments/customer-service/README.md +5 -0
  108. package/schema/examples/workspace/ventures/acme-labs/operations/departments/customer-service/department.json +5 -0
  109. package/schema/examples/workspace/ventures/acme-labs/operations/departments/finance/README.md +5 -0
  110. package/schema/examples/workspace/ventures/acme-labs/operations/departments/finance/department.json +5 -0
  111. package/schema/examples/workspace/ventures/acme-labs/operations/departments/human-capital/README.md +5 -0
  112. package/schema/examples/workspace/ventures/acme-labs/operations/departments/human-capital/department.json +5 -0
  113. package/schema/examples/workspace/ventures/acme-labs/operations/departments/it/README.md +5 -0
  114. package/schema/examples/workspace/ventures/acme-labs/operations/departments/it/department.json +5 -0
  115. package/schema/examples/workspace/ventures/acme-labs/operations/departments/marketing-and-sales/README.md +5 -0
  116. package/schema/examples/workspace/ventures/acme-labs/operations/departments/marketing-and-sales/department.json +5 -0
  117. package/schema/examples/workspace/ventures/acme-labs/operations/departments/products/README.md +5 -0
  118. package/schema/examples/workspace/ventures/acme-labs/operations/departments/products/department.json +5 -0
  119. package/schema/examples/workspace/ventures/acme-labs/operations/departments/strategy/README.md +5 -0
  120. package/schema/examples/workspace/ventures/acme-labs/operations/departments/strategy/department.json +5 -0
  121. package/schema/examples/workspace/ventures/acme-labs/people/founders/maya-chen.json +15 -0
  122. package/schema/examples/workspace/ventures/acme-labs/people/people.json +22 -0
  123. package/schema/examples/workspace/ventures/acme-labs/pillars/brand.md +5 -0
  124. package/schema/examples/workspace/ventures/acme-labs/pillars/business.md +5 -0
  125. package/schema/examples/workspace/ventures/acme-labs/pillars/product.md +5 -0
  126. package/schema/examples/workspace/ventures/acme-labs/products/.gitkeep +0 -0
  127. package/schema/examples/workspace/ventures/acme-labs/products/decisions/product.core-product.decision.json +28 -0
  128. package/schema/examples/workspace/ventures/acme-labs/products/decisions/product.exists.decision.json +38 -0
  129. package/schema/examples/workspace/ventures/acme-labs/products/decisions/product.flagship.decision.json +27 -0
  130. package/schema/examples/workspace/ventures/acme-labs/profile.md +12 -0
  131. package/schema/examples/workspace/ventures/acme-labs/provenance.jsonl +12 -0
  132. package/schema/examples/workspace/ventures/acme-labs/raw/dump.md +6 -0
  133. package/schema/examples/workspace/ventures/acme-labs/venture.json +27 -0
  134. package/schema/examples/workspace/ventures/northstar/AGENTS.md +17 -0
  135. package/schema/examples/workspace/ventures/northstar/accounts/.gitkeep +0 -0
  136. package/schema/examples/workspace/ventures/northstar/deals/ductline.json +8 -0
  137. package/schema/examples/workspace/ventures/northstar/deals/kilnworks.json +14 -0
  138. package/schema/examples/workspace/ventures/northstar/decisions/venture.team.decision.json +31 -0
  139. package/schema/examples/workspace/ventures/northstar/evidence/README.md +3 -0
  140. package/schema/examples/workspace/ventures/northstar/fund/decisions/terms.decision.json +27 -0
  141. package/schema/examples/workspace/ventures/northstar/fund/decisions/terms.first-close.decision.json +27 -0
  142. package/schema/examples/workspace/ventures/northstar/fund/decisions/thesis.decision.json +26 -0
  143. package/schema/examples/workspace/ventures/northstar/fund/terms.json +22 -0
  144. package/schema/examples/workspace/ventures/northstar/fund/thesis.json +22 -0
  145. package/schema/examples/workspace/ventures/northstar/governance/README.md +3 -0
  146. package/schema/examples/workspace/ventures/northstar/governance/departments/external-relationships/charter.md +5 -0
  147. package/schema/examples/workspace/ventures/northstar/governance/departments/external-relationships/department.json +5 -0
  148. package/schema/examples/workspace/ventures/northstar/governance/departments/finance/charter.md +5 -0
  149. package/schema/examples/workspace/ventures/northstar/governance/departments/finance/department.json +5 -0
  150. package/schema/examples/workspace/ventures/northstar/governance/departments/human-capital/charter.md +5 -0
  151. package/schema/examples/workspace/ventures/northstar/governance/departments/human-capital/department.json +5 -0
  152. package/schema/examples/workspace/ventures/northstar/governance/departments/risk-and-compliance/charter.md +5 -0
  153. package/schema/examples/workspace/ventures/northstar/governance/departments/risk-and-compliance/department.json +5 -0
  154. package/schema/examples/workspace/ventures/northstar/governance/departments/strategy/charter.md +5 -0
  155. package/schema/examples/workspace/ventures/northstar/governance/departments/strategy/department.json +5 -0
  156. package/schema/examples/workspace/ventures/northstar/knowledge/README.md +3 -0
  157. package/schema/examples/workspace/ventures/northstar/operations/README.md +3 -0
  158. package/schema/examples/workspace/ventures/northstar/operations/departments/external-relationships/README.md +5 -0
  159. package/schema/examples/workspace/ventures/northstar/operations/departments/external-relationships/department.json +5 -0
  160. package/schema/examples/workspace/ventures/northstar/operations/departments/finance/README.md +5 -0
  161. package/schema/examples/workspace/ventures/northstar/operations/departments/finance/department.json +5 -0
  162. package/schema/examples/workspace/ventures/northstar/operations/departments/human-capital/README.md +5 -0
  163. package/schema/examples/workspace/ventures/northstar/operations/departments/human-capital/department.json +5 -0
  164. package/schema/examples/workspace/ventures/northstar/operations/departments/risk-and-compliance/README.md +5 -0
  165. package/schema/examples/workspace/ventures/northstar/operations/departments/risk-and-compliance/department.json +5 -0
  166. package/schema/examples/workspace/ventures/northstar/operations/departments/strategy/README.md +5 -0
  167. package/schema/examples/workspace/ventures/northstar/operations/departments/strategy/department.json +5 -0
  168. package/schema/examples/workspace/ventures/northstar/people/founders/ana-ruiz.json +13 -0
  169. package/schema/examples/workspace/ventures/northstar/people/founders/ben-okafor.json +7 -0
  170. package/schema/examples/workspace/ventures/northstar/people/people.json +27 -0
  171. package/schema/examples/workspace/ventures/northstar/pillars/brand.md +5 -0
  172. package/schema/examples/workspace/ventures/northstar/pillars/business.md +5 -0
  173. package/schema/examples/workspace/ventures/northstar/pillars/product.md +5 -0
  174. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/AGENTS.md +17 -0
  175. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/accounts/.gitkeep +0 -0
  176. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/decisions/venture.team.decision.json +31 -0
  177. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/knowledge/README.md +3 -0
  178. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/customer-service/README.md +5 -0
  179. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/customer-service/department.json +5 -0
  180. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/finance/README.md +5 -0
  181. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/finance/department.json +5 -0
  182. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/human-capital/README.md +5 -0
  183. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/human-capital/department.json +5 -0
  184. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/it/README.md +5 -0
  185. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/it/department.json +5 -0
  186. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/marketing-and-sales/README.md +5 -0
  187. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/marketing-and-sales/department.json +5 -0
  188. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/products/README.md +5 -0
  189. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/products/department.json +5 -0
  190. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/strategy/README.md +5 -0
  191. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/strategy/department.json +5 -0
  192. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/pillars/brand.md +5 -0
  193. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/pillars/business.md +5 -0
  194. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/pillars/product.md +5 -0
  195. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/.gitkeep +0 -0
  196. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/decisions/product.core-product.decision.json +28 -0
  197. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/decisions/product.exists.decision.json +32 -0
  198. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/decisions/product.flagship.decision.json +27 -0
  199. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/profile.md +5 -0
  200. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/venture.json +27 -0
  201. package/schema/examples/workspace/ventures/northstar/products/.gitkeep +0 -0
  202. package/schema/examples/workspace/ventures/northstar/profile.md +5 -0
  203. package/schema/examples/workspace/ventures/northstar/provenance.jsonl +3 -0
  204. package/schema/examples/workspace/ventures/northstar/purpose/README.md +3 -0
  205. package/schema/examples/workspace/ventures/northstar/venture.json +49 -0
  206. package/schema/founder.schema.json +72 -0
  207. package/schema/frame.schema.json +240 -0
  208. package/schema/frames.mjs +228 -0
  209. package/schema/freshness-log.schema.json +40 -0
  210. package/schema/freshness-profiles.schema.json +44 -0
  211. package/schema/freshness.mjs +473 -0
  212. package/schema/fund-terms.schema.json +107 -0
  213. package/schema/fund-thesis.schema.json +87 -0
  214. package/schema/gate-drafts.mjs +130 -0
  215. package/schema/gate.mjs +105 -11
  216. package/schema/glossary.schema.json +25 -0
  217. package/schema/init-venture.mjs +38 -8
  218. package/schema/judgment.schema.json +38 -0
  219. package/schema/kit.schema.json +47 -0
  220. package/schema/kits.mjs +24 -0
  221. package/schema/knowledge-sources.schema.json +145 -15
  222. package/schema/layer.json +16 -3
  223. package/schema/marketing-brand.schema.json +116 -0
  224. package/schema/migrations/kit-to-package.mjs +94 -0
  225. package/schema/migrations/package-layout.mjs +86 -0
  226. package/schema/model-steps.mjs +717 -0
  227. package/schema/money-summary.schema.json +138 -0
  228. package/schema/naive-config.mjs +165 -0
  229. package/schema/naive-config.schema.json +268 -0
  230. package/schema/need-now.json +171 -0
  231. package/schema/need-now.mjs +3 -2
  232. package/schema/packages.mjs +10 -5
  233. package/schema/people.schema.json +86 -0
  234. package/schema/public-assets.schema.json +76 -0
  235. package/schema/release-read.mjs +111 -0
  236. package/schema/releases.mjs +497 -0
  237. package/schema/setup.mjs +164 -0
  238. package/schema/stale.mjs +111 -0
  239. package/schema/start-release.mjs +41 -0
  240. package/schema/structure.mjs +186 -0
  241. package/schema/systems-catalog.json +126 -0
  242. package/schema/systems-catalog.schema.json +78 -0
  243. package/schema/trigger.schema.json +44 -0
  244. package/schema/triggers.mjs +237 -0
  245. package/schema/upgrade-registry.schema.json +60 -0
  246. package/schema/upgrade-venture.mjs +96 -118
  247. package/schema/upgrades.json +69 -0
  248. package/schema/upgrades.mjs +385 -0
  249. package/schema/validate.py +19 -10
  250. package/schema/venture-role.schema.json +64 -0
  251. package/schema/venture-type.mjs +62 -0
  252. package/schema/venture-types.json +346 -0
  253. package/schema/venture-types.schema.json +129 -0
  254. package/schema/venture.schema.json +53 -0
@@ -0,0 +1,71 @@
1
+ ---
2
+ type: knowledge
3
+ tags: [everything-ecosystem, naive, skills, interface, setup, artifacts, docket]
4
+ ai-model: claude-opus-5.5
5
+ created: 2026-10-29T06:30:00Z
6
+ source: hybrid
7
+ name: naive-setup
8
+ description: >
9
+ Walk a founder through setting up a new Naive venture inside the model's own
10
+ harness: their people and hats, where each function keeps its truth, the
11
+ strategic foundation and first decisions, and a goal for discovery. Show the
12
+ progress as a Claude artifact where the harness has artifacts (EE-083).
13
+ MANDATORY TRIGGERS: set up my venture, naive setup, finish setup, walk me
14
+ through setup, I just ran create-venture, establish my venture, structure my
15
+ business, what do I do after create-venture.
16
+ ---
17
+
18
+ # Naive setup
19
+
20
+ Interface layer (EE-083). `create-venture` scaffolds the venture. This skill finishes the job in conversation. You ask the questions, the founder answers in their own words, and Naive writes each answer as a decision or a source-of-truth pointer, with provenance. The progress is a view the harness renders, not a server Naive runs. In Claude, it is an artifact.
21
+
22
+ The questions and their order come from Naive, not from you. Read them from `mentura_setup` (MCP) or `node schema/setup.mjs <venture dir> state`, and never invent a question.
23
+
24
+ ## 1. Read the state
25
+
26
+ Call `mentura_setup` with the venture id. The result has:
27
+
28
+ - `state`: the people, sources of truth, docket and goal, plus `steps` (which of the four are done), `done`, and `counts`.
29
+ - `artifact`: the state, already rendered into `interface/skills/naive-setup/artifact.html`, as one self-contained HTML page.
30
+
31
+ Without MCP, run `node schema/setup.mjs <venture dir> state` and `node schema/setup.mjs <venture dir> artifact`.
32
+
33
+ ## 2. Show it
34
+
35
+ - **Claude (claude.ai, the desktop app, or Claude Code with the Artifact tool):** render `artifact` as an HTML artifact. Do not edit its contents; it is generated. Render it again after every answer, so the founder sees the progress bar move.
36
+ - **A harness without artifacts:** show the four steps as a short checklist in Markdown, with the next open question underneath.
37
+
38
+ ## 3. Ask one question at a time, in order
39
+
40
+ Work through the first step that is not done, and ask only its next open question:
41
+
42
+ 1. **People and hats.** If `state.people` is missing, ask for the founder's name, role, and whether they are solo or a team. A solo founder wears every hat. These come from `create-venture`. If they are missing, tell the founder to run `npx create-venture` again with `--name`, `--role` and `--team`. Do not write `people/` by hand.
43
+ 2. **Sources of truth.** For each function, ask where its truth lives, offering the systems in `state.catalog.functions[<function>]`. Write each answer with `mentura_setup_point` (`function`, `system`, and an `address` such as `acme/app`). If the founder has nothing for a function yet, leave it unpointed and move on. For legal, if there are no documents, say so and name the options in the catalog.
44
+ 3. **Foundation and first decisions.** These are the `state.docket` items whose status is not `decided`, taken in order. Ask the question as written. If it has options, offer them, but take the founder's own words. Write the answer with `mentura_setup_answer` (`id` and `answer`).
45
+ 4. **A goal for discovery.** Ask what must be true for the venture to leave discovery. Write it with `mentura_setup_answer`, using `id: "discovery-goal"`.
46
+
47
+ ## 4. The founder's words, not yours
48
+
49
+ - Pass the founder's answer exactly as they wrote it. Do not polish it, summarize it, or fill in an answer they did not give.
50
+ - If an answer is unclear, ask a follow-up question. Do not guess.
51
+ - A foundation statement is the founder's to state. If they ask you to draft one, show the draft and ask them to accept it or rewrite it in their own words. Write it only after they reply, and write what they replied.
52
+
53
+ ## 5. When every step is done
54
+
55
+ `state.done` is true. Render the artifact one last time: it shows "Your venture is structured." Then tell the founder, in a few lines:
56
+
57
+ - the venture now has its people, its sources of truth, its foundation and first decisions, and a discovery goal;
58
+ - how many decisions wait for later phases (`state.later`); the docket brings each one up when it matters;
59
+ - each next decision should be oriented around the discovery goal;
60
+ - to operate the business day to day, with a team and agents, they use Mentura. Naive is the structure; Mentura is where it runs, the way a Next.js app is deployed on Vercel.
61
+
62
+ ## Without a model
63
+
64
+ The same steps run from the command line:
65
+
66
+ ```sh
67
+ node schema/setup.mjs ~/ventures/acme state
68
+ node schema/setup.mjs ~/ventures/acme point finance rho
69
+ node schema/setup.mjs ~/ventures/acme answer discovery-goal "Ten clinic owners confirm the scheduling problem by December"
70
+ node schema/setup.mjs ~/ventures/acme artifact > setup.html
71
+ ```
@@ -0,0 +1,83 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Venture setup</title>
7
+ <style>
8
+ :root { --bg:#f6f7f4; --panel:#fff; --fg:#1d2320; --muted:#5d675f; --line:#d9ded8; --accent:#2f6b4f; --accent-soft:#e3efe8; --warn:#8a5a00; --warn-soft:#f6ecd8;
9
+ --body: system-ui, -apple-system, "Segoe UI", sans-serif; --mono: ui-monospace, "SF Mono", Menlo, monospace; color-scheme: light; }
10
+ @media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --bg:#121614; --panel:#1a201d; --fg:#e4e9e5; --muted:#9aa59d; --line:#2b332e; --accent:#86c4a3; --accent-soft:#1d2b24; --warn:#e3b25c; --warn-soft:#2c2414; color-scheme: dark; } }
11
+ :root[data-theme="dark"] { --bg:#121614; --panel:#1a201d; --fg:#e4e9e5; --muted:#9aa59d; --line:#2b332e; --accent:#86c4a3; --accent-soft:#1d2b24; --warn:#e3b25c; --warn-soft:#2c2414; color-scheme: dark; }
12
+ * { box-sizing: border-box }
13
+ body { margin:0; background:var(--bg); color:var(--fg); font:16px/1.55 var(--body); }
14
+ .wrap { max-width: 820px; margin: 0 auto; padding: 28px 16px 64px; display: grid; gap: 22px; }
15
+ header { display:grid; gap:6px } h1 { margin:0; font-size:1.7rem; letter-spacing:-.01em } h2 { margin:0 0 2px; font-size:1.1rem }
16
+ .muted { color: var(--muted) } .mono { font-family: var(--mono); font-size: .86em; overflow-wrap: anywhere }
17
+ .bar { height: 8px; border-radius: 999px; background: var(--line); overflow: hidden } .bar > div { height: 100%; background: var(--accent) }
18
+ .steps { display:flex; gap:6px; flex-wrap:wrap } .step { font:600 .76rem/1 var(--mono); padding:6px 9px; border-radius:999px; border:1px solid var(--line); color:var(--muted) }
19
+ .step.ok { background: var(--accent-soft); color: var(--accent); border-color: transparent } .step.next { border-color: var(--accent); color: var(--accent) }
20
+ section { background: var(--panel); border:1px solid var(--line); border-radius:10px; padding:18px; display:grid; gap:12px; min-width: 0 }
21
+ .table { overflow-x: auto } table { width:100%; border-collapse: collapse; font-size:.93rem }
22
+ td.mono { white-space: nowrap }
23
+ td, th { text-align:left; padding:7px 6px; border-bottom:1px solid var(--line); vertical-align: top }
24
+ th { font: 600 .72rem/1.2 var(--mono); text-transform: uppercase; letter-spacing:.05em; color: var(--muted) }
25
+ .pill { display:inline-block; font:600 .72rem/1.2 var(--mono); padding:4px 7px; border-radius:999px; background: var(--accent-soft); color: var(--accent); margin: 0 4px 4px 0 }
26
+ .pill.pointed { background: var(--line); color: var(--fg) } .pill.none { background: var(--warn-soft); color: var(--warn) }
27
+ .card { border:1px solid var(--line); border-radius:8px; padding:12px; display:grid; gap:6px } .card.done { opacity:.7 } .card.next { border-color: var(--accent) }
28
+ .q { font-weight:600 } .hint { font-size:.88rem; color: var(--muted) }
29
+ .celebrate { text-align:center; padding: 28px 18px; background: var(--accent-soft); border-color: transparent }
30
+ .celebrate .big { font-size: 1.9rem; font-weight: 700; color: var(--accent) } ol { margin:0; padding-left: 1.2em; display:grid; gap:6px; text-align:left }
31
+ </style>
32
+ </head>
33
+ <body>
34
+ <div class="wrap" id="app"></div>
35
+ <script id="naive-setup-state" type="application/json">__NAIVE_SETUP_STATE__</script>
36
+ <script>
37
+ // A view of the venture's setup state, filled in by `node schema/setup.mjs <venture dir> artifact`.
38
+ // It reads nothing from the network and writes nothing: the founder answers in the chat, the model writes
39
+ // each answer through Naive, and renders this page again.
40
+ const S = JSON.parse(document.getElementById("naive-setup-state").textContent);
41
+ const esc = (s) => String(s ?? "").replace(/[&<>"]/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[c]);
42
+ const st = S.steps, v = S.venture;
43
+ const order = [["people", "People and hats"], ["truth", "Sources of truth"], ["docket", "Foundation and first decisions"], ["goal", "A goal for discovery"]];
44
+ const next = order.find(([k]) => !st[k])?.[0];
45
+ const doneCount = order.filter(([k]) => st[k]).length;
46
+ const label = ([k, t]) => '<span class="step ' + (st[k] ? "ok" : k === next ? "next" : "") + '">' + (st[k] ? "&#10003; " : "") + t + "</span>";
47
+
48
+ const people = S.people
49
+ ? '<div class="table"><table><tr><th>Person</th><th>Role</th><th>Hats</th></tr>' + S.people.people.map((p) => "<tr><td>" + esc(p.name) + '</td><td class="mono">' + esc(p.role) + "</td><td>" + (p.hats.map((h) => '<span class="pill pointed">' + esc(h) + "</span>").join("") || '<span class="muted">none</span>') + "</td></tr>").join("") + "</table></div>"
50
+ : '<p class="muted">Nobody is listed yet. Tell me your name, your role, and whether you are solo or a team.</p>';
51
+
52
+ const fns = [...new Set([...Object.keys(S.catalog.functions).filter((f) => f === "legal" || (S.people?.people ?? []).some((p) => p.hats.includes(f))), ...Object.keys(S.functions)])];
53
+ const systemsOf = (f) => { const x = S.functions[f]; return x?.systems?.length ? x.systems.map((s) => '<span class="pill ' + (s.status === "connected" ? "" : "pointed") + '">' + esc(S.catalog.systems[s.system]?.label ?? s.system) + (s.address ? " &middot; " + esc(s.address) : "") + " &middot; " + esc(s.status) + (s.fixture ? " (fixture)" : "") + "</span>").join("") : '<span class="pill none">not pointed yet</span>'; };
54
+ const offered = (f) => (S.catalog.functions[f] ?? []).map((s) => esc(S.catalog.systems[s]?.label ?? s)).join(", ");
55
+ const truth = '<div class="table"><table><tr><th>Function</th><th>Source of truth</th><th>You can point it at</th></tr>' + fns.map((f) => "<tr><td>" + esc(f) + "</td><td>" + systemsOf(f) + '</td><td class="hint">' + offered(f) + "</td></tr>").join("") + "</table></div>";
56
+
57
+ const open = S.docket.filter((d) => d.status !== "decided");
58
+ const cards = S.docket.map((d) => '<div class="card ' + (d.status === "decided" ? "done" : d === open[0] ? "next" : "") + '"><div class="q">' + esc(d.question) + "</div>"
59
+ + (d.status === "decided" ? "<div>&#10003; " + esc(d.answer) + "</div>"
60
+ : d.relayed ? "<div>" + esc(d.answer) + '</div><div class="hint">Your answer, waiting for you to confirm it.</div>'
61
+
62
+ : (d.options.length ? '<div class="hint">Options: ' + d.options.map(esc).join(" / ") + "</div>" : "") + '<div class="hint">Answer in the chat, in your own words.</div>')
63
+ + "</div>").join("");
64
+
65
+ const goal = S.goal?.status === "decided" ? "<p>&#10003; " + esc(S.goal.answer) + "</p>" : S.goal?.relayed ? "<p>" + esc(S.goal.answer) + '</p><p class="hint">Your answer, waiting for you to confirm it.</p>' : '<p class="muted">What must be true for ' + esc(v.name) + " to leave discovery? For example: ten clinic owners confirm the scheduling problem in interviews by December.</p>";
66
+
67
+ const done = S.done
68
+ ? '<section class="celebrate"><div class="big">Your venture is structured.</div><p>' + esc(v.name) + " has its people and their hats, a source of truth for each function, a settled foundation and first decisions, and a goal for discovery. Every decision from here routes through the docket.</p><ol>"
69
+ + "<li>Orient each next decision around the discovery goal.</li><li>" + (S.later ? S.later + " more decisions wait for later phases; the docket brings each one up when it matters." : "The docket brings up each new decision when it matters.") + "</li><li>To operate the business day to day, with your team and your agents, use Mentura.</li></ol></section>"
70
+ : "";
71
+
72
+ document.getElementById("app").innerHTML =
73
+ '<header><span class="muted mono">' + esc(v.type?.label ?? "venture") + " &middot; " + esc(v.phase) + "</span><h1>Set up " + esc(v.name) + '</h1><p class="muted">The structure of your venture, step by step. Answer in the chat; each answer is saved as a decision, and this page updates.</p>'
74
+ + '<div class="bar" role="progressbar" aria-valuemin="0" aria-valuemax="4" aria-valuenow="' + doneCount + '"><div style="width:' + doneCount * 25 + '%"></div></div><div class="steps">' + order.map(label).join("") + "</div></header>"
75
+ + (S.waiting.length ? '<section><h2>' + S.waiting.length + (S.waiting.length === 1 ? " answer waits" : " answers wait") + ' for you</h2><p class="muted">The model wrote these down from your words. They become your decisions when you confirm them yourself: run <span class="mono">npx naive setup confirm</span> in the venture.</p></section>' : "")
76
+ + done
77
+ + "<section><h2>1. People and hats</h2>" + people + "</section>"
78
+ + '<section><h2>2. Sources of truth</h2><p class="muted">Where each function keeps its truth. Naive keeps pointers, never copies.</p>' + truth + "</section>"
79
+ + '<section><h2>3. Foundation and first decisions</h2><p class="muted">The decision docket: ' + S.counts.settled + " of " + S.counts.of + " settled.</p>" + cards + "</section>"
80
+ + "<section><h2>4. A goal for discovery</h2>" + goal + "</section>";
81
+ </script>
82
+ </body>
83
+ </html>
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env node
2
+ // Agent vitals (N-6): Naive's Core Web Vitals. Where Next.js measures time to first byte and time to
3
+ // interactive, Naive measures what it costs an agent to get work done through the router:
4
+ //
5
+ // calls_per_task router calls an agent makes in one session (a task)
6
+ // tokens_per_call tokens of context each call sends back
7
+ // time_to_useful_ms time from a session's first call to its first useful answer
8
+ // decision_hours time from a decision opening to a person deciding it (open ones count their age)
9
+ //
10
+ // Like Web Vitals, each is assessed at the 75th percentile and checked against a threshold (C-15),
11
+ // so vitals are checked, not only measured. Calls and judgments come from the events log that
12
+ // instrumentation writes (interface/instrumentation.mjs); decisions come from provenance.jsonl, so
13
+ // decision latency is measured even with instrumentation off. Thresholds are the defaults below,
14
+ // overridden by "vitals" in the venture's naive.config.json.
15
+ //
16
+ // node interface/vitals.mjs <venture dir> [--json] [--check] --check exits 1 when a vital fails
17
+ // node interface/vitals.mjs <venture dir> --trace [--session <id>] the events as a trace, for
18
+ // platform/integrations/langsmith.mjs
19
+
20
+ import { existsSync, readFileSync } from "node:fs";
21
+ import { join } from "node:path";
22
+ import { events } from "./instrumentation.mjs";
23
+ import { entries } from "./provenance.mjs";
24
+
25
+ export const THRESHOLDS = { calls_per_task: 25, tokens_per_call: 6000, time_to_useful_ms: 10000, decision_hours: 72 };
26
+ const DECISION = /(^|\/)decisions\/[^/]+\.decision\.json$/;
27
+
28
+ /** The 75th percentile, nearest rank. */
29
+ export const p75 = (xs) => { if (!xs.length) return null; const s = [...xs].sort((a, b) => a - b); return s[Math.ceil(0.75 * s.length) - 1]; };
30
+ const startOf = (e) => Date.parse(e.at) - (e.ms ?? 0);
31
+ const config = (dir) => { const f = join(dir, "naive.config.json"); try { return existsSync(f) ? JSON.parse(readFileSync(f, "utf8")) : {}; } catch { return {}; } };
32
+
33
+ /** Top-level calls grouped by session: one task per session. */
34
+ export function tasks(dir) {
35
+ const calls = events(dir).filter((e) => e.kind === "call" && !e.parent);
36
+ const judgments = events(dir).filter((e) => e.kind === "judgment");
37
+ const by = new Map();
38
+ for (const e of calls) { const k = e.session ?? "(no session)"; if (!by.has(k)) by.set(k, []); by.get(k).push(e); }
39
+ return [...by.entries()].map(([session, es]) => {
40
+ const t0 = Math.min(...es.map(startOf));
41
+ const useful = es.filter((e) => e.useful).sort((a, b) => Date.parse(a.at) - Date.parse(b.at))[0];
42
+ return { session, calls: es.length, tokens_per_call: Math.round(es.reduce((n, e) => n + (e.tokens ?? 0), 0) / es.length), max_tokens: Math.max(...es.map((e) => e.tokens ?? 0)),
43
+ time_to_useful_ms: useful ? Date.parse(useful.at) - t0 : null, judgments: judgments.filter((j) => (j.session ?? "(no session)") === session).length };
44
+ });
45
+ }
46
+
47
+ /** Each decision the provenance log saw open: when it opened, when a person decided it, and the hours between. */
48
+ export function decisionLatency(dir, now = Date.now()) {
49
+ const by = new Map();
50
+ for (const e of entries(dir).filter((x) => DECISION.test(x.entity ?? ""))) {
51
+ const d = by.get(e.entity) ?? { file: e.entity, opened: null, decided: null };
52
+ if (!d.opened) d.opened = e.at;
53
+ if (e.activity === "accept" && !d.decided) d.decided = e.at;
54
+ by.set(e.entity, d);
55
+ }
56
+ return [...by.values()].map((d) => {
57
+ let id = d.file.split("/").at(-1).replace(/\.decision\.json$/, "");
58
+ try { id = JSON.parse(readFileSync(join(dir, d.file), "utf8")).id ?? id; } catch {}
59
+ const end = d.decided ? Date.parse(d.decided) : now;
60
+ return { id, ...d, open: !d.decided, hours: Math.round(((end - Date.parse(d.opened)) / 36e5) * 100) / 100 };
61
+ });
62
+ }
63
+
64
+ /** The venture's vitals, each at p75 against its threshold. */
65
+ export function vitals(dir, now = Date.now()) {
66
+ const limits = { ...THRESHOLDS, ...(config(dir).vitals ?? {}) };
67
+ const ts = tasks(dir), ds = decisionLatency(dir, now);
68
+ const measure = (name, xs, never = 0) => {
69
+ const v = p75(xs);
70
+ const n = xs.length + never;
71
+ const passed = n === 0 ? null : never > 0 && never / n > 0.25 ? false : v === null ? false : v <= limits[name];
72
+ return { p75: v, threshold: limits[name], n, passed, status: passed === null ? "no data" : passed ? "good" : "needs work", ...(never ? { never_useful: never } : {}) };
73
+ };
74
+ const out = {
75
+ calls_per_task: measure("calls_per_task", ts.map((t) => t.calls)),
76
+ tokens_per_call: measure("tokens_per_call", ts.map((t) => t.tokens_per_call)),
77
+ time_to_useful_ms: measure("time_to_useful_ms", ts.filter((t) => t.time_to_useful_ms !== null).map((t) => t.time_to_useful_ms), ts.filter((t) => t.time_to_useful_ms === null).length),
78
+ decision_hours: measure("decision_hours", ds.map((d) => d.hours)),
79
+ };
80
+ const failing = Object.entries(out).filter(([, v]) => v.passed === false).map(([k]) => k);
81
+ return { events: events(dir).length, tasks: ts, decisions: ds, vitals: out, passed: failing.length === 0, failing,
82
+ note: events(dir).length ? "p75 of each vital against its threshold (naive.config.json vitals overrides the defaults)" : "no events yet: turn instrumentation on in naive.config.json ({\"instrumentation\": {\"events\": true}}) to measure calls, tokens and time to a useful answer" };
83
+ }
84
+
85
+ /** The events as one trace (root run per session, a child per call, nested calls under their parent), with the vitals as feedback. */
86
+ export function trace(dir, session) {
87
+ const es = events(dir).filter((e) => !session || (e.session ?? "(no session)") === session);
88
+ const calls = es.filter((e) => e.kind === "call");
89
+ const node = (e) => ({ name: `${e.action} ${e.route}`, run_type: e.action === "run" ? "tool" : "retriever", start: new Date(startOf(e)).toISOString(), end: e.at,
90
+ inputs: { venture: e.venture, route: e.route, action: e.action }, outputs: { ok: e.ok, useful: e.useful, tokens: e.tokens, ms: e.ms }, ...(e.ok ? {} : { error: "call failed" }),
91
+ metadata: { via: e.via, actor: e.actor }, children: calls.filter((c) => c.parent === e.id).map(node) });
92
+ const judged = es.filter((e) => e.kind === "judgment").map((e) => ({ name: `judgment ${e.question ?? e.route ?? ""}`.trim(), run_type: "llm", start: new Date(Date.parse(e.at) - (e.ms ?? 0)).toISOString(), end: e.at,
93
+ inputs: { question: e.question, route: e.route }, outputs: { score: e.score, threshold: e.threshold, outcome: e.outcome }, metadata: { model: e.model, owner: e.owner } }));
94
+ const v = vitals(dir);
95
+ const start = es.length ? new Date(Math.min(...es.map((e) => Date.parse(e.at) - (e.ms ?? 0)))).toISOString() : new Date().toISOString();
96
+ const end = es.length ? es.at(-1).at : start;
97
+ return { name: `naive ${JSON.parse(readFileSync(join(dir, "venture.json"), "utf8")).id}${session ? ` ${session}` : ""}`, run_type: "chain", start, end,
98
+ inputs: { session: session ?? null }, outputs: { calls: calls.filter((c) => !c.parent).length, judgments: judged.length },
99
+ children: [...calls.filter((c) => !c.parent).map(node), ...judged].sort((a, b) => a.start.localeCompare(b.start)),
100
+ feedback: Object.entries(v.vitals).filter(([, x]) => x.passed !== null).map(([key, x]) => ({ key, score: x.passed ? 1 : 0, comment: `p75 ${x.p75} against ${x.threshold}` })) };
101
+ }
102
+
103
+ if (import.meta.url === `file://${process.argv[1]}`) {
104
+ const dir = process.argv[2];
105
+ if (!dir || !existsSync(join(dir, "venture.json"))) { console.error("usage: node interface/vitals.mjs <venture dir> [--json] [--check] [--trace [--session <id>]]"); process.exit(2); }
106
+ const arg = (n) => { const i = process.argv.indexOf(`--${n}`); return i >= 0 ? process.argv[i + 1] : undefined; };
107
+ if (process.argv.includes("--trace")) { console.log(JSON.stringify(trace(dir, arg("session")), null, 2)); process.exit(0); }
108
+ const r = vitals(dir);
109
+ if (process.argv.includes("--json")) console.log(JSON.stringify(r, null, 2));
110
+ else {
111
+ console.log(`${r.events} events, ${r.tasks.length} tasks, ${r.decisions.length} decisions. ${r.note}`);
112
+ for (const [k, x] of Object.entries(r.vitals)) console.log(` ${k.padEnd(18)} ${x.status.padEnd(10)} p75 ${x.p75 ?? "-"} (threshold ${x.threshold}, n ${x.n})`);
113
+ }
114
+ if (process.argv.includes("--check") && !r.passed) { console.error(`vitals failing: ${r.failing.join(", ")}`); process.exit(1); }
115
+ }
@@ -0,0 +1,190 @@
1
+ // What a write answers, what a layout offers, and the wrapper the router puts around every call
2
+ // (Next.js translation M-3, M-9, M-17; it also wires in interface/reads.mjs, interface/boundaries.mjs
3
+ // and interface/package-routes.mjs).
4
+ //
5
+ // changed M-3 one round trip: a write answers with the new state and what it changed: the
6
+ // record's state before and after, each package whose progress or state moved,
7
+ // the records that move now because of it, what it unlocked (a package that
8
+ // completed and what that opens, a decision that no longer waits) and the
9
+ // need-now rows it settled
10
+ // next M-17 a write answers with the next route to act on: accept the draft it made, else
11
+ // the next record in the same package that moves now, else what it unlocked,
12
+ // else what need-now suggests, else the decision that matters most
13
+ // actions M-9 a layout lists the actions available in its folder to the actor asking: each
14
+ // route's actions, which of them this actor may take now, and whether a write
15
+ // lands as the record, as a draft, or is locked or refused, with why
16
+ //
17
+ // around() runs before and after the router's own call: the framework and venture global errors
18
+ // first (E-8), then package, group and venture routes (L-6, P-36, P-3), then the call, then what
19
+ // reads and layouts add (L-9, L-10, O-1 to O-3, P-28) and what writes answer (M-3, M-17). It never
20
+ // calls a model.
21
+
22
+ import { allowed, draftOf, gateOf, resolve, routes, ventureDir } from "./router.mjs";
23
+ import { frameworkHealth, globalError, ventureHealth } from "./boundaries.mjs";
24
+ import { groupLayout, packageOfRecord, routeOfType, specialCall } from "./package-routes.mjs";
25
+ import { filterRead, hierarchy, metadataFor, resolvedBy, withParams } from "./reads.mjs";
26
+
27
+ /** The state a write can change, taken before and after it. */
28
+ export async function snapshot(dir) {
29
+ const safe = async (f) => { try { return await f(); } catch { return null; } };
30
+ const { packages } = await import("../schema/packages.mjs");
31
+ const { needNow } = await import("../schema/need-now.mjs");
32
+ const { decisions } = await import("../schema/decisions.mjs");
33
+ return { packages: await safe(() => packages(dir)), need: await safe(() => needNow(dir)), decisions: await safe(() => decisions(dir)) };
34
+ }
35
+
36
+ const pkgMap = (s) => new Map([...(s?.packages?.core ?? []), ...(s?.packages?.handoff ?? [])].map((p) => [p.id, p]));
37
+ const rowOf = (s, type) => (s?.packages?.core ?? []).flatMap((p) => p.records).find((x) => x.record === type && x.role !== "reads") ?? null;
38
+
39
+ /** What a write changed (M-3), from the state before and after it. */
40
+ export async function changed(before, after, { record }) {
41
+ const b = pkgMap(before), a = pkgMap(after);
42
+ const packages = [...a.values()].filter((p) => { const o = b.get(p.id); return !o || o.progress !== p.progress || o.state !== p.state; })
43
+ .map((p) => ({ package: p.id, title: p.title, progress: { from: b.get(p.id)?.progress ?? null, to: p.progress }, state: { from: b.get(p.id)?.state ?? null, to: p.state } }));
44
+ const was = new Map((before?.packages?.core ?? []).flatMap((p) => p.records.map((x) => [`${p.id}:${x.record}`, x])));
45
+ const moves = [];
46
+ for (const p of after?.packages?.core ?? []) for (const x of p.records) {
47
+ const o = was.get(`${p.id}:${x.record}`);
48
+ if (x.role !== "reads" && x.moves === "now" && o?.moves === "waits" && !moves.some((m) => m.record === x.record)) moves.push({ record: x.record, package: p.id, route: await routeOfType(x.record) });
49
+ }
50
+ const unlocked = [...a.values()].filter((p) => p.state === "complete" && b.get(p.id)?.state !== "complete").map((p) => ({ package: p.id, unlocks: p.unlocks ?? [] }));
51
+ const dBefore = new Map((before?.decisions?.decisions ?? []).map((d) => [d.id, d.render]));
52
+ const freed = (after?.decisions?.decisions ?? []).filter((d) => ["waiting", "later"].includes(dBefore.get(d.id)) && ["now", "overdue"].includes(d.render)).map((d) => ({ decision: d.id, question: d.question ?? null }));
53
+ const nBefore = new Map((before?.need?.rows ?? []).map((x) => [x.type, x.status]));
54
+ const need = (after?.need?.rows ?? []).filter((x) => nBefore.has(x.type) && nBefore.get(x.type) !== x.status).map((x) => ({ record: x.type, from: nBefore.get(x.type), to: x.status }));
55
+ return {
56
+ record: { type: record, from: rowOf(before, record)?.status ?? null, to: rowOf(after, record)?.status ?? null, package: packageOfRecord(record) },
57
+ packages, moves_now: moves, unlocked: [...unlocked, ...freed], need_now: need,
58
+ };
59
+ }
60
+
61
+ const commandFor = (route, venture) => route?.endsWith("[id]") ? `mentura ${route.replace("[id]", "<id>")} write --venture ${venture} --input <file>` : `mentura ${route} write --venture ${venture} --input <file>`;
62
+
63
+ /** The next route to act on after a write (M-17). */
64
+ export async function next(after, { record, route, draft, venture, change }) {
65
+ if (draft) return { route, action: "accept", who: "a person", command: `mentura accept ${route} --venture ${venture}`, why: "the write is held as a draft until a person accepts it" };
66
+ const home = packageOfRecord(record);
67
+ const p = (after?.packages?.core ?? []).find((x) => x.id === home);
68
+ const missing = (p?.records ?? []).filter((x) => x.role !== "reads" && x.record !== record && x.moves === "now" && x.status === "missing");
69
+ const required = missing.find((x) => x.role === "required");
70
+ if (required) { const rt = await routeOfType(required.record); return { route: rt, action: "write", command: commandFor(rt, venture), why: `the next required record in ${p.title} that moves now` }; }
71
+ // An agent's write waits for a person before what reads it can move.
72
+ const review = (p?.records ?? []).filter((x) => x.role !== "reads" && x.status === "agent");
73
+ if (review.length) { const rt = await routeOfType(review[0].record); return { route: rt, action: "review", who: "a person", command: `mentura ${rt} read --venture ${venture}`, why: `${review[0].title} was written by an agent: a person confirms it by writing it with --as person, and what reads it moves then` }; }
74
+ const freed = change?.moves_now?.[0];
75
+ if (freed) return { route: freed.route, action: "write", command: commandFor(freed.route, venture), why: `this write let ${freed.record} move` };
76
+ if (missing.length) { const rt = await routeOfType(missing[0].record); return { route: rt, action: "write", command: commandFor(rt, venture), why: `the next ${missing[0].role} record in ${p.title} that moves now` }; }
77
+ const suggest = (after?.need?.rows ?? []).filter((x) => x.status === "suggest now" && x.type !== record).sort((a, b) => b.now - a.now)[0];
78
+ if (suggest) { const rt = await routeOfType(suggest.type); if (rt) return { route: rt, action: "write", command: commandFor(rt, venture), why: `need-now suggests it now: ${suggest.why}` }; }
79
+ const { rank } = await import("../schema/decisions.mjs");
80
+ const ds = after?.decisions ? rank(after.decisions.decisions, after.decisions.phase).filter((d) => d.rank != null && d.source === "file") : [];
81
+ if (ds.length) return { route: "governance/decisions", action: "decide", who: "a person", command: `mentura decide ${ds[0].id} --venture ${venture} --by <your name>`, why: ds[0].question };
82
+ return { route: null, action: null, why: "nothing waits on this write" };
83
+ }
84
+
85
+ /** The actions available in a route's folder to one actor (M-9). */
86
+ export async function actionsIn({ dir, r, route, actor = "agent", actor_id, venture }) {
87
+ const { holding, locked } = await import("../schema/decisions.mjs");
88
+ const { configOf, hold } = await import("../schema/gate.mjs");
89
+ const folder = r.collection === "item" ? r.route.slice(0, -"/[id]".length) : route.includes("/") ? route.slice(0, route.lastIndexOf("/")) : route;
90
+ const rs = routes().filter((x) => x.route === folder || x.route.startsWith(`${folder}/`));
91
+ const list = [];
92
+ for (const x of rs) {
93
+ const concrete = x.route === r.route ? route : x.route;
94
+ const entry = { route: concrete, kind: x.kind, actions: x.actions };
95
+ if (!dir) { list.push(entry); continue; }
96
+ const reads = allowed(dir, actor_id, "read", concrete);
97
+ const avail = x.actions.filter((a) => !["write", "run"].includes(a) && (reads || a === "template" || a === "layout"));
98
+ if (x.actions.includes("run")) {
99
+ const lock = actor !== "person" ? locked(dir, concrete, actor_id) : null;
100
+ if (reads && !lock) avail.push("run");
101
+ entry.run = lock ? { runs: false, why: `locked until decision ${lock.id} is made` } : reads ? { runs: true } : { runs: false, why: "the team plan does not let this role reach it" };
102
+ }
103
+ if (x.actions.includes("write")) {
104
+ let w;
105
+ if (!allowed(dir, actor_id, "write", concrete)) w = { lands: null, why: `${actor_id} may not write it (team plan routes)` };
106
+ else {
107
+ const lock = actor !== "person" ? locked(dir, concrete, actor_id) : null;
108
+ if (lock) w = { lands: null, why: `locked until decision ${lock.id} is made: ${lock.question}` };
109
+ else if (actor === "person") w = { lands: "record", why: "a person's write goes straight to the record" };
110
+ else {
111
+ const gate = gateOf(x, dir);
112
+ const d = !concrete.includes("[id]") ? draftOf(concrete, venture, undefined) : null;
113
+ const held = d ? holding(dir, d.file) : null;
114
+ const cfg = hold(configOf(dir), x.route, actor);
115
+ w = gate?.drafts ? { lands: "draft", why: `${x.record} is a ${gate.class} decision (${gate.level})` } : held ? { lands: "draft", why: `decision ${held.id} ${held.why}` } : cfg ? { lands: "draft", why: `${cfg.rule} fails closed in naive.config.json` } : { lands: "record", why: "no gate holds it" };
116
+ }
117
+ }
118
+ if (w.lands) avail.push("write");
119
+ entry.write = w;
120
+ }
121
+ entry.available = avail;
122
+ list.push(entry);
123
+ }
124
+ return { folder, actor: { kind: actor, ...(actor_id ? { id: actor_id } : {}) }, routes: list };
125
+ }
126
+
127
+ // The venture-relative file behind a read's source address (venture://path), for local sources only.
128
+ const fileOfAddress = (a) => a?.startsWith("venture://") ? a.slice("venture://".length) : null;
129
+
130
+ /**
131
+ * The wrapper around the router's call (see the top of this file). inner is the router's own call;
132
+ * args are what call takes. Returns what call returns, with the additions above.
133
+ */
134
+ export async function around(inner, args) {
135
+ const { venture, route, action, input, actor = "agent", workspace } = args;
136
+ const actor_id = args.actor_id ?? process.env.MENTURA_ACTOR_ID;
137
+ // E-8: a broken framework file stops every route, with its recovery steps.
138
+ const fw = frameworkHealth();
139
+ if (fw) return globalError(fw);
140
+ let res;
141
+ try { res = resolve(route); } catch (e) { return globalError({ scope: "framework", file: "schema/data-model.json", problem: `the route table cannot be built: ${String(e.message ?? e).split("\n")[0]}`, recovery: ["Check the data model and the manifests: node schema/check-data-model.mjs", "Restore the file it names from git"] }); }
142
+ const dir = venture ? ventureDir(venture, workspace) : null;
143
+ // E-8: a broken venture.json answers with recovery steps, before anything reads it.
144
+ if (dir) { const h = ventureHealth(dir); if (h) return globalError(h, venture); }
145
+ // L-6, P-36, P-3: package, group and venture routes are answered here, outside the route table.
146
+ if (!res.r) return (await specialCall(args)) ?? inner(args);
147
+ const r = res.r, params = res.params;
148
+ const concrete = r.collection === "item" ? r.route.replace("[id]", params.id) : r.route;
149
+ const before = action === "write" && dir && r.kind === "record" ? await snapshot(dir) : null;
150
+ let out;
151
+ try { out = await inner(args); }
152
+ catch (e) {
153
+ // E-6: a record that cannot be read is that record's error, not a crash.
154
+ if (action !== "read") throw e;
155
+ return { ok: false, outcome: "error", error: `${concrete}: the record does not parse: ${String(e.message ?? e).split("\n")[0]}`, fix: { schema: r.schema ?? null, template: r.template ?? null }, resolved_by: "error" };
156
+ }
157
+
158
+ if (action === "read" && dir && r.kind === "record") {
159
+ if (out.ok) {
160
+ const items = r.collection === "list" ? Object.fromEntries(Object.entries(out.sources ?? {}).map(([id, s]) => [id, fileOfAddress(s.address)]).filter(([, f]) => f))
161
+ : out.source && fileOfAddress(out.source.address) ? { [params.id ?? r.record]: fileOfAddress(out.source.address) } : {};
162
+ out = { ...out, params, metadata: await metadataFor({ dir, r, route: concrete, params, result: out.result, items }) };
163
+ out = filterRead(out, input?.where, r);
164
+ }
165
+ out.resolved_by = resolvedBy(out);
166
+ if (input?.hierarchy) {
167
+ const { layout } = await import("./router.mjs");
168
+ const pkg = packageOfRecord(r.record);
169
+ const lay = withParams(layout(r, dir), { dir, params, file: draftOf(concrete, venture, workspace)?.file, group: pkg ? groupLayout(pkg, dir) : null });
170
+ out.hierarchy = hierarchy({ answer: out, layout: lay }).levels;
171
+ }
172
+ return out;
173
+ }
174
+
175
+ if (action === "layout" && out.ok) {
176
+ const pkg = r.kind === "record" ? packageOfRecord(r.record) : null;
177
+ const file = dir && r.kind === "record" && r.collection !== "list" && !concrete.includes("[id]") ? draftOf(concrete, venture, workspace)?.file : null;
178
+ const result = withParams(out.result, { dir, params, file, group: pkg ? groupLayout(pkg, dir) : null });
179
+ result.actions = await actionsIn({ dir, r, route: concrete, actor, actor_id, venture: venture ?? null });
180
+ return { ...out, result };
181
+ }
182
+
183
+ if (action === "write" && before && out.ok && out.result?.written) {
184
+ const after = await snapshot(dir);
185
+ const change = await changed(before, after, { record: r.record });
186
+ out.result.changed = change;
187
+ out.result.next = await next(after, { record: r.record, route: concrete, draft: out.result.draft, venture, change });
188
+ }
189
+ return out;
190
+ }
@@ -0,0 +1,85 @@
1
+ {
2
+ "$schema": "../schema/freshness-profiles.schema.json",
3
+ "note": "Default freshness profiles (Revalidating, V-1 to V-3): how long a record stays fresh, by record type, after Next.js cacheLife profiles. A venture overrides any of them under freshness in its naive.config.json, as a Next.js app defines cacheLife profiles in next.config.js. stale: how long an agent may reuse what it read without reading it again. revalidate: after this the record is stale, still readable with a stale flag, and should be checked or redone. expire: after this it is expired and not frozen into a release. per_phase: the record is stale once the venture changes phase after it was last checked. live: a fast-changing record, never frozen into a release; it stays a live hole. Durations are seconds, or a number with s, m, h, d or w. Version 0.x: ours and unevaluated.",
4
+ "version": "0.1.0",
5
+ "default": "max",
6
+ "profiles": {
7
+ "live": {
8
+ "live": true,
9
+ "stale": "0s",
10
+ "revalidate": "7d",
11
+ "note": "Pipeline, money and streams: read from their system of record every time, synced at least weekly, never frozen"
12
+ },
13
+ "feedback": {
14
+ "stale": "1d",
15
+ "revalidate": "30d",
16
+ "expire": "90d",
17
+ "note": "What customers said: stale after 30 days, too old to rely on after 90"
18
+ },
19
+ "research": {
20
+ "stale": "1d",
21
+ "revalidate": "90d",
22
+ "expire": "365d",
23
+ "note": "Market research, product cards and site measurements: stale after 90 days"
24
+ },
25
+ "assumption": {
26
+ "per_phase": true,
27
+ "stale": "1d",
28
+ "revalidate": "90d",
29
+ "expire": "365d",
30
+ "note": "What the venture believes about its problem, solution, price and market: tested again each phase, and stale after 90 days"
31
+ },
32
+ "foundation": {
33
+ "per_phase": true,
34
+ "stale": "1d",
35
+ "revalidate": "365d",
36
+ "note": "The strategic foundation: tested again each phase; in Discovery even confirmed statements are"
37
+ },
38
+ "max": {
39
+ "stale": "1d",
40
+ "revalidate": "365d",
41
+ "note": "Governance and other slow records: looked at again once a year"
42
+ },
43
+ "none": {
44
+ "note": "Generated or configuration records: never stale by time, only when what they depend on changes"
45
+ }
46
+ },
47
+ "records": {
48
+ "customer": "live",
49
+ "investor": "live",
50
+ "money-account": "live",
51
+ "data-stream": "live",
52
+ "raw-source": "feedback",
53
+ "raw-text": "feedback",
54
+ "evidence": "feedback",
55
+ "product": "research",
56
+ "account": "research",
57
+ "site-presence": "research",
58
+ "anatomy-input": "research",
59
+ "anatomy-answers": "research",
60
+ "validation-problem": "assumption",
61
+ "validation-solution": "assumption",
62
+ "validation-product-market-fit": "assumption",
63
+ "validation-pricing": "assumption",
64
+ "validation-go-to-market": "assumption",
65
+ "validation-team": "assumption",
66
+ "validation-operations-readiness": "assumption",
67
+ "telos": "foundation",
68
+ "icp": "foundation",
69
+ "alignment": "foundation",
70
+ "idea-dump": "none",
71
+ "idea-map": "none",
72
+ "idea-graph": "none",
73
+ "venture-profile": "max",
74
+ "provenance": "none",
75
+ "freshness-log": "none",
76
+ "venture-package": "none",
77
+ "knowledge-sources": "none",
78
+ "where-used": "none",
79
+ "decision-record": "none",
80
+ "decision-rights": "none",
81
+ "team-plan": "max",
82
+ "marketing-sitemap": "none",
83
+ "marketing-content": "none"
84
+ }
85
+ }
@@ -19,11 +19,18 @@
19
19
  "design-document",
20
20
  "nextjs-status",
21
21
  "knowledge-sources",
22
- "where-used"
22
+ "where-used",
23
+ "freshness-profiles",
24
+ "freshness-log",
25
+ "judgment",
26
+ "systems-catalog",
27
+ "glossary"
23
28
  ],
24
29
  "reads": [
25
30
  "venture",
26
- "product"
31
+ "product",
32
+ "provenance",
33
+ "decision-record"
27
34
  ],
28
35
  "writes": [
29
36
  "reference"
@@ -36,7 +43,8 @@
36
43
  "No check on the venture profile or design documents of its own; design-coverage (evidence) is the only one",
37
44
  "Two connectors so far (filesystem and GitHub); a database, Notion, Slack or Salesforce each need their own module meeting the same contract",
38
45
  "Checks and command routes (need-now, time-to-ready, validation score) still read the venture folder, so they do not yet see a record kept in another source",
39
- "A merged pull request is not logged as an accept in provenance; the read after the merge is the only sign"
46
+ "A merged pull request is not logged as an accept in provenance; the read after the merge is the only sign",
47
+ "Freshness (schema/freshness.mjs) checks children in the venture folder only; a child in another source is listed as needing the platform, and a webhook from a system of record that marks summaries stale (V-9) is the platform's"
40
48
  ],
41
49
  "name": "knowledge"
42
50
  }
@@ -0,0 +1,23 @@
1
+ ---
2
+ type: template
3
+ tags: [everything-ecosystem, knowledge, glossary, template]
4
+ ai-model: claude-opus-5.5
5
+ created: 2026-10-29T06:04:07Z
6
+ source: hybrid
7
+ ---
8
+
9
+ # Template: package glossary
10
+
11
+ Fills `<venture>/glossary/<package>.json` (`schema/glossary.schema.json`). A package's terms stay local to it: an agent working in another package sees only the terms marked `export`. See what a package sees with `mentura glossary/terms run --value <package>`.
12
+
13
+ ```json
14
+ {
15
+ "package": "finance",
16
+ "terms": [
17
+ { "term": "burn multiple", "meaning": "net burn divided by net new ARR" },
18
+ { "term": "runway", "meaning": "months of cash at the current burn", "export": true }
19
+ ]
20
+ }
21
+ ```
22
+
23
+ Two packages may not export one term with different meanings. A package's own term wins over another's exported one.