groundworkers 0.4.0__tar.gz → 0.6.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.
- groundworkers-0.6.0/.github/workflows/ci.yml +52 -0
- groundworkers-0.6.0/CHANGELOG.md +58 -0
- groundworkers-0.6.0/PKG-INFO +133 -0
- groundworkers-0.6.0/README.md +75 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/adapters/omop_emb.md +1 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/development/extending.md +1 -1
- groundworkers-0.6.0/docs/development/plugins.md +195 -0
- groundworkers-0.6.0/docs/from-scratch.md +134 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/index.md +18 -8
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/services/grounding.md +1 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/services/vocab.md +34 -16
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/tools/embedding.md +19 -1
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/tools/overview.md +1 -1
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/tools/resolver.md +4 -1
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/usage/testing.md +1 -1
- {groundworkers-0.4.0 → groundworkers-0.6.0}/mkdocs.yaml +1 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/pyproject.toml +11 -15
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/adapters/omop_emb.py +120 -20
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/adapters/omop_graph.py +36 -70
- groundworkers-0.6.0/src/groundworkers/app.py +394 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/setup/configuration_provider.py +14 -1
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/setup/databases.py +132 -24
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/setup/embedding_population.py +6 -22
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/setup/graph_maintenance.py +11 -45
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/setup/maintenance_runs.py +169 -94
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/setup/models.py +0 -30
- groundworkers-0.6.0/src/groundworkers/application/setup/performance_maintenance.py +239 -0
- groundworkers-0.6.0/src/groundworkers/application/setup/plugin_configuration.py +861 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/setup/runtime_setup.py +90 -9
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/base/__init__.py +2 -1
- groundworkers-0.6.0/src/groundworkers/base/concept_payload.py +160 -0
- groundworkers-0.6.0/src/groundworkers/base/domain_names.py +78 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/base/errors.py +1 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/base/server.py +137 -11
- groundworkers-0.6.0/src/groundworkers/base/sql.py +165 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/bootstrap.py +1 -1
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/config.py +0 -6
- groundworkers-0.6.0/src/groundworkers/plugins.py +413 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/server.py +18 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/domain.py +5 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/graph.py +44 -44
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/grounding.py +29 -7
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/mapping.py +327 -60
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/semantic_projection/definitions.py +8 -12
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/semantic_projection/models.py +1 -3
- groundworkers-0.6.0/src/groundworkers/services/vocab.py +1108 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tools/embedding_tools.py +53 -2
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tools/mapping_tools.py +14 -2
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tools/resolver_tools.py +2 -0
- groundworkers-0.6.0/src/groundworkers/tui/app.py +208 -0
- groundworkers-0.6.0/src/groundworkers/tui/pages/__init__.py +7 -0
- groundworkers-0.6.0/src/groundworkers/tui/pages/plugin_config.py +211 -0
- groundworkers-0.6.0/src/groundworkers/tui/pages/plugin_setup.py +34 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/pages/setup.py +65 -17
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/presenters/database.py +6 -5
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/presenters/performance.py +71 -27
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/presenters/runs.py +3 -58
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/routes.py +1 -1
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/wizards/embeddings.py +15 -38
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/wizards/graph_maintenance.py +11 -30
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/wizards/performance_maintenance.py +44 -11
- groundworkers-0.6.0/src/groundworkers/tui/wizards/plugin_setup.py +164 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/integration/test_omop_emb_adapter.py +11 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/integration/test_omop_graph_adapter.py +51 -38
- groundworkers-0.6.0/tests/support/postgres_ci_config.toml +5 -0
- groundworkers-0.6.0/tests/support/seed_postgres_fixture.py +339 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/test_server_registry.py +63 -2
- groundworkers-0.6.0/tests/unit/test_concept_payload.py +162 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_concept_tools.py +2 -0
- groundworkers-0.6.0/tests/unit/test_domain_names.py +102 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_embedding_population_scope.py +0 -1
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_embedding_tools.py +105 -4
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_graph_maintenance_wizard.py +37 -20
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_grounding_constraints.py +23 -111
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_grounding_service.py +2 -6
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_maintenance_runs_phase2.py +134 -51
- groundworkers-0.6.0/tests/unit/test_mapping_context.py +103 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_mapping_service.py +299 -50
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_mapping_tools.py +11 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_migration_boundaries.py +2 -11
- groundworkers-0.6.0/tests/unit/test_normalized_index.py +201 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_omop_emb_adapter.py +111 -1
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_performance.py +16 -6
- groundworkers-0.6.0/tests/unit/test_performance_maintenance_wizard.py +25 -0
- groundworkers-0.6.0/tests/unit/test_plugin_configuration.py +206 -0
- groundworkers-0.6.0/tests/unit/test_plugins.py +238 -0
- groundworkers-0.6.0/tests/unit/test_schema_resolution.py +251 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_setup_databases.py +1 -3
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_setup_runtime.py +123 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_tui_app.py +211 -5
- groundworkers-0.6.0/tests/unit/test_vocab_service.py +328 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/uv.lock +90 -326
- groundworkers-0.4.0/.github/workflows/ci.yml +0 -10
- groundworkers-0.4.0/CHANGELOG.md +0 -500
- groundworkers-0.4.0/PKG-INFO +0 -182
- groundworkers-0.4.0/README.md +0 -124
- groundworkers-0.4.0/docs/from-scratch.md +0 -102
- groundworkers-0.4.0/groundworkers.bundle +0 -0
- groundworkers-0.4.0/src/groundworkers/app.py +0 -186
- groundworkers-0.4.0/src/groundworkers/application/setup/maintenance.py +0 -85
- groundworkers-0.4.0/src/groundworkers/application/setup/performance_maintenance.py +0 -153
- groundworkers-0.4.0/src/groundworkers/base/sql.py +0 -16
- groundworkers-0.4.0/src/groundworkers/services/vocab.py +0 -809
- groundworkers-0.4.0/src/groundworkers/tui/app.py +0 -132
- groundworkers-0.4.0/src/groundworkers/tui/pages/__init__.py +0 -5
- groundworkers-0.4.0/tests/unit/test_maintenance_phase1.py +0 -68
- groundworkers-0.4.0/tests/unit/test_vocab_service.py +0 -141
- {groundworkers-0.4.0 → groundworkers-0.6.0}/.githooks/pre-commit +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/.github/CONTRIBUTING.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/.github/ISSUE_TEMPLATE/not_working.yml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/.github/release-drafter.yml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/.github/workflows/docs.yml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/.github/workflows/merge.yml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/.github/workflows/publish.yml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/.gitignore +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/.python-version +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/Makefile +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/config/docker-compose.yaml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/config/groundworkers.example.toml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/config/groundworkers_db.env +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/adapters/cdm.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/adapters/omop_graph.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/architecture.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/concepts.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/development/integration.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/js/mermaid-init.js +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/reference/ref_adapters.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/reference/ref_base.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/reference/ref_config.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/reference/ref_services.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/reference/ref_tools.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/services/domain.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/services/graph.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/services/mapping.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/services/semantic_projection.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/services/source_planning.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/services/text.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/static/01_create_config.png +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/static/02_empty_config.png +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/static/03_config_wizard.png +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/static/04_test_cnx.png +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/static/04_warnings.png +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/static/05_graph_setup.png +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/static/06_load_predicates.png +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/static/07_vector_store.png +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/static/08_register_embedding.png +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/static/10_setup_complete.png +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/tools/concept.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/tools/domain.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/tools/knowledge.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/tools/mapping.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/tools/search.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/tools/semantic_projection.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/tools/source_planning.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/tools/system.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/tools/text.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/usage/configuration.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/usage/installation.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/usage/integrations.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/docs/usage/setup_journey.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/_env.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/adapters/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/adapters/cdm.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/adapters/llm.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/setup/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/setup/configuration.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/setup/embedding_artifacts.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/setup/embedding_capability.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/setup/embedding_coverage.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/setup/embedding_reconciliation.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/setup/embedding_registry.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/setup/embedding_setup.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/setup/integration.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/application/setup/model_inventory.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/base/results.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/config/README +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/config/predicate_classification.csv +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/config/predicate_mapping.csv +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/knowledge/packs/core/criteria-gate-yesno/guidance.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/knowledge/packs/core/criteria-gate-yesno/manifest.yaml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/knowledge/packs/core/diagnosis-role-modifier/guidance.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/knowledge/packs/core/diagnosis-role-modifier/manifest.yaml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/knowledge/packs/core/domain-routing/guidance.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/knowledge/packs/core/domain-routing/manifest.yaml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/knowledge/packs/core/domain-routing/rules.yaml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/knowledge/packs/core/drug-concept-granularity/guidance.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/knowledge/packs/core/drug-concept-granularity/manifest.yaml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/knowledge/packs/core/drug-concept-granularity/rules.yaml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/knowledge/packs/core/history-of-event/guidance.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/knowledge/packs/core/history-of-event/manifest.yaml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/knowledge/packs/core/standard-concept-preference/guidance.md +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/knowledge/packs/core/standard-concept-preference/manifest.yaml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/knowledge/packs/core/standard-concept-preference/rules.yaml +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/knowledge/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/knowledge/catalogue.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/knowledge/models.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/semantic_projection/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/semantic_projection/service.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/assisted.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/canonical_headers.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/classifier.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/decomposer.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/decomposers/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/decomposers/csv_.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/decomposers/ddl_.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/decomposers/docx_.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/decomposers/json_.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/decomposers/pdf_.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/decomposers/xlsx_.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/decomposers/xml_.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/detector.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/models.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/normalisation.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/provenance.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/router.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/serialisation.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/service.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/source_profiles/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/source_profiles/base.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/source_profiles/redcap.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/source_profiles/registry.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/source_planning/warnings.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/text/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/text/models.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/text/prompts.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/services/text/service.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tools/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tools/concept_tools.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tools/domain_tools.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tools/knowledge_tools.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tools/search_tools.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tools/semantic_projection_tools.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tools/source_planning_tools.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tools/system_tools.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tools/text_tools.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/transports/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/transports/rest/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/transports/rest/api.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/transports/rest/models.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/pages/base.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/presenters/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/presenters/base.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/presenters/chat.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/presenters/configuration.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/presenters/embeddings.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/presenters/graph.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/presenters/llm_provider.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/presenters/overview.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/state.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/wizards/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/wizards/config_location.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/src/groundworkers/tui/wizards/embedding_store.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/conftest.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/integration/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/support/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/support/stack_config.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/test_bootstrap_config.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/test_rest_api.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/__init__.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_config_location_wizard.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_configuration_provider.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_domain_tools.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_embedding_reconciliation.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_embedding_registry_step.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_env_bootstrap.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_error_boundary.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_graph_maintenance.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_graph_service.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_graph_status.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_knowledge_catalogue.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_llm_adapter.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_omop_emb_setup_config.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_omop_graph_adapter.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_phase3_overview.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_provider_fields.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_semantic_projection_service.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_semantic_projection_tools.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_setup_artifacts_and_coverage.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_setup_configuration.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_setup_configuration_section.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_setup_embeddings.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_setup_provider_conformance.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_setup_truth.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_setup_write_flows.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_source_planning_classifier.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_source_planning_decomposer.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_source_planning_detector.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_source_planning_models.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_source_planning_normalisation.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_source_planning_router.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_source_planning_service.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_source_planning_tools.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_stack_config_fixtures.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_system_tools.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_text_service.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_text_tools.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.0}/tests/unit/test_tui_state.py +0 -0
- {groundworkers-0.4.0 → groundworkers-0.6.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.6.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.9; 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 · config class · build() · 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, or the host's shared grounding cascade. 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
|
+
- **Shared mapping access.** `PluginContext.mapping_context` is an optional,read-only capability façade over the host's mapping and grounding policy. Use its operations when a plugin needs candidate bundles, text grounding, or concept context. `concept_shared_standard_ancestor(concept_ids, max_depth=5)` returns the unique nearest shared standard ancestor when one exists; raise `max_depth` to widen the hierarchy search. The underlying vocabulary, graph, and service objects are deliberately not exposed. Do not construct a second `omop-graph` or vocabulary adapter from `context.cdm_engine`. The field is `None` only when the host did not compose services for the plugin context.
|
|
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, the optional read-only `mapping_context`, 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.
|