groundworkers 0.4.0__tar.gz → 0.5.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 (301) hide show
  1. groundworkers-0.5.0/.github/workflows/ci.yml +52 -0
  2. groundworkers-0.5.0/CHANGELOG.md +58 -0
  3. groundworkers-0.5.0/PKG-INFO +133 -0
  4. groundworkers-0.5.0/README.md +75 -0
  5. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/adapters/omop_emb.md +1 -0
  6. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/development/extending.md +1 -1
  7. groundworkers-0.5.0/docs/development/plugins.md +195 -0
  8. groundworkers-0.5.0/docs/from-scratch.md +134 -0
  9. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/index.md +18 -8
  10. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/services/grounding.md +1 -0
  11. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/tools/embedding.md +19 -1
  12. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/tools/overview.md +1 -1
  13. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/tools/resolver.md +4 -1
  14. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/usage/testing.md +1 -1
  15. {groundworkers-0.4.0 → groundworkers-0.5.0}/mkdocs.yaml +1 -0
  16. {groundworkers-0.4.0 → groundworkers-0.5.0}/pyproject.toml +5 -14
  17. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/adapters/omop_emb.py +108 -18
  18. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/adapters/omop_graph.py +36 -70
  19. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/app.py +172 -3
  20. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/configuration_provider.py +14 -1
  21. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/databases.py +3 -3
  22. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/embedding_population.py +6 -22
  23. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/graph_maintenance.py +11 -45
  24. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/maintenance_runs.py +169 -94
  25. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/models.py +0 -30
  26. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/performance_maintenance.py +9 -11
  27. groundworkers-0.5.0/src/groundworkers/application/setup/plugin_configuration.py +861 -0
  28. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/runtime_setup.py +90 -8
  29. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/base/__init__.py +2 -1
  30. groundworkers-0.5.0/src/groundworkers/base/concept_payload.py +160 -0
  31. groundworkers-0.5.0/src/groundworkers/base/domain_names.py +78 -0
  32. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/base/server.py +137 -11
  33. groundworkers-0.5.0/src/groundworkers/base/sql.py +30 -0
  34. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/bootstrap.py +1 -1
  35. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/config.py +0 -6
  36. groundworkers-0.5.0/src/groundworkers/plugins.py +336 -0
  37. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/server.py +18 -0
  38. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/domain.py +5 -0
  39. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/graph.py +44 -44
  40. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/grounding.py +29 -7
  41. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/mapping.py +22 -2
  42. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/semantic_projection/definitions.py +8 -12
  43. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/semantic_projection/models.py +1 -3
  44. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/vocab.py +199 -125
  45. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tools/embedding_tools.py +39 -0
  46. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tools/resolver_tools.py +2 -0
  47. groundworkers-0.5.0/src/groundworkers/tui/app.py +208 -0
  48. groundworkers-0.5.0/src/groundworkers/tui/pages/__init__.py +7 -0
  49. groundworkers-0.5.0/src/groundworkers/tui/pages/plugin_config.py +211 -0
  50. groundworkers-0.5.0/src/groundworkers/tui/pages/plugin_setup.py +34 -0
  51. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/pages/setup.py +35 -5
  52. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/presenters/runs.py +3 -58
  53. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/wizards/embeddings.py +15 -38
  54. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/wizards/graph_maintenance.py +11 -30
  55. groundworkers-0.5.0/src/groundworkers/tui/wizards/plugin_setup.py +164 -0
  56. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/integration/test_omop_emb_adapter.py +11 -0
  57. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/integration/test_omop_graph_adapter.py +51 -38
  58. groundworkers-0.5.0/tests/support/postgres_ci_config.toml +5 -0
  59. groundworkers-0.5.0/tests/support/seed_postgres_fixture.py +339 -0
  60. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/test_server_registry.py +63 -2
  61. groundworkers-0.5.0/tests/unit/test_concept_payload.py +162 -0
  62. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_concept_tools.py +2 -0
  63. groundworkers-0.5.0/tests/unit/test_domain_names.py +102 -0
  64. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_embedding_population_scope.py +0 -1
  65. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_embedding_tools.py +53 -0
  66. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_graph_maintenance_wizard.py +37 -20
  67. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_grounding_constraints.py +23 -111
  68. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_grounding_service.py +2 -6
  69. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_maintenance_runs_phase2.py +134 -51
  70. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_mapping_service.py +157 -44
  71. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_migration_boundaries.py +2 -11
  72. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_omop_emb_adapter.py +111 -1
  73. groundworkers-0.5.0/tests/unit/test_plugin_configuration.py +206 -0
  74. groundworkers-0.5.0/tests/unit/test_plugins.py +238 -0
  75. groundworkers-0.5.0/tests/unit/test_schema_resolution.py +251 -0
  76. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_setup_runtime.py +123 -0
  77. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_tui_app.py +211 -5
  78. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_vocab_service.py +9 -2
  79. {groundworkers-0.4.0 → groundworkers-0.5.0}/uv.lock +61 -302
  80. groundworkers-0.4.0/.github/workflows/ci.yml +0 -10
  81. groundworkers-0.4.0/CHANGELOG.md +0 -500
  82. groundworkers-0.4.0/PKG-INFO +0 -182
  83. groundworkers-0.4.0/README.md +0 -124
  84. groundworkers-0.4.0/docs/from-scratch.md +0 -102
  85. groundworkers-0.4.0/groundworkers.bundle +0 -0
  86. groundworkers-0.4.0/src/groundworkers/application/setup/maintenance.py +0 -85
  87. groundworkers-0.4.0/src/groundworkers/base/sql.py +0 -16
  88. groundworkers-0.4.0/src/groundworkers/tui/app.py +0 -132
  89. groundworkers-0.4.0/src/groundworkers/tui/pages/__init__.py +0 -5
  90. groundworkers-0.4.0/tests/unit/test_maintenance_phase1.py +0 -68
  91. {groundworkers-0.4.0 → groundworkers-0.5.0}/.githooks/pre-commit +0 -0
  92. {groundworkers-0.4.0 → groundworkers-0.5.0}/.github/CONTRIBUTING.md +0 -0
  93. {groundworkers-0.4.0 → groundworkers-0.5.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  94. {groundworkers-0.4.0 → groundworkers-0.5.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  95. {groundworkers-0.4.0 → groundworkers-0.5.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  96. {groundworkers-0.4.0 → groundworkers-0.5.0}/.github/ISSUE_TEMPLATE/not_working.yml +0 -0
  97. {groundworkers-0.4.0 → groundworkers-0.5.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  98. {groundworkers-0.4.0 → groundworkers-0.5.0}/.github/release-drafter.yml +0 -0
  99. {groundworkers-0.4.0 → groundworkers-0.5.0}/.github/workflows/docs.yml +0 -0
  100. {groundworkers-0.4.0 → groundworkers-0.5.0}/.github/workflows/merge.yml +0 -0
  101. {groundworkers-0.4.0 → groundworkers-0.5.0}/.github/workflows/publish.yml +0 -0
  102. {groundworkers-0.4.0 → groundworkers-0.5.0}/.gitignore +0 -0
  103. {groundworkers-0.4.0 → groundworkers-0.5.0}/.python-version +0 -0
  104. {groundworkers-0.4.0 → groundworkers-0.5.0}/Makefile +0 -0
  105. {groundworkers-0.4.0 → groundworkers-0.5.0}/config/docker-compose.yaml +0 -0
  106. {groundworkers-0.4.0 → groundworkers-0.5.0}/config/groundworkers.example.toml +0 -0
  107. {groundworkers-0.4.0 → groundworkers-0.5.0}/config/groundworkers_db.env +0 -0
  108. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/adapters/cdm.md +0 -0
  109. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/adapters/omop_graph.md +0 -0
  110. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/architecture.md +0 -0
  111. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/concepts.md +0 -0
  112. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/development/integration.md +0 -0
  113. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/js/mermaid-init.js +0 -0
  114. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/reference/ref_adapters.md +0 -0
  115. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/reference/ref_base.md +0 -0
  116. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/reference/ref_config.md +0 -0
  117. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/reference/ref_services.md +0 -0
  118. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/reference/ref_tools.md +0 -0
  119. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/services/domain.md +0 -0
  120. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/services/graph.md +0 -0
  121. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/services/mapping.md +0 -0
  122. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/services/semantic_projection.md +0 -0
  123. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/services/source_planning.md +0 -0
  124. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/services/text.md +0 -0
  125. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/services/vocab.md +0 -0
  126. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/static/01_create_config.png +0 -0
  127. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/static/02_empty_config.png +0 -0
  128. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/static/03_config_wizard.png +0 -0
  129. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/static/04_test_cnx.png +0 -0
  130. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/static/04_warnings.png +0 -0
  131. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/static/05_graph_setup.png +0 -0
  132. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/static/06_load_predicates.png +0 -0
  133. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/static/07_vector_store.png +0 -0
  134. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/static/08_register_embedding.png +0 -0
  135. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/static/10_setup_complete.png +0 -0
  136. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/tools/concept.md +0 -0
  137. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/tools/domain.md +0 -0
  138. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/tools/knowledge.md +0 -0
  139. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/tools/mapping.md +0 -0
  140. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/tools/search.md +0 -0
  141. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/tools/semantic_projection.md +0 -0
  142. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/tools/source_planning.md +0 -0
  143. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/tools/system.md +0 -0
  144. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/tools/text.md +0 -0
  145. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/usage/configuration.md +0 -0
  146. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/usage/installation.md +0 -0
  147. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/usage/integrations.md +0 -0
  148. {groundworkers-0.4.0 → groundworkers-0.5.0}/docs/usage/setup_journey.md +0 -0
  149. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/__init__.py +0 -0
  150. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/_env.py +0 -0
  151. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/adapters/__init__.py +0 -0
  152. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/adapters/cdm.py +0 -0
  153. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/adapters/llm.py +0 -0
  154. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/__init__.py +0 -0
  155. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/__init__.py +0 -0
  156. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/configuration.py +0 -0
  157. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/embedding_artifacts.py +0 -0
  158. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/embedding_capability.py +0 -0
  159. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/embedding_coverage.py +0 -0
  160. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/embedding_reconciliation.py +0 -0
  161. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/embedding_registry.py +0 -0
  162. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/embedding_setup.py +0 -0
  163. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/integration.py +0 -0
  164. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/application/setup/model_inventory.py +0 -0
  165. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/base/errors.py +0 -0
  166. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/base/results.py +0 -0
  167. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/config/README +0 -0
  168. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/config/predicate_classification.csv +0 -0
  169. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/config/predicate_mapping.csv +0 -0
  170. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/knowledge/packs/core/criteria-gate-yesno/guidance.md +0 -0
  171. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/knowledge/packs/core/criteria-gate-yesno/manifest.yaml +0 -0
  172. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/knowledge/packs/core/diagnosis-role-modifier/guidance.md +0 -0
  173. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/knowledge/packs/core/diagnosis-role-modifier/manifest.yaml +0 -0
  174. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/knowledge/packs/core/domain-routing/guidance.md +0 -0
  175. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/knowledge/packs/core/domain-routing/manifest.yaml +0 -0
  176. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/knowledge/packs/core/domain-routing/rules.yaml +0 -0
  177. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/knowledge/packs/core/drug-concept-granularity/guidance.md +0 -0
  178. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/knowledge/packs/core/drug-concept-granularity/manifest.yaml +0 -0
  179. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/knowledge/packs/core/drug-concept-granularity/rules.yaml +0 -0
  180. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/knowledge/packs/core/history-of-event/guidance.md +0 -0
  181. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/knowledge/packs/core/history-of-event/manifest.yaml +0 -0
  182. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/knowledge/packs/core/standard-concept-preference/guidance.md +0 -0
  183. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/knowledge/packs/core/standard-concept-preference/manifest.yaml +0 -0
  184. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/knowledge/packs/core/standard-concept-preference/rules.yaml +0 -0
  185. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/__init__.py +0 -0
  186. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/knowledge/__init__.py +0 -0
  187. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/knowledge/catalogue.py +0 -0
  188. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/knowledge/models.py +0 -0
  189. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/semantic_projection/__init__.py +0 -0
  190. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/semantic_projection/service.py +0 -0
  191. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/__init__.py +0 -0
  192. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/assisted.py +0 -0
  193. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/canonical_headers.py +0 -0
  194. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/classifier.py +0 -0
  195. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/decomposer.py +0 -0
  196. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/decomposers/__init__.py +0 -0
  197. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/decomposers/csv_.py +0 -0
  198. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/decomposers/ddl_.py +0 -0
  199. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/decomposers/docx_.py +0 -0
  200. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/decomposers/json_.py +0 -0
  201. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/decomposers/pdf_.py +0 -0
  202. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/decomposers/xlsx_.py +0 -0
  203. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/decomposers/xml_.py +0 -0
  204. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/detector.py +0 -0
  205. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/models.py +0 -0
  206. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/normalisation.py +0 -0
  207. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/provenance.py +0 -0
  208. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/router.py +0 -0
  209. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/serialisation.py +0 -0
  210. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/service.py +0 -0
  211. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/source_profiles/__init__.py +0 -0
  212. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/source_profiles/base.py +0 -0
  213. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/source_profiles/redcap.py +0 -0
  214. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/source_profiles/registry.py +0 -0
  215. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/source_planning/warnings.py +0 -0
  216. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/text/__init__.py +0 -0
  217. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/text/models.py +0 -0
  218. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/text/prompts.py +0 -0
  219. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/services/text/service.py +0 -0
  220. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tools/__init__.py +0 -0
  221. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tools/concept_tools.py +0 -0
  222. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tools/domain_tools.py +0 -0
  223. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tools/knowledge_tools.py +0 -0
  224. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tools/mapping_tools.py +0 -0
  225. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tools/search_tools.py +0 -0
  226. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tools/semantic_projection_tools.py +0 -0
  227. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tools/source_planning_tools.py +0 -0
  228. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tools/system_tools.py +0 -0
  229. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tools/text_tools.py +0 -0
  230. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/transports/__init__.py +0 -0
  231. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/transports/rest/__init__.py +0 -0
  232. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/transports/rest/api.py +0 -0
  233. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/transports/rest/models.py +0 -0
  234. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/__init__.py +0 -0
  235. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/pages/base.py +0 -0
  236. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/presenters/__init__.py +0 -0
  237. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/presenters/base.py +0 -0
  238. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/presenters/chat.py +0 -0
  239. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/presenters/configuration.py +0 -0
  240. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/presenters/database.py +0 -0
  241. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/presenters/embeddings.py +0 -0
  242. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/presenters/graph.py +0 -0
  243. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/presenters/llm_provider.py +0 -0
  244. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/presenters/overview.py +0 -0
  245. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/presenters/performance.py +0 -0
  246. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/routes.py +0 -0
  247. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/state.py +0 -0
  248. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/wizards/__init__.py +0 -0
  249. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/wizards/config_location.py +0 -0
  250. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/wizards/embedding_store.py +0 -0
  251. {groundworkers-0.4.0 → groundworkers-0.5.0}/src/groundworkers/tui/wizards/performance_maintenance.py +0 -0
  252. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/__init__.py +0 -0
  253. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/conftest.py +0 -0
  254. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/integration/__init__.py +0 -0
  255. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/support/__init__.py +0 -0
  256. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/support/stack_config.py +0 -0
  257. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/test_bootstrap_config.py +0 -0
  258. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/test_rest_api.py +0 -0
  259. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/__init__.py +0 -0
  260. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_config_location_wizard.py +0 -0
  261. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_configuration_provider.py +0 -0
  262. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_domain_tools.py +0 -0
  263. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_embedding_reconciliation.py +0 -0
  264. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_embedding_registry_step.py +0 -0
  265. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_env_bootstrap.py +0 -0
  266. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_error_boundary.py +0 -0
  267. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_graph_maintenance.py +0 -0
  268. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_graph_service.py +0 -0
  269. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_graph_status.py +0 -0
  270. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_knowledge_catalogue.py +0 -0
  271. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_llm_adapter.py +0 -0
  272. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_mapping_tools.py +0 -0
  273. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_omop_emb_setup_config.py +0 -0
  274. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_omop_graph_adapter.py +0 -0
  275. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_performance.py +0 -0
  276. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_phase3_overview.py +0 -0
  277. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_provider_fields.py +0 -0
  278. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_semantic_projection_service.py +0 -0
  279. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_semantic_projection_tools.py +0 -0
  280. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_setup_artifacts_and_coverage.py +0 -0
  281. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_setup_configuration.py +0 -0
  282. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_setup_configuration_section.py +0 -0
  283. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_setup_databases.py +0 -0
  284. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_setup_embeddings.py +0 -0
  285. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_setup_provider_conformance.py +0 -0
  286. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_setup_truth.py +0 -0
  287. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_setup_write_flows.py +0 -0
  288. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_source_planning_classifier.py +0 -0
  289. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_source_planning_decomposer.py +0 -0
  290. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_source_planning_detector.py +0 -0
  291. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_source_planning_models.py +0 -0
  292. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_source_planning_normalisation.py +0 -0
  293. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_source_planning_router.py +0 -0
  294. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_source_planning_service.py +0 -0
  295. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_source_planning_tools.py +0 -0
  296. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_stack_config_fixtures.py +0 -0
  297. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_system_tools.py +0 -0
  298. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_text_service.py +0 -0
  299. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_text_tools.py +0 -0
  300. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_tui_state.py +0 -0
  301. {groundworkers-0.4.0 → groundworkers-0.5.0}/tests/unit/test_vector_store_setup.py +0 -0
@@ -0,0 +1,52 @@
1
+ name: CI
2
+ on:
3
+ pull_request:
4
+ branches: [main]
5
+ types: [opened, synchronize, reopened, labeled, unlabeled]
6
+ jobs:
7
+ label-gate:
8
+ uses: AustralianCancerDataNetwork/cava-devops/.github/workflows/label-gate.yml@main
9
+ build-test:
10
+ uses: AustralianCancerDataNetwork/cava-devops/.github/workflows/build-test.yml@main
11
+ build-test-postgres:
12
+ uses: AustralianCancerDataNetwork/cava-devops/.github/workflows/build-test-postgres.yml@main
13
+ with:
14
+ ty-src: src
15
+ postgres-image: pgvector/pgvector:pg18
16
+ postgres-db: test_db
17
+ postgres-user: postgres
18
+ postgres-password: postgres
19
+ setup-commands: |
20
+ mkdir -p "$RUNNER_TEMP/omop"
21
+ cp tests/support/postgres_ci_config.toml "$RUNNER_TEMP/omop/config.toml"
22
+ export OA_CONFIG_PATH="$RUNNER_TEMP/omop/config.toml"
23
+ export GROUNDWORKERS_CONFIG_PATH="$RUNNER_TEMP/omop/config.toml"
24
+ export GROUNDWORKERS_REQUIRE_INTEGRATION=1
25
+ export GROUNDWORKERS_TEST_DATABASE_URL="postgresql+psycopg://postgres:postgres@localhost:5432/test_db"
26
+ echo "OA_CONFIG_PATH=$RUNNER_TEMP/omop/config.toml" >> "$GITHUB_ENV"
27
+ echo "GROUNDWORKERS_CONFIG_PATH=$RUNNER_TEMP/omop/config.toml" >> "$GITHUB_ENV"
28
+ echo "GROUNDWORKERS_REQUIRE_INTEGRATION=1" >> "$GITHUB_ENV"
29
+ echo "GROUNDWORKERS_TEST_DATABASE_URL=postgresql+psycopg://postgres:postgres@localhost:5432/test_db" >> "$GITHUB_ENV"
30
+ uv run omop-config connections add pg_test \
31
+ --dialect postgresql+psycopg \
32
+ --host localhost \
33
+ --port 5432 \
34
+ --user postgres \
35
+ --password postgres \
36
+ --database-name test_db \
37
+ --test-only false
38
+ uv run omop-config databases add test_cdm_db \
39
+ --kind cdm \
40
+ --connection pg_test \
41
+ --schema-name public
42
+ uv run omop-config databases add test_vector_db \
43
+ --kind generic \
44
+ --connection pg_test \
45
+ --schema-name public
46
+ uv run omop-config vector-stores add test_embeddings \
47
+ --backend-type pgvector \
48
+ --database test_vector_db
49
+ uv run omop-config configure groundworkers \
50
+ --cdm-db test_cdm_db \
51
+ --vector-store-name test_embeddings
52
+ uv run python -m tests.support.seed_postgres_fixture
@@ -0,0 +1,58 @@
1
+ ### CHANGELOG NO LONGER MAINTAINED
2
+ now handled in ci/cd automation consistent the rest of the cava-devops stack
3
+
4
+ ## 0.3.4
5
+ - started building out the configuration TUI
6
+ - lock upper boundary for oa_configurator compatibility
7
+
8
+ ## 0.3.3
9
+
10
+ feature: changed the way that knowledge packs are registered, updated baseline knowledge packs (status is very draft for this part - ymmv)
11
+
12
+ ## 0.3.2
13
+
14
+ fix: repaired integration tests
15
+
16
+ ## 0.3.1
17
+
18
+ chore: version bump
19
+
20
+ ## 0.3.0
21
+
22
+ feat: knowledge-base integration, layer cleanup, oa-configurator integration, graph and embedding services
23
+ fix: candidate-bundle metadata, knowledge content-serving, embedding-backend honesty, source-profile signals
24
+
25
+ - populate identity metadata (`concept_code`, `vocabulary_id`, `domain_id`, `concept_class_id`) on embedding-only candidates in `concept_candidate_bundle` via a single batch `concept_views` backfill (omop-emb never carries these); warn when the graph service is unavailable to enrich them
26
+ - finish the knowledge catalogue: add `KnowledgeCatalogue.get_pack()` and a `knowledge_pack` MCP tool that serve pack `guidance`/`rules`/`examples` content — previously only manifest metadata and filenames were exposed; also collapse the dead tail branch in `PackApplicability.matches`
27
+ - reject an unsupported embedding backend eagerly at build time with an actionable message, clarifying that FAISS is a query-time cache accelerator (`faiss_cache_dir` + the `embedding-faiss` extra), not a standalone backend value
28
+ - record `inferred_vocab` on source-vocabulary columns so the router derives a table-level domain hint from them, and surface the matched source profile's `structural_skip_field_types` and `packed_value_column_hint` on `PreIngestBundle` / the assisted-plan REST response instead of discarding them
29
+ - require `omop-emb>=1.1.1`
30
+ - add knowledge-base catalogue integration and expand the knowledge-facing tool and service surface
31
+ - introduce dedicated graph and grounding services so concept and resolver tools delegate through a cleaner service-layer split
32
+ - integrate `oa-configurator` into application/bootstrap wiring and refresh the example configuration path
33
+ - expand the `omop-graph` and `omop-emb` adapter layer, including parentless domain-constrained grounding support via `omop-graph>=1.3.0`
34
+ - refresh architecture and service documentation, including new graph, grounding, resolver, and source-planning pages
35
+
36
+ ## 0.2.0
37
+
38
+ feat: add direct Python service layer, mapping workflows, and docs refresh
39
+
40
+ - add `build_application()` and a shared application container for direct Python consumers
41
+ - add `MappingService` as a reusable service-layer API for mapping-oriented workflows
42
+ - add mapping tools for normalized search, candidate bundles, parent backoff, mapping context, `Maps to value`, mapping-expression resolution, and candidate evaluation
43
+ - keep mapping MCP tools thin by delegating orchestration to the service layer
44
+ - tighten `omop-emb` typing through the adapter and server composition path
45
+ - extend docs to cover MCP and direct-Python integration, layer boundaries, and mapping workflows
46
+
47
+ ## 0.1.1
48
+
49
+ feat: add chunk coherence pass and review-state transitions
50
+
51
+ - add coherence reranking based on approved-set distribution
52
+ - infer provisional sets for inferred chunks
53
+ - transition processed chunks to REVIEW and skip them on resume
54
+ - add unit coverage for coherence behavior
55
+
56
+ ## 0.1.0
57
+
58
+ - alpha release for review
@@ -0,0 +1,133 @@
1
+ Metadata-Version: 2.5
2
+ Name: groundworkers
3
+ Version: 0.5.0
4
+ Summary: Groundworkers MCP server — read-only agentive access to OMOP vocabularies, concept graphs, and embeddings.
5
+ Requires-Python: >=3.12
6
+ Requires-Dist: fastapi<1.0,>=0.110
7
+ Requires-Dist: mcp[cli]<2,>=1
8
+ Requires-Dist: numpy<3,>=1.26
9
+ Requires-Dist: oa-configurator<2,>=1.3.0
10
+ Requires-Dist: omop-alchemy<2,>=1.1
11
+ Requires-Dist: omop-emb<3,>=2.1
12
+ Requires-Dist: omop-graph<3,>=2.1
13
+ Requires-Dist: omop-llm<2,>=1
14
+ Requires-Dist: omop-semantics<1,>=0.6
15
+ Requires-Dist: psutil<8,>=5.9
16
+ Requires-Dist: psycopg[binary]<4,>=3.1
17
+ Requires-Dist: pydantic<3,>=2
18
+ Requires-Dist: python-dotenv<2,>=1
19
+ Requires-Dist: pyyaml<7,>=6
20
+ Requires-Dist: sqlalchemy<3,>=2
21
+ Requires-Dist: uvicorn[standard]<1.0,>=0.29
22
+ Provides-Extra: all-source
23
+ Requires-Dist: openpyxl<4,>=3.1; extra == 'all-source'
24
+ Requires-Dist: pdfplumber>=0.10; extra == 'all-source'
25
+ Requires-Dist: python-docx>=1.0; extra == 'all-source'
26
+ Provides-Extra: dev
27
+ Requires-Dist: httpx<1,>=0.27; extra == 'dev'
28
+ Requires-Dist: ipython>=8.0; extra == 'dev'
29
+ Requires-Dist: mkdocs-material>=9.7.1; extra == 'dev'
30
+ Requires-Dist: mkdocs-mermaid2-plugin; extra == 'dev'
31
+ Requires-Dist: mkdocs>=1.6.1; extra == 'dev'
32
+ Requires-Dist: mkdocstrings-python>=2.0.1; extra == 'dev'
33
+ Requires-Dist: mypy>=1.8; extra == 'dev'
34
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
35
+ Requires-Dist: pytest>=9.0.3; extra == 'dev'
36
+ Requires-Dist: requests>=2.33.0; extra == 'dev'
37
+ Requires-Dist: ruff>=0.4; extra == 'dev'
38
+ Requires-Dist: textual>=0.60; extra == 'dev'
39
+ Requires-Dist: tornado>=6.5.5; extra == 'dev'
40
+ Requires-Dist: ty>=0.0.59; extra == 'dev'
41
+ Provides-Extra: docx
42
+ Requires-Dist: python-docx>=1.0; extra == 'docx'
43
+ Provides-Extra: embedding-artifacts
44
+ Requires-Dist: h5py<4,>=3.10; extra == 'embedding-artifacts'
45
+ Provides-Extra: embedding-faiss
46
+ Requires-Dist: omop-emb[faiss-cpu]<3,>=2.1; extra == 'embedding-faiss'
47
+ Provides-Extra: embedding-pgvector
48
+ Requires-Dist: omop-emb[pgvector]<3,>=2.1; extra == 'embedding-pgvector'
49
+ Provides-Extra: pdf
50
+ Requires-Dist: pdfplumber>=0.10; extra == 'pdf'
51
+ Provides-Extra: tui
52
+ Requires-Dist: groundskeeping<1,>=0.8.1; extra == 'tui'
53
+ Requires-Dist: rich<15,>=13; extra == 'tui'
54
+ Requires-Dist: textual>=0.60; extra == 'tui'
55
+ Provides-Extra: xlsx
56
+ Requires-Dist: openpyxl<4,>=3.1; extra == 'xlsx'
57
+ Description-Content-Type: text/markdown
58
+
59
+ # groundworkers
60
+
61
+ Groundworkers is the reusable, read-only capability layer for OMOP vocabulary lookup, concept mapping, source planning, and related analysis. It combines deterministic services with optional embeddings and model-assisted operations.
62
+
63
+ It does not own patient-level writes, session state, or job lifecycle. Those concerns belong to the calling application; `groundcrew` is the usual stateful orchestrator.
64
+
65
+ ## Choose an interface
66
+
67
+ | Interface | Use it when |
68
+ | --- | --- |
69
+ | MCP | An agent needs discoverable tools, prompts, resources, and a shared remote runtime. |
70
+ | REST | An application needs the curated HTTP workflows for candidate bundles or assisted source planning. |
71
+ | Python | A process owns batching, evaluation, or orchestration and can run in-process. |
72
+
73
+ Start with the [documentation home](docs/index.md), or choose a path directly:
74
+
75
+ - [Concepts and capability choices](docs/concepts.md) explains retrieval, grounding, mapping, source planning, and projection.
76
+ - [Installation](docs/usage/installation.md) covers package extras and prerequisites.
77
+ - [Initial local setup](docs/from-scratch.md) walks through a fresh CDM-backed deployment.
78
+ - [Integrations](docs/usage/integrations.md) shows MCP, REST, and Python calls.
79
+ - [Configuration](docs/usage/configuration.md) explains shared-stack references and optional capabilities.
80
+ - [Tools overview](docs/tools/overview.md) maps jobs to the discoverable MCP surface.
81
+
82
+ ## Quick start
83
+
84
+ Install the package and configure the shared OMOP stack:
85
+
86
+ ```bash
87
+ pip install groundworkers
88
+ omop-config configure groundworkers
89
+ ```
90
+
91
+ Inspect the active configuration and MCP surface before starting a service:
92
+
93
+ ```bash
94
+ groundworkers --describe
95
+ ```
96
+
97
+ Run MCP over stdio for a client that starts the process, or over Streamable HTTP for a shared service:
98
+
99
+ ```bash
100
+ groundworkers
101
+ groundworkers --transport streamable-http --host 127.0.0.1 --port 8000
102
+ ```
103
+
104
+ REST is a separate, curated interface:
105
+
106
+ ```bash
107
+ groundworkers --transport rest --host 127.0.0.1 --port 8080
108
+ ```
109
+
110
+ ## Direct Python
111
+
112
+ Build the application once and reuse it. Services are optional when their prerequisites are not configured:
113
+
114
+ ```python
115
+ from groundworkers.app import build_application
116
+ from groundworkers.bootstrap import build_app_config
117
+
118
+ config = build_app_config()
119
+ app = build_application(config)
120
+
121
+ bundle = app.services.mapping.concept_candidate_bundle(
122
+ "type 2 diabetes",
123
+ domain="Condition",
124
+ )
125
+ ```
126
+
127
+ The `mapping` service in this example requires a configured CDM database. Embedding-backed channels require an embedding model and vector store; text, domain classification, and assisted source planning require a configured chat model. Use `groundworkers --describe` to see what the current deployment exposes.
128
+
129
+ ## Companion repositories
130
+
131
+ - [groundcrew](https://github.com/AustralianCancerDataNetwork/groundcrew) owns session state and orchestration.
132
+ - [omop-graph](https://australiancancerdatanetwork.github.io/omop-graph/) provides graph-backed OMOP traversal.
133
+ - [omop-emb](https://australiancancerdatanetwork.github.io/omop-emb/) provides embedding stores and indexes.
@@ -0,0 +1,75 @@
1
+ # groundworkers
2
+
3
+ Groundworkers is the reusable, read-only capability layer for OMOP vocabulary lookup, concept mapping, source planning, and related analysis. It combines deterministic services with optional embeddings and model-assisted operations.
4
+
5
+ It does not own patient-level writes, session state, or job lifecycle. Those concerns belong to the calling application; `groundcrew` is the usual stateful orchestrator.
6
+
7
+ ## Choose an interface
8
+
9
+ | Interface | Use it when |
10
+ | --- | --- |
11
+ | MCP | An agent needs discoverable tools, prompts, resources, and a shared remote runtime. |
12
+ | REST | An application needs the curated HTTP workflows for candidate bundles or assisted source planning. |
13
+ | Python | A process owns batching, evaluation, or orchestration and can run in-process. |
14
+
15
+ Start with the [documentation home](docs/index.md), or choose a path directly:
16
+
17
+ - [Concepts and capability choices](docs/concepts.md) explains retrieval, grounding, mapping, source planning, and projection.
18
+ - [Installation](docs/usage/installation.md) covers package extras and prerequisites.
19
+ - [Initial local setup](docs/from-scratch.md) walks through a fresh CDM-backed deployment.
20
+ - [Integrations](docs/usage/integrations.md) shows MCP, REST, and Python calls.
21
+ - [Configuration](docs/usage/configuration.md) explains shared-stack references and optional capabilities.
22
+ - [Tools overview](docs/tools/overview.md) maps jobs to the discoverable MCP surface.
23
+
24
+ ## Quick start
25
+
26
+ Install the package and configure the shared OMOP stack:
27
+
28
+ ```bash
29
+ pip install groundworkers
30
+ omop-config configure groundworkers
31
+ ```
32
+
33
+ Inspect the active configuration and MCP surface before starting a service:
34
+
35
+ ```bash
36
+ groundworkers --describe
37
+ ```
38
+
39
+ Run MCP over stdio for a client that starts the process, or over Streamable HTTP for a shared service:
40
+
41
+ ```bash
42
+ groundworkers
43
+ groundworkers --transport streamable-http --host 127.0.0.1 --port 8000
44
+ ```
45
+
46
+ REST is a separate, curated interface:
47
+
48
+ ```bash
49
+ groundworkers --transport rest --host 127.0.0.1 --port 8080
50
+ ```
51
+
52
+ ## Direct Python
53
+
54
+ Build the application once and reuse it. Services are optional when their prerequisites are not configured:
55
+
56
+ ```python
57
+ from groundworkers.app import build_application
58
+ from groundworkers.bootstrap import build_app_config
59
+
60
+ config = build_app_config()
61
+ app = build_application(config)
62
+
63
+ bundle = app.services.mapping.concept_candidate_bundle(
64
+ "type 2 diabetes",
65
+ domain="Condition",
66
+ )
67
+ ```
68
+
69
+ The `mapping` service in this example requires a configured CDM database. Embedding-backed channels require an embedding model and vector store; text, domain classification, and assisted source planning require a configured chat model. Use `groundworkers --describe` to see what the current deployment exposes.
70
+
71
+ ## Companion repositories
72
+
73
+ - [groundcrew](https://github.com/AustralianCancerDataNetwork/groundcrew) owns session state and orchestration.
74
+ - [omop-graph](https://australiancancerdatanetwork.github.io/omop-graph/) provides graph-backed OMOP traversal.
75
+ - [omop-emb](https://australiancancerdatanetwork.github.io/omop-emb/) provides embedding stores and indexes.
@@ -37,6 +37,7 @@ No live model API is required.
37
37
  Requires an embedding client configured through `omop-emb` package settings.
38
38
 
39
39
  - `embedding_search` encodes a text query on the fly
40
+ - `embedding_search_batch` encodes and searches multiple text queries with one provider/index batch, returning rows aligned to input order
40
41
  - `embedding_encode` returns a raw embedding vector
41
42
 
42
43
  ## Availability model
@@ -1,6 +1,6 @@
1
1
  # Extending groundworkers
2
2
 
3
- This guide is for contributors adding new adapters, services, MCP tools, or REST endpoints. The main rule is simple:
3
+ This guide is for contributors adding new adapters, services, MCP tools, or REST endpoints directly in this repository. If you're adding a self-contained capability as a separate installable package instead — no core file edits — see [Plugin architecture](plugins.md). The main rule here is simple:
4
4
 
5
5
  **keep business logic above the transport layer and keep dependency details below it.**
6
6
 
@@ -0,0 +1,195 @@
1
+ # Plugin architecture
2
+
3
+ ## What a plugin is
4
+
5
+ Groundworkers plugins are independently installed packages that add an adapter, service, and MCP surface without adding plugin-specific imports to Groundworkers. They register one ready-to-use plugin object under the `groundworkers.plugins` entry-point group.
6
+
7
+ ```toml
8
+ [project.entry-points."groundworkers.plugins"]
9
+ my_plugin = "my_package.plugin:plugin"
10
+ ```
11
+
12
+ ```mermaid
13
+ flowchart LR
14
+ subgraph PKG["my_package — a separate installed package"]
15
+ direction TB
16
+ CFG["Config class<br/><i>the settings this plugin needs</i>"]
17
+ OBJ["Plugin object<br/>name &middot; config class &middot; build() &middot; register()"]
18
+ end
19
+
20
+ subgraph HOST["Groundworkers — the host application"]
21
+ direction TB
22
+ DISC["Discovery<br/><i>looks up installed plugins</i>"]
23
+ CTX["Shared connections<br/><i>database, embeddings — already<br/>set up by Groundworkers itself</i>"]
24
+ SRV["Shared MCP tool server"]
25
+ end
26
+
27
+ OBJ -.->|"found via the environment's<br/>own package listing"| DISC
28
+ DISC -->|"reads + validates"| CFG
29
+ CTX -->|"handed to"| OBJ
30
+ OBJ -->|"register() adds its tools"| SRV
31
+ ```
32
+
33
+ The object implements `GroundworkersPlugin`: a stable `name`, an optional `PackageConfigBase` class, `build(context, config)`, and `register(server, state)`. The plugin name and `config_cls.tool_name` must match. **Installed plugin names must be unique.**
34
+
35
+ ```python
36
+ class MyPlugin:
37
+ name = "my_plugin"
38
+ config_cls = ExampleConfig # or None, if this plugin needs no configuration
39
+
40
+ def build(self, context, config):
41
+ ... # return a service object, or None if a prerequisite is unavailable
42
+
43
+ def register(self, server, state):
44
+ ... # add this plugin's MCP tools/resources
45
+
46
+
47
+ plugin = MyPlugin()
48
+ ```
49
+
50
+ ## Start from the use case
51
+
52
+ A plugin's configuration should follow from what it needs to be able to complete its task.
53
+
54
+ Work through each requirement before writing the class.
55
+
56
+ For example, a plugin recommending comparator cohorts might reason like this.
57
+
58
+ **Reuse a resource Groundworkers already resolved.** Nothing to declare — read it straight off `PluginContext` inside `build()`:
59
+
60
+ | Use case | What you need | How you get it |
61
+ |---|---|---|
62
+ | Look up existing OMOP concepts | Read access to the CDM vocabulary connection Groundworkers already opened | `context.cdm_engine` / `context.resolver` |
63
+ | Rank or filter by similarity to concepts Groundworkers already embedded | The concept embeddings Groundworkers already populated, via omop-emb | `context.vector_store` + `context.embedding_backend_factory` |
64
+ | Ask an LLM to help decide something | The chat model Groundworkers already configured, via omop-llm | `context.chat_backend_factory` |
65
+
66
+ **Create something this plugin owns.** Each becomes a field on its own `PackageConfigBase` — see [Package configuration](#package-configuration):
67
+
68
+ | Use case | What you need | Configuration field established | Notes |
69
+ |---|---|---|---|
70
+ | Store its own distinct non-CDM source tables | A database connection this plugin owns and writes to | `comparator_db: Annotated[str, RefTo(CDMDatabaseConfig)] = "cdm_db"` | Same shape as a core reference, but the operator points it at a new entry when they configure the plugin |
71
+ | Vectorised *arbitrary free text or objects* for similarity search | Its own embedding model | `embedding_model_name: Annotated[str \| None, RefTo(ModelConfig)] = None` | Optional, independent of Groundworkers' own model choice |
72
+ | Store and search those vectors | Its own vector index | `vector_store_name: Annotated[str \| None, RefTo(VectorStoreConfig)] = None` | **Not existing OMOP concepts, see above** |
73
+ | Let operators tune how strict "similar enough" is | Parameter the plugin's logic requires | `min_databases_default: int = Field(default=2, ge=1)` | A plain setting, nothing to resolve |
74
+
75
+ The concept-embedding row and the free-text-embedding row look similar but are not the same decision: the first reuses a vector store Groundworkers already populated with OMOP concepts; the second stands up an independent embedding model and vector store for data that was never a concept to begin with. Reusing `context.vector_store` for the second case would put unrelated vectors in Groundworkers' own concept index.
76
+
77
+ ### Assumptions this table is making
78
+
79
+ - **Vocabulary only, so far.** Every example above reads OMOP *vocabulary* i.e. operations over concepts, concept relationships, concept embeddings. Nothing about `context.cdm_engine` restricts a plugin to vocabulary tables specifically, however. These tables are available over the same CDM connection groundworkers itself uses, and a plugin *could* query clinical/person-level tables (`condition_occurrence`, `drug_exposure`, etc.) through it just as easily, subject to whatever environmental and procedural access controls actually govern that data.
80
+ - **Plugin graph access is TODO.** `PluginContext` does not expose graph traversal at this time, which means that a plugin that wants graph traversal would have to depend on `omop-graph` itself and build its own adapter, reusing `context.cdm_engine` for the connection but not groundworkers' own shared instance. Recommend not doing it that way, however, as it would be easier to expose the core graph the same way `vector_store` and `embedding_backend_factory` already are.
81
+
82
+ ## Build and register a new plugin
83
+
84
+ `build()` receives `PluginContext`. The context provides the resolved CDM database and engine, vector store, shared lazy model backend factories, and a deliberately narrow resolver for independent named OA resources. Return `None` when a prerequisite is unavailable. Groundworkers then keeps serving its core capabilities and reports why the plugin was not activated.
85
+
86
+ `register()` adds MCP tools, prompts, or resources against the state returned by `build()`. The shared MCP registration wrapper supplies the same safe error translation used by core tools. Code-defined prompts can continue to derive their arguments from the callable signature. A plugin publishing data-defined prompts can pass explicit string metadata with `PromptArgument`; this keeps dynamic pack fields out of Python closure signatures:
87
+
88
+ ```python
89
+ from groundworkers.base import PromptArgument
90
+
91
+ server.prompt(
92
+ "my_pack_workflow",
93
+ title="Run my pack workflow",
94
+ description="Start the workflow published by my pack.",
95
+ arguments=[
96
+ PromptArgument(
97
+ "request",
98
+ "The user's starting request.",
99
+ required=False,
100
+ )
101
+ ],
102
+ )(handler)
103
+ ```
104
+
105
+ ```mermaid
106
+ sequenceDiagram
107
+ participant Env as Installed packages
108
+ participant GW as Groundworkers (host)
109
+ participant P as my_package (a plugin)
110
+
111
+ Note over Env: 1.
112
+
113
+ GW->>Env: At startup: list every registered plugin
114
+ Env-->>GW: my_package's plugin object
115
+
116
+ Note over GW,P: 2.
117
+
118
+ GW->>P: Resolve its config class into validated settings
119
+ GW->>P: build(shared connections, those settings)
120
+ P-->>GW: its own service object (or "not available")
121
+
122
+ GW->>P: register(shared MCP server, that service object)
123
+ P-->>GW: adds its own tools to the shared server
124
+
125
+ Note over GW: 3.
126
+ ```
127
+
128
+ 1. The plugin's own installer registered one entry: "here is my plugin object."
129
+ 2. Groundworkers' code never imports `my_package` by name. It only expects four things on the object (`name`, optional `PackageConfigBase` class, plus `build` and `register` methods, described above).
130
+ 3. The plugin's tools are now callable through the one Groundworkers server.
131
+
132
+ ## Package configuration
133
+
134
+ A plugin with scalar and `RefTo` fields receives a setup-console page without any Groundskeeping-aware plugin code:
135
+
136
+ ```python
137
+ from typing import Annotated, ClassVar
138
+
139
+ from oa_configurator import CDMDatabaseConfig, PackageConfigBase, RefTo
140
+ from pydantic import Field
141
+
142
+
143
+ class ExampleConfig(PackageConfigBase):
144
+ tool_name: ClassVar[str] = "my_plugin"
145
+
146
+ database: Annotated[str, RefTo(CDMDatabaseConfig)] = "cdm_db"
147
+ retries: int = Field(default=2, ge=1)
148
+ ```
149
+
150
+ The generic workflow maps supported Pydantic scalars to Groundskeeping fields, offers existing references of the correct concrete type, and can create a new reference chain recursively through oa-configurator's public `plan_configure()` API. Candidates remain private to the Groundworkers provider; review output is redacted and persistence is revision-aware.
151
+
152
+ Schemas requiring live discovery or a conditional flow (and therefore not fitting the default configuration UX specification) may additionally implement the runtime-checkable `GroundworkersPluginConfigUI` protocol. Its `tui_workflow(operation)` method returns a custom `(ConfigWorkflowSpec, ConfigMutationService)` pair. Keep Groundskeeping in the plugin's optional TUI dependencies so headless plugin imports remain lightweight.
153
+
154
+ ### Sensitive fields
155
+
156
+ `PackageConfigBase` inherits oa-configurator's `SecretSafeModel`. A plugin developer must mark every plugin-owned secret with `Sensitive()` so model representations, interactive fields, configuration views, and review diffs can redact it by schema declaration. Groundworkers does not infer sensitivity from field names.
157
+
158
+ ```python
159
+ from typing import Annotated, ClassVar
160
+
161
+ from oa_configurator import PackageConfigBase, Sensitive
162
+ from pydantic import Field
163
+
164
+
165
+ class ExampleConfig(PackageConfigBase):
166
+ tool_name: ClassVar[str] = "my_plugin"
167
+ api_token: Annotated[str | None, Sensitive()] = Field(default=None)
168
+ ```
169
+
170
+ The `oa_configurator.Secret` alias is equivalent to `Annotated[str | None, Sensitive()]`. Prefer a `RefTo` field when a plugin can reuse an existing database, model, provider, or vector-store entry. The plugin then stores only the logical reference name; sensitivity remains declared on the referenced schema, such as `ConnectionConfig.password` or `ProviderConfig.api_key`, and the generic recursive configuration workflow preserves those declarations.
171
+
172
+ This protects display and logging surfaces; it does not encrypt persisted configuration. Plugin documentation must describe the storage expectations for any secret it introduces.
173
+
174
+ ## Setup steps
175
+
176
+ Plugin data preparation belongs in registered setup steps. A plugin may expose a `setup_steps` tuple of `PluginSetupStep` instances. Each step declares a stable key, operator copy, typed arguments, and a `build_plan(values, config_path)` callable that returns a `MaintenancePlan`.
177
+
178
+ The host provides the common setup-console form and review flow, passes argument values only to that run, and starts the resulting plan through the durable maintenance-run store. Logs, progress, cancellation, retry, and the Runs view are therefore shared by core operations and plugins.
179
+
180
+ Setup arguments are separate from package configuration: database/model references and policy defaults belong in configuration, while paths to an input export belong to the one-off setup run.
181
+
182
+ Long-running plugin work should be represented by commands in the plan and run out of process. The command may invoke the plugin's own setup module or console entry point; Groundworkers does not import plugin internals or reproduce their loading logic.
183
+
184
+ ## Readiness verification
185
+
186
+ A plugin may implement `GroundworkersPluginReadiness.verify_readiness(state)` when operators need to distinguish valid package configuration from an initialised, usable capability.
187
+
188
+ Verification is read-only and returns a `PluginReadinessResult` containing a stable state, a summary, and `PluginReadinessField` values. Display values must never contain credentials, connection URLs, or raw exception text.
189
+
190
+ The contract is headless: it contains no Groundskeeping types. Groundworkers uses the same result for generic setup-console rendering, while a plugin may return `result.as_dict()` from its own MCP status tool. Plugins own dependency- specific checks; the host only builds current plugin state, handles unavailable configuration safely, and maps readiness states to existing Groundskeeping status, table, empty, action, and detail contracts.
191
+
192
+
193
+ ## Lifecycle and diagnostics
194
+
195
+ Groundworkers discovers the plugin set once per application build, validates its identities, resolves each package configuration, and builds state. MCP registration uses those same discovered objects. `groundworkers --describe` lists active plugins and safe `plugin_issues` for plugins skipped because their configuration, prerequisites, build, or registration failed.