open-ux 0.1.1__tar.gz

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 (250) hide show
  1. open_ux-0.1.1/.gitignore +56 -0
  2. open_ux-0.1.1/LICENSE +21 -0
  3. open_ux-0.1.1/PKG-INFO +159 -0
  4. open_ux-0.1.1/README.md +137 -0
  5. open_ux-0.1.1/hatch_build.py +33 -0
  6. open_ux-0.1.1/hatch_metadata.py +40 -0
  7. open_ux-0.1.1/pyproject.toml +58 -0
  8. open_ux-0.1.1/src/open_ux/__init__.py +13 -0
  9. open_ux-0.1.1/src/open_ux/__main__.py +74 -0
  10. open_ux-0.1.1/src/open_ux/_version.py +24 -0
  11. open_ux-0.1.1/src/open_ux/audit.py +136 -0
  12. open_ux-0.1.1/src/open_ux/auth.py +191 -0
  13. open_ux-0.1.1/src/open_ux/catalog.py +646 -0
  14. open_ux-0.1.1/src/open_ux/data/catalog/MANIFEST.md +362 -0
  15. open_ux-0.1.1/src/open_ux/data/catalog/README.md +77 -0
  16. open_ux-0.1.1/src/open_ux/data/catalog/index.json +2605 -0
  17. open_ux-0.1.1/src/open_ux/data/catalog/jobs.json +1012 -0
  18. open_ux-0.1.1/src/open_ux/data/catalog/manifest.json +1592 -0
  19. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/ant/conversation-vs-navigation-order.json +32 -0
  20. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/ant/danger-cancel-primary-when-not-recommended.json +32 -0
  21. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/ant/footer-buttons-when-body-cannot-carry.json +32 -0
  22. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/ant/group-spacing-overflow-dropdown.json +32 -0
  23. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/ant/named-button-type-map.json +32 -0
  24. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/ant/never-two-icons-in-one-button.json +32 -0
  25. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/ant/ok-cancel-default-vs-explicit-verb.json +32 -0
  26. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/ant/one-cta-per-screen.json +32 -0
  27. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/ant/prefer-undo-or-popconfirm-over-modal.json +32 -0
  28. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/canada/supertask-once-never-promo.json +32 -0
  29. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/fluent/apply-versus-save-prefer-autosave.json +32 -0
  30. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/fluent/create-labels-new-thing.json +32 -0
  31. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/fluent/end-of-task-labels-named.json +32 -0
  32. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/fluent/ios-chrome-back-done-cancel.json +32 -0
  33. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/fluent/multistep-next-not-continue.json +32 -0
  34. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/fluent/split-button-dont-repeat-primary.json +32 -0
  35. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/gold/next-primary-save-progress-secondary.json +32 -0
  36. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/gold/visual-loudness-primary-secondary-tertiary.json +32 -0
  37. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/govuk/button-types-named.json +32 -0
  38. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/govuk/dont-use-disabled-buttons.json +32 -0
  39. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/govuk/stop-accidental-double-submit.json +32 -0
  40. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/mui/button-variant-roles.json +32 -0
  41. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/polar/encourage-action-cta-verb.json +32 -0
  42. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/suomi/button-max-three-words-mobile-full-width.json +32 -0
  43. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/tidwell/action_panel.json +31 -0
  44. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/tidwell/button_groups.json +31 -0
  45. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/tidwell/cancelability.json +31 -0
  46. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/tidwell/command_history.json +31 -0
  47. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/tidwell/hover_or_popup_tools.json +31 -0
  48. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/tidwell/macros.json +31 -0
  49. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/tidwell/multilevel_undo.json +31 -0
  50. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/tidwell/preview.json +31 -0
  51. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/tidwell/prominent_done_or_assumed_next.json +31 -0
  52. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/tidwell/smart_menu_items.json +31 -0
  53. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/uswds/filled-next-outline-this-page.json +32 -0
  54. open_ux-0.1.1/src/open_ux/data/catalog/rules/actions/uswds/real-button-with-type-space-vs-enter.json +32 -0
  55. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/canada/equivalent-content-both-official-languages.json +32 -0
  56. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/canada/find-understand-use-nonpriority-must-not-block.json +32 -0
  57. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/canada/four-writing-qualities.json +32 -0
  58. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/canada/intranet-destinations-labelled.json +32 -0
  59. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/canada/inverted-pyramid-no-welcome-filler.json +32 -0
  60. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/canada/lists-max-7-or-split.json +32 -0
  61. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/canada/must-need-may-might.json +32 -0
  62. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/canada/no-click-here-same-text-same-destination.json +32 -0
  63. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/canada/no-eg-ie-spell-out-and.json +32 -0
  64. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/canada/underline-links-only-no-italics-emphasis.json +32 -0
  65. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/canada/unique-title-one-h1-heading-every-200-words.json +32 -0
  66. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/canada/you-your-never-i-my.json +32 -0
  67. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/gold/no-abbr-expand-on-first-mention.json +32 -0
  68. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/nsw/100pct-stacked-show-absolute-totals.json +32 -0
  69. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/nsw/chart-anatomy-title-insight-table.json +32 -0
  70. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/nsw/chart-text-horizontal.json +32 -0
  71. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/nsw/charts-start-with-story.json +32 -0
  72. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/nsw/direct-labels-over-legends.json +32 -0
  73. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/nsw/established-colour-conventions.json +32 -0
  74. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/nsw/honest-baseline-bars-zero-or-truncation.json +32 -0
  75. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/nsw/lines-dash-fills-patterns.json +32 -0
  76. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/nsw/map-pan-from-centre-select-jumps-listing.json +32 -0
  77. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/nsw/maps-never-only-channel.json +32 -0
  78. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/nsw/no-tooltip-only-values.json +32 -0
  79. open_ux-0.1.1/src/open_ux/data/catalog/rules/content/nsw/white-canvas-single-colour-when-labelled.json +32 -0
  80. open_ux-0.1.1/src/open_ux/data/catalog/rules/copy/polar/dont-duplicate-content.json +32 -0
  81. open_ux-0.1.1/src/open_ux/data/catalog/rules/copy/polar/guide-dont-prescribe.json +32 -0
  82. open_ux-0.1.1/src/open_ux/data/catalog/rules/copy/polar/match-shopify-admin-voice.json +32 -0
  83. open_ux-0.1.1/src/open_ux/data/catalog/rules/copy/polar/plain-language-grade-7.json +32 -0
  84. open_ux-0.1.1/src/open_ux/data/catalog/rules/dialogs/mui/avoid-apologies-alarm-ambiguity-in-dialog-titles.json +32 -0
  85. open_ux-0.1.1/src/open_ux/data/catalog/rules/dialogs/mui/confirmation-cancel-discards.json +32 -0
  86. open_ux-0.1.1/src/open_ux/data/catalog/rules/dialogs/mui/most-alerts-dont-need-titles.json +32 -0
  87. open_ux-0.1.1/src/open_ux/data/catalog/rules/dialogs/mui/non-modal-dialogs-allowed.json +32 -0
  88. open_ux-0.1.1/src/open_ux/data/catalog/rules/dialogs/polar/dont-use-modals-for-complex-forms.json +32 -0
  89. open_ux-0.1.1/src/open_ux/data/catalog/rules/empty_failure/nl/name-next-organisational-steps.json +32 -0
  90. open_ux-0.1.1/src/open_ux/data/catalog/rules/empty_failure/nl/success-confirms-what-not-bounce-home.json +32 -0
  91. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/ant/dialog-feedback-only-important-actionable.json +32 -0
  92. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/ant/hover-detail-overlay-timing.json +32 -0
  93. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/ant/message-not-for-important-failures.json +32 -0
  94. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/spectrum/bundle-instead-of-spam-toasts.json +32 -0
  95. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/spectrum/dont-place-mobile-toasts-over-navigation.json +32 -0
  96. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/spectrum/one-toast-at-a-time.json +32 -0
  97. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/spectrum/toast-at-most-one-action.json +32 -0
  98. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/spectrum/toast-auto-dismiss-min-5s.json +32 -0
  99. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/spectrum/toast-no-redundant-dismiss.json +32 -0
  100. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/spectrum/toast-placement-geometry.json +32 -0
  101. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/spectrum/toast-sentence-case-generic-tone.json +32 -0
  102. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/spectrum/toast-vs-dialog.json +32 -0
  103. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/spectrum/toast-writing-formulas.json +32 -0
  104. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/spectrum/users-can-turn-off-alert-types.json +32 -0
  105. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/suomi/notification-first-load-not-post-action.json +32 -0
  106. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/suomi/toast-10s-hover-stick-then-float.json +32 -0
  107. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/uswds/alert-first-word-is-type.json +32 -0
  108. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/uswds/alerts-dont-blame-name-next-step.json +32 -0
  109. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/uswds/dont-hide-then-reveal-alerts.json +32 -0
  110. open_ux-0.1.1/src/open_ux/data/catalog/rules/feedback/uswds/site-alert-dont-stack-dont-panic.json +32 -0
  111. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/ant/checkbox-vs-switch.json +36 -0
  112. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/ant/dropdown-when-over-5-no-truncate.json +32 -0
  113. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/ant/editable-list-pattern-by-field-count.json +32 -0
  114. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/ant/form-in-modal-lifecycle.json +32 -0
  115. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/ant/inline-input-feedback-does-not-auto-dismiss.json +32 -0
  116. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/ant/input-overlay-click-outside-preserves.json +32 -0
  117. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/ant/label-left-default-vs-top.json +32 -0
  118. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/ant/no-multi-column-form-in-one-area.json +32 -0
  119. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/ant/radio-count-2-to-5.json +32 -0
  120. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/ant/settings-mode-and-grouping-thresholds.json +32 -0
  121. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/ant/slider-intensity-grade.json +32 -0
  122. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/canada/interactive-questions-max-7-same-place.json +32 -0
  123. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/fluent/disabled-field-label-stays-perceivable.json +32 -0
  124. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/fluent/helper-text-below.json +32 -0
  125. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/fluent/labels-top-aligned-by-default.json +32 -0
  126. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/fluent/validation-messages-brief-no-end-punctuation.json +32 -0
  127. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/gold/avoid-select-except-long-lists.json +32 -0
  128. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/gold/search-input-attributes.json +32 -0
  129. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/calendar-control-when.json +32 -0
  130. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/character-count-fieldset-legend.json +32 -0
  131. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/conditionally-reveal-related-question.json +32 -0
  132. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/date-input-only-memorable.json +32 -0
  133. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/dob-autocomplete-tokens.json +32 -0
  134. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/dont-assume-single-vs-multi-from-visuals.json +32 -0
  135. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/error-summary-plus-per-field.json +32 -0
  136. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/example-dates-unambiguous-order.json +32 -0
  137. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/file-upload-reuse-already-uploaded.json +32 -0
  138. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/four-date-types.json +32 -0
  139. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/item-hints-one-sentence.json +32 -0
  140. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/labels-sentence-case-no-colons-above.json +32 -0
  141. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/never-auto-tab-date-fields.json +32 -0
  142. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/question-pages-continue-back-no-sliders.json +32 -0
  143. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/radio-divider-or.json +32 -0
  144. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/radios-left-of-labels.json +32 -0
  145. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/select-last-resort.json +32 -0
  146. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/select-preselect-settings-not-questions.json +32 -0
  147. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/govuk/task-list-statuses.json +32 -0
  148. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/material/errors.replace_supporting_text.json +31 -0
  149. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/mui/dont-type-number.json +32 -0
  150. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/mui/explicit-id-for-label-helper.json +32 -0
  151. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/mui/helper-text-changes-field-height.json +32 -0
  152. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/nl/form-draft-links-new-tab-named-in-link.json +32 -0
  153. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/nl/header-search-placeholder-visible-search-control.json +32 -0
  154. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/nl/labels-contain-only-text.json +32 -0
  155. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/nl/long-legal-jargon-before-form-not-tooltip.json +32 -0
  156. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/nl/native-required-bubbles-not-error-ui.json +32 -0
  157. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/nl/no-min-max-length-names-places.json +32 -0
  158. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/nl/no-select-multiple.json +32 -0
  159. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/nl/privacy-terms-link-outside-label.json +32 -0
  160. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/nl/step-n-of-m-in-title-and-above-form.json +32 -0
  161. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/polar/default-option-selected-when-possible.json +32 -0
  162. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/polar/labels-1-3-words-sentence-case-i18n.json +32 -0
  163. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/polar/long-form-errors-banner-plus-inline.json +32 -0
  164. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/polar/select-4plus-choice-list-under-4.json +32 -0
  165. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/polar/validate-after-finished-interacting.json +32 -0
  166. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/spectrum/asterisk-is-icon-not-label-text.json +32 -0
  167. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/spectrum/error-icon-overrides-validation-icon.json +32 -0
  168. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/spectrum/min-width-1-5x-field-height.json +32 -0
  169. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/spectrum/mixed-values-en-dash.json +32 -0
  170. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/spectrum/picker-concise-items-full-value.json +32 -0
  171. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/spectrum/picker-ghost-text-placeholder.json +32 -0
  172. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/spectrum/picker-min-width-2x-height.json +32 -0
  173. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/spectrum/picker-mobile-tray-when-overwhelming.json +32 -0
  174. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/spectrum/picker-no-max-menu-height.json +32 -0
  175. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/spectrum/picker-readonly-only-if-selection.json +32 -0
  176. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/spectrum/quiet-vs-standard-background.json +32 -0
  177. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/spectrum/readonly-vs-disabled.json +32 -0
  178. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/spectrum/tab-into-field-selects-text.json +32 -0
  179. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/spectrum/validation-icon-when-format-valid.json +32 -0
  180. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/suomi/date-hint-ppkkvvvv-calendar-optional-focus-trap.json +32 -0
  181. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/suomi/errorsummary-link-text-equals-field-error.json +32 -0
  182. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/suomi/file-hint-and-datetime-fieldset.json +32 -0
  183. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/suomi/radio-extras-hidden-then-indented.json +32 -0
  184. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/suomi/search-hide-label-only-if-name-states-context.json +32 -0
  185. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/suomi/static-validation-on-submit-default.json +32 -0
  186. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/suomi/time-field-60px-hint-tmm-always-visible.json +32 -0
  187. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/tidwell/inputs.autocompletion.json +31 -0
  188. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/tidwell/inputs.dropdown_chooser.json +31 -0
  189. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/tidwell/inputs.fill_in_the_blanks.json +31 -0
  190. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/tidwell/inputs.good_defaults_smart_prefills.json +31 -0
  191. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/tidwell/inputs.list_builder.json +31 -0
  192. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/tidwell/inputs.password_strength_meter.json +31 -0
  193. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/tidwell/inputs.structured_format.json +31 -0
  194. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/uswds/character-count-brevity-or-legal.json +32 -0
  195. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/uswds/date-picker-when-weekday-always-type.json +32 -0
  196. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/uswds/dont-split-phone-ssn-card.json +32 -0
  197. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/uswds/forms-simple-vertical-stack.json +32 -0
  198. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/vercel/errors.focus_first_error.json +31 -0
  199. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/vercel/inputs.html_autocomplete_and_name.json +31 -0
  200. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/vercel/inputs.shared_hit_target_choice.json +31 -0
  201. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/vercel/labels.clickable.json +31 -0
  202. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/vercel/navigation.warn_unsaved.json +31 -0
  203. open_ux-0.1.1/src/open_ux/data/catalog/rules/forms/vercel/submit.enabled_until_request.json +31 -0
  204. open_ux-0.1.1/src/open_ux/data/catalog/rules/foundations/gold/consistent-not-uniform.json +32 -0
  205. open_ux-0.1.1/src/open_ux/data/catalog/rules/hit_targets/gold/card-one-inner-link-hit-area.json +32 -0
  206. open_ux-0.1.1/src/open_ux/data/catalog/rules/system_status/nl/dont-auto-dismiss-status-announce-complete.json +32 -0
  207. open_ux-0.1.1/src/open_ux/data/catalog/rules/trust/nsw/privacy-by-design-pia-security-day-one.json +32 -0
  208. open_ux-0.1.1/src/open_ux/data/catalog/rules/wayfinding/canada/doormats-max-9.json +32 -0
  209. open_ux-0.1.1/src/open_ux/data/catalog/rules/wayfinding/canada/no-separate-mobile-site.json +32 -0
  210. open_ux-0.1.1/src/open_ux/data/catalog/rules/wayfinding/gold/accordion-find-in-page-misses-collapsed.json +32 -0
  211. open_ux-0.1.1/src/open_ux/data/catalog/rules/wayfinding/gold/progress-indicator-out-of-order-returnable.json +32 -0
  212. open_ux-0.1.1/src/open_ux/data/catalog/rules/wayfinding/gold/search-placement-home-vs-results.json +32 -0
  213. open_ux-0.1.1/src/open_ux/data/catalog/rules/wayfinding/suomi/hide-breadcrumbs-on-mobile.json +32 -0
  214. open_ux-0.1.1/src/open_ux/data/catalog/rules/wayfinding/suomi/pagination-skip-link-to-listing.json +32 -0
  215. open_ux-0.1.1/src/open_ux/data/catalog/rules/wayfinding/uswds/banner-gov-mil-https-every-page.json +32 -0
  216. open_ux-0.1.1/src/open_ux/data/catalog/rules/wayfinding/uswds/homepage-search-box-not-link.json +32 -0
  217. open_ux-0.1.1/src/open_ux/data/catalog/rules/wayfinding/uswds/identifier-darker-than-footer.json +32 -0
  218. open_ux-0.1.1/src/open_ux/data/catalog/rules/wayfinding/uswds/identifier-required-links-not-footer-dup.json +32 -0
  219. open_ux-0.1.1/src/open_ux/data/catalog/schema.json +218 -0
  220. open_ux-0.1.1/src/open_ux/health.py +20 -0
  221. open_ux-0.1.1/src/open_ux/http_app.py +39 -0
  222. open_ux-0.1.1/src/open_ux/jobs.py +484 -0
  223. open_ux-0.1.1/src/open_ux/public_html.py +344 -0
  224. open_ux-0.1.1/src/open_ux/rate_limit.py +54 -0
  225. open_ux-0.1.1/src/open_ux/server.py +607 -0
  226. open_ux-0.1.1/src/open_ux/settings.py +93 -0
  227. open_ux-0.1.1/src/open_ux/situations.py +295 -0
  228. open_ux-0.1.1/src/open_ux/static/favicon.svg +3 -0
  229. open_ux-0.1.1/src/open_ux/static/logo-mark.svg +7 -0
  230. open_ux-0.1.1/src/open_ux/store.py +341 -0
  231. open_ux-0.1.1/tests/conftest.py +45 -0
  232. open_ux-0.1.1/tests/fixtures/situation_queries.json +68 -0
  233. open_ux-0.1.1/tests/test_agent_path.py +304 -0
  234. open_ux-0.1.1/tests/test_agent_scripts.py +140 -0
  235. open_ux-0.1.1/tests/test_audit.py +207 -0
  236. open_ux-0.1.1/tests/test_auth.py +66 -0
  237. open_ux-0.1.1/tests/test_branding.py +62 -0
  238. open_ux-0.1.1/tests/test_catalog.py +583 -0
  239. open_ux-0.1.1/tests/test_consent.py +51 -0
  240. open_ux-0.1.1/tests/test_health.py +32 -0
  241. open_ux-0.1.1/tests/test_invite.py +352 -0
  242. open_ux-0.1.1/tests/test_privacy.py +83 -0
  243. open_ux-0.1.1/tests/test_public_html.py +60 -0
  244. open_ux-0.1.1/tests/test_rate_limit.py +58 -0
  245. open_ux-0.1.1/tests/test_settings.py +47 -0
  246. open_ux-0.1.1/tests/test_situations.py +240 -0
  247. open_ux-0.1.1/tests/test_situations_fixture.py +87 -0
  248. open_ux-0.1.1/tests/test_tools.py +340 -0
  249. open_ux-0.1.1/tests/test_uns50_smoke.py +64 -0
  250. open_ux-0.1.1/tests/test_web.py +164 -0
@@ -0,0 +1,56 @@
1
+ # Generated by hatch-vcs
2
+ packages/mcp/src/open_ux/_version.py
3
+
4
+ # Python
5
+ __pycache__/
6
+ *.py[cod]
7
+ *$py.class
8
+ *.egg-info/
9
+ .eggs/
10
+ dist/
11
+ build/
12
+ .venv/
13
+ venv/
14
+ .pytest_cache/
15
+ .mypy_cache/
16
+ .ruff_cache/
17
+ .coverage
18
+ htmlcov/
19
+
20
+ # Node
21
+ node_modules/
22
+ npm-debug.log*
23
+ yarn-debug.log*
24
+ yarn-error.log*
25
+ pnpm-debug.log*
26
+
27
+ # Env / secrets
28
+ .env
29
+ .env.*
30
+ !.env.example
31
+ *.pem
32
+ id_rsa
33
+ id_ed25519
34
+ .fly/
35
+
36
+ # Hosted ops live in the private repo. Copy locally to deploy; do not commit.
37
+ /fly.toml
38
+ /railway.toml
39
+
40
+ # Local hosted store
41
+ data/
42
+ *.sqlite
43
+ *.sqlite-journal
44
+
45
+ # Editor / agent local (never publish chats or transcripts)
46
+ .cursor/
47
+ .claude/
48
+ .codex/
49
+ agent-transcripts/
50
+ *.jsonl
51
+
52
+ # OS / editors
53
+ .DS_Store
54
+ *.swp
55
+ .idea/
56
+ .vscode/
open_ux-0.1.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Yonatan Lev Ari
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
open_ux-0.1.1/PKG-INFO ADDED
@@ -0,0 +1,159 @@
1
+ Metadata-Version: 2.5
2
+ Name: open-ux
3
+ Version: 0.1.1
4
+ Summary: Cited UX rules agents audit against — shared cited guidelines
5
+ Project-URL: Homepage, https://open-ux.dev
6
+ Project-URL: Repository, https://github.com/3dyonic/open-ux
7
+ Project-URL: Issues, https://github.com/3dyonic/open-ux/issues
8
+ Author: 3dyonic
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Requires-Python: >=3.11
12
+ Requires-Dist: fastmcp<5,>=2.13
13
+ Requires-Dist: jsonschema<5,>=4.23
14
+ Requires-Dist: pydantic>=2
15
+ Requires-Dist: starlette>=0.40
16
+ Requires-Dist: uvicorn>=0.30
17
+ Provides-Extra: dev
18
+ Requires-Dist: httpx>=0.27; extra == 'dev'
19
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
20
+ Requires-Dist: pytest>=8; extra == 'dev'
21
+ Description-Content-Type: text/markdown
22
+
23
+ # Open UX
24
+
25
+ ![Open UX](https://raw.githubusercontent.com/3dyonic/open-ux/master/docs/readme-hero.svg)
26
+
27
+ **Cited UX rules agents can list, fetch, and audit against.**
28
+
29
+ Stop inventing UX guidance from memory. Open UX is a shared, open-source catalog of UX rules with citations, plus tools so an agent can find the right criteria and apply them to work it already has.
30
+
31
+ **Hosted:** [open-ux.dev](https://open-ux.dev) · **License:** [MIT](https://github.com/3dyonic/open-ux/blob/master/LICENSE)
32
+
33
+ ## What it is
34
+
35
+ A curated, machine-readable store of UX guidelines and a small tool surface so an agent can:
36
+
37
+ 1. **Browse situations** — pick a compose job (Situation Card) that matches the work
38
+ 2. **Fetch criteria** — get cited rules for that job (`rule`, `pass_when`, `fail_when`)
39
+ 3. **Apply locally** — the client judges the artifact; the host never takes the file and never returns pass/fail
40
+
41
+ There is no server-side LLM. One shared catalog for every caller — an account unlocks the hosted API; it does not give you a private rulebook.
42
+
43
+ ## What it is not
44
+
45
+ * A generative design copilot or “does this look good?” scorer
46
+ * A WCAG / accessibility compliance checker (we do not claim conformance, contrast audits, or screen-reader naming)
47
+ * A closed corpus — the catalog and server are open source; you can self-host the same tools
48
+
49
+ ## Features
50
+
51
+ * **Cited catalog** — one JSON file per rule, with sources you can follow
52
+ * **Public catalog site** — browse rules in the browser at [`/catalog`](https://open-ux.dev/catalog)
53
+ * **Agent tools** — list / search / get guidelines; suggest situations; audit by need (job or ids)
54
+ * **Hosted or self-host** — waitlist + API key on the hosted service, or stdio locally with no auth
55
+ * **Privacy-minded hosted mode** — we do not store UI payloads or prompts; see [Privacy](https://open-ux.dev/privacy)
56
+
57
+ ## Quick start
58
+
59
+ ### Hosted
60
+
61
+ 1. Request access at [open-ux.dev/invite](https://open-ux.dev/invite)
62
+ 2. After approval, redeem your invite for a bearer API key (`uxmcp_…`)
63
+ 3. Point your MCP client at the hosted `/mcp` endpoint with that key
64
+ 4. Call `list_guidelines` or `audit` with a job (no file upload)
65
+
66
+ Tools return **401** without a key.
67
+
68
+ ### Self-host
69
+
70
+ ```bash
71
+ pip install open-ux
72
+ python -m open_ux validate-catalog
73
+ python -m open_ux stdio
74
+ OPEN_UX_MODE=hosted python -m open_ux http
75
+ ```
76
+
77
+ Browse the local site at `http://127.0.0.1:8080/catalog`. Point MCP clients at local stdio, or at hosted `/mcp` with a `uxmcp_` key.
78
+
79
+ ### Contribute from this repo
80
+
81
+ ```bash
82
+ python -m venv .venv && source .venv/bin/activate
83
+ pip install -e "packages/mcp[dev]"
84
+ python -m open_ux validate-catalog
85
+ python -m open_ux stdio
86
+ ```
87
+
88
+ ### Tests
89
+
90
+ ```bash
91
+ cd packages/mcp && python -m pytest
92
+ ```
93
+
94
+ ### Claude plugin
95
+
96
+ Thin client in [`clients/claude`](https://github.com/3dyonic/open-ux/tree/master/clients/claude). It connects to the catalog; it does not ship a second copy of the rules.
97
+
98
+ ## Agent tools
99
+
100
+ | Tool | Purpose |
101
+ | -- | -- |
102
+ | `list_situations` | Page Situation Cards (optional container filter) |
103
+ | `get_situation` | One Card plus facets / rule pointers |
104
+ | `suggest_situations` | Rank Cards from task text (allowlisted) |
105
+ | `list_guidelines` | Paged catalog index |
106
+ | `search_guidelines` | Filter index by query / jobs / lane |
107
+ | `get_guideline` | Full rule body by id |
108
+ | `audit` | Say the need (`jobs` Card/container or `guideline_ids`); get matching criteria |
109
+
110
+ `audit` accepts optional `query` and `limit` (default 10, max 50). It does **not** take a file target and does **not** return a host verdict. If nothing matches, you get an empty list and a note.
111
+
112
+ ## Catalog layout
113
+
114
+ ```
115
+ catalog/
116
+ rules/{category}/{source}/ one JSON file per rule
117
+ index.json generated index
118
+ jobs.json Situation tree
119
+ schema.json rule schema
120
+ MANIFEST.md human map (no rule bodies)
121
+ ```
122
+
123
+ Rules are never forked per tenant. Soft size budget ~50–100 KB; hard ceiling ~384 KB. Details: [`catalog/README.md`](https://github.com/3dyonic/open-ux/blob/master/catalog/README.md).
124
+
125
+ ## Repository layout
126
+
127
+ ```
128
+ packages/mcp Python server (FastMCP)
129
+ catalog/ shared rules + schema
130
+ clients/claude thin Claude plugin
131
+ docs/ privacy, assets
132
+ ```
133
+
134
+ Python package: `open-ux` · npm / plugin scope: `@3dyonic/open-ux`
135
+
136
+ ## Hosted vs self-host
137
+
138
+ | | Hosted HTTP | Self-host (stdio) |
139
+ | -- | -- | -- |
140
+ | Auth | Waitlist → invite → bearer `uxmcp_` | None |
141
+ | Rate limits | Per-key and per-IP on `/mcp` | None |
142
+ | Telemetry | Aggregated usage (key hash, tools, rule ids) | Off |
143
+
144
+ Privacy on the hosted product: [open-ux.dev/privacy](https://open-ux.dev/privacy) (Eng constraints also in [`docs/PRIVACY.md`](https://github.com/3dyonic/open-ux/blob/master/docs/PRIVACY.md)).
145
+
146
+ ## Contributing
147
+
148
+ Issues and pull requests are welcome. Keep the catalog cited — every rule should point at a real source. Prefer small, reviewable PRs: one concern per change (catalog rows, server behavior, or docs).
149
+
150
+ Before opening a PR:
151
+
152
+ ```bash
153
+ python -m open_ux validate-catalog
154
+ cd packages/mcp && python -m pytest
155
+ ```
156
+
157
+ ## License
158
+
159
+ [MIT](https://github.com/3dyonic/open-ux/blob/master/LICENSE)
@@ -0,0 +1,137 @@
1
+ # Open UX
2
+
3
+ ![Open UX](docs/readme-hero.svg)
4
+
5
+ **Cited UX rules agents can list, fetch, and audit against.**
6
+
7
+ Stop inventing UX guidance from memory. Open UX is a shared, open-source catalog of UX rules with citations, plus tools so an agent can find the right criteria and apply them to work it already has.
8
+
9
+ **Hosted:** [open-ux.dev](https://open-ux.dev) · **License:** [MIT](LICENSE)
10
+
11
+ ## What it is
12
+
13
+ A curated, machine-readable store of UX guidelines and a small tool surface so an agent can:
14
+
15
+ 1. **Browse situations** — pick a compose job (Situation Card) that matches the work
16
+ 2. **Fetch criteria** — get cited rules for that job (`rule`, `pass_when`, `fail_when`)
17
+ 3. **Apply locally** — the client judges the artifact; the host never takes the file and never returns pass/fail
18
+
19
+ There is no server-side LLM. One shared catalog for every caller — an account unlocks the hosted API; it does not give you a private rulebook.
20
+
21
+ ## What it is not
22
+
23
+ * A generative design copilot or “does this look good?” scorer
24
+ * A WCAG / accessibility compliance checker (we do not claim conformance, contrast audits, or screen-reader naming)
25
+ * A closed corpus — the catalog and server are open source; you can self-host the same tools
26
+
27
+ ## Features
28
+
29
+ * **Cited catalog** — one JSON file per rule, with sources you can follow
30
+ * **Public catalog site** — browse rules in the browser at [`/catalog`](https://open-ux.dev/catalog)
31
+ * **Agent tools** — list / search / get guidelines; suggest situations; audit by need (job or ids)
32
+ * **Hosted or self-host** — waitlist + API key on the hosted service, or stdio locally with no auth
33
+ * **Privacy-minded hosted mode** — we do not store UI payloads or prompts; see [Privacy](https://open-ux.dev/privacy)
34
+
35
+ ## Quick start
36
+
37
+ ### Hosted
38
+
39
+ 1. Request access at [open-ux.dev/invite](https://open-ux.dev/invite)
40
+ 2. After approval, redeem your invite for a bearer API key (`uxmcp_…`)
41
+ 3. Point your MCP client at the hosted `/mcp` endpoint with that key
42
+ 4. Call `list_guidelines` or `audit` with a job (no file upload)
43
+
44
+ Tools return **401** without a key.
45
+
46
+ ### Self-host
47
+
48
+ ```bash
49
+ pip install open-ux
50
+ python -m open_ux validate-catalog
51
+ python -m open_ux stdio
52
+ OPEN_UX_MODE=hosted python -m open_ux http
53
+ ```
54
+
55
+ Browse the local site at `http://127.0.0.1:8080/catalog`. Point MCP clients at local stdio, or at hosted `/mcp` with a `uxmcp_` key.
56
+
57
+ ### Contribute from this repo
58
+
59
+ ```bash
60
+ python -m venv .venv && source .venv/bin/activate
61
+ pip install -e "packages/mcp[dev]"
62
+ python -m open_ux validate-catalog
63
+ python -m open_ux stdio
64
+ ```
65
+
66
+ ### Tests
67
+
68
+ ```bash
69
+ cd packages/mcp && python -m pytest
70
+ ```
71
+
72
+ ### Claude plugin
73
+
74
+ Thin client in [`clients/claude`](clients/claude). It connects to the catalog; it does not ship a second copy of the rules.
75
+
76
+ ## Agent tools
77
+
78
+ | Tool | Purpose |
79
+ | -- | -- |
80
+ | `list_situations` | Page Situation Cards (optional container filter) |
81
+ | `get_situation` | One Card plus facets / rule pointers |
82
+ | `suggest_situations` | Rank Cards from task text (allowlisted) |
83
+ | `list_guidelines` | Paged catalog index |
84
+ | `search_guidelines` | Filter index by query / jobs / lane |
85
+ | `get_guideline` | Full rule body by id |
86
+ | `audit` | Say the need (`jobs` Card/container or `guideline_ids`); get matching criteria |
87
+
88
+ `audit` accepts optional `query` and `limit` (default 10, max 50). It does **not** take a file target and does **not** return a host verdict. If nothing matches, you get an empty list and a note.
89
+
90
+ ## Catalog layout
91
+
92
+ ```
93
+ catalog/
94
+ rules/{category}/{source}/ one JSON file per rule
95
+ index.json generated index
96
+ jobs.json Situation tree
97
+ schema.json rule schema
98
+ MANIFEST.md human map (no rule bodies)
99
+ ```
100
+
101
+ Rules are never forked per tenant. Soft size budget ~50–100 KB; hard ceiling ~384 KB. Details: [`catalog/README.md`](catalog/README.md).
102
+
103
+ ## Repository layout
104
+
105
+ ```
106
+ packages/mcp Python server (FastMCP)
107
+ catalog/ shared rules + schema
108
+ clients/claude thin Claude plugin
109
+ docs/ privacy, assets
110
+ ```
111
+
112
+ Python package: `open-ux` · npm / plugin scope: `@3dyonic/open-ux`
113
+
114
+ ## Hosted vs self-host
115
+
116
+ | | Hosted HTTP | Self-host (stdio) |
117
+ | -- | -- | -- |
118
+ | Auth | Waitlist → invite → bearer `uxmcp_` | None |
119
+ | Rate limits | Per-key and per-IP on `/mcp` | None |
120
+ | Telemetry | Aggregated usage (key hash, tools, rule ids) | Off |
121
+
122
+ Privacy on the hosted product: [open-ux.dev/privacy](https://open-ux.dev/privacy) (Eng constraints also in [`docs/PRIVACY.md`](docs/PRIVACY.md)).
123
+
124
+ ## Contributing
125
+
126
+ Issues and pull requests are welcome. Keep the catalog cited — every rule should point at a real source. Prefer small, reviewable PRs: one concern per change (catalog rows, server behavior, or docs).
127
+
128
+ Before opening a PR:
129
+
130
+ ```bash
131
+ python -m open_ux validate-catalog
132
+ cd packages/mcp && python -m pytest
133
+ ```
134
+
135
+ ## License
136
+
137
+ [MIT](LICENSE)
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from hatchling.builders.hooks.plugin.interface import BuildHookInterface
6
+
7
+
8
+ class CustomBuildHook(BuildHookInterface):
9
+ """Ship repo catalog/ in the wheel and sdist (not copied into git src/)."""
10
+
11
+ def initialize(self, version: str, build_data: dict) -> None:
12
+ in_tree = Path(self.root) / "src" / "open_ux" / "data" / "catalog"
13
+ repo = Path(self.root).resolve().parent.parent / "catalog"
14
+ if (in_tree / "schema.json").is_file():
15
+ catalog = in_tree
16
+ elif (repo / "schema.json").is_file():
17
+ catalog = repo
18
+ else:
19
+ raise RuntimeError(
20
+ "catalog/schema.json not found; expected repo catalog/ or "
21
+ "sdist src/open_ux/data/catalog"
22
+ )
23
+ dest = (
24
+ "src/open_ux/data/catalog"
25
+ if self.target_name == "sdist"
26
+ else "open_ux/data/catalog"
27
+ )
28
+ build_data.setdefault("force_include", {})
29
+ build_data["force_include"][str(catalog)] = dest
30
+ if self.target_name == "sdist":
31
+ repo_readme = Path(self.root).resolve().parent.parent / "README.md"
32
+ if repo_readme.is_file():
33
+ build_data["force_include"][str(repo_readme)] = "README.md"
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from hatchling.metadata.plugin.interface import MetadataHookInterface
6
+
7
+ _REPO = "https://github.com/3dyonic/open-ux"
8
+ _RAW = "https://raw.githubusercontent.com/3dyonic/open-ux/master"
9
+
10
+ _PYPI_LINKS = (
11
+ ("](docs/readme-hero.svg)", f"]({_RAW}/docs/readme-hero.svg)"),
12
+ ("](LICENSE)", f"]({_REPO}/blob/master/LICENSE)"),
13
+ ("](catalog/README.md)", f"]({_REPO}/blob/master/catalog/README.md)"),
14
+ ("](clients/claude)", f"]({_REPO}/tree/master/clients/claude)"),
15
+ ("](docs/PRIVACY.md)", f"]({_REPO}/blob/master/docs/PRIVACY.md)"),
16
+ )
17
+
18
+
19
+ def _for_pypi(text: str) -> str:
20
+ for src, dest in _PYPI_LINKS:
21
+ text = text.replace(src, dest)
22
+ return text
23
+
24
+
25
+ class CustomMetadataHook(MetadataHookInterface):
26
+ """Use the public root README as the package description."""
27
+
28
+ def update(self, metadata: dict) -> None:
29
+ repo_readme = Path(self.root).resolve().parent.parent / "README.md"
30
+ local_readme = Path(self.root) / "README.md"
31
+ if repo_readme.is_file() and repo_readme.resolve() != local_readme.resolve():
32
+ readme = repo_readme
33
+ elif local_readme.is_file():
34
+ readme = local_readme
35
+ else:
36
+ raise RuntimeError("README.md not found for package metadata")
37
+ metadata["readme"] = {
38
+ "content-type": "text/markdown",
39
+ "text": _for_pypi(readme.read_text(encoding="utf-8")),
40
+ }
@@ -0,0 +1,58 @@
1
+ [build-system]
2
+ requires = ["hatchling", "hatch-vcs"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "open-ux"
7
+ dynamic = ["version", "readme"]
8
+ description = "Cited UX rules agents audit against — shared cited guidelines"
9
+ license = "MIT"
10
+ license-files = ["LICENSE"]
11
+ requires-python = ">=3.11"
12
+ authors = [{ name = "3dyonic" }]
13
+ dependencies = [
14
+ "fastmcp>=2.13,<5",
15
+ "jsonschema>=4.23,<5",
16
+ "starlette>=0.40",
17
+ "uvicorn>=0.30",
18
+ "pydantic>=2",
19
+ ]
20
+
21
+ [project.optional-dependencies]
22
+ dev = ["pytest>=8", "pytest-asyncio>=0.24", "httpx>=0.27"]
23
+
24
+ [project.urls]
25
+ Homepage = "https://open-ux.dev"
26
+ Repository = "https://github.com/3dyonic/open-ux"
27
+ Issues = "https://github.com/3dyonic/open-ux/issues"
28
+
29
+ [project.scripts]
30
+ open-ux = "open_ux.__main__:main"
31
+
32
+ [tool.hatch.version]
33
+ source = "vcs"
34
+
35
+ [tool.hatch.version.raw-options]
36
+ search_parent_directories = true
37
+
38
+ [tool.hatch.build.hooks.vcs]
39
+ version-file = "src/open_ux/_version.py"
40
+
41
+ [tool.hatch.metadata.hooks.custom]
42
+ path = "hatch_metadata.py"
43
+
44
+ [tool.hatch.build.hooks.custom]
45
+ path = "hatch_build.py"
46
+
47
+ [tool.hatch.build.targets.wheel]
48
+ packages = ["src/open_ux"]
49
+
50
+ [tool.hatch.build.targets.wheel.force-include]
51
+ "src/open_ux/static/favicon.svg" = "open_ux/static/favicon.svg"
52
+ "src/open_ux/static/logo-mark.svg" = "open_ux/static/logo-mark.svg"
53
+
54
+ [tool.pytest.ini_options]
55
+ testpaths = ["tests"]
56
+ pythonpath = ["src"]
57
+ asyncio_mode = "auto"
58
+ asyncio_default_fixture_loop_scope = "function"
@@ -0,0 +1,13 @@
1
+ """Open UX — cited UX rules agents audit against."""
2
+
3
+ from __future__ import annotations
4
+
5
+ try:
6
+ from open_ux._version import __version__
7
+ except ImportError: # pragma: no cover - editable tree before first build
8
+ try:
9
+ from importlib.metadata import version
10
+
11
+ __version__ = version("open-ux")
12
+ except Exception:
13
+ __version__ = "0.0.0"
@@ -0,0 +1,74 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import os
6
+ import sys
7
+
8
+
9
+ def main(argv: list[str] | None = None) -> int:
10
+ parser = argparse.ArgumentParser(prog="open-ux", description="Open UX server")
11
+ parser.add_argument(
12
+ "mode",
13
+ nargs="?",
14
+ choices=("stdio", "http", "validate-catalog", "approve-invite"),
15
+ default=os.environ.get("OPEN_UX_MODE", "stdio"),
16
+ )
17
+ parser.add_argument("email", nargs="?", default="")
18
+ parser.add_argument("--host", default=os.environ.get("HOST", "0.0.0.0"))
19
+ parser.add_argument(
20
+ "--port",
21
+ type=int,
22
+ default=int(os.environ.get("PORT", os.environ.get("OPEN_UX_PORT", "8080"))),
23
+ )
24
+ args = parser.parse_args(argv)
25
+
26
+ if args.mode == "validate-catalog":
27
+ from open_ux.catalog import load_catalog
28
+
29
+ catalog = load_catalog()
30
+ print(
31
+ f"catalog ok version={catalog.version} "
32
+ f"guidelines={len(catalog.guidelines)} bytes={catalog.size_bytes}"
33
+ )
34
+ return 0
35
+
36
+ if args.mode == "approve-invite":
37
+ if not args.email:
38
+ print("usage: open-ux approve-invite EMAIL", file=sys.stderr)
39
+ return 2
40
+ from open_ux.auth import AuthError, approve_invite
41
+
42
+ try:
43
+ issued = approve_invite(args.email)
44
+ except AuthError as exc:
45
+ print(str(exc), file=sys.stderr)
46
+ return 1
47
+ print(
48
+ json.dumps(
49
+ {
50
+ "email": issued.email,
51
+ "token": issued.token,
52
+ "token_prefix": "inv_",
53
+ "redeem_url": issued.redeem_url,
54
+ "expires_at": issued.expires_at,
55
+ },
56
+ indent=2,
57
+ )
58
+ )
59
+ return 0
60
+
61
+ if args.mode == "stdio":
62
+ from open_ux.server import create_mcp
63
+
64
+ create_mcp(hosted=False).run(transport="stdio")
65
+ return 0
66
+
67
+ from open_ux.http_app import serve_http
68
+
69
+ serve_http(host=args.host, port=args.port)
70
+ return 0
71
+
72
+
73
+ if __name__ == "__main__":
74
+ sys.exit(main())
@@ -0,0 +1,24 @@
1
+ # file generated by vcs-versioning
2
+ # don't change, don't track in version control
3
+ from __future__ import annotations
4
+
5
+ __all__ = [
6
+ "__version__",
7
+ "__version_tuple__",
8
+ "version",
9
+ "version_tuple",
10
+ "__commit_id__",
11
+ "commit_id",
12
+ ]
13
+
14
+ version: str
15
+ __version__: str
16
+ __version_tuple__: tuple[int | str, ...]
17
+ version_tuple: tuple[int | str, ...]
18
+ commit_id: str | None
19
+ __commit_id__: str | None
20
+
21
+ __version__ = version = '0.1.1'
22
+ __version_tuple__ = version_tuple = (0, 1, 1)
23
+
24
+ __commit_id__ = commit_id = None