matrx-graph 0.1.0__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 (206) hide show
  1. matrx_graph-0.1.0/.gitignore +271 -0
  2. matrx_graph-0.1.0/CLAUDE.md +92 -0
  3. matrx_graph-0.1.0/PKG-INFO +110 -0
  4. matrx_graph-0.1.0/README.md +80 -0
  5. matrx_graph-0.1.0/docs/GAPS_AND_ROADMAP.md +283 -0
  6. matrx_graph-0.1.0/docs/README.md +34 -0
  7. matrx_graph-0.1.0/docs/action-authoring.md +229 -0
  8. matrx_graph-0.1.0/docs/architecture.md +361 -0
  9. matrx_graph-0.1.0/docs/node-authoring.md +304 -0
  10. matrx_graph-0.1.0/docs/study-pack-workflow.md +284 -0
  11. matrx_graph-0.1.0/docs/testing.md +231 -0
  12. matrx_graph-0.1.0/matrx_graph/__init__.py +236 -0
  13. matrx_graph-0.1.0/matrx_graph/actions/ACTION_STANDARDS.md +165 -0
  14. matrx_graph-0.1.0/matrx_graph/actions/__init__.py +36 -0
  15. matrx_graph-0.1.0/matrx_graph/actions/decorator.py +273 -0
  16. matrx_graph-0.1.0/matrx_graph/actions/registry.py +67 -0
  17. matrx_graph-0.1.0/matrx_graph/actions/spec.py +160 -0
  18. matrx_graph-0.1.0/matrx_graph/checkpoint/__init__.py +37 -0
  19. matrx_graph-0.1.0/matrx_graph/checkpoint/memory.py +60 -0
  20. matrx_graph-0.1.0/matrx_graph/checkpoint/postgres.py +284 -0
  21. matrx_graph-0.1.0/matrx_graph/checkpoint/protocol.py +247 -0
  22. matrx_graph-0.1.0/matrx_graph/compile.py +412 -0
  23. matrx_graph-0.1.0/matrx_graph/contracts/__init__.py +39 -0
  24. matrx_graph-0.1.0/matrx_graph/contracts/audit.py +595 -0
  25. matrx_graph-0.1.0/matrx_graph/db/__init__.py +76 -0
  26. matrx_graph-0.1.0/matrx_graph/db/_registry.py +105 -0
  27. matrx_graph-0.1.0/matrx_graph/db/db_requirements.py +57 -0
  28. matrx_graph-0.1.0/matrx_graph/db/definition_store.py +420 -0
  29. matrx_graph-0.1.0/matrx_graph/db/event_store.py +221 -0
  30. matrx_graph-0.1.0/matrx_graph/db/migrations/0020_wf_run_announce.sql +66 -0
  31. matrx_graph-0.1.0/matrx_graph/db/migrations/0021_join_semantics.sql +30 -0
  32. matrx_graph-0.1.0/matrx_graph/db/migrations/0022_node_data_slot.sql +109 -0
  33. matrx_graph-0.1.0/matrx_graph/db/migrations/0023_fanout_identity.sql +55 -0
  34. matrx_graph-0.1.0/matrx_graph/db/migrations/0024_definition_variables.sql +17 -0
  35. matrx_graph-0.1.0/matrx_graph/db/migrations/0100_baseline_post_reorg.sql +878 -0
  36. matrx_graph-0.1.0/matrx_graph/db/migrations/README.md +89 -0
  37. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0001_wf_initial.sql +271 -0
  38. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0002_wf_queue.sql +68 -0
  39. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0003_wf_node_events.sql +82 -0
  40. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0004_wf_trigger.sql +88 -0
  41. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0005_wf_rls.sql +211 -0
  42. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0006_wf_run_cancelling.sql +25 -0
  43. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0007_wf_run_paused_and_errored.sql +36 -0
  44. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0008_wf_node_outcome_source.sql +30 -0
  45. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0009_wf_run_recovery_limit.sql +42 -0
  46. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0010_wf_idempotency.sql +73 -0
  47. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0011_wf_definition_concurrency_limit.sql +37 -0
  48. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0012_wf_trigger_fire.sql +52 -0
  49. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0013_wf_recovery_audit.sql +46 -0
  50. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0014_wf_node_events_notify.sql +43 -0
  51. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0016_wf_template.sql +62 -0
  52. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0017_wf_hardening.sql +27 -0
  53. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0018_wf_node_events_seq.sql +62 -0
  54. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/0019_wf_node_events_drop_check.sql +21 -0
  55. matrx_graph-0.1.0/matrx_graph/db/migrations/legacy_pre_reorg/README.md +28 -0
  56. matrx_graph-0.1.0/matrx_graph/db/node_data_slot_store.py +312 -0
  57. matrx_graph-0.1.0/matrx_graph/db/pool.py +56 -0
  58. matrx_graph-0.1.0/matrx_graph/db/run_store.py +625 -0
  59. matrx_graph-0.1.0/matrx_graph/db/trigger_store.py +291 -0
  60. matrx_graph-0.1.0/matrx_graph/db/wf_manager.py +53 -0
  61. matrx_graph-0.1.0/matrx_graph/diagnostics/__init__.py +0 -0
  62. matrx_graph-0.1.0/matrx_graph/diagnostics/compile_validation.py +172 -0
  63. matrx_graph-0.1.0/matrx_graph/dry_run.py +547 -0
  64. matrx_graph-0.1.0/matrx_graph/errors.py +160 -0
  65. matrx_graph-0.1.0/matrx_graph/examples/__init__.py +7 -0
  66. matrx_graph-0.1.0/matrx_graph/examples/self_validating_news.py +335 -0
  67. matrx_graph-0.1.0/matrx_graph/executor/__init__.py +23 -0
  68. matrx_graph-0.1.0/matrx_graph/executor/_retry.py +50 -0
  69. matrx_graph-0.1.0/matrx_graph/executor/channels.py +151 -0
  70. matrx_graph-0.1.0/matrx_graph/executor/introspect.py +57 -0
  71. matrx_graph-0.1.0/matrx_graph/executor/json_dump.py +49 -0
  72. matrx_graph-0.1.0/matrx_graph/executor/primitives.py +11 -0
  73. matrx_graph-0.1.0/matrx_graph/executor/registry.py +142 -0
  74. matrx_graph-0.1.0/matrx_graph/executor/scheduler.py +3507 -0
  75. matrx_graph-0.1.0/matrx_graph/executor/schema_validation.py +67 -0
  76. matrx_graph-0.1.0/matrx_graph/kinds.py +187 -0
  77. matrx_graph-0.1.0/matrx_graph/nodes/__init__.py +159 -0
  78. matrx_graph-0.1.0/matrx_graph/nodes/_sandbox.py +93 -0
  79. matrx_graph-0.1.0/matrx_graph/nodes/control/__init__.py +50 -0
  80. matrx_graph-0.1.0/matrx_graph/nodes/control/branch.py +110 -0
  81. matrx_graph-0.1.0/matrx_graph/nodes/control/gather.py +194 -0
  82. matrx_graph-0.1.0/matrx_graph/nodes/control/human_input.py +108 -0
  83. matrx_graph-0.1.0/matrx_graph/nodes/control/loop.py +148 -0
  84. matrx_graph-0.1.0/matrx_graph/nodes/control/map.py +162 -0
  85. matrx_graph-0.1.0/matrx_graph/nodes/control/send.py +109 -0
  86. matrx_graph-0.1.0/matrx_graph/nodes/crypto/__init__.py +25 -0
  87. matrx_graph-0.1.0/matrx_graph/nodes/crypto/ops.py +235 -0
  88. matrx_graph-0.1.0/matrx_graph/nodes/data/__init__.py +1 -0
  89. matrx_graph-0.1.0/matrx_graph/nodes/data/assert_.py +96 -0
  90. matrx_graph-0.1.0/matrx_graph/nodes/data/filter.py +92 -0
  91. matrx_graph-0.1.0/matrx_graph/nodes/data/json_io.py +135 -0
  92. matrx_graph-0.1.0/matrx_graph/nodes/data/merge.py +67 -0
  93. matrx_graph-0.1.0/matrx_graph/nodes/data/pick_omit.py +126 -0
  94. matrx_graph-0.1.0/matrx_graph/nodes/data/transform.py +91 -0
  95. matrx_graph-0.1.0/matrx_graph/nodes/datetime_/__init__.py +21 -0
  96. matrx_graph-0.1.0/matrx_graph/nodes/datetime_/ops.py +311 -0
  97. matrx_graph-0.1.0/matrx_graph/nodes/http/__init__.py +23 -0
  98. matrx_graph-0.1.0/matrx_graph/nodes/http/_shared.py +119 -0
  99. matrx_graph-0.1.0/matrx_graph/nodes/http/custom_api.py +294 -0
  100. matrx_graph-0.1.0/matrx_graph/nodes/http/get.py +103 -0
  101. matrx_graph-0.1.0/matrx_graph/nodes/http/graphql.py +167 -0
  102. matrx_graph-0.1.0/matrx_graph/nodes/http/post.py +128 -0
  103. matrx_graph-0.1.0/matrx_graph/nodes/io/__init__.py +10 -0
  104. matrx_graph-0.1.0/matrx_graph/nodes/io/user_input.py +235 -0
  105. matrx_graph-0.1.0/matrx_graph/nodes/output/__init__.py +9 -0
  106. matrx_graph-0.1.0/matrx_graph/nodes/output/to_frontend.py +171 -0
  107. matrx_graph-0.1.0/matrx_graph/nodes/subgraph/__init__.py +5 -0
  108. matrx_graph-0.1.0/matrx_graph/nodes/subgraph/call.py +162 -0
  109. matrx_graph-0.1.0/matrx_graph/nodes/text/__init__.py +37 -0
  110. matrx_graph-0.1.0/matrx_graph/nodes/text/custom_extract.py +387 -0
  111. matrx_graph-0.1.0/matrx_graph/nodes/text/json_path.py +156 -0
  112. matrx_graph-0.1.0/matrx_graph/nodes/text/manipulate.py +401 -0
  113. matrx_graph-0.1.0/matrx_graph/nodes/text/regex.py +271 -0
  114. matrx_graph-0.1.0/matrx_graph/nodes/tool/__init__.py +5 -0
  115. matrx_graph-0.1.0/matrx_graph/nodes/tool/call.py +163 -0
  116. matrx_graph-0.1.0/matrx_graph/observability/__init__.py +117 -0
  117. matrx_graph-0.1.0/matrx_graph/py.typed +0 -0
  118. matrx_graph-0.1.0/matrx_graph/references.py +113 -0
  119. matrx_graph-0.1.0/matrx_graph/types/__init__.py +107 -0
  120. matrx_graph-0.1.0/matrx_graph/types/canonical_payloads.py +138 -0
  121. matrx_graph-0.1.0/matrx_graph/types/channel.py +73 -0
  122. matrx_graph-0.1.0/matrx_graph/types/compiled.py +149 -0
  123. matrx_graph-0.1.0/matrx_graph/types/context.py +225 -0
  124. matrx_graph-0.1.0/matrx_graph/types/definition.py +240 -0
  125. matrx_graph-0.1.0/matrx_graph/types/events.py +424 -0
  126. matrx_graph-0.1.0/matrx_graph/types/handle.py +39 -0
  127. matrx_graph-0.1.0/matrx_graph/types/node_spec.py +209 -0
  128. matrx_graph-0.1.0/matrx_graph/types/primitives.py +117 -0
  129. matrx_graph-0.1.0/matrx_graph/types/result.py +133 -0
  130. matrx_graph-0.1.0/matrx_graph/types/run.py +39 -0
  131. matrx_graph-0.1.0/matrx_graph/types/send.py +59 -0
  132. matrx_graph-0.1.0/matrx_graph/types/usl.py +112 -0
  133. matrx_graph-0.1.0/matrx_graph/types/value_objects.py +36 -0
  134. matrx_graph-0.1.0/matrx_graph/types/variables.py +143 -0
  135. matrx_graph-0.1.0/matrx_graph/validation.py +559 -0
  136. matrx_graph-0.1.0/matrx_graph/workers/__init__.py +62 -0
  137. matrx_graph-0.1.0/matrx_graph/workers/cron_watcher.py +100 -0
  138. matrx_graph-0.1.0/matrx_graph/workers/queue.py +360 -0
  139. matrx_graph-0.1.0/matrx_graph/workers/runner.py +164 -0
  140. matrx_graph-0.1.0/pyproject.toml +72 -0
  141. matrx_graph-0.1.0/tests/__init__.py +0 -0
  142. matrx_graph-0.1.0/tests/_db_guard.py +93 -0
  143. matrx_graph-0.1.0/tests/_fixtures.py +75 -0
  144. matrx_graph-0.1.0/tests/ci/00_supabase_shim.sql +74 -0
  145. matrx_graph-0.1.0/tests/ci/10_canonical_reorg_shim.sql +161 -0
  146. matrx_graph-0.1.0/tests/ci/bootstrap_test_db.sh +163 -0
  147. matrx_graph-0.1.0/tests/conftest.py +43 -0
  148. matrx_graph-0.1.0/tests/judge/__init__.py +0 -0
  149. matrx_graph-0.1.0/tests/judge/test_self_validating_news_e2e.py +153 -0
  150. matrx_graph-0.1.0/tests/judge/test_study_pack_e2e.py +443 -0
  151. matrx_graph-0.1.0/tests/level2/__init__.py +0 -0
  152. matrx_graph-0.1.0/tests/test_actions.py +486 -0
  153. matrx_graph-0.1.0/tests/test_barrier_removed.py +60 -0
  154. matrx_graph-0.1.0/tests/test_channel.py +72 -0
  155. matrx_graph-0.1.0/tests/test_channels_reducers.py +103 -0
  156. matrx_graph-0.1.0/tests/test_context_propagation.py +89 -0
  157. matrx_graph-0.1.0/tests/test_contract_audit.py +317 -0
  158. matrx_graph-0.1.0/tests/test_data_nodes.py +251 -0
  159. matrx_graph-0.1.0/tests/test_db_guard.py +76 -0
  160. matrx_graph-0.1.0/tests/test_definition.py +142 -0
  161. matrx_graph-0.1.0/tests/test_dry_run.py +288 -0
  162. matrx_graph-0.1.0/tests/test_dry_run_source_input.py +104 -0
  163. matrx_graph-0.1.0/tests/test_end_to_end.py +501 -0
  164. matrx_graph-0.1.0/tests/test_http_nodes.py +290 -0
  165. matrx_graph-0.1.0/tests/test_io_nodes.py +355 -0
  166. matrx_graph-0.1.0/tests/test_json_dump.py +17 -0
  167. matrx_graph-0.1.0/tests/test_kinds.py +376 -0
  168. matrx_graph-0.1.0/tests/test_map_payload_template.py +219 -0
  169. matrx_graph-0.1.0/tests/test_multi_dispatch_fanin.py +281 -0
  170. matrx_graph-0.1.0/tests/test_node_cost_event.py +71 -0
  171. matrx_graph-0.1.0/tests/test_node_data_slot_store.py +287 -0
  172. matrx_graph-0.1.0/tests/test_node_data_slot_validation.py +72 -0
  173. matrx_graph-0.1.0/tests/test_node_result_envelope.py +720 -0
  174. matrx_graph-0.1.0/tests/test_node_spec.py +106 -0
  175. matrx_graph-0.1.0/tests/test_output_channel_binding.py +225 -0
  176. matrx_graph-0.1.0/tests/test_pause_cancel_and_recovery.py +344 -0
  177. matrx_graph-0.1.0/tests/test_postgres_checkpointer.py +614 -0
  178. matrx_graph-0.1.0/tests/test_primitives.py +83 -0
  179. matrx_graph-0.1.0/tests/test_references.py +84 -0
  180. matrx_graph-0.1.0/tests/test_registry.py +87 -0
  181. matrx_graph-0.1.0/tests/test_run_variables.py +305 -0
  182. matrx_graph-0.1.0/tests/test_scheduler_conditional_edge.py +125 -0
  183. matrx_graph-0.1.0/tests/test_scheduler_config_override.py +252 -0
  184. matrx_graph-0.1.0/tests/test_scheduler_events.py +179 -0
  185. matrx_graph-0.1.0/tests/test_scheduler_failsoft.py +422 -0
  186. matrx_graph-0.1.0/tests/test_scheduler_failure_cost_settlement.py +147 -0
  187. matrx_graph-0.1.0/tests/test_scheduler_fanout_identity.py +769 -0
  188. matrx_graph-0.1.0/tests/test_scheduler_fork_to_new_run.py +243 -0
  189. matrx_graph-0.1.0/tests/test_scheduler_interrupt_siblings.py +286 -0
  190. matrx_graph-0.1.0/tests/test_scheduler_join_hardening.py +835 -0
  191. matrx_graph-0.1.0/tests/test_scheduler_joins.py +809 -0
  192. matrx_graph-0.1.0/tests/test_scheduler_loop_contract.py +243 -0
  193. matrx_graph-0.1.0/tests/test_scheduler_mock_response.py +207 -0
  194. matrx_graph-0.1.0/tests/test_scheduler_node_retry_override.py +151 -0
  195. matrx_graph-0.1.0/tests/test_scheduler_node_timeout.py +241 -0
  196. matrx_graph-0.1.0/tests/test_scheduler_retry_policy.py +349 -0
  197. matrx_graph-0.1.0/tests/test_scheduler_skip_edge_ids.py +118 -0
  198. matrx_graph-0.1.0/tests/test_scheduler_step_mode.py +205 -0
  199. matrx_graph-0.1.0/tests/test_self_validating_news.py +261 -0
  200. matrx_graph-0.1.0/tests/test_subgraph_call.py +82 -0
  201. matrx_graph-0.1.0/tests/test_text_nodes.py +363 -0
  202. matrx_graph-0.1.0/tests/test_triggers_and_observability.py +204 -0
  203. matrx_graph-0.1.0/tests/test_utility_nodes.py +344 -0
  204. matrx_graph-0.1.0/tests/test_validation_hints.py +64 -0
  205. matrx_graph-0.1.0/tests/test_validation_s4.py +161 -0
  206. matrx_graph-0.1.0/tests/test_workers.py +60 -0
@@ -0,0 +1,271 @@
1
+ *.pyc
2
+ secrets/
3
+ ignore/
4
+ temp/
5
+ logs/
6
+ # The broad `logs/` rule above is for RUNTIME log output, but it also matched
7
+ # the dashboard's SOURCE directory and silently swallowed an entire feature's
8
+ # files (only the pre-existing index.tsx stayed tracked), breaking the prod
9
+ # Docker build with "Could not resolve ./structured-tab". Re-include the source.
10
+ !apps/dashboard/src/features/logs/
11
+ !apps/dashboard/src/features/logs/**
12
+ todo
13
+ text_notes/
14
+ aidream/secrets/2.env
15
+ automation_matrix/matrix_processing/temp/*
16
+ cd
17
+ # Byte-compiled / optimized / DLL files
18
+ __pycache__/
19
+ *.py[cod]
20
+ *$py.class
21
+
22
+ # C extensions
23
+ *.so
24
+ .venv/
25
+
26
+ # Distribution / packaging
27
+ .Python
28
+ build/
29
+ develop-eggs/
30
+ dist/
31
+ downloads/
32
+ eggs/
33
+ .eggs/
34
+ lib/
35
+ lib64/
36
+ # The blanket lib/ rule above is from the standard Python .gitignore template
37
+ # and was silently swallowing TS source under the SPA `src/lib/` folders.
38
+ # Re-allow them explicitly so frontend builds don't ship without their lib layer.
39
+ !apps/dashboard/src/lib/
40
+ !apps/dashboard/src/lib/**
41
+ !apps/workflow-studio/src/lib/
42
+ !apps/workflow-studio/src/lib/**
43
+ parts/
44
+ sdist/
45
+ var/
46
+ wheels/
47
+ share/python-wheels/
48
+ *.egg-info/
49
+ .installed.cfg
50
+ *.egg
51
+ MANIFEST
52
+
53
+ # PyInstaller
54
+ # Usually these files are written by a python script from a template
55
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
56
+ *.manifest
57
+ *.spec
58
+
59
+ # Installer logs
60
+ pip-log.txt
61
+ pip-delete-this-directory.txt
62
+
63
+ # Unit test / coverage reports
64
+ ai/tests/clean_response.json
65
+ ai/tests/cx_storage_response.json
66
+ ai/tests/execution_test.py
67
+ ai/tests/final_response.json
68
+ htmlcov/
69
+ .tox/
70
+ .nox/
71
+ .coverage
72
+ .coverage.*
73
+ .cache
74
+ nosetests.xml
75
+ coverage.xml
76
+ *.cover
77
+ *.py,cover
78
+ .hypothesis/
79
+ .pytest_cache/
80
+ cover/
81
+
82
+ # Translations
83
+ *.mo
84
+ *.pot
85
+
86
+ # Django stuff:
87
+ *.log
88
+ local_settings.py
89
+ db.sqlite3
90
+ db.sqlite3-journal
91
+
92
+ # Flask stuff:
93
+ instance/
94
+ .webassets-cache
95
+
96
+ # Scrapy stuff:
97
+ .scrapy
98
+
99
+ # Sphinx documentation
100
+ docs/_build/
101
+
102
+ # PyBuilder
103
+ .pybuilder/
104
+ target/
105
+
106
+ # Jupyter Notebook
107
+ .ipynb_checkpoints
108
+
109
+ # IPython
110
+ profile_default/
111
+ ipython_config.py
112
+
113
+ # pyenv
114
+ # For a library or package, you might want to ignore these files since the code is
115
+ # intended to run in multiple environments; otherwise, check them in:
116
+ # .python-version
117
+
118
+ # pipenv
119
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
120
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
121
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
122
+ # install all needed dependencies.
123
+ #Pipfile.lock
124
+
125
+ # poetry
126
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
127
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
128
+ # commonly ignored for libraries.
129
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
130
+
131
+ # pdm
132
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
133
+ #pdm.lock
134
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
135
+ # in version control.
136
+ # https://pdm.fming.dev/#use-with-ide
137
+ .pdm.toml
138
+
139
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
140
+ __pypackages__/
141
+
142
+ # Celery stuff
143
+ celerybeat-schedule
144
+ celerybeat.pid
145
+
146
+ # SageMath parsed files
147
+ *.sage.py
148
+
149
+ # Environments
150
+ .env
151
+ .env_remote
152
+ .venv
153
+ env/
154
+ venv/
155
+ ENV/
156
+ env.bak/
157
+ venv.bak/
158
+ .env.armanonly
159
+
160
+ # Spyder project settings
161
+ .spyderproject
162
+ .spyproject
163
+
164
+ # Rope project settings
165
+ .ropeproject
166
+
167
+ # mkdocs documentation
168
+ /site
169
+
170
+ # mypy
171
+ .mypy_cache/
172
+ .dmypy.json
173
+ dmypy.json
174
+
175
+ # Pyre type checker
176
+ .pyre/
177
+
178
+ # random armani files
179
+ /armani_dev/secrets/
180
+ /armani/
181
+ /_armani/
182
+
183
+
184
+
185
+ # pytype static type analyzer
186
+ .pytype/
187
+
188
+ # Cython debug symbols
189
+ cython_debug/
190
+
191
+ .idea/
192
+ .vscode/
193
+ /node_modules/
194
+
195
+ # Frontend pnpm workspace (apps/) — node_modules at the workspace root and any
196
+ # member, plus Vite caches and build output. The unified lockfile (apps/pnpm-lock.yaml)
197
+ # IS committed; everything below is regenerated.
198
+ node_modules/
199
+ apps/**/.vite/
200
+ apps/**/dist/
201
+ .vite/
202
+
203
+ dump.rdb
204
+
205
+ frontend/
206
+
207
+ # AME Temp Files and directory structure
208
+ # Ignore all files in the temp directory and its subdirectories
209
+ /temp/**/*
210
+ /tmp/**/*
211
+
212
+ # Allow .gitkeep files to retain directory structure
213
+ !/temp/**/.gitkeep
214
+ !/tmp/**/.gitkeep
215
+
216
+ # Armani
217
+ .history*
218
+ .history/
219
+ local_data/
220
+ local_reports_data/
221
+ webscraper/quick_scrapes/temp/
222
+ automation_matrix/ai_apis/fireworks/_dev/*
223
+ automation_matrix/ai_apis/fireworks/_dev/fireworks_sample.py
224
+ *.pdf
225
+ *.flac
226
+ *.mp3
227
+ *.wav
228
+ miniconda.sh
229
+ /database/python_sql/temp_data/
230
+ .history*
231
+ .history/
232
+ .history/
233
+
234
+ _dev/
235
+ /_dev/
236
+ requirements_filtered.txt
237
+
238
+ # matrx-dev-tools backups
239
+ .env-backups/
240
+ # Matrx Ship config (contains API key)
241
+ .matrx-ship.json
242
+
243
+ # Matrx config (contains API keys)
244
+ .matrx.json
245
+ .matrx-tools.conf
246
+
247
+ # Claude Code local worktrees and per-user settings
248
+ .claude/worktrees/
249
+ .claude/settings.local.json
250
+
251
+ # Append-only snapshots from matrx_utils.update_history (unbounded; do not commit)
252
+ common/utils/data_in_code/data_history.json
253
+ packages/matrx-utils/matrx_utils/data_in_code/data_history.json
254
+
255
+ # Tool-dispatch debug logs — one file per server start, never committed
256
+ .matrx-debug/
257
+
258
+ # macOS Finder metadata
259
+ .DS_Store
260
+ **/.DS_Store
261
+
262
+ # Environment files
263
+ .env
264
+ .env.*
265
+ *.env
266
+ *.env.*
267
+
268
+ # Keep safe templates trackable
269
+ !.env.example
270
+ !.env.sample
271
+ !.env.template
@@ -0,0 +1,92 @@
1
+ # CLAUDE.md — matrx-graph
2
+
3
+ > **Operating Principle: Build the platform, not the artifact.** Every task is a probe that exposes a missing capability — build it, then consume it. Code that only serves one artifact is forbidden. Full doctrine: [/PRINCIPLES.md](../../PRINCIPLES.md).
4
+
5
+ **Package:** `matrx-graph` (PyPI) — Python 3.13+ — currently v0.1.0 (alpha)
6
+ **Role in the graph:** Tier 2. Depends on `matrx-utils` and `matrx-connect`. Optionally depends on `matrx-orm` (for Postgres-backed checkpointing). Used by `matrx-ai` and by the aidream app.
7
+
8
+ ---
9
+
10
+ ## Read this first
11
+
12
+ matrx-graph is the canonical DAG workflow engine for the Matrx family: typed nodes + edges → compiled graph → Pregel-style super-step scheduler → channel-based state + checkpointing + optional human-in-the-loop interrupts. It **replaces** the legacy root-level `workflows/` and `workflows_v2/` directories. Do not add new code there; add it here.
13
+
14
+ ---
15
+
16
+ ## What this package provides
17
+
18
+ - **Definition types** (`matrx_graph.types`): `Definition`, `NodeDef`, `EdgeDef`, `EdgeKind` (Data / Control / Conditional / Error / Stream), Pydantic input/output/config schemas per node.
19
+ - **Compilation** (`matrx_graph.compile`): `compile_graph(definition)` → `CompiledGraph`, plus `validate_definition()`.
20
+ - **Execution** (`matrx_graph.executor`): `Scheduler`, Pregel super-steps, `asyncio.TaskGroup` parallelism, reducer-based channel writes, `ctx.send(target, payload)` for dynamic routing, `GraphInterrupt` for human-in-the-loop.
21
+ - **Channels** (`matrx_graph.channels` via `ChannelManager`): named typed channels with reducers.
22
+ - **Checkpointing** (`matrx_graph.checkpoint`): `Checkpoint`, `Checkpointer`; in-memory default, Postgres backend via optional matrx-orm dependency.
23
+ - **Node registry** (`matrx_graph.nodes`): `NodeRegistry`, `register_builtin_nodes()`, executors under `nodes/{http,llm,text,data,control,scraper,tool}/`. Host apps register their own executors via `@register("action.name")`.
24
+ - **Node Result System** (`matrx_graph.types.result` + `canonical_payloads` + `value_objects`): every node returns **`NodeResult[T] = Success[T] | Failure`** via `success()`/`failure()`; the **scheduler unwraps** (consumers see bare `T`; `spec.output_schema` stays `T`); payload `T` must not carry `ok`/`success`/`error`; failures route ERROR edges or `on_item_failure='hole'` fan-out holes. Contract: [docs/workflow/NODE_RESULT_CONTRACT.md](../../docs/workflow/NODE_RESULT_CONTRACT.md) · authoring: [docs/node-authoring.md](docs/node-authoring.md).
25
+ - **Kind-declared I/O** (`matrx_graph.kinds`): node I/O is declared as platform kinds (`content_ir.kind_definition` slugs) — `NodeSpec.input_kind`/`output_kind`, per-node `data.*_kind` overrides, scheduler input gate + loud output-drift check, `output_kind` stamped on every `NodeOutcome`. **Every non-dynamic node declares `output_kind`** (generic `"json"` at minimum). Read [docs/node-authoring.md](docs/node-authoring.md) §"Declare your I/O as platform kinds" before adding a node.
26
+ - **Type-contract audit** (`matrx_graph.contracts`): `audit_registry()` walks every registered node's input/output/config schema recursively (versioned `Ruleset`, currently v3: `pydantic.JsonValue` blessed as the dynamic-JSON primitive; inputs excused from `extra="allow"`; justified-forever-open models declare `json_schema_extra={"x-contract-dynamic": "<why>"}` → `dynamic` state) and reports exactly where typing stops (`Any`, bare containers, `extra="allow"`, unknown leaf types) as `full` / `dynamic` / `partial` / `non_conformant` with exact leak paths + shared-model blast radius. Ratchet: `scripts/validate_type_contracts.py` (STRICT in release.sh). Computed live from model classes — never hand-maintained. Served admin-only at aidream `GET /workflow/contracts/audit` → dashboard `/node-contracts`.
27
+ - **Observability** (`matrx_graph.observability`): optional OpenTelemetry integration behind an extra.
28
+ - **Workers** (`matrx_graph.workers`): long-running execution / retry wrappers.
29
+ - **Scheduling**: `croniter`-based cron triggers.
30
+
31
+ Public API is the ~48 symbols exported from `matrx_graph/__init__.py`. Treat changes there as breaking.
32
+
33
+ ---
34
+
35
+ ## Configuration / injection pattern
36
+
37
+ - Nodes declare a `config_schema` (Pydantic). Configuration is passed **in the node definition**, not read from env vars inside the executor.
38
+ - Actions referenced by name (e.g. `"action.news_api.top_headlines"`) are resolved from a registry at compile/run time. The host app registers its actions at startup.
39
+ - `AppContext` + `Emitter` from matrx-connect are passed into executors. If matrx-connect isn't installed in a lightweight use case, a console-only emitter fallback is provided — but the preferred path is that consumers have matrx-connect.
40
+ - The graph **engine core** is pure in-memory and needs no database (the default checkpointer is in-memory). But **the moment matrx-graph touches Postgres, it uses matrx-orm — the ONLY DB access path, no exceptions.** `matrx_graph[postgres]` is about whether the DB layer is *installed*, never about whether the ORM may be *bypassed*: there is no non-ORM DB path and no hand-written SQL. `definition_store`, `trigger_store`, `run_store`, `event_store`, and `workers/queue.py` all run on host-injected ORM models — **zero raw `conn.fetch/execute` remains in this package.** Missing ORM capability (advisory locks, `SKIP LOCKED` claim, `LISTEN/NOTIFY`) → **build the primitive in matrx-orm** (celebrate), then convert. Canonical doctrine: [`.claude/skills/eliminate-raw-sql/SKILL.md`](../../.claude/skills/eliminate-raw-sql/SKILL.md).
41
+ - Host DB models/bases/instances (`configure_db(...)`) are injected **declaratively** by the aidream host: what matrx-graph needs is declared in [`matrx_graph/db/db_requirements.py`](matrx_graph/db/db_requirements.py) (data-only manifest in THIS package) and resolved by `python db/generate.py`. Add a `workflow.*` table matrx-graph needs → that manifest, never aidream's `package_integration.py`.
42
+ - **Matrx Envelope `reference` resolution** (`matrx_graph.references`) — graph data may carry a Matrx Envelope reference (a pure pointer to an internal resource: a udt row, a file, a record). The host injects its single `ReferenceOrchestrator` once at startup via `configure_reference_resolver(resolver)`; node code then calls `await resolve_references(payload, user_id=ctx.user_id)` to materialize embedded pointers into live, ownership-gated text. It is deliberately **opt-in** (a deterministic node usually wants the structured ids, not flattened text) and a **no-op passthrough** when unconfigured, so standalone graphs keep working. Detection is the generic protocol sentinel (`matrx_version` + `kind=="reference"`), never an aidream schema import; the injected resolver owns decode + per-type dispatch + the ownership gate. Wired in aidream by `package_integration.py::_configure_matrx_graph`.
43
+
44
+ See `examples/self_validating_news.py` for the canonical full example.
45
+
46
+ ---
47
+
48
+ ## Dependency rules specific to this package
49
+
50
+ - ✅ `from matrx_utils import …`, `from matrx_connect import …` — declared hard deps.
51
+ - ✅ `from matrx_orm import …` — inside the DB layer (`matrx_graph/db/`, checkpointer, stores), behind the `[postgres]` extra and guarded so `import matrx_graph` still works for a DB-free in-memory graph. **Every DB access uses it — it is not optional *for code that touches Postgres*, only for installs that have no DB at all.**
52
+ - ❌ No hand-written SQL and no raw `asyncpg` calls in new code (the raw statements left in the stores are debt — do not add to them).
53
+ - ❌ No `from matrx_ai import …` (would be a cycle — matrx-ai depends on matrx-graph).
54
+ - ❌ No `from matrx_scraper import …` at module top level. If a node needs scraping, it should be registered as an external action in the host app or accept a scraper callable via its `config_schema`.
55
+ - ❌ No `from aidream import …`. No imports from root `workflows/`, `workflows_v2/`, `common/`, `config/`, `api_management/`.
56
+
57
+ If a node type genuinely needs another sibling package, add it as an optional extra in `pyproject.toml` and lazy-import it inside the executor, not at module top.
58
+
59
+ ---
60
+
61
+ ## Python standards (same as root)
62
+
63
+ - Full type hints. The node/edge/graph types are the public contract — Pydantic with strict validation.
64
+ - No docstrings except on public API (`compile_graph`, `Scheduler`, `NodeDef`, `EdgeDef`, `register`).
65
+ - Hot paths: scheduler step loop, channel reducer application, checkpoint serialization. Keep allocations low; prefer `orjson` / Pydantic v2 fast paths.
66
+ - `GraphInterrupt` is part of the control flow, not an error — catch it in the scheduler, surface it through the emitter. Other exceptions terminate the run with an error event.
67
+
68
+ ---
69
+
70
+ ## Testing this package in isolation
71
+
72
+ ```bash
73
+ uv run pytest packages/matrx-graph/tests
74
+ ```
75
+
76
+ Tests must pass without matrx-orm installed — cover the in-memory checkpointer by default, gate the Postgres checkpointer tests behind an `importlib.util.find_spec("matrx_orm")` check.
77
+
78
+ ---
79
+
80
+ ## Relationship to legacy `workflows/` and `workflows_v2/`
81
+
82
+ Both root-level directories are **deprecated**. Migration status is tracked in the root `PACKAGES_MIGRATION_PLAN.md`. Rules for the transition:
83
+
84
+ - Do not add new workflow/node/edge code under `workflows/` or `workflows_v2/`.
85
+ - When a feature in the legacy code is needed, port it into an appropriate `matrx_graph.nodes.*` module with a typed schema.
86
+ - Host-specific actions (things that only make sense inside aidream) live in `aidream/graph_actions/` and are registered into matrx-graph's action registry at startup. They are NOT added to matrx-graph itself.
87
+
88
+ ---
89
+
90
+ ## Known issues
91
+
92
+ Tracked in root `PACKAGES_MIGRATION_PLAN.md`. This package is currently clean (no known cross-package or root-module imports); the main open work is feature parity with legacy workflow code.
@@ -0,0 +1,110 @@
1
+ Metadata-Version: 2.4
2
+ Name: matrx-graph
3
+ Version: 0.1.0
4
+ Summary: Channel-based, super-step workflow orchestration engine for the Matrx ecosystem
5
+ Project-URL: Homepage, https://github.com/AI-Matrix-Engine/aidream-current
6
+ Project-URL: Repository, https://github.com/AI-Matrix-Engine/aidream-current
7
+ Project-URL: Issues, https://github.com/AI-Matrix-Engine/aidream-current/issues
8
+ Author-email: Matrx <admin@aimatrx.com>
9
+ Maintainer-email: Matrx <admin@aimatrx.com>
10
+ License: MIT
11
+ Keywords: agentic,checkpoint,dag,matrx,orchestration,workflow
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Requires-Python: >=3.13
19
+ Requires-Dist: croniter>=2.0
20
+ Requires-Dist: httpx>=0.27
21
+ Requires-Dist: jsonschema>=4.20
22
+ Requires-Dist: matrx-connect>=0.1.1
23
+ Requires-Dist: matrx-utils>=1.0.20
24
+ Requires-Dist: pydantic>=2.12
25
+ Provides-Extra: otel
26
+ Requires-Dist: opentelemetry-api>=1.25; extra == 'otel'
27
+ Provides-Extra: postgres
28
+ Requires-Dist: matrx-orm>=3.0.32; extra == 'postgres'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # matrx-graph
32
+
33
+ Channel-based, super-step workflow orchestration engine for the Matrx ecosystem. Think of it as a typed DAG + Pregel scheduler designed for mixing deterministic nodes with agent-style nodes in the same graph, with durable checkpoints and optional human-in-the-loop interrupts.
34
+
35
+ ## Install
36
+
37
+ ```bash
38
+ pip install matrx-graph # core engine, in-memory checkpointer
39
+ pip install "matrx-graph[postgres]" # + durable Postgres checkpointer (via matrx-orm)
40
+ pip install "matrx-graph[otel]" # + OpenTelemetry instrumentation
41
+ ```
42
+
43
+ Python 3.13+ required. Depends on `matrx-connect` (for `AppContext` and `Emitter`), `matrx-utils`, `pydantic`.
44
+
45
+ ## Design pillars
46
+
47
+ - **Channels + reducers, not mutable state.** Nodes return partial updates; a reducer merges them into typed channels. Safe under parallel writes.
48
+ - **Pregel super-steps.** Each step: active nodes run in parallel via `asyncio.TaskGroup` → writes reduced into state → next wave scheduled. Predictable and debuggable.
49
+ - **Durable checkpoints.** Every super-step produces a checkpoint. Resume, fork, or time-travel from any point. `MemoryCheckpointer` for tests, `PostgresCheckpointer` (via `matrx-graph[postgres]`) for prod.
50
+ - **JSON-only channel values.** Pydantic models are dumped at write. Checkpoints round-trip losslessly.
51
+ - **Typed nodes.** Every `NodeSpec` declares `input_schema`, `output_schema`, `config_schema` (Pydantic). JSON Schema is auto-exported for UI form generation.
52
+ - **Explicit edge semantics.** Data / Control / Conditional / Error / Stream edges — no guessing from topology.
53
+ - **Interrupts + Send.** First-class primitives for human-in-the-loop pauses and dynamic fanout.
54
+
55
+ ## Design principle
56
+
57
+ > Choose where to be deterministic and where to delegate to an agent.
58
+
59
+ A workflow can do everything an agent can (branch, loop, dispatch tools) but is more predictable, debuggable, and cheaper. An agent can do everything a workflow can but adapts to unexpected input. `matrx-graph` exists so authors draw that line consciously per node.
60
+
61
+ ## Usage sketch
62
+
63
+ ```python
64
+ from matrx_graph import (
65
+ Definition, NodeDef, EdgeDef, EdgeKind,
66
+ compile_graph, Scheduler, register, register_builtin_nodes,
67
+ )
68
+
69
+ register_builtin_nodes()
70
+
71
+ # A custom action — registered once, referenced by name in node definitions
72
+ @register("greet")
73
+ async def greet(ctx, inputs, config):
74
+ return {"message": f"Hello, {inputs['name']}!"}
75
+
76
+ definition = Definition(
77
+ nodes=[
78
+ NodeDef(id="start", action="noop"),
79
+ NodeDef(id="greet", action="greet"),
80
+ ],
81
+ edges=[
82
+ EdgeDef(source="start", target="greet", kind=EdgeKind.Data),
83
+ ],
84
+ )
85
+
86
+ graph = compile_graph(definition)
87
+ scheduler = Scheduler(graph)
88
+ result = await scheduler.run(inputs={"name": "world"})
89
+ print(result.channels["greet"]) # {"message": "Hello, world!"}
90
+ ```
91
+
92
+ For a full example including conditional edges, dynamic `ctx.send(...)` fanout, checkpoints, and resume, see [`examples/self_validating_news.py`](matrx_graph/examples/self_validating_news.py).
93
+
94
+ ## Dependency posture
95
+
96
+ `matrx-graph` is a generic engine. It depends only on `matrx-connect`, `matrx-utils`, and `pydantic`. Optional `postgres` extra adds `matrx-orm` for durable checkpointing.
97
+
98
+ Domain-specific node packs (LLM, agent, scraper) live in their sibling packages (`matrx-ai`, `matrx-scraper`) and register executors with the engine at runtime via `matrx_graph.registry`. **No hard import cycles.**
99
+
100
+ ## Status
101
+
102
+ Phase 1 in progress — foundation + in-process executor. Not yet production-ready. The legacy root-level `workflows/` and `workflows_v2/` directories in the monorepo are being consolidated into this package.
103
+
104
+ ## Contributing
105
+
106
+ See [CLAUDE.md](CLAUDE.md) for package-specific rules. This package lives in the aidream monorepo at [github.com/AI-Matrix-Engine/aidream-current](https://github.com/AI-Matrix-Engine/aidream-current/tree/main/packages/matrx-graph).
107
+
108
+ ## License
109
+
110
+ MIT.
@@ -0,0 +1,80 @@
1
+ # matrx-graph
2
+
3
+ Channel-based, super-step workflow orchestration engine for the Matrx ecosystem. Think of it as a typed DAG + Pregel scheduler designed for mixing deterministic nodes with agent-style nodes in the same graph, with durable checkpoints and optional human-in-the-loop interrupts.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install matrx-graph # core engine, in-memory checkpointer
9
+ pip install "matrx-graph[postgres]" # + durable Postgres checkpointer (via matrx-orm)
10
+ pip install "matrx-graph[otel]" # + OpenTelemetry instrumentation
11
+ ```
12
+
13
+ Python 3.13+ required. Depends on `matrx-connect` (for `AppContext` and `Emitter`), `matrx-utils`, `pydantic`.
14
+
15
+ ## Design pillars
16
+
17
+ - **Channels + reducers, not mutable state.** Nodes return partial updates; a reducer merges them into typed channels. Safe under parallel writes.
18
+ - **Pregel super-steps.** Each step: active nodes run in parallel via `asyncio.TaskGroup` → writes reduced into state → next wave scheduled. Predictable and debuggable.
19
+ - **Durable checkpoints.** Every super-step produces a checkpoint. Resume, fork, or time-travel from any point. `MemoryCheckpointer` for tests, `PostgresCheckpointer` (via `matrx-graph[postgres]`) for prod.
20
+ - **JSON-only channel values.** Pydantic models are dumped at write. Checkpoints round-trip losslessly.
21
+ - **Typed nodes.** Every `NodeSpec` declares `input_schema`, `output_schema`, `config_schema` (Pydantic). JSON Schema is auto-exported for UI form generation.
22
+ - **Explicit edge semantics.** Data / Control / Conditional / Error / Stream edges — no guessing from topology.
23
+ - **Interrupts + Send.** First-class primitives for human-in-the-loop pauses and dynamic fanout.
24
+
25
+ ## Design principle
26
+
27
+ > Choose where to be deterministic and where to delegate to an agent.
28
+
29
+ A workflow can do everything an agent can (branch, loop, dispatch tools) but is more predictable, debuggable, and cheaper. An agent can do everything a workflow can but adapts to unexpected input. `matrx-graph` exists so authors draw that line consciously per node.
30
+
31
+ ## Usage sketch
32
+
33
+ ```python
34
+ from matrx_graph import (
35
+ Definition, NodeDef, EdgeDef, EdgeKind,
36
+ compile_graph, Scheduler, register, register_builtin_nodes,
37
+ )
38
+
39
+ register_builtin_nodes()
40
+
41
+ # A custom action — registered once, referenced by name in node definitions
42
+ @register("greet")
43
+ async def greet(ctx, inputs, config):
44
+ return {"message": f"Hello, {inputs['name']}!"}
45
+
46
+ definition = Definition(
47
+ nodes=[
48
+ NodeDef(id="start", action="noop"),
49
+ NodeDef(id="greet", action="greet"),
50
+ ],
51
+ edges=[
52
+ EdgeDef(source="start", target="greet", kind=EdgeKind.Data),
53
+ ],
54
+ )
55
+
56
+ graph = compile_graph(definition)
57
+ scheduler = Scheduler(graph)
58
+ result = await scheduler.run(inputs={"name": "world"})
59
+ print(result.channels["greet"]) # {"message": "Hello, world!"}
60
+ ```
61
+
62
+ For a full example including conditional edges, dynamic `ctx.send(...)` fanout, checkpoints, and resume, see [`examples/self_validating_news.py`](matrx_graph/examples/self_validating_news.py).
63
+
64
+ ## Dependency posture
65
+
66
+ `matrx-graph` is a generic engine. It depends only on `matrx-connect`, `matrx-utils`, and `pydantic`. Optional `postgres` extra adds `matrx-orm` for durable checkpointing.
67
+
68
+ Domain-specific node packs (LLM, agent, scraper) live in their sibling packages (`matrx-ai`, `matrx-scraper`) and register executors with the engine at runtime via `matrx_graph.registry`. **No hard import cycles.**
69
+
70
+ ## Status
71
+
72
+ Phase 1 in progress — foundation + in-process executor. Not yet production-ready. The legacy root-level `workflows/` and `workflows_v2/` directories in the monorepo are being consolidated into this package.
73
+
74
+ ## Contributing
75
+
76
+ See [CLAUDE.md](CLAUDE.md) for package-specific rules. This package lives in the aidream monorepo at [github.com/AI-Matrix-Engine/aidream-current](https://github.com/AI-Matrix-Engine/aidream-current/tree/main/packages/matrx-graph).
77
+
78
+ ## License
79
+
80
+ MIT.