@nurix/etna 0.18.19 → 0.18.21

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 (283) hide show
  1. package/README.md +1 -1
  2. package/data/harness-index.json +1 -1
  3. package/data/harnesses/code/CLAUDE.md +1 -1
  4. package/data/harnesses/code/agents/brainstorm.md +1 -1
  5. package/data/harnesses/code/agents/maintenance.md +2 -2
  6. package/data/harnesses/code/harness.json +2 -2
  7. package/data/harnesses/code/rules/database.md +38 -0
  8. package/data/harnesses/code/rules/express.md +28 -0
  9. package/data/harnesses/code/rules/frontend.md +14 -0
  10. package/data/harnesses/code/rules/general.md +2 -40
  11. package/data/harnesses/code/rules/nomenclature.md +1 -8
  12. package/data/harnesses/code/rules/nustack.md +150 -0
  13. package/data/harnesses/code/skills/brainstorm/README.md +1 -1
  14. package/data/harnesses/code/skills/brainstorm/SKILL.md +1 -1
  15. package/data/harnesses/code/skills/brainstorm/exit-artifacts.md +4 -4
  16. package/data/harnesses/code/skills/brainstorm/templates/source-of-truth.md +3 -3
  17. package/data/harnesses/code/skills/design/SKILL.md +68 -0
  18. package/data/harnesses/code/skills/design/data/catalog/rules.csv +132 -0
  19. package/data/harnesses/code/skills/design/data/combinations/Readme.md +29 -0
  20. package/data/harnesses/code/skills/design/data/combinations/charts.csv +33 -0
  21. package/data/harnesses/code/skills/design/data/combinations/fonts-known.json +437 -0
  22. package/data/harnesses/code/skills/design/data/combinations/icons.csv +157 -0
  23. package/data/harnesses/code/skills/design/data/combinations/landing.csv +38 -0
  24. package/data/harnesses/code/skills/design/data/combinations/lucide-names.json +2001 -0
  25. package/data/harnesses/code/skills/design/data/combinations/manifest.json +283 -0
  26. package/data/harnesses/code/skills/design/data/combinations/palettes.csv +49 -0
  27. package/data/harnesses/code/skills/design/data/combinations/product-router.csv +80 -0
  28. package/data/harnesses/code/skills/design/data/combinations/styles.csv +54 -0
  29. package/data/harnesses/code/skills/design/data/combinations/typography.csv +61 -0
  30. package/data/harnesses/code/skills/design/data/design-md/SCHEMA.md +106 -0
  31. package/data/harnesses/code/skills/design/data/design-md/library/airbnb.md +154 -0
  32. package/data/harnesses/code/skills/design/data/design-md/library/airtable.md +151 -0
  33. package/data/harnesses/code/skills/design/data/design-md/library/anthropic-claude.md +139 -0
  34. package/data/harnesses/code/skills/design/data/design-md/library/apple.md +139 -0
  35. package/data/harnesses/code/skills/design/data/design-md/library/binance.md +140 -0
  36. package/data/harnesses/code/skills/design/data/design-md/library/bmw.md +140 -0
  37. package/data/harnesses/code/skills/design/data/design-md/library/cal.md +140 -0
  38. package/data/harnesses/code/skills/design/data/design-md/library/clay.md +139 -0
  39. package/data/harnesses/code/skills/design/data/design-md/library/clickhouse.md +139 -0
  40. package/data/harnesses/code/skills/design/data/design-md/library/cohere.md +147 -0
  41. package/data/harnesses/code/skills/design/data/design-md/library/coinbase.md +156 -0
  42. package/data/harnesses/code/skills/design/data/design-md/library/composio.md +138 -0
  43. package/data/harnesses/code/skills/design/data/design-md/library/cursor.md +138 -0
  44. package/data/harnesses/code/skills/design/data/design-md/library/elevenlabs.md +137 -0
  45. package/data/harnesses/code/skills/design/data/design-md/library/expo.md +148 -0
  46. package/data/harnesses/code/skills/design/data/design-md/library/figma.md +141 -0
  47. package/data/harnesses/code/skills/design/data/design-md/library/framer.md +156 -0
  48. package/data/harnesses/code/skills/design/data/design-md/library/hashicorp.md +140 -0
  49. package/data/harnesses/code/skills/design/data/design-md/library/ibm.md +153 -0
  50. package/data/harnesses/code/skills/design/data/design-md/library/intercom.md +158 -0
  51. package/data/harnesses/code/skills/design/data/design-md/library/kraken.md +156 -0
  52. package/data/harnesses/code/skills/design/data/design-md/library/linear-app.md +122 -0
  53. package/data/harnesses/code/skills/design/data/design-md/library/lovable.md +140 -0
  54. package/data/harnesses/code/skills/design/data/design-md/library/meta.md +139 -0
  55. package/data/harnesses/code/skills/design/data/design-md/library/minimax.md +139 -0
  56. package/data/harnesses/code/skills/design/data/design-md/library/mintlify.md +139 -0
  57. package/data/harnesses/code/skills/design/data/design-md/library/miro.md +153 -0
  58. package/data/harnesses/code/skills/design/data/design-md/library/mistral-ai.md +140 -0
  59. package/data/harnesses/code/skills/design/data/design-md/library/mongodb.md +155 -0
  60. package/data/harnesses/code/skills/design/data/design-md/library/notion.md +140 -0
  61. package/data/harnesses/code/skills/design/data/design-md/library/nvidia.md +141 -0
  62. package/data/harnesses/code/skills/design/data/design-md/library/ollama.md +145 -0
  63. package/data/harnesses/code/skills/design/data/design-md/library/opencode-ai.md +142 -0
  64. package/data/harnesses/code/skills/design/data/design-md/library/posthog.md +152 -0
  65. package/data/harnesses/code/skills/design/data/design-md/library/raycast.md +137 -0
  66. package/data/harnesses/code/skills/design/data/design-md/library/replicate.md +140 -0
  67. package/data/harnesses/code/skills/design/data/design-md/library/resend.md +170 -0
  68. package/data/harnesses/code/skills/design/data/design-md/library/revolut.md +145 -0
  69. package/data/harnesses/code/skills/design/data/design-md/library/runwayml.md +137 -0
  70. package/data/harnesses/code/skills/design/data/design-md/library/sanity.md +168 -0
  71. package/data/harnesses/code/skills/design/data/design-md/library/sentry.md +163 -0
  72. package/data/harnesses/code/skills/design/data/design-md/library/shopify.md +147 -0
  73. package/data/harnesses/code/skills/design/data/design-md/library/slack.md +158 -0
  74. package/data/harnesses/code/skills/design/data/design-md/library/spacex.md +171 -0
  75. package/data/harnesses/code/skills/design/data/design-md/library/spotify.md +166 -0
  76. package/data/harnesses/code/skills/design/data/design-md/library/stripe.md +160 -0
  77. package/data/harnesses/code/skills/design/data/design-md/library/supabase.md +173 -0
  78. package/data/harnesses/code/skills/design/data/design-md/library/superhuman.md +145 -0
  79. package/data/harnesses/code/skills/design/data/design-md/library/tesla.md +153 -0
  80. package/data/harnesses/code/skills/design/data/design-md/library/theverge.md +167 -0
  81. package/data/harnesses/code/skills/design/data/design-md/library/together-ai.md +140 -0
  82. package/data/harnesses/code/skills/design/data/design-md/library/uber.md +140 -0
  83. package/data/harnesses/code/skills/design/data/design-md/library/vercel.md +140 -0
  84. package/data/harnesses/code/skills/design/data/design-md/library/voltagent.md +130 -0
  85. package/data/harnesses/code/skills/design/data/design-md/library/warp.md +140 -0
  86. package/data/harnesses/code/skills/design/data/design-md/library/webflow.md +140 -0
  87. package/data/harnesses/code/skills/design/data/design-md/library/wired.md +139 -0
  88. package/data/harnesses/code/skills/design/data/design-md/library/wise.md +137 -0
  89. package/data/harnesses/code/skills/design/data/design-md/library/x-ai.md +138 -0
  90. package/data/harnesses/code/skills/design/data/design-md/library/zapier.md +158 -0
  91. package/data/harnesses/code/skills/design/data/design-md/nurix.md +134 -0
  92. package/data/harnesses/code/skills/design/data/design-tokens/SCHEMA.md +580 -0
  93. package/data/harnesses/code/skills/design/data/design-tokens/airbnb/design.resolver.json +20 -0
  94. package/data/harnesses/code/skills/design/data/design-tokens/airbnb/design.tokens.json +964 -0
  95. package/data/harnesses/code/skills/design/data/design-tokens/airtable/design.resolver.json +20 -0
  96. package/data/harnesses/code/skills/design/data/design-tokens/airtable/design.tokens.json +960 -0
  97. package/data/harnesses/code/skills/design/data/design-tokens/anthropic-claude/design.resolver.json +20 -0
  98. package/data/harnesses/code/skills/design/data/design-tokens/anthropic-claude/design.tokens.json +965 -0
  99. package/data/harnesses/code/skills/design/data/design-tokens/apple/design.resolver.json +20 -0
  100. package/data/harnesses/code/skills/design/data/design-tokens/apple/design.tokens.json +954 -0
  101. package/data/harnesses/code/skills/design/data/design-tokens/binance/design.resolver.json +20 -0
  102. package/data/harnesses/code/skills/design/data/design-tokens/binance/design.tokens.json +949 -0
  103. package/data/harnesses/code/skills/design/data/design-tokens/bmw/design.resolver.json +20 -0
  104. package/data/harnesses/code/skills/design/data/design-tokens/bmw/design.tokens.json +962 -0
  105. package/data/harnesses/code/skills/design/data/design-tokens/cal/design.resolver.json +20 -0
  106. package/data/harnesses/code/skills/design/data/design-tokens/cal/design.tokens.json +958 -0
  107. package/data/harnesses/code/skills/design/data/design-tokens/clay/design.resolver.json +20 -0
  108. package/data/harnesses/code/skills/design/data/design-tokens/clay/design.tokens.json +953 -0
  109. package/data/harnesses/code/skills/design/data/design-tokens/clickhouse/design.resolver.json +20 -0
  110. package/data/harnesses/code/skills/design/data/design-tokens/clickhouse/design.tokens.json +960 -0
  111. package/data/harnesses/code/skills/design/data/design-tokens/cohere/design.resolver.json +20 -0
  112. package/data/harnesses/code/skills/design/data/design-tokens/cohere/design.tokens.json +973 -0
  113. package/data/harnesses/code/skills/design/data/design-tokens/coinbase/design.resolver.json +20 -0
  114. package/data/harnesses/code/skills/design/data/design-tokens/coinbase/design.tokens.json +954 -0
  115. package/data/harnesses/code/skills/design/data/design-tokens/composio/design.resolver.json +20 -0
  116. package/data/harnesses/code/skills/design/data/design-tokens/composio/design.tokens.json +963 -0
  117. package/data/harnesses/code/skills/design/data/design-tokens/cursor/design.resolver.json +20 -0
  118. package/data/harnesses/code/skills/design/data/design-tokens/cursor/design.tokens.json +968 -0
  119. package/data/harnesses/code/skills/design/data/design-tokens/elevenlabs/design.resolver.json +20 -0
  120. package/data/harnesses/code/skills/design/data/design-tokens/elevenlabs/design.tokens.json +981 -0
  121. package/data/harnesses/code/skills/design/data/design-tokens/expo/design.resolver.json +20 -0
  122. package/data/harnesses/code/skills/design/data/design-tokens/expo/design.tokens.json +962 -0
  123. package/data/harnesses/code/skills/design/data/design-tokens/figma/design.resolver.json +20 -0
  124. package/data/harnesses/code/skills/design/data/design-tokens/figma/design.tokens.json +964 -0
  125. package/data/harnesses/code/skills/design/data/design-tokens/framer/design.resolver.json +20 -0
  126. package/data/harnesses/code/skills/design/data/design-tokens/framer/design.tokens.json +959 -0
  127. package/data/harnesses/code/skills/design/data/design-tokens/goldens.json +251 -0
  128. package/data/harnesses/code/skills/design/data/design-tokens/hashicorp/design.resolver.json +20 -0
  129. package/data/harnesses/code/skills/design/data/design-tokens/hashicorp/design.tokens.json +965 -0
  130. package/data/harnesses/code/skills/design/data/design-tokens/ibm/design.resolver.json +20 -0
  131. package/data/harnesses/code/skills/design/data/design-tokens/ibm/design.tokens.json +978 -0
  132. package/data/harnesses/code/skills/design/data/design-tokens/intercom/design.resolver.json +20 -0
  133. package/data/harnesses/code/skills/design/data/design-tokens/intercom/design.tokens.json +982 -0
  134. package/data/harnesses/code/skills/design/data/design-tokens/kraken/design.resolver.json +20 -0
  135. package/data/harnesses/code/skills/design/data/design-tokens/kraken/design.tokens.json +958 -0
  136. package/data/harnesses/code/skills/design/data/design-tokens/linear-app/design.resolver.json +23 -0
  137. package/data/harnesses/code/skills/design/data/design-tokens/linear-app/design.tokens.dark.json +589 -0
  138. package/data/harnesses/code/skills/design/data/design-tokens/linear-app/design.tokens.json +964 -0
  139. package/data/harnesses/code/skills/design/data/design-tokens/lovable/design.resolver.json +20 -0
  140. package/data/harnesses/code/skills/design/data/design-tokens/lovable/design.tokens.json +955 -0
  141. package/data/harnesses/code/skills/design/data/design-tokens/meta/design.resolver.json +20 -0
  142. package/data/harnesses/code/skills/design/data/design-tokens/meta/design.tokens.json +977 -0
  143. package/data/harnesses/code/skills/design/data/design-tokens/minimax/design.resolver.json +20 -0
  144. package/data/harnesses/code/skills/design/data/design-tokens/minimax/design.tokens.json +950 -0
  145. package/data/harnesses/code/skills/design/data/design-tokens/mintlify/design.resolver.json +20 -0
  146. package/data/harnesses/code/skills/design/data/design-tokens/mintlify/design.tokens.json +976 -0
  147. package/data/harnesses/code/skills/design/data/design-tokens/miro/design.resolver.json +20 -0
  148. package/data/harnesses/code/skills/design/data/design-tokens/miro/design.tokens.json +979 -0
  149. package/data/harnesses/code/skills/design/data/design-tokens/mistral-ai/design.resolver.json +20 -0
  150. package/data/harnesses/code/skills/design/data/design-tokens/mistral-ai/design.tokens.json +955 -0
  151. package/data/harnesses/code/skills/design/data/design-tokens/mongodb/design.resolver.json +20 -0
  152. package/data/harnesses/code/skills/design/data/design-tokens/mongodb/design.tokens.json +958 -0
  153. package/data/harnesses/code/skills/design/data/design-tokens/notion/design.resolver.json +20 -0
  154. package/data/harnesses/code/skills/design/data/design-tokens/notion/design.tokens.json +953 -0
  155. package/data/harnesses/code/skills/design/data/design-tokens/nurix/design.resolver.json +20 -0
  156. package/data/harnesses/code/skills/design/data/design-tokens/nurix/design.tokens.json +904 -0
  157. package/data/harnesses/code/skills/design/data/design-tokens/nvidia/design.resolver.json +20 -0
  158. package/data/harnesses/code/skills/design/data/design-tokens/nvidia/design.tokens.json +957 -0
  159. package/data/harnesses/code/skills/design/data/design-tokens/ollama/design.resolver.json +20 -0
  160. package/data/harnesses/code/skills/design/data/design-tokens/ollama/design.tokens.json +945 -0
  161. package/data/harnesses/code/skills/design/data/design-tokens/opencode-ai/design.resolver.json +20 -0
  162. package/data/harnesses/code/skills/design/data/design-tokens/opencode-ai/design.tokens.json +960 -0
  163. package/data/harnesses/code/skills/design/data/design-tokens/posthog/design.resolver.json +20 -0
  164. package/data/harnesses/code/skills/design/data/design-tokens/posthog/design.tokens.json +953 -0
  165. package/data/harnesses/code/skills/design/data/design-tokens/raycast/design.resolver.json +20 -0
  166. package/data/harnesses/code/skills/design/data/design-tokens/raycast/design.tokens.json +955 -0
  167. package/data/harnesses/code/skills/design/data/design-tokens/replicate/design.resolver.json +20 -0
  168. package/data/harnesses/code/skills/design/data/design-tokens/replicate/design.tokens.json +958 -0
  169. package/data/harnesses/code/skills/design/data/design-tokens/resend/design.resolver.json +23 -0
  170. package/data/harnesses/code/skills/design/data/design-tokens/resend/design.tokens.dark.json +613 -0
  171. package/data/harnesses/code/skills/design/data/design-tokens/resend/design.tokens.json +968 -0
  172. package/data/harnesses/code/skills/design/data/design-tokens/revolut/design.resolver.json +20 -0
  173. package/data/harnesses/code/skills/design/data/design-tokens/revolut/design.tokens.json +956 -0
  174. package/data/harnesses/code/skills/design/data/design-tokens/runwayml/design.resolver.json +20 -0
  175. package/data/harnesses/code/skills/design/data/design-tokens/runwayml/design.tokens.json +960 -0
  176. package/data/harnesses/code/skills/design/data/design-tokens/sanity/design.resolver.json +20 -0
  177. package/data/harnesses/code/skills/design/data/design-tokens/sanity/design.tokens.json +958 -0
  178. package/data/harnesses/code/skills/design/data/design-tokens/sentry/design.resolver.json +20 -0
  179. package/data/harnesses/code/skills/design/data/design-tokens/sentry/design.tokens.json +980 -0
  180. package/data/harnesses/code/skills/design/data/design-tokens/shopify/design.resolver.json +20 -0
  181. package/data/harnesses/code/skills/design/data/design-tokens/shopify/design.tokens.json +964 -0
  182. package/data/harnesses/code/skills/design/data/design-tokens/slack/design.resolver.json +20 -0
  183. package/data/harnesses/code/skills/design/data/design-tokens/slack/design.tokens.json +957 -0
  184. package/data/harnesses/code/skills/design/data/design-tokens/spacex/design.resolver.json +20 -0
  185. package/data/harnesses/code/skills/design/data/design-tokens/spacex/design.tokens.json +979 -0
  186. package/data/harnesses/code/skills/design/data/design-tokens/spotify/design.resolver.json +20 -0
  187. package/data/harnesses/code/skills/design/data/design-tokens/spotify/design.tokens.json +974 -0
  188. package/data/harnesses/code/skills/design/data/design-tokens/stripe/design.resolver.json +20 -0
  189. package/data/harnesses/code/skills/design/data/design-tokens/stripe/design.tokens.json +973 -0
  190. package/data/harnesses/code/skills/design/data/design-tokens/supabase/design.resolver.json +20 -0
  191. package/data/harnesses/code/skills/design/data/design-tokens/supabase/design.tokens.json +979 -0
  192. package/data/harnesses/code/skills/design/data/design-tokens/superhuman/design.resolver.json +20 -0
  193. package/data/harnesses/code/skills/design/data/design-tokens/superhuman/design.tokens.json +966 -0
  194. package/data/harnesses/code/skills/design/data/design-tokens/tesla/design.resolver.json +20 -0
  195. package/data/harnesses/code/skills/design/data/design-tokens/tesla/design.tokens.json +961 -0
  196. package/data/harnesses/code/skills/design/data/design-tokens/theverge/design.resolver.json +20 -0
  197. package/data/harnesses/code/skills/design/data/design-tokens/theverge/design.tokens.json +977 -0
  198. package/data/harnesses/code/skills/design/data/design-tokens/together-ai/design.resolver.json +20 -0
  199. package/data/harnesses/code/skills/design/data/design-tokens/together-ai/design.tokens.json +991 -0
  200. package/data/harnesses/code/skills/design/data/design-tokens/uber/design.resolver.json +20 -0
  201. package/data/harnesses/code/skills/design/data/design-tokens/uber/design.tokens.json +966 -0
  202. package/data/harnesses/code/skills/design/data/design-tokens/vercel/design.resolver.json +20 -0
  203. package/data/harnesses/code/skills/design/data/design-tokens/vercel/design.tokens.json +988 -0
  204. package/data/harnesses/code/skills/design/data/design-tokens/voltagent/design.resolver.json +23 -0
  205. package/data/harnesses/code/skills/design/data/design-tokens/voltagent/design.tokens.dark.json +602 -0
  206. package/data/harnesses/code/skills/design/data/design-tokens/voltagent/design.tokens.json +974 -0
  207. package/data/harnesses/code/skills/design/data/design-tokens/warp/design.resolver.json +20 -0
  208. package/data/harnesses/code/skills/design/data/design-tokens/warp/design.tokens.json +979 -0
  209. package/data/harnesses/code/skills/design/data/design-tokens/webflow/design.resolver.json +20 -0
  210. package/data/harnesses/code/skills/design/data/design-tokens/webflow/design.tokens.json +960 -0
  211. package/data/harnesses/code/skills/design/data/design-tokens/wired/design.resolver.json +20 -0
  212. package/data/harnesses/code/skills/design/data/design-tokens/wired/design.tokens.json +968 -0
  213. package/data/harnesses/code/skills/design/data/design-tokens/wise/design.resolver.json +20 -0
  214. package/data/harnesses/code/skills/design/data/design-tokens/wise/design.tokens.json +965 -0
  215. package/data/harnesses/code/skills/design/data/design-tokens/x-ai/design.resolver.json +20 -0
  216. package/data/harnesses/code/skills/design/data/design-tokens/x-ai/design.tokens.json +988 -0
  217. package/data/harnesses/code/skills/design/data/design-tokens/zapier/design.resolver.json +20 -0
  218. package/data/harnesses/code/skills/design/data/design-tokens/zapier/design.tokens.json +978 -0
  219. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/command-center.tsx +249 -0
  220. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/create-edit.tsx +249 -0
  221. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/dashboard.tsx +248 -0
  222. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/entity-detail.tsx +245 -0
  223. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/list-detail.tsx +223 -0
  224. package/data/harnesses/code/skills/design/data/operator-pack/exemplars/log-stream.tsx +249 -0
  225. package/data/harnesses/code/skills/design/data/operator-pack/fixtures.md +88 -0
  226. package/data/harnesses/code/skills/design/data/operator-pack/surface-catalog.md +132 -0
  227. package/data/harnesses/code/skills/design/data/operator-pack/trust-rubric.md +76 -0
  228. package/data/harnesses/code/skills/design/references/create.md +131 -0
  229. package/data/harnesses/code/skills/design/references/diagnosis.md +108 -0
  230. package/data/harnesses/code/skills/design/references/hard-rules.md +155 -0
  231. package/data/harnesses/code/skills/design/references/improve.md +87 -0
  232. package/data/harnesses/code/skills/design/references/interaction.md +77 -0
  233. package/data/harnesses/code/skills/design/references/introspect.md +100 -0
  234. package/data/harnesses/code/skills/design/references/lifecycle.md +73 -0
  235. package/data/harnesses/code/skills/design/references/personality.md +428 -0
  236. package/data/harnesses/code/skills/design/references/structure.md +138 -0
  237. package/data/harnesses/code/skills/design/scripts/convert-design-md.mjs +1032 -0
  238. package/data/harnesses/code/skills/design/scripts/derive-personality.mjs +1006 -0
  239. package/data/harnesses/code/skills/design/scripts/generate-fixtures.mjs +551 -0
  240. package/data/harnesses/code/skills/design/scripts/lib/checks.mjs +903 -0
  241. package/data/harnesses/code/skills/design/scripts/lib/golden.mjs +26 -0
  242. package/data/harnesses/code/skills/design/scripts/phase-gate.mjs +454 -0
  243. package/data/harnesses/code/skills/design/scripts/preship-sweep.mjs +267 -0
  244. package/data/harnesses/code/skills/design/scripts/render-rung.mjs +690 -0
  245. package/data/harnesses/code/skills/design/scripts/scaffold.mjs +552 -0
  246. package/data/harnesses/code/skills/design/scripts/self-integrity.mjs +600 -0
  247. package/data/harnesses/code/skills/design/scripts/snapshot-goldens.mjs +68 -0
  248. package/data/harnesses/code/skills/design/scripts/validate-combinations.mjs +314 -0
  249. package/data/harnesses/code/skills/documentation/SKILL.md +61 -17
  250. package/data/harnesses/code/skills/documentation/references/examples.md +41 -0
  251. package/data/harnesses/code/skills/documentation/references/style-guide.md +14 -9
  252. package/data/harnesses/code/skills/documentation/references/templates.md +305 -51
  253. package/data/harnesses/etna/CLAUDE.md +1 -1
  254. package/data/harnesses/etna/agents/brainstorm.md +1 -1
  255. package/data/harnesses/etna/agents/maintenance.md +2 -2
  256. package/data/harnesses/etna/harness.json +2 -2
  257. package/data/harnesses/etna/rules/general.md +2 -40
  258. package/data/harnesses/etna/rules/nomenclature.md +1 -8
  259. package/data/harnesses/etna/skills/brainstorm/README.md +1 -1
  260. package/data/harnesses/etna/skills/brainstorm/SKILL.md +1 -1
  261. package/data/harnesses/etna/skills/brainstorm/exit-artifacts.md +4 -4
  262. package/data/harnesses/etna/skills/brainstorm/templates/source-of-truth.md +3 -3
  263. package/data/harnesses/etna/skills/documentation/SKILL.md +61 -17
  264. package/data/harnesses/etna/skills/documentation/references/examples.md +41 -0
  265. package/data/harnesses/etna/skills/documentation/references/style-guide.md +14 -9
  266. package/data/harnesses/etna/skills/documentation/references/templates.md +305 -51
  267. package/data/harnesses/mobile/CLAUDE.md +1 -1
  268. package/data/harnesses/mobile/agents/brainstorm.md +1 -1
  269. package/data/harnesses/mobile/agents/maintenance.md +2 -2
  270. package/data/harnesses/mobile/harness.json +2 -2
  271. package/data/harnesses/mobile/rules/database.md +38 -0
  272. package/data/harnesses/mobile/rules/general.md +2 -40
  273. package/data/harnesses/mobile/rules/nomenclature.md +1 -8
  274. package/data/harnesses/mobile/rules/nustack.md +150 -0
  275. package/data/harnesses/mobile/skills/brainstorm/README.md +1 -1
  276. package/data/harnesses/mobile/skills/brainstorm/SKILL.md +1 -1
  277. package/data/harnesses/mobile/skills/brainstorm/exit-artifacts.md +4 -4
  278. package/data/harnesses/mobile/skills/brainstorm/templates/source-of-truth.md +3 -3
  279. package/data/harnesses/mobile/skills/documentation/SKILL.md +61 -17
  280. package/data/harnesses/mobile/skills/documentation/references/examples.md +41 -0
  281. package/data/harnesses/mobile/skills/documentation/references/style-guide.md +14 -9
  282. package/data/harnesses/mobile/skills/documentation/references/templates.md +305 -51
  283. package/package.json +1 -1
@@ -0,0 +1,428 @@
1
+ # Personality — the look pipeline
2
+
3
+ `design-tokens artifact → --check → --emit`. A look travels as a **design-tokens artifact** — three
4
+ DTCG JSON files whose grammar, payload, and resolution rules are the frozen transport schema,
5
+ [SCHEMA.md](../data/design-tokens/SCHEMA.md). [`derive-personality.mjs`](../scripts/derive-personality.mjs)
6
+ is the reference consumer: `--check` is the coverage gate that must pass before `--emit` writes
7
+ `personality.css`, `globals.css`, and the `<html>` attributes. The emitted files *are* the state —
8
+ no sidecar cache, no intermediate document. (The design.md format exists only as the library's
9
+ curated documentation corpus, `data/design-md/library/`; the machine path reads token files.)
10
+
11
+ The look comes entirely from the cascade. A surface composes in semantic tokens (`bg-card`,
12
+ `text-foreground`) and reads its personality from the CSS variables emission writes. Swap the
13
+ artifact, re-emit, and every surface re-skins with zero JSX edits — the invariant the exemplars are
14
+ validated against.
15
+
16
+ Every CSS and comment excerpt in this document is pasted from a real emission of the shipped Nurix
17
+ default (`data/design-tokens/nurix/`); gate transcripts are from real runs, with scratch paths
18
+ shown as `<artifact-dir>`.
19
+
20
+ ## 1. The pipeline — artifact in, CSS out
21
+
22
+ ```
23
+ design-tokens artifact ──▶ derive-personality.mjs --check ──▶ (green) ──▶ --emit <outdir>
24
+ design.tokens.json the coverage gate (rules 1–12): src/styles/personality.css
25
+ design.tokens.dark.json? 26 primitives + 2 dials + density tier src/styles/globals.css
26
+ design.resolver.json + 34 color roles + typography 3+6, index-html-attributes.txt
27
+ each assigned or hinted, or exit 1
28
+ ```
29
+
30
+ ```
31
+ derive-personality.mjs <artifact-dir> [--check | --emit <outdir>] [--theme light|dark]
32
+ ```
33
+
34
+ **The artifact.** Three files in one directory: `design.tokens.json` (the base set — primitives,
35
+ color roles, typography, and the file-level `$extensions["com.nurix.design"]` payload carrying
36
+ `product`, `provenance`, the dials, and the lever manifest), `design.tokens.dark.json` (only when
37
+ the look has dark values), and `design.resolver.json`. The script resolves them in the resolver's
38
+ deterministic order — concatenate the set files, overlay the selected theme context, resolve aliases
39
+ after overlay — then validates or emits. File shapes, `$type` grammar, and payload spec live in
40
+ [SCHEMA.md](../data/design-tokens/SCHEMA.md); this document covers what emission does with a
41
+ resolved artifact.
42
+
43
+ **`--check` never best-efforts.** It runs the schema's rules 1–12 and exits non-zero naming every
44
+ offending path, so the fix is mechanical; the `tokens` phase gate (and the verify/pre-ship sweeps)
45
+ stay shut until it is green. Over the shipped default, from the skill root,
46
+ `node scripts/derive-personality.mjs data/design-tokens/nurix --check` prints:
47
+
48
+ ```
49
+ check PASSED (data/design-tokens/nurix): rules 1–11 OK — 26 primitives, 34 color roles, typography 3+6, payload/manifest/parse-back OK — provenance=default, style=nurix, theme=light
50
+ ```
51
+
52
+ Rule 12 (the emission precondition) is enforced at emit time; `--check` surfaces it as the
53
+ outstanding-hint count (§3). A failing artifact names its gaps — this run is against a scratch copy
54
+ of the default with one color token deleted:
55
+
56
+ ```
57
+ check FAILED (<artifact-dir>): 1 issue(s)
58
+ - rule 4 — color.warning: missing
59
+ ```
60
+
61
+ **`--emit <outdir>`** runs only over a passing artifact and refuses while any token carries a hint
62
+ (§3). It writes three files: `<outdir>/src/styles/personality.css`, `<outdir>/src/styles/globals.css`,
63
+ and `<outdir>/index-html-attributes.txt` — the attribute set the project's `index.html` `<html>` tag
64
+ must carry. In real use `<outdir>` is the project root.
65
+
66
+ ### The emitted header is the cache record
67
+
68
+ There is no sidecar state file. The header comment of the emitted `personality.css` carries the
69
+ active personality — dials, theme, and the artifact citation with its provenance — and the `<html>`
70
+ attributes carry the same state in markup:
71
+
72
+ ```css
73
+ /* src/styles/personality.css — operator-UI personality tokens (emitted; do not hand-edit).
74
+ *
75
+ * Active personality — code is the cache. These values and the <html data-*>
76
+ * attributes in index.html are emitted from the design-tokens artifact. To change
77
+ * the look, edit design.tokens.json and re-run derive-personality.mjs --emit.
78
+ * style: nurix (<html data-style="nurix">) — the project's own personality (rosterless)
79
+ * density: standard (<html data-density="standard">)
80
+ * verbosity: default (<html data-verbosity="default">)
81
+ * feedback: subtle (<html data-feedback="subtle">)
82
+ * theme: light (<html data-theme="light">) — light is the default; dark is opt-in
83
+ * artifact: design.tokens.json (resolved via design.resolver.json) — provenance: default, sourced 2026-07-04
84
+ *
85
+ * Semantic-token doctrine: components name purpose (bg-card, text-foreground, border-border);
86
+ * this file resolves those names to values. Components never use dark: prefixes or literal colors.
87
+ */
88
+ ```
89
+
90
+ Recovery therefore reads two things: the token artifact (the source) and the emitted attributes
91
+ (the active state). `index-html-attributes.txt` from the same run:
92
+
93
+ ```html
94
+ <!-- Personality state lives in these <html data-*> attributes — code is the cache.
95
+ The design-tokens artifact is the source. To change the look, edit design.tokens.json
96
+ and re-run derive-personality.mjs --emit; to nudge one axis, edit an attribute here. -->
97
+ <html
98
+ lang="en"
99
+ data-style="nurix"
100
+ data-density="standard"
101
+ data-verbosity="default"
102
+ data-feedback="subtle"
103
+ data-theme="light"
104
+ >
105
+ ```
106
+
107
+ ## 2. Derivation — token paths to emitted CSS variables
108
+
109
+ Leaf names are law: a `primitive.*` or `color.*` token maps 1:1 to the CSS variable of the same
110
+ name, without the leading `--`.
111
+
112
+ | Artifact source | Emitted target | Rule |
113
+ | --- | --- | --- |
114
+ | `primitive.<name>` (24 static) | `[data-style="<slug>"] { --<name>: … }` | 1:1 by leaf name |
115
+ | `primitive.density-gap` / `density-inset` | governed refs `var(--density-base-gap/inset)` in `[data-style]` | the density tier writes the base (§4) |
116
+ | `color.<name>` (34) | `:root, :root[data-theme="light"] { --<name>: … }` | 1:1 by leaf name |
117
+ | dark set `color.<name>` | `[data-theme="dark"] { --<name>: … }` | only when the dark file ships (§5) |
118
+ | payload `product` | `<html data-style="<slug>">` | slugified (lowercase, non-alphanumeric runs → `-`) |
119
+ | payload `verbosity` / `feedback` / `density-tier` | `<html data-verbosity / data-feedback / data-density>` | dial → attribute |
120
+ | payload `product-traits` | read by the front gate; **not** emitted to CSS | — |
121
+ | `primitive.font-sans` / `font-mono`, `font-weight-normal` | `[data-style]` **and** literals in `@theme inline` | §4, two-weight discipline / no self-reference |
122
+ | `typography.family.*` / `typography.ramp.*` | data for emitters and exemplars | reaches CSS only through the primitives it aliases |
123
+ | — (derived at emit) | `--ease-enter`, `--ease-exit`, `--stagger-delay` | computed from `ease-default` + `duration-unit` |
124
+
125
+ **The preserved-css rule.** For every emitted value the emitters prefer the token's
126
+ `$extensions["com.nurix.design"].css` — the exact source string — so output is byte-stable across
127
+ convert/emit round trips (an aliased token takes its target's `.css`). Absent `.css`, the schema's
128
+ deterministic serialization applies: `dimension`/`duration` as `<value><unit>`; `number`/`fontWeight`
129
+ as the plain number; `cubicBezier` as `cubic-bezier(x1, y1, x2, y2)`; `fontFamily` as the families
130
+ joined with `", "`, multi-word names double-quoted; `color` as the `hex` field when srgb, else
131
+ `oklch(…)`. The parse-back check (rule 9) guarantees the two forms agree before anything is emitted.
132
+
133
+ **Derived, never stored.** Three temporal variables are computed at emit from `ease-default` and
134
+ `duration-unit` — they are not tokens, not authored, and not gated (do not add them to an artifact):
135
+
136
+ - `--ease-exit: var(--ease-default)` — departure mirrors the neutral curve.
137
+ - `--ease-enter` — the emphasized-decelerate arrival curve `cubic-bezier(0.16, 1, 0.3, 1)` (fast
138
+ in, settles clean); `ease-default` is reused verbatim when it is already a decelerate curve
139
+ (y1 ≥ 0.9).
140
+ - `--stagger-delay` — `duration-unit × 0.15`, rounded, clamped 0–40ms; a snappier tempo staggers
141
+ less.
142
+
143
+ Emitted into the `[data-style]` block, directly after `ease-default`:
144
+
145
+ ```css
146
+ --ease-default: cubic-bezier(0.4,0,0.2,1);
147
+ --ease-enter: cubic-bezier(0.16, 1, 0.3, 1); /* derived from ease-default */
148
+ --ease-exit: var(--ease-default); /* derived: departure mirrors the neutral curve */
149
+ --stagger-delay: 8ms; /* derived: duration-unit × 0.15, clamped 0–40ms */
150
+ ```
151
+
152
+ **Dial semantics.** The payload's two behavioral dials become `<html>` attributes, and
153
+ `personality.css` carries one block per dial value setting the behavioral variables the lifecycle
154
+ and interaction layers read:
155
+
156
+ ```css
157
+ /* ── Behavioral dials (D4) — orthogonal to the visual primitives. ── */
158
+ [data-verbosity="full"] { --label-display: inline-flex; --helper-text-display: block; --tooltip-delay: 800ms; }
159
+ [data-verbosity="default"] { --label-display: inline-flex; --helper-text-display: block; --tooltip-delay: 500ms; }
160
+ [data-verbosity="compact"] { --label-display: none; --helper-text-display: none; --tooltip-delay: 200ms; }
161
+ [data-verbosity="expert"] { --label-display: none; --helper-text-display: none; --tooltip-delay: 0ms; }
162
+
163
+ [data-feedback="subtle"] { --feedback-press-scale: 0.99; --focus-ring-width: 2px; --focus-ring-offset: 1px; }
164
+ [data-feedback="minimal"] { --feedback-press-scale: 1; --focus-ring-width: 1px; --focus-ring-offset: 0px; }
165
+ ```
166
+
167
+ - `--label-display` / `--helper-text-display` — `compact`/`expert` verbosity collapse form labels
168
+ and helper text; `full`/`default` keep them. Field chrome reads these, not a JS branch.
169
+ - `--tooltip-delay` — tightens with verbosity (`800ms → 0ms`).
170
+ - `--feedback-press-scale`, `--focus-ring-width`, `--focus-ring-offset` — `minimal` feedback
171
+ flattens the press and thins the focus ring; `subtle` keeps the operator-default ring.
172
+
173
+ The lifecycle pattern ([lifecycle.md](./lifecycle.md)) consumes the dials directly — empty-state
174
+ richness scales with verbosity, confirmation depth rides feedback; focus and overlay discipline read
175
+ the ring variables ([interaction.md](./interaction.md)). A component that must branch structurally
176
+ on a dial reads the `<html>` attribute — it never duplicates the state. Density (`data-density`) is
177
+ spatial chrome, not behavior — it composes with the dials, never replaces them (§4).
178
+
179
+ ## 3. Hints — provisional values that pass the gate but block emission
180
+
181
+ Where a value needs judgment, the token carries a **valid provisional `$value`** plus
182
+ `$extensions["com.nurix.design"].hint` — the intent in plain words (the full convention, with the
183
+ JSON shape, is SCHEMA.md's hint section; payload fields are always concrete — hints exist only on
184
+ tokens). Every gated token is in exactly one state:
185
+
186
+ | State | Marker | `--check` | `--emit` |
187
+ | --- | --- | --- | --- |
188
+ | **assigned** | real value, no `hint` key | passes | emits |
189
+ | **hinted** | `hint` key present | passes | **refuses**, naming every hinted path |
190
+ | **missing** | token absent | fails, naming the key | — |
191
+
192
+ A hinted artifact is checkable — the pass line counts the outstanding hints (this run: a scratch
193
+ copy of the default with a hint added to `primitive.contrast-boost`):
194
+
195
+ ```
196
+ check PASSED (<artifact-dir>): rules 1–11 OK — 26 primitives, 34 color roles, typography 3+6, payload/manifest/parse-back OK — provenance=default, style=nurix, theme=light, 1 hint(s) outstanding (emit will refuse)
197
+ ```
198
+
199
+ — but not emittable. `--emit` over the same artifact:
200
+
201
+ ```
202
+ emit REFUSED (<artifact-dir>): 1 unresolved hint(s) — rule 12: every gated token must be concrete before emission.
203
+ - primitive.contrast-boost: hint: nudge borders up a step so the dense table grid reads as a grid
204
+ Resolve each with judgment: set the real $value, delete the hint key, record the rationale in $description — then re-run --emit.
205
+ ```
206
+
207
+ Resolving a hint is exactly that three-step: set the real `$value`, delete the `hint` key, record
208
+ the rationale in the token's `$description` — so the resolved artifact stays self-explaining and
209
+ re-derivable. Judgment is recorded, never silent.
210
+
211
+ ## 4. The substrate contracts — living with `@nurix/components`
212
+
213
+ `@nurix/components/dist/styles.css` ships its own bare-`:root` token defaults and its own `@theme`
214
+ radius scale. Two cascade contracts keep the personality in charge; both are hardened with the
215
+ emitted in-CSS comments below and enforced by the code-and-token rules (`cod-*`) in
216
+ [hard-rules.md](./hard-rules.md). The library's actual consumption is enumerated in
217
+ [the substrate audit](../../../docs/brainstorm/design/u1-audit-report.md).
218
+
219
+ **CASCADE CONTRACT 1 — the specificity/attribute pair.** The color tokens are emitted under a
220
+ doubled selector, and `<html>` must carry `data-theme="light"`:
221
+
222
+ ```css
223
+ /* ── Semantic + substrate color tokens — light theme. ──
224
+ * CASCADE CONTRACT 1: the doubled selector out-specifies the library's bare
225
+ * :root defaults in @nurix/components/styles.css — but ONLY because <html> carries
226
+ * data-theme="light". A bare :root here loses to the later library import. All 34
227
+ * tokens are set (D6): no consumed token falls back to a shadcn-gray default. */
228
+ :root,
229
+ :root[data-theme="light"] {
230
+ ```
231
+
232
+ *Failure mode:* a bare `:root { --background: … }` is specificity `(0,1,0)` — the library's own
233
+ `:root { --background: … }` is also `(0,1,0)` and imported *later*, so it wins and every surface
234
+ silently reverts to shadcn gray. The `:root[data-theme="light"]` arm is `(0,2,0)` and out-wins — but
235
+ only if `data-theme="light"` is actually on `<html>`; drop the attribute and the arm never matches,
236
+ leaving only the losing bare `:root`. Both halves are load-bearing together.
237
+
238
+ **CASCADE CONTRACT 2 — the four-step import order.** The emitted `globals.css` opens:
239
+
240
+ ```css
241
+ /* src/styles/globals.css — Tailwind v4 glue + @theme inline mappings (emitted). */
242
+
243
+ /* CASCADE CONTRACT 2: this four-step order is LOAD-BEARING. The library's
244
+ * styles.css ships its own :root token defaults and its own @theme radius scale;
245
+ * our @theme MUST come AFTER the import to win the radius scale and own every
246
+ * mapping. rules/frontend.md states the same order — co-authority. */
247
+ @import "./personality.css"; /* 1. token source (must be first) */
248
+ @import "tailwindcss"; /* 2. framework */
249
+ @import "@nurix/components/styles.css"; /* 3. library (before our @theme) */
250
+
251
+ @theme inline { /* 4. consumer theme — AFTER the library, so it wins */
252
+ ```
253
+
254
+ *Failure mode:* put `@theme inline` (or the whole consumer theme) *before* the library import and
255
+ the library's own `@theme` radius scale (`--radius-lg: var(--radius)`, its own offsets) comes later
256
+ and wins — the personality `--radius` stops driving the scale and archetype radius switching breaks.
257
+ `rules/frontend.md` states this same order — co-authority, not a restatement to
258
+ drift from. `@theme inline` inlines each value into the generated utilities (so `bg-card` compiles
259
+ to `background-color: var(--card)`).
260
+
261
+ **The gray-fallback trap — all 34 roles, always.** Beyond the 15 semantic color tokens it maps
262
+ (888 semantic-token class uses), the library consumes **16 more shadcn tokens** — `--popover(-foreground)`,
263
+ `--secondary(-foreground)`, `--chart-1..5`, and the `--sidebar` family — that silently fall back to
264
+ the shadcn-gray defaults inside `dist/styles.css` when unset: popovers, menus, secondary buttons,
265
+ sidebars, and charts render visibly off-palette next to personality surfaces. The artifact's
266
+ substrate group carries 17 roles covering them, and emission sets all 34 color roles every time.
267
+ `--color-destructive-foreground` is mapped explicitly in `@theme` because the library leaves it
268
+ unmapped.
269
+
270
+ **Coverage — every token the library consumes is emitted.**
271
+
272
+ | Library consumes | How | Emitted at |
273
+ | --- | --- | --- |
274
+ | `--radius` (283 `rounded-*`) | direct primitive + `@theme` radius scale | `[data-style]` · `@theme` |
275
+ | shadow (`shadow-xs/sm/md/lg`, 58) | `--shadow-*` alpha rides `--shadow-intensity` | `@theme` |
276
+ | font weight (`font-medium/semibold/bold/normal`, 139) | two-weight map to `--font-weight-strong` | `@theme` |
277
+ | tracking (`tracking-*`, 13) | `--tracking-tight/tighter → --heading-tracking` | `@theme` |
278
+ | spacing (all `p-*`/`gap-*`) | `--spacing` density remap | `@theme` |
279
+ | `font-mono` (9) / `font-sans` | literal font stacks | `@theme` |
280
+ | 15 semantic colors (888 uses) | direct token values | `:root[data-theme=light]` |
281
+ | `--success`, `--warning` | direct token values (library ignores today — upstream gaps) | `:root[data-theme=light]` |
282
+ | `--destructive-foreground` (unmapped by library) | explicit `--color-destructive-foreground` map | `@theme` |
283
+ | 17 substrate (`popover`/`secondary`/`chart-1..5`/`sidebar` family) | direct token values | `:root[data-theme=light]` |
284
+ | `--sidebar-width` / `--sidebar-width-icon` | SidebarProvider `style` prop | shell (below) |
285
+
286
+ **Density — global tier composed with a per-surface relative step.** Two composed levels, pure
287
+ cascade, no JS. The payload's `density-tier` becomes `data-density` on `<html>`, and the emitted
288
+ blocks write only the **base** multipliers; a surface carries `data-density-step` (from its
289
+ surface-catalog `density-modifier`, [surface-catalog.md](../data/operator-pack/surface-catalog.md),
290
+ emitted by `scaffold.mjs`) and re-derives one relative step off whatever tier the app runs:
291
+
292
+ ```css
293
+ /* ── Density: global tier → base multipliers (D31). ──
294
+ * The tier writes ONLY the base; --density-gap/inset resolve from it (above),
295
+ * so a per-surface step can re-derive relative to the tier. */
296
+ [data-density="dense"] { --density-base-gap: 0.85; --density-base-inset: 0.85; }
297
+ [data-density="standard"] { --density-base-gap: 1; --density-base-inset: 1; }
298
+ [data-density="spacious"] { --density-base-gap: 1.15; --density-base-inset: 1.15; }
299
+
300
+ /* ── Per-archetype density modifier (D31) — relative step on the tier, pure cascade, no JS. ──
301
+ * A surface element carries data-density-step; it re-derives one step off the
302
+ * inherited base. Reads --density-base-* (never itself) so it composes with the
303
+ * tier and never absolutely overrides it. The recomputed --density-gap flows into
304
+ * the library's p-*/gap-* through the @theme --spacing remap. */
305
+ [data-density-step="tighter"] { --density-gap: calc(var(--density-base-gap) * 0.85); --density-inset: calc(var(--density-base-inset) * 0.85); }
306
+ [data-density-step="looser"] { --density-gap: calc(var(--density-base-gap) * 1.15); --density-inset: calc(var(--density-base-inset) * 1.15); }
307
+ ```
308
+
309
+ A log-stream inside a `standard` app resolves one step denser without pinning an absolute value.
310
+ Both levels reach the library's internals through one `@theme` line — every library `p-*`/`gap-*`
311
+ is `calc(var(--spacing) × N)`, and `--density-gap` resolves per element (respecting a
312
+ `data-density-step` ancestor):
313
+
314
+ ```css
315
+ /* density remap — the single line that scales ALL library spacing. Every p-*/gap-*
316
+ * is calc(var(--spacing) × N); driving --spacing off --density-gap flows the tier
317
+ * AND the per-surface density step into the library's internals. */
318
+ --spacing: calc(0.25rem * var(--density-gap));
319
+ ```
320
+
321
+ **The two-weight discipline.** Operator UI carries exactly two font weights; the `@theme` map folds
322
+ the library's whole weight vocabulary onto them:
323
+
324
+ ```css
325
+ /* font weight — two-weight discipline: medium/semibold/bold all resolve to the
326
+ * single emphasis weight; operator UI carries no third weight. normal is emitted
327
+ * as a literal because its theme key and the primitive share a name (no self-ref). */
328
+ --font-weight-normal: 400;
329
+ --font-weight-medium: var(--font-weight-strong);
330
+ --font-weight-semibold: var(--font-weight-strong);
331
+ --font-weight-bold: var(--font-weight-strong);
332
+ ```
333
+
334
+ Fonts follow the same no-self-reference rule: `--font-sans`/`--font-mono` are emitted into `@theme`
335
+ as literal stacks (a font is not a runtime-toggled token, and the theme key shares the primitive's
336
+ name), while `personality.css` carries the same variables for direct `var()` use.
337
+
338
+ **Sidebar width — the style-prop seam.** The library hardcodes `--sidebar-width` /
339
+ `--sidebar-width-icon` as inline styles, overridable only via the provider's `style` prop — the one
340
+ layout primitive that cannot reach the library through `@theme`. The shell wires the personality
341
+ primitives in:
342
+
343
+ ```tsx
344
+ <SidebarProvider
345
+ style={{
346
+ "--sidebar-width": "var(--sidebar-width-expanded)",
347
+ "--sidebar-width-icon": "var(--sidebar-width-collapsed)",
348
+ } as React.CSSProperties}
349
+ >
350
+ ```
351
+
352
+ **Upstream gaps — expected, never worked around.** Some values live in `@nurix/components` JS, not
353
+ CSS, so they do not follow tokens until the library adopts them. This is user-owned upstream work —
354
+ never patched with brittle per-instance overrides:
355
+
356
+ - **Chart palettes** — the d3 family hardcodes oklch/hex and ignores `--chart-1..5`; color props are
357
+ per-instance overridable, but the defaults are upstream. Emit `--chart-1..5` regardless, so
358
+ adoption is a drop-in.
359
+ - **Status literals** — `changes-list` and `statistics` hardcode emerald/amber/sky rather than
360
+ `--success`/`--warning`.
361
+ - **Motion & icon stroke** — `duration: .2/.3` and `strokeWidth: 2/1.75` are JS numbers;
362
+ `--duration-*` and `--icon-stroke` reach consumer-emitted markup but not library internals.
363
+ - **Filled-control foreground** — `text-white` pinned on filled primary/destructive; the mapped
364
+ `--destructive-foreground` waits on the library reading it.
365
+
366
+ The stance: emit the complete token surface so the library "just works" the moment it adopts each
367
+ token; do not build an override layer that fights the library and rots.
368
+
369
+ ## 5. Dark and themes — the base set is light
370
+
371
+ The base token set **is** the light rendering — light is never omitted, and the resolver's `light`
372
+ context is always the empty overlay. A look with dark values ships `design.tokens.dark.json` —
373
+ exactly the `color` group, all 34 roles, nothing else — named by the resolver's `dark` context and
374
+ overlaid per the resolution order. When it ships, emission adds a `[data-theme="dark"]` block
375
+ remapping all 34 roles:
376
+
377
+ ```css
378
+ /* ── Dark theme — OPT-IN ONLY (this look ships a dark overlay). ──
379
+ * design.tokens.dark.json remaps all 34 color tokens; <html data-theme="dark">
380
+ * opts in. Light stays the default. */
381
+ [data-theme="dark"] {
382
+ ```
383
+
384
+ For a light-only artifact (the shipped default is one), the emitted file carries a placeholder
385
+ comment instead:
386
+
387
+ ```css
388
+ /* ── Dark theme — OPT-IN ONLY. ──
389
+ * Emitted only when the artifact ships a design.tokens.dark.json dark overlay.
390
+ * Light stays the default; this block never appears for a light-only project.
391
+ [data-theme="dark"] {
392
+ --background: ...; --foreground: ...; ... all 34 tokens remapped ...
393
+ } */
394
+ ```
395
+
396
+ `--theme dark` selects the dark context and sets `<html data-theme="dark">` in the emitted
397
+ attributes (the header's `theme:` line follows). The default is `light`; requesting dark from a
398
+ light-only artifact fails cleanly —
399
+ `node scripts/derive-personality.mjs data/design-tokens/nurix --check --theme dark` prints:
400
+
401
+ ```
402
+ check FAILED (data/design-tokens/nurix): 1 issue(s)
403
+ - rule 1 — resolver: --theme dark requested but the resolver carries no dark context
404
+ ```
405
+
406
+ The library's `dark:` utilities are class-based; a dark-shipping project redefines the variant to
407
+ follow the attribute. `globals.css` carries the instruction as a comment, enabled only when dark
408
+ ships:
409
+
410
+ ```css
411
+ /* dark variant — emitted ONLY when the project ships dark; redefines the library's
412
+ * class-based dark to follow data-theme so the library's dark: utilities honor our
413
+ * convention. Absent for a light-only project.
414
+ @custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *)); */
415
+ ```
416
+
417
+ Components never use `dark:` prefixes or literal colors regardless — the semantic tokens remap and
418
+ every surface follows (the semantic-token doctrine in the emitted header).
419
+
420
+ ## 6. Precedence and provenance — which artifact gets emitted
421
+
422
+ Look resolution is project-first: a `project` or `extracted` artifact wins outright; a `library`
423
+ entry serves only when the brief names or resembles the product and the user confirms; the Nurix
424
+ default (`data/design-tokens/nurix/`) is worn when nothing else speaks. The origin is the payload's
425
+ `provenance` field, and the emitted header's `artifact:` line records it alongside the `sourced`
426
+ date — so the emitted CSS always says where its look came from. The full precedence table, payload
427
+ spec, and per-value provenance convention (`$description`) are
428
+ [SCHEMA.md](../data/design-tokens/SCHEMA.md).
@@ -0,0 +1,138 @@
1
+ # Structure derivation
2
+
3
+ The second create phase. Runs after intake, before scaffold. Two steps, in order: the **object pass**, then **archetype assignment**. The output is one small, durable file — `docs/design/structure.md` — that every later phase reads and `scaffold.mjs` consumes.
4
+
5
+ The pass is never skipped. A small brief earns a proportionally small pass — a two-entity brief gets a two-entity map — but it always runs. Skipping straight to layout is the characteristic structural failure: screens that look plausible and model the domain wrongly. The structure phase gate requires a populated map before scaffold opens; an empty pass fails it.
6
+
7
+ ## The object pass
8
+
9
+ Extract the domain model from the brief. Record, per the map schema below:
10
+
11
+ - **Entities** — the nouns the operator works with (Ticket, Customer, Agent, Device). Extract what the brief and its domain support; do not fabricate entities the domain lacks, and do not promote an attribute to an entity.
12
+ - **Attributes** — the fields each entity carries.
13
+ - **Relationships and cardinalities** — how entities connect, recorded as `{to, cardinality}` (`one-to-one`, `one-to-many`, `many-to-one`, `many-to-many`).
14
+ - **Lifecycle states** — the ordered states an entity moves through (new → open → pending → resolved → closed). Omit for stateless entities.
15
+ - **Unit of work** — the one entity the operator's day turns on (the ticket, the case, the job). It anchors the home surface.
16
+ - **Core loop** — the verb sequence the operator runs on the unit of work (triage → assign → work → resolve → close).
17
+
18
+ Two modeling traps, both fatal to structure:
19
+
20
+ - **Metrics are not entities.** CAC, open-ticket-count, and p95-latency are instances of one Metric object, not entity rows. They render on a dashboard; they never earn their own list surface.
21
+ - **One entity, one home.** An entity's data and actions gather on one surface, cross-linked from everywhere else — never scattered across screens.
22
+
23
+ ## The temporal probe
24
+
25
+ Runs inside the object pass — temporal semantics are model facts, not styling facts, and the brief states none of them. Probe five questions:
26
+
27
+ - **Intermediate states** — does an action pass through pending / saving / processing / awaiting-approval before its terminal state?
28
+ - **Read-model lag** — is there delay between write and read visibility? Where yes, staleness is marked honestly downstream.
29
+ - **Deletion semantics** — archive, trash, hard delete, or regulatory retention? Each is a different surface and a different affordance.
30
+ - **History** — is prior state auditable or required? Its answer surfaces as a model fact — a History/audit entity, a timeline, or a versioned attribute.
31
+ - **Failure paths** — validation, server error, disconnection, concurrent edit.
32
+
33
+ Four answers land in the map's `temporal` block (`intermediate-states`, `read-model-lag`, `deletion`, `failure-paths`); history's answer lands wherever the model puts it (an entity, an attribute, a surface). The probe is what makes the lifecycle phase's states bindable — the tool spends most of its life in states the brief never mentions.
34
+
35
+ ## Archetype assignment
36
+
37
+ Each entity and workflow claims surfaces from the closed six-archetype catalog. `data/operator-pack/surface-catalog.md` is canonical for the choosing rules, the per-archetype density modifier, and the exemplar pointer; the assignment reads them. Orientation:
38
+
39
+ | archetype | claimed when |
40
+ | --- | --- |
41
+ | `list-detail` | a high-cardinality collection worked one item at a time — the unit of work's home |
42
+ | `dashboard` | a read-first overview answering a few standing questions across entities (Metric instances) |
43
+ | `entity-detail` | one rich entity's attributes, relationships, and actions gathered on a single surface |
44
+ | `create-edit` | minting or editing one entity — a stepper that mirrors edit; templates prefill |
45
+ | `log-stream` | append-only, high-volume, time-ordered events — read and filter, rarely edit |
46
+ | `command-center` | a live multi-pane monitor over several entities at once, with drill-down |
47
+
48
+ Membership is closed. New archetypes enter only as pack data, ledger-recorded — never invented per run.
49
+
50
+ **Navigation derives from the object model, never decorated on.** Top-level nav entries are the primary entities and their home surfaces; secondary entities are reached through their parent's detail surface, not promoted. The unit of work is the home. Cap top-level entries at what stays countable on one hand — nav categories the model does not carry are a structural defect, not a convenience.
51
+
52
+ ## The map: `docs/design/structure.md`
53
+
54
+ The derivation's whole output. Human prose above the block; the fenced `yaml structure` block is the machine contract — `scaffold.mjs` reads it, so the field names are law. Scaffold generates routes, navigation wiring, and per-surface state-shell stubs from `surfaces[]`, and keys fixture wiring off `entities[]`.
55
+
56
+ ```yaml structure
57
+ unit-of-work: <entity>
58
+ core-loop: <verb → verb → verb>
59
+ entities:
60
+ - name: <Entity>
61
+ attributes: [<field>, ...]
62
+ lifecycle: [<state>, ...] # omit for stateless entities
63
+ relationships:
64
+ - { to: <Entity>, cardinality: one-to-one | one-to-many | many-to-one | many-to-many }
65
+ temporal:
66
+ intermediate-states: [<state>, ...]
67
+ read-model-lag: <none | description>
68
+ deletion: <archive | trash | hard | retained>
69
+ failure-paths: [validation, server-error, disconnection, concurrent-edit, ...]
70
+ surfaces:
71
+ - name: <Surface>
72
+ archetype: list-detail | dashboard | entity-detail | create-edit | log-stream | command-center
73
+ route: /<path>
74
+ entity: <Entity>
75
+ density-modifier: <integer step; positive = denser; mirrors the catalog's per-archetype modifier>
76
+ states: [loading, empty, error, partial] # applicable subset; data surfaces carry all four
77
+ ```
78
+
79
+ ## OOUX structural diagnostics
80
+
81
+ Four judged diagnostics for a wrong object model (after Sophia Prater's OOUX vocabulary). Run them over the map and over any UI under review; each is a one-line detection question:
82
+
83
+ - **Shapeshifter** — is one entity rendered inconsistently across surfaces? (Does a Ticket's status pill look different in the queue than in the detail?)
84
+ - **Masked** — is an entity hidden inside another's UI, with no surface of its own? (Is Customer only ever a string on a Ticket, never its own object?)
85
+ - **Broken** — is an entity's data or actions split across surfaces with no complete home? (Are a Device's config and its telemetry on two unrelated screens?)
86
+ - **Isolated** — is an entity unreachable from the navigation and from its relationships? (Can the operator reach an Agent from anywhere?)
87
+
88
+ These are judgment, not machine rules — no waiver, no score. A finding is raised, ranked, and fixed at the model layer, never patched at the surface.
89
+
90
+ ## Worked example — a ticket queue
91
+
92
+ Brief: *"A support ticket queue. Agents triage incoming tickets, assign them, work them to resolution, and close them. Tickets come from customers."*
93
+
94
+ ```yaml structure
95
+ unit-of-work: Ticket
96
+ core-loop: triage → assign → work → resolve → close
97
+ entities:
98
+ - name: Ticket
99
+ attributes: [subject, body, status, priority, channel, requester, assignee, created_at, updated_at]
100
+ lifecycle: [new, open, pending, resolved, closed]
101
+ relationships:
102
+ - { to: Customer, cardinality: many-to-one }
103
+ - { to: Agent, cardinality: many-to-one }
104
+ - name: Customer
105
+ attributes: [name, email, org]
106
+ relationships:
107
+ - { to: Ticket, cardinality: one-to-many }
108
+ - name: Agent
109
+ attributes: [name, email, role, availability]
110
+ relationships:
111
+ - { to: Ticket, cardinality: one-to-many }
112
+ temporal:
113
+ intermediate-states: [assigning, saving-reply, pending-customer]
114
+ read-model-lag: none # single-writer per ticket
115
+ deletion: archive # tickets are retained for audit, never hard-deleted
116
+ failure-paths: [validation, server-error, disconnection, concurrent-edit]
117
+ surfaces:
118
+ - name: Ticket Queue
119
+ archetype: list-detail
120
+ route: /tickets
121
+ entity: Ticket
122
+ density-modifier: 1
123
+ states: [loading, empty, error, partial]
124
+ - name: Ticket Detail
125
+ archetype: entity-detail
126
+ route: /tickets/:id
127
+ entity: Ticket
128
+ density-modifier: 0
129
+ states: [loading, empty, error, partial]
130
+ - name: New Ticket
131
+ archetype: create-edit
132
+ route: /tickets/new
133
+ entity: Ticket
134
+ density-modifier: -1
135
+ states: [loading, error]
136
+ ```
137
+
138
+ Navigation: top-level is **Tickets** — the unit of work's home. Customer and Agent are reached through Ticket Detail, not promoted to top-level nav (derived, not decorated). History — the audit of status changes and replies — surfaces as a timeline on the detail, not a fifth temporal key. OOUX pass: the status pill renders identically on queue and detail (no Shapeshifter), and Customer links out to its own detail rather than living only as a string (no Masked).