openmapstack 0.3.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 (122) hide show
  1. openmapstack-0.5.0/PKG-INFO +565 -0
  2. openmapstack-0.5.0/README.md +541 -0
  3. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/__init__.py +1 -1
  4. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/api.py +23 -2
  5. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/checks/__init__.py +4 -3
  6. openmapstack-0.5.0/openmapstack/checks/_axis_order.py +66 -0
  7. openmapstack-0.5.0/openmapstack/checks/credits.py +318 -0
  8. openmapstack-0.5.0/openmapstack/checks/delivery.py +231 -0
  9. openmapstack-0.5.0/openmapstack/checks/findings.py +19 -0
  10. openmapstack-0.5.0/openmapstack/checks/geodata.py +656 -0
  11. openmapstack-0.5.0/openmapstack/checks/integration.py +39 -0
  12. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/checks/overrides.py +10 -7
  13. openmapstack-0.5.0/openmapstack/checks/presentation.py +401 -0
  14. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/checks/project.py +38 -10
  15. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/checks/qgis.py +177 -18
  16. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/checks/rerun.py +102 -0
  17. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/checks/spatial.py +17 -7
  18. openmapstack-0.5.0/openmapstack/checks/tables.py +330 -0
  19. openmapstack-0.5.0/openmapstack/checks/tiling.py +83 -0
  20. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/checks/validation.py +51 -4
  21. openmapstack-0.5.0/openmapstack/checks/visual.py +1434 -0
  22. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/cli.py +361 -10
  23. openmapstack-0.5.0/openmapstack/collection.py +191 -0
  24. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/connectors/__init__.py +101 -14
  25. openmapstack-0.5.0/openmapstack/connectors/bigquery.py +410 -0
  26. openmapstack-0.5.0/openmapstack/connectors/motherduck.py +279 -0
  27. openmapstack-0.5.0/openmapstack/credits.py +150 -0
  28. openmapstack-0.5.0/openmapstack/declarations.py +41 -0
  29. openmapstack-0.5.0/openmapstack/delivery.py +209 -0
  30. openmapstack-0.5.0/openmapstack/environment.py +193 -0
  31. openmapstack-0.5.0/openmapstack/findings.py +197 -0
  32. openmapstack-0.5.0/openmapstack/integration.py +154 -0
  33. openmapstack-0.5.0/openmapstack/integrations/__init__.py +1 -0
  34. openmapstack-0.5.0/openmapstack/integrations/qgis.py +132 -0
  35. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/integrity.py +16 -9
  36. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/parameters.py +64 -2
  37. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/rerun.py +19 -0
  38. openmapstack-0.5.0/openmapstack/sampling.py +202 -0
  39. openmapstack-0.5.0/openmapstack/schema.py +76 -0
  40. openmapstack-0.5.0/openmapstack/schemas/findings-v1.schema.json +53 -0
  41. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/schemas/project-v1.schema.json +318 -7
  42. openmapstack-0.5.0/openmapstack/schemas/skill-snapshot-v2.schema.json +25 -0
  43. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/snapshot.py +3 -0
  44. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/validation.py +302 -98
  45. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/verify.py +127 -9
  46. openmapstack-0.5.0/openmapstack.egg-info/PKG-INFO +565 -0
  47. openmapstack-0.5.0/openmapstack.egg-info/SOURCES.txt +111 -0
  48. openmapstack-0.5.0/openmapstack.egg-info/requires.txt +21 -0
  49. {openmapstack-0.3.0 → openmapstack-0.5.0}/pyproject.toml +9 -4
  50. openmapstack-0.5.0/tests/test_assumptions.py +95 -0
  51. openmapstack-0.5.0/tests/test_benchmark_ci.py +102 -0
  52. {openmapstack-0.3.0 → openmapstack-0.5.0}/tests/test_check_api.py +54 -0
  53. {openmapstack-0.3.0 → openmapstack-0.5.0}/tests/test_cli.py +237 -12
  54. openmapstack-0.5.0/tests/test_cloud_connectors.py +788 -0
  55. openmapstack-0.5.0/tests/test_cloud_fixture_sql.py +653 -0
  56. openmapstack-0.5.0/tests/test_collection.py +140 -0
  57. {openmapstack-0.3.0 → openmapstack-0.5.0}/tests/test_connectors.py +63 -4
  58. openmapstack-0.5.0/tests/test_credits.py +457 -0
  59. openmapstack-0.5.0/tests/test_credits_visual.py +64 -0
  60. openmapstack-0.5.0/tests/test_delivery.py +465 -0
  61. openmapstack-0.5.0/tests/test_duckdb_pipelines.py +128 -0
  62. openmapstack-0.5.0/tests/test_environment.py +297 -0
  63. openmapstack-0.5.0/tests/test_established_stack_tools.py +144 -0
  64. openmapstack-0.5.0/tests/test_eval_report.py +176 -0
  65. {openmapstack-0.3.0 → openmapstack-0.5.0}/tests/test_evals.py +258 -0
  66. openmapstack-0.5.0/tests/test_example_findings.py +96 -0
  67. openmapstack-0.5.0/tests/test_findings.py +197 -0
  68. openmapstack-0.5.0/tests/test_guidance_regressions.py +422 -0
  69. openmapstack-0.5.0/tests/test_integration.py +273 -0
  70. openmapstack-0.5.0/tests/test_langsmith_report.py +210 -0
  71. openmapstack-0.5.0/tests/test_nyc_dashboard.py +273 -0
  72. openmapstack-0.5.0/tests/test_nyc_h3_fixture.py +131 -0
  73. openmapstack-0.5.0/tests/test_nyc_live_demand.py +63 -0
  74. openmapstack-0.5.0/tests/test_nyc_live_market.py +77 -0
  75. openmapstack-0.5.0/tests/test_nyc_tlc_fleet.py +60 -0
  76. openmapstack-0.5.0/tests/test_observable_cities.py +198 -0
  77. openmapstack-0.5.0/tests/test_portolan_conformance.py +136 -0
  78. openmapstack-0.5.0/tests/test_private_fixture_postgis.py +364 -0
  79. openmapstack-0.5.0/tests/test_project_pages.py +251 -0
  80. openmapstack-0.5.0/tests/test_raster_access.py +452 -0
  81. {openmapstack-0.3.0 → openmapstack-0.5.0}/tests/test_release.py +5 -0
  82. {openmapstack-0.3.0 → openmapstack-0.5.0}/tests/test_rerun.py +67 -0
  83. openmapstack-0.5.0/tests/test_sampling.py +632 -0
  84. openmapstack-0.5.0/tests/test_skill_routing.py +77 -0
  85. {openmapstack-0.3.0 → openmapstack-0.5.0}/tests/test_snapshot.py +2 -2
  86. {openmapstack-0.3.0 → openmapstack-0.5.0}/tests/test_sources.py +24 -0
  87. openmapstack-0.5.0/tests/test_tables.py +460 -0
  88. openmapstack-0.5.0/tests/test_tartu_dashboard_sources.py +172 -0
  89. openmapstack-0.5.0/tests/test_tartu_routing.py +221 -0
  90. openmapstack-0.5.0/tests/test_tartu_run_evidence.py +120 -0
  91. openmapstack-0.5.0/tests/test_template_pipeline.py +157 -0
  92. openmapstack-0.5.0/tests/test_tylertoo.py +106 -0
  93. {openmapstack-0.3.0 → openmapstack-0.5.0}/tests/test_verify.py +161 -0
  94. {openmapstack-0.3.0 → openmapstack-0.5.0}/tests/test_verify_foreign.py +2 -0
  95. openmapstack-0.3.0/PKG-INFO +0 -300
  96. openmapstack-0.3.0/README.md +0 -281
  97. openmapstack-0.3.0/openmapstack/checks/geodata.py +0 -318
  98. openmapstack-0.3.0/openmapstack/checks/presentation.py +0 -168
  99. openmapstack-0.3.0/openmapstack/checks/visual.py +0 -642
  100. openmapstack-0.3.0/openmapstack/schema.py +0 -39
  101. openmapstack-0.3.0/openmapstack.egg-info/PKG-INFO +0 -300
  102. openmapstack-0.3.0/openmapstack.egg-info/SOURCES.txt +0 -55
  103. openmapstack-0.3.0/openmapstack.egg-info/requires.txt +0 -14
  104. {openmapstack-0.3.0 → openmapstack-0.5.0}/LICENSE +0 -0
  105. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/__main__.py +0 -0
  106. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/checks/metamorphic.py +0 -0
  107. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/checks/provenance.py +0 -0
  108. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/connectors/duckdb_local.py +0 -0
  109. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/connectors/postgis.py +0 -0
  110. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/expectations.py +0 -0
  111. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/metamorphic.py +0 -0
  112. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/project.py +0 -0
  113. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/schemas/__init__.py +0 -0
  114. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/schemas/check-result-v1.schema.json +0 -0
  115. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/schemas/verify-result-v1.schema.json +0 -0
  116. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack/sources.py +0 -0
  117. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack.egg-info/dependency_links.txt +0 -0
  118. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack.egg-info/entry_points.txt +0 -0
  119. {openmapstack-0.3.0 → openmapstack-0.5.0}/openmapstack.egg-info/top_level.txt +0 -0
  120. {openmapstack-0.3.0 → openmapstack-0.5.0}/setup.cfg +0 -0
  121. {openmapstack-0.3.0 → openmapstack-0.5.0}/tests/test_expectations.py +0 -0
  122. {openmapstack-0.3.0 → openmapstack-0.5.0}/tests/test_metamorphic.py +0 -0
@@ -0,0 +1,565 @@
1
+ Metadata-Version: 2.4
2
+ Name: openmapstack
3
+ Version: 0.5.0
4
+ Summary: Validate, run, and inspect reproducible OpenMapStack projects
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: jsonschema<5,>=4
9
+ Requires-Dist: PyYAML<7,>=6
10
+ Requires-Dist: packaging>=23
11
+ Provides-Extra: geo
12
+ Requires-Dist: duckdb>=1.5.3; extra == "geo"
13
+ Provides-Extra: visual
14
+ Requires-Dist: playwright>=1.40; extra == "visual"
15
+ Provides-Extra: postgis
16
+ Requires-Dist: psycopg[binary]>=3.1; extra == "postgis"
17
+ Provides-Extra: bigquery
18
+ Requires-Dist: google-cloud-bigquery>=3.11; extra == "bigquery"
19
+ Provides-Extra: motherduck
20
+ Requires-Dist: duckdb>=1.5.3; extra == "motherduck"
21
+ Provides-Extra: all
22
+ Requires-Dist: openmapstack[bigquery,geo,motherduck,postgis,visual]; extra == "all"
23
+ Dynamic: license-file
24
+
25
+ # openmapstack
26
+
27
+ **AI agent skills for geospatial decisions, data discovery, spatial SQL and reproducible analysis projects.**
28
+
29
+ Explore the [project homepage](https://jaakla.github.io/openmapstack-skills/), with bundled NYC and Tartu examples in standalone HTML and Observable Framework. The [Observable city samples](examples/observable-cities/) include reactive filters, thematic maps, downloads, and delivery evidence. Browse more projects in the [examples gallery](https://jaakla.github.io/openmapstack-samples/). Build the complete Pages site with `python3 scripts/build_project_pages.py` (Python project dependencies, Node 20+ and npm required); no warehouse credentials or Observable account are needed.
30
+
31
+ Install (assuming you have git and nodejs with npx already installed):
32
+ ```bash
33
+ npx skills@1.5.26 add jaakla/openmapstack-skills --skill open-map-stack -g
34
+ ```
35
+
36
+ OpenMapStack gives your favorite AI agent: Claude Code, Codex, Cursor, OpenCode, PI and 50+ other agents not just a one-off analysis, but a well-defined **workflow project** (`project.yaml`) defining from data discovery through reusable analysis (`pipeline.py`) to interactive web (`dashboard.html`) and selected deliverables (built-in dashboard by default; optional QGIS or Observable views). The workflow becomes **inspectable** and **repeatable** as a clearly specified project with pinned sources, explicit assumptions and CRS choices and deterministic processing in a python script. It allows also isolated overrides, machine-readable validation, and surfaced provenance.
37
+
38
+ It is open-first (both data and code-wise) and cloud-native by default, built on shoulders of the established Open GIS stack: STAC for discovery; GeoParquet, COG, and PMTiles for storage and delivery; DuckDB and PostGIS for compute; and QGIS, MapLibre, and Martin for presentation. It also teaches to deploy GDAL/OGR, GeoPandas, xarray/rioxarray, PDAL, routing engines, spatial SQL, and pragmatic hosted services when scale or reliability requires them.
39
+
40
+ Dashboard basemaps honor user choices and appropriate local or regional services, then fall back to preconfigured goplex.ee Protomaps vector tiles with light/dark switching and visible provider credit. See [web-delivery.md](skills/open-map-stack/references/web-delivery.md#style-and-basemap-sources-open) for the configuration.
41
+
42
+ Existing v1 manifests with a map must declare `presentation.map.basemap.kind` (`raster-xyz`, `raster-wms`, or `vector-style`). Vector basemaps require a style `url`; add the actual kind to older manifests before validation or regeneration. See the [basemap contract](skills/open-map-stack/references/project-spec.md#27-presentation-semantics).
43
+
44
+ ## What's in this repo
45
+
46
+ The skill collection has four independently installable skills:
47
+
48
+ | Skill | Use it for |
49
+ |---|---|
50
+ | [open-map-stack](skills/open-map-stack/SKILL.md) | Ambiguous or multi-stage GIS work; choose sources, compute, storage and delivery together. |
51
+ | [reproducible-gis-project](skills/reproducible-gis-project/SKILL.md) | Compile or maintain the project manifest, canonical pipeline, pinned sources, corrections, validation and reruns. |
52
+ | [geospatial-data-discovery](skills/geospatial-data-discovery/SKILL.md) | Find and assess open geospatial data under known requirements. |
53
+ | [spatial-sql](skills/spatial-sql/SKILL.md) | Write, review or optimize spatial SQL on an already chosen engine. |
54
+
55
+ Each skill has a small entry point and local references loaded as needed. The
56
+ generalist retains bounded-task support and material-analysis requirements when
57
+ installed alone. Optional product help is documented in the installed
58
+ [companion reference](skills/open-map-stack/references/companion-skills.md).
59
+
60
+
61
+ ### Open Map Stack - general guidance
62
+
63
+ Includes all the skills.
64
+
65
+ - [generalist SKILL.md](skills/open-map-stack/SKILL.md) — the skill entry point: triggers, global defaults, format and compute decision matrices, anti-patterns, and a quick triage guide.
66
+ - [references/data-sources.md](skills/open-map-stack/references/data-sources.md) - lists OSM, Overture, Sentinel/Landsat, regional portals, STAC catalogs and others.
67
+ - [references/services-and-scale.md](skills/open-map-stack/references/services-and-scale.md) - depending on case use local installs or hosted/SaaS services for global-scale basemaps, elevation, routing, geocoding, place search, and postcodes.
68
+ - [references/user-data-sources.md](skills/open-map-stack/references/user-data-sources.md) - the user's own warehouse data: credentials by reference, read-only discovery, approval-gated snapshots, and the pin classes that make a warehouse table reproducible.
69
+ - [references/formats-and-crs.md](skills/open-map-stack/references/formats-and-crs.md) - how to choose formats, conversions, projections, EPSG codes.
70
+ - [references/processing.md](skills/open-map-stack/references/processing.md) - when and how to use GDAL/OGR, GeoPandas, xarray, DuckDB, PostGIS, PDAL and other open geo processing tools.
71
+ - [references/analytics.md](skills/open-map-stack/references/analytics.md) — do vector/raster analytics, terrain, hydrology, network, point clouds, geocoding etc.
72
+ - [references/web-delivery.md](skills/open-map-stack/references/web-delivery.md) — renderer selection for maps, tylertoo/Tippecanoe vector tiling, PMTiles, MVT, Martin, TiTiler, MapLibre, deck.gl, kepler.gl, and lonboard formats and engines.
73
+ - [references/qgis.md](skills/open-map-stack/references/qgis.md) — QGIS desktop, plugins, PyQGIS, Processing, QGIS MCP.
74
+ - [references/validation-and-ops.md](skills/open-map-stack/references/validation-and-ops.md) — validation, manifests, attribution, and deployment checks, including the machine-readable reproducible-project contract.
75
+ - [references/project-spec.md](skills/open-map-stack/references/project-spec.md) — the specific`openmapstack-project/v1` schema: compiling any material analysis into a reproducible GIS project (`project.yaml`, pipeline, source provenance, overrides, validation, semantic presentation, selected delivery outputs).
76
+ - [references/project-workflow.md](skills/open-map-stack/references/project-workflow.md) — the mandatory material-analysis workflow and delivery rules, loaded when a task needs a reproducible project.
77
+ - [templates/](templates/) — ready scaffolds (`project.yaml`, `pipeline.py`, `presentation.yaml`, `validation.yaml`) for new projects.
78
+
79
+ ### Reproducible GIS project
80
+
81
+ Use [reproducible-gis-project](skills/reproducible-gis-project/SKILL.md) when the
82
+ analysis method and stack are chosen and another analyst needs to inspect,
83
+ execute and verify the result without the original conversation. It guides the
84
+ agent to produce:
85
+
86
+ - A `project.yaml` manifest with pinned sources, CRS, assumptions, ordered steps
87
+ and outputs, so the inputs and decisions are explicit. Its
88
+ [contract](skills/open-map-stack/references/project-spec.md#2-projectyaml-schema-openmapstack-projectv1)
89
+ permits project-specific metadata in open objects; extra fields have no built-in behavior.
90
+ - One canonical pipeline with corrections and scenarios recorded as data or
91
+ executable logic, so derived results can be rebuilt without manual edits.
92
+ - Machine-readable validation and run evidence, including a clean rerun, so
93
+ failures and reproducibility claims can be checked.
94
+ - Selected web/desktop presentation derived from the same project, so maps and reports
95
+ reflect the validated analysis.
96
+
97
+ The skill includes its own [project templates](skills/reproducible-gis-project/templates/)
98
+ and these local references:
99
+
100
+ - [project-workflow.md](skills/reproducible-gis-project/references/project-workflow.md) — required steps and delivery rules for a material analysis.
101
+ - [project-spec.md](skills/reproducible-gis-project/references/project-spec.md) — the `openmapstack-project/v1` manifest and artifact contract.
102
+ - [data-sources.md](skills/reproducible-gis-project/references/data-sources.md) — public data discovery and source assessment.
103
+ - [user-data-sources.md](skills/reproducible-gis-project/references/user-data-sources.md) — warehouse access and reproducible snapshots.
104
+ - [formats-and-crs.md](skills/reproducible-gis-project/references/formats-and-crs.md) — format choices and coordinate-system correctness.
105
+ - [qgis.md](skills/reproducible-gis-project/references/qgis.md) — QGIS project delivery and desktop integration.
106
+ - [validation-and-ops.md](skills/reproducible-gis-project/references/validation-and-ops.md) — checks, provenance and operational validation.
107
+ - [installation.md](skills/reproducible-gis-project/references/installation.md) — CLI setup and local example requirements.
108
+ - [companion-skills.md](skills/reproducible-gis-project/references/companion-skills.md) — optional product-specific help.
109
+
110
+ Installing the other skills is optional. If the source, compute or delivery
111
+ architecture is still undecided, start with `open-map-stack`.
112
+
113
+ ### Geospatial data discovery
114
+
115
+ Use [geospatial-data-discovery](skills/geospatial-data-discovery/SKILL.md) when
116
+ the data requirements are known and the task is to find and assess suitable
117
+ public datasets or the user's own geospatial data. It guides the agent to:
118
+
119
+ - Match coverage, time, feature meaning, attributes and resolution to the
120
+ question, so a convenient dataset is not mistaken for the right one.
121
+ - Check current provider metadata, access and license terms, so availability
122
+ and permission claims have evidence.
123
+ - Assess completeness and distinguish a sample or partial catalog from a full
124
+ extract, so missing features are not misread as absent features.
125
+ - Report a reproducible version or snapshot strategy, retrieval details and
126
+ limitations, so a later analysis can use the same source.
127
+
128
+ The standalone skill includes these local references:
129
+
130
+ - [data-sources.md](skills/geospatial-data-discovery/references/data-sources.md) — public data providers, catalogs and discovery methods.
131
+ - [user-data-sources.md](skills/geospatial-data-discovery/references/user-data-sources.md) — read-only warehouse discovery and snapshot rules.
132
+ - [formats-and-crs.md](skills/geospatial-data-discovery/references/formats-and-crs.md) — formats, coordinate systems and spatial extents.
133
+ - [companion-skills.md](skills/geospatial-data-discovery/references/companion-skills.md) — optional product-specific help.
134
+
135
+ A source assessment needs no project templates, worked example or OpenMapStack
136
+ CLI. Use `open-map-stack` when source selection depends on unresolved compute,
137
+ storage or delivery choices; add `reproducible-gis-project` if the user wants to
138
+ turn a chosen analysis into a full project.
139
+
140
+ ### Spatial SQL
141
+
142
+ Use [spatial-sql](skills/spatial-sql/SKILL.md) to write, review, debug or
143
+ optimize a spatial query on an already chosen engine, such as PostGIS or DuckDB
144
+ Spatial. It guides the agent to:
145
+
146
+ - Check the engine, geometry types, CRS, input grain and expected result, so
147
+ the query uses supported functions and returns the intended entities.
148
+ - Choose spatial predicates and boundary behavior deliberately, including how
149
+ null, invalid or multiply matched geometries affect the result.
150
+ - Use appropriate metric or geodesic operations for distances, areas and
151
+ buffers, so a numeric threshold has the intended units.
152
+ - Review indexes, candidate filters and query plans, then run small controls
153
+ when the engine is available, so performance changes preserve the result.
154
+
155
+ The standalone skill includes these local references:
156
+
157
+ - [spatial-sql.md](skills/spatial-sql/references/spatial-sql.md) — engine-specific spatial SQL patterns and query review.
158
+ - [formats-and-crs.md](skills/spatial-sql/references/formats-and-crs.md) — coordinate, unit and format semantics.
159
+ - [companion-skills.md](skills/spatial-sql/references/companion-skills.md) — optional product-specific help.
160
+
161
+ A bounded query review needs no project templates, worked example or
162
+ OpenMapStack CLI. Use `open-map-stack` when engine selection or cross-system
163
+ architecture is undecided; add `reproducible-gis-project` if the user wants to
164
+ compile a chosen analysis into a full project.
165
+
166
+
167
+ ### Additional materials:
168
+
169
+ - [examples/tartu-development/](examples/tartu-development/) — a fully-worked reproducible project matching the acceptance scenario: source provenance + timestamps, explicit assumptions, two verified project overrides (a scenario attribute change with prior-value verification, and hypothetical scenario geometry), deterministic pipeline, machine-readable validation, and semantic presentation.
170
+ - [evals/](evals/) — the eval suite grading whether an agent reaches the right analytical answer, respects the GIS-method guardrails, and reruns reproducibly, with the `openmapstack-project/v1` contract as the substrate that makes those independently checkable: `python evals/run.py --mode fixture` runs deterministic, no-LLM checks against real generated artifacts (analytical correctness against known geospatial truth, metric CRS, source immutability, schema, overrides, validation integrity, presentation contract, and clean reruns), plus adversarial cases and a pluggable live-agent benchmark (Claude Code, Codex, and any OpenAI-compatible API such as OpenRouter — URL and model via `OPENAI_COMPATIBLE_*` env, API key as a secret).
171
+ - [`openmapstack/`](openmapstack/) — the installable `openmapstack validate/run/inspect` CLI for auditing and executing `openmapstack-project/v1` projects, plus [`openmapstack/checks/`](openmapstack/checks/): the reusable, semantic check library. All but five of its checks are oracle-free, so the same functions that grade the eval suite also grade a user's own project on data this repository has never seen.
172
+ - [docs/openmapbench-interop.md](docs/openmapbench-interop.md) — the narrow, versioned contract a benchmark harness such as OpenMapBench consumes: `openmapstack checks` / `check` / `api-info` (`openmapstack-check-api/v1`), the packaged result schemas, skill snapshots, arm provenance, and exported task bundles.
173
+ - [`.claude-plugin/`](.claude-plugin/) — Claude Code plugin and marketplace manifests, so the repository can also be installed with `/plugin install`. Validated in CI by [`.github/workflows/plugin.yml`](.github/workflows/plugin.yml).
174
+
175
+ Some my local Estonia-specific guidance (Maa- ja Ruumiamet, ETAK, EPSG:3301 / L-EST97) is included for convenience. But most of the major global sources are included for world-wide coverage.
176
+
177
+ ## Install
178
+
179
+ The 0.5.0 release candidate provides four independently installable skills. The
180
+ OpenMapStack CLI is a separate installation for project execution and validation.
181
+ From a checkout, install the generalist and CLI for project work:
182
+
183
+ ```bash
184
+ npx skills@1.5.26 add . --skill open-map-stack -a codex -y
185
+ python -m pip install '.[geo]'
186
+ ```
187
+
188
+ Use `-a claude-code` for Claude Code, `-g` for global installation and `--copy`
189
+ for independent copies. Select additional skills by repeating `--skill NAME`;
190
+ `--skill '*'` selects the full collection. `open-map-stack` and
191
+ `reproducible-gis-project` include local project templates, the project schema,
192
+ a trimmed worked Tartu example and CLI setup instructions. The two bounded
193
+ specialists ship their task guidance and local references; they need no CLI or
194
+ installed sibling. Generated example outputs and downloaded source data are
195
+ omitted; the example pipeline needs network access and its documented GIS
196
+ environment.
197
+
198
+ The following 0.5.0 commands are unavailable until the release tag and Python
199
+ package are published. Before publication, use the matching checkout or a wheel
200
+ built from it. After publication, pin both parts of the coordinated release:
201
+
202
+ ```bash
203
+ npx skills@1.5.26 add https://github.com/jaakla/openmapstack-skills/tree/v0.5.0/skills/open-map-stack -a codex -y
204
+ python -m pip install 'openmapstack[geo]==0.5.0'
205
+ ```
206
+
207
+ For a floating install use `npx skills@1.5.26 add jaakla/openmapstack-skills
208
+ --skill open-map-stack`. Check installed skills with `npx skills@1.5.26 list`,
209
+ update with `npx skills@1.5.26 update open-map-stack --project`, and remove with
210
+ `npx skills@1.5.26 remove open-map-stack`. Use `--global` instead of `--project` for a global update; match the scope for list/remove too.
211
+ Updating a floating install advances its version; release-pinned installs
212
+ should be replaced with an explicitly chosen release.
213
+
214
+ ### Claude Code plugin
215
+
216
+ ```text
217
+ /plugin marketplace add jaakla/openmapstack-skills
218
+ /plugin install open-map-stack@open-map-stack
219
+ ```
220
+
221
+ The plugin retains its identity and discovers `skills/<name>/SKILL.md`.
222
+ For local development use `claude --plugin-dir /path/to/checkout`; metadata
223
+ validation and component inventory require no paid model run.
224
+
225
+ ### Manual installation and migration
226
+
227
+ Copy `skills/<name>/` into your agent's skill directory. Do not copy the whole
228
+ collection checkout into a single skill folder. If replacing a 0.3.0 root
229
+ installation, retain the `open-map-stack` name and replace its installed payload;
230
+ do not keep both root and nested copies. Inspect your actual installer lockfile
231
+ and scope before changing anything. Legacy `open-gis` is a different identifier:
232
+ remove it explicitly if it is an unwanted duplicate, rather than silently
233
+ rewriting its lock entry.
234
+
235
+ The CLI is separate from skill installation and is needed only for project
236
+ execution or validation. When installing it, verify `openmapstack --version`
237
+ against the project skill's `metadata.version`. Before publication, a wheel or
238
+ pinned Git commit from the matching checkout is the supported alternative.
239
+
240
+ ## Use
241
+
242
+ Agents discover the installed skill descriptions and select relevant guidance.
243
+ Selection depends on the agent; explicitly naming a skill can help when you
244
+ want a particular owner. Installing the collection does not require loading
245
+ all four skills for every request.
246
+
247
+ - “We need regional analysis and browser maps for a billion building records; choose the architecture.” → `open-map-stack`.
248
+ - “Keep this analysis and stack, but make it reproducible and auditable.” → `reproducible-gis-project`.
249
+ - “Find authoritative Estonian building footprints; explain coverage, license and a reproducible pin.” → `geospatial-data-discovery`.
250
+ - “Review this PostGIS query for a 500-metre distance test on SRID 4326 geometries.” → `spatial-sql`.
251
+
252
+ The primary skill can use focused support. A bounded lookup or query review
253
+ does not require a project; material multi-stage analyses retain the complete
254
+ reproducibility contract. Casual place lookups and ordinary non-spatial coding
255
+ are outside the collection's scope.
256
+
257
+ See the [0.5.0 release preparation](docs/release-0.5.0.md) and
258
+ [candidate evidence](docs/acceptance-0.5.0-rc.json) for current checks and pending
259
+ acceptance. The published [0.4.0 release notes](https://github.com/jaakla/openmapstack-skills/releases/tag/v0.4.0)
260
+ retain the previous release's validation and installation evidence.
261
+
262
+ ## Use your established stack
263
+
264
+ OpenMapStack supplies GIS methodology, source provenance and an inspectable
265
+ project contract around existing tools. It does not replace loaders, schedulers
266
+ or BI platforms. Preserve the user's stack and give each transformation and
267
+ dependency one authoritative owner.
268
+
269
+ The [focused and composed examples](examples/established-stack/README.md) run
270
+ dlt file ingestion/cursor state, dbt + DuckDB Spatial models/tests, Dagster assets
271
+ and failure handling, real Observable Framework builds, and optional native QGIS
272
+ delivery. The default example requires only the base spatial runtime and produces
273
+ a dashboard. Choosing one integration does not install all tools. Composed runs
274
+ use Dagster → dlt → dbt → Observable, with optional QGIS from the same validated
275
+ outputs. Observable hosted notebook publication is not implemented.
276
+
277
+ Read [the integration boundary](skills/open-map-stack/references/established-stack.md)
278
+ for who benefits, ownership, optional versioned bindings, clean reruns, capability
279
+ checks and future enterprise surfaces. MotherDuck/BigQuery source connectors
280
+ already exist; remote compute, Snowflake and Esri integrations remain extensions.
281
+
282
+ ## Selectable delivery profiles
283
+
284
+ New project templates explicitly select the built-in dashboard using
285
+ `delivery.schema: openmapstack-delivery/v1`. Users can replace that default with
286
+ QGIS-only or Observable-only delivery, or choose multiple targets. Each target
287
+ binds declared document/evidence outputs to the same validated analytical data.
288
+ Unselected integrations have no artifact/runtime obligation; source provenance,
289
+ CRS correctness, immutable overrides and clean reruns remain required.
290
+
291
+ ```yaml
292
+ delivery:
293
+ schema: openmapstack-delivery/v1
294
+ targets:
295
+ - id: dashboard
296
+ kind: dashboard
297
+ output: dashboard
298
+ inputs: [candidate_parcels]
299
+ evidence: dashboard_evidence
300
+ ```
301
+
302
+ `dashboard` and `dashboard_evidence` must be declared document outputs. The
303
+ canonical pipeline embeds input-bound metadata, generates the view and writes
304
+ its evidence before run hashes. Missing selected artifacts fail; unavailable
305
+ browser/QGIS checks are `not_testable`. The [established-stack examples](examples/established-stack/README.md) add
306
+ native optional QGIS generation and a real Observable Framework static build.
307
+ Hosted Observable targets additionally retain an export, build/configuration,
308
+ URL and retrieval identity. A URL alone is insufficient; verification does not
309
+ certify current remote state or publish anything.
310
+
311
+ Try the offline [delivery-profile example](examples/delivery-profiles/README.md),
312
+ which demonstrates default, external-only and combined selections without
313
+ cloud credentials. The Tartu worked example retains legacy combined delivery.
314
+
315
+ **Migration is explicit:** existing v1 manifests without `delivery` retain their
316
+ legacy presentation/QGIS obligations. Add the selection, update output/evidence
317
+ bindings and canonical generation, deliberately remove obsolete target-specific
318
+ dependencies/checks, and regenerate run evidence before `verify --rerun`. The CLI
319
+ never silently migrates or deletes old outputs. Use a CLI whose check catalog
320
+ contains `delivery.declaration_valid`; older tools that ignore the extension
321
+ cannot certify it. Full semantics and migration instructions are in
322
+ [project-spec.md section 2.0](skills/open-map-stack/references/project-spec.md#20-selectable-delivery--openmapstack-deliveryv1).
323
+
324
+ ## Project CLI
325
+
326
+ > The key innovation of the skill is not just do the work every time again and then forget it, but to create special well-defined project with data and process descriptions and rerunnable scripts, so the whole process becomes investigatable and repeatable.
327
+
328
+ To help with that we have special CLI to work with the projects.
329
+
330
+ The CLI operates on an `openmapstack-project/v1` manifest. A project directory may
331
+ be supplied in place of its `project.yaml` file.
332
+
333
+ ```bash
334
+ # Audit the complete artifact, including outputs, report, and run record.
335
+ openmapstack validate path/to/project.yaml
336
+
337
+ # Check the produced artifacts without requiring a golden answer.
338
+ openmapstack verify path/to/project.yaml
339
+
340
+ # Run the one canonical pipeline, then validate what it produced.
341
+ openmapstack run path/to/project.yaml
342
+
343
+ # Review sources, versions, overrides, ordered steps, outputs, and latest run.
344
+ openmapstack inspect path/to/project.yaml
345
+
346
+ # Copy SKILL.md, references/, and templates/ into a hashed, inspectable snapshot.
347
+ openmapstack skill-snapshot --out /tmp/oms-skill --json
348
+ openmapstack skill-snapshot --inspect /tmp/oms-skill
349
+
350
+ # Read-only discovery of a warehouse source, then an approval-gated snapshot.
351
+ openmapstack source discover path/to/project.yaml --source parcels
352
+ openmapstack source snapshot path/to/project.yaml --source parcels \
353
+ --query "SELECT id, geom FROM cadastre.parcels" --destination data/source/parcels.parquet --approve
354
+ ```
355
+
356
+ Useful automation options:
357
+
358
+ ```bash
359
+ openmapstack validate project.yaml --json --output validation/cli-report.json
360
+ openmapstack validate project.yaml --strict # warnings also return non-zero
361
+ openmapstack validate project.yaml --preflight # skip not-yet-generated artifacts
362
+ openmapstack run project.yaml --dry-run # print the command, execute nothing
363
+ openmapstack run project.yaml --json
364
+ openmapstack inspect project.yaml --json
365
+ ```
366
+
367
+ `run` reads Python dependencies from `runtime.environment` in `project.yaml`
368
+ and installs them into a reusable project virtualenv, including when invoked
369
+ through `uvx`. It warns if the CLI's Python version differs from the declared
370
+ version: `python: '3.12'` accepts any 3.12 patch release. Select a matching
371
+ interpreter with `uvx --python 3.12 openmapstack run project.yaml`.
372
+
373
+ Native dependencies such as GDAL, PROJ, QGIS, PostgreSQL, and PostGIS require
374
+ external setup. `run` emits installation and verification guidance for declared
375
+ native dependencies; their availability remains **unverified**. A GDAL installation
376
+ may need particular drivers and matching Python bindings in the pipeline's runtime.
377
+ PostGIS must be installed on the database server and enabled in the target database;
378
+ installing a Python client is insufficient. Use a prepared system, Conda, or container
379
+ runtime via `runtime.implementation.command` when needed. The declaration
380
+ `gdal: DuckDB spatial extension` does not request a system GDAL installation:
381
+ the pipeline must install/load DuckDB's `spatial` extension. See the
382
+ [runtime contract](skills/open-map-stack/references/project-spec.md#28-runtime-runs-warnings)
383
+ for dependency syntax and execution behavior.
384
+
385
+ Runtime advisories appear on stderr, or in the JSON `warnings` array, including
386
+ for `--dry-run`. They are non-blocking and separate from artifact validation;
387
+ `--strict` continues to apply to validation, not these advisories. An explicit
388
+ launch command owns its interpreter, so the CLI does not compare that interpreter
389
+ against its own Python version.
390
+
391
+ ### Sampled runs — nail it before you scale it
392
+
393
+ A wide-area analysis can run for hours before a late step fails. A sampled run
394
+ executes the same pipeline over a deliberately smaller slice, so failure
395
+ arrives in minutes:
396
+
397
+ ```bash
398
+ openmapstack run project.yaml --sample # the manifest's declared sample
399
+ openmapstack run project.yaml --sample-area 26.6,58.3,26.8,58.4
400
+ openmapstack run project.yaml --sample-rows 5000
401
+ openmapstack run project.yaml --sample-fraction 1.0
402
+ ```
403
+
404
+ Each flag binds a `runtime.implementation.parameters` entry that declares the
405
+ matching `role`; sampling a project that declares none is refused, naming what
406
+ the manifest must add. The canonical run still passes nothing.
407
+
408
+ **A sampled run proves the pipeline executes; it does not establish the
409
+ result.** Clipping to a test AOI breaks neighbourhood operations at the cut and
410
+ row sampling destroys the spatial coherence a join needs, so sampled counts are
411
+ not answers. That is enforced, not merely advised: a sampled run record is
412
+ marked `mode: sampled`, must record what it *realized* rather than only what
413
+ was requested, and can never become `runs.latest` — `openmapstack validate`
414
+ reports this as `runs.sample_isolation`, and `run --sample` fails outright if a
415
+ pipeline promotes its own sampled run — by moving `runs.latest`, by rewriting
416
+ the record it already points at, or by leaving no sampled record behind at all.
417
+ See `references/project-spec.md`.
418
+
419
+ ### `openmapstack verify` — check the analysis, not just the paperwork
420
+
421
+ `validate` audits the manifest and its bookkeeping. `verify` runs the check
422
+ library in `openmapstack/checks/` against what the pipeline actually produced:
423
+ geometry read back through DuckDB Spatial, dataset CRS read from the artifact
424
+ rather than the manifest's claim, validation evidence recomputed from the
425
+ geodata it summarises, non-spatial `kind: table` outputs read back as tables
426
+ (declared columns and types, unique key, CSV/XLSX downloads holding the same
427
+ rows), QGIS project structure and runtime loading where PyQGIS is available, and
428
+ — for projects that declare a design-language version — every dashboard or
429
+ report page operated in a real browser.
430
+
431
+ ```bash
432
+ openmapstack verify path/to/project.yaml
433
+ openmapstack verify path/to/project.yaml --rerun # + rebuild from source and compare
434
+ openmapstack verify path/to/project.yaml --metamorphic # + run declared no-oracle relations
435
+ openmapstack verify path/to/project.yaml --json --output validation/verify-report.json
436
+ openmapstack verify path/to/project.yaml --strict # warnings and not-testable also return 1
437
+ ```
438
+
439
+ DuckDB Python pipelines also receive a warning-only static axis-order check.
440
+ Reprojection or GDAL export with no explicit setup evidence produces a warning;
441
+ every other outcome is `not_testable`, never `passed`. Static analysis cannot
442
+ prove axis order: an independent runtime coordinate-order assertion supplies
443
+ that guarantee. The shared Spatial setup uses GIS x/y order on each connection. See the
444
+ [spatial SQL setup](skills/open-map-stack/references/spatial-sql.md#duckdb-spatial).
445
+
446
+ These checks require no repository-owned golden answer, so they work on data
447
+ neither this repository nor the model has seen. They establish bounded
448
+ structural, provenance, artifact, and reproducibility predicates; they do not
449
+ prove every project-specific analytical answer.
450
+
451
+ `--rerun` is the strongest signal available without a known answer. It rebuilds
452
+ the project in an empty workspace from only the manifest, the declared
453
+ immutable inputs, and the declared dependencies, runs the one canonical
454
+ entrypoint, re-hashes the sources, and compares the outputs semantically. A
455
+ pipeline that cannot reproduce itself, or that mutates its own declared
456
+ immutable inputs, is not trustworthy whatever its numbers say.
457
+
458
+ The check plan is derived from the manifest rather than configured, so a
459
+ project cannot opt out of a check by omitting it: a declared output is a
460
+ checked output. A check whose dependency is missing reports `not_testable` and
461
+ is counted separately — never a silent pass. A mixture of executed and
462
+ `not_testable` checks has aggregate status `warning`, and every report includes
463
+ `applicable`, `executed`, and `execution_rate` coverage. Install
464
+ `openmapstack[geo]` for the DuckDB-backed geodata checks and for reading XLSX
465
+ (DuckDB `excel` extension) and Parquet tables; CSV and JSON tables need nothing
466
+ extra. PyQGIS comes from a system QGIS install. For the browser check, install
467
+ `openmapstack[visual]` and run `python -m playwright install chromium`.
468
+
469
+ The browser check runs when the manifest sets `presentation.design_language`
470
+ (see `references/design-language.md`). It opens every declared page and
471
+ operates each declared control through the language's state hooks, including
472
+ controls on inactive tabs: a control must change the page, an exploratory one
473
+ must show the exploratory label, and the reset must restore the published
474
+ state. Projects without a language version keep their existing plan: selected
475
+ web delivery targets receive smoke checks, and selected map-primary dashboards
476
+ also receive the existing visual check.
477
+
478
+ New material projects also generate `findings.md` from pipeline results before
479
+ output hashing. Its readable Markdown and YAML frontmatter share findings,
480
+ question/scope, run identity, assumptions, validation status and cited output
481
+ definitions/hashes. CSV/Parquet/geodata remain the underlying results; the view
482
+ need not display them all. `validate` and `verify` check a declared findings
483
+ artifact for stale/missing evidence and consistency with the current run.
484
+ Evidence inventories hash and link every declared table download as well as the
485
+ primary result, so changing or removing an XLSX/JSON export invalidates findings.
486
+ The offline example also exposes a portable findings reference in QGIS metadata.
487
+ Try the [offline example](examples/delivery-profiles/README.md);
488
+ see [the findings contract](skills/open-map-stack/references/project-spec.md#findings)
489
+ for the writer API and format. Embedded chat is a separate optional enhancement.
490
+
491
+ Delivered project views credit the declared author, free OpenMapStack toolkit
492
+ and canonical analysis time. `validate` and `verify` check the metadata and
493
+ actual HTML/QGIS credit values and links. Existing v1 projects missing both
494
+ identity fields receive an explicit legacy warning; declaring either requires
495
+ the complete pair and rendered credits. See the [credits contract](skills/open-map-stack/references/project-spec.md#credits-header).
496
+
497
+ See [the applicability reference](docs/verify-applicability.md) for the exact
498
+ plan conditions, dependencies, current regression evidence, and deliberate
499
+ exclusions. Explicit delivery targets add input-bound view evidence and web
500
+ smoke checks; selected map-primary built-in dashboards also run existing visual
501
+ checks. Legacy projects retain their previous delivery and rendering plan,
502
+ with the explicit credits migration warning described above. These checks establish
503
+ bounded properties, not every analytical or cartographic claim.
504
+
505
+ Project-specific known answers can be declared under
506
+ `validation.expectations[]`. The five allowlisted checks cover row count,
507
+ feature presence/absence, one feature-field value, and field range. New
508
+ expectations start as `attestation.status: unverified`; they produce a warning
509
+ and are not executed. The JSON report supplies the exact
510
+ `expected_expectation_sha256` an independent reviewer must bind, together with
511
+ the current `runs.latest.inputs_hash`. Changing the expected check, arguments,
512
+ inputs, or a retained local evidence file invalidates the attestation and
513
+ returns it to warning status. See
514
+ [the project contract](skills/open-map-stack/references/project-spec.md#26-validation).
515
+
516
+ Where no golden answer exists at all, `validation.metamorphic[]` declares
517
+ relations that must hold under a controlled perturbation: shuffle a source and
518
+ the result must not change, duplicate every feature and a keyed set must not
519
+ change, widen an inclusion buffer and no candidate may disappear. Each relation
520
+ states the precondition that makes it valid, is executed by
521
+ `verify --metamorphic` in an isolated copy against the project's own pipeline,
522
+ and reports `not_testable` with the reason when the precondition does not hold
523
+ on the actual data. See [the project contract](skills/open-map-stack/references/project-spec.md#26-validation).
524
+
525
+ `openmapstack source` is the connector pilot for the user's own data
526
+ (DuckDB local files and PostGIS). Credentials are referenced, never stored;
527
+ discovery is read-only with a statement timeout; a snapshot is a dry run
528
+ until `--approve`, is limited by rows and bytes, lands only under
529
+ `data/source/`, and hands back the `pin` block that makes the source
530
+ reproducible. A warehouse table with only a timestamp is not pinned; an
531
+ expired backend snapshot is reported as `not_reproducible`. See
532
+ [user data sources](skills/open-map-stack/references/user-data-sources.md).
533
+
534
+ `validate` checks manifest structure, source retrieval/version/licensing data,
535
+ CRS declarations, processing graph resolution, override provenance and files,
536
+ output existence, validation-report parity/status propagation, override
537
+ application results, and run-record identity/hashes. GIS-specific checks such as
538
+ geometry validity remain the pipeline's responsibility; the CLI verifies that
539
+ each declared check appears exactly once with an explicit result.
540
+
541
+ Normal validation warnings return exit code 0 so known limitations remain
542
+ representable. Failures return 1; malformed invocation or an unstartable runtime
543
+ returns 2. `--strict` makes warnings return 1.
544
+
545
+ ## What this skill will and won't do
546
+
547
+ **Will:**
548
+ - Recommend modern, cloud-native formats (GeoParquet, COG, PMTiles) and flag legacy patterns (Shapefile output, MBTiles for new deployments).
549
+ - Push spatial joins to DuckDB / PostGIS instead of Python loops.
550
+ - Discover data via STAC before downloading.
551
+ - Preserve license metadata (OSM ODbL, Overture per-source, Sentinel attribution).
552
+ - Pin dataset versions for reproducibility (Overture releases, STAC item IDs, OSM extract dates).
553
+ - Compile material multi-stage analysis into a reproducible GIS project (`project.yaml` + pipeline + overrides + validation), deriving the final map/dashboard from it.
554
+
555
+ **Won't:**
556
+ - Trigger on simple location lookups ("what city is this?") or casual map references with no analytical work.
557
+ - Default to proprietary services when an open/self-hosted option fits the scale, quality, privacy, and budget.
558
+
559
+ ## License
560
+
561
+ Licensed under the [MIT License](LICENSE).
562
+
563
+ ## Contributing
564
+
565
+ Issues and PRs welcome at [github.com/jaakla/openmapstack-skills](https://github.com/jaakla/openmapstack-skills). When adding a new tool or workflow, place it in the matching reference file and add a one-row entry to the relevant decision matrix in [generalist SKILL.md](skills/open-map-stack/SKILL.md).