feat(sandbox): add geospatial Python packages - #33
Conversation
Adds a geospatial stack to the sandbox Python image: rasterio and rioxarray for raster IO, geopandas/pyogrio/pyproj/shapely for vector data and reprojection, osmnx for OSM extracts, folium for map output, and gpxpy for GPX export. The sandbox runs with clone_newnet, so nothing is installable at runtime -- these have to be baked into the image to be usable at all. All packages resolve to cp314 manylinux wheels on x86_64 and aarch64, so no source builds are introduced. Marginal installed size is ~263 MB, of which rasterio (110 MB), pyogrio (99 MB) and pyproj (32 MB) are vendored GDAL/PROJ copies. Adds test_geospatial to test-sandbox.sh, which reprojects a point to EPSG:26918 -- this exercises pyproj's bundled PROJ data and GDAL loading under NsJail, the parts most likely to break in the sandbox.
Validation summaryRecording the review rounds and the out-of-band testing, since neither is visible from the diff. Review rounds
Codex rounds were Testing performedThe image build was not run (no Docker in the authoring environment initially), so the packages were validated directly in cp314 wheels — all 8 install as genuine cp314 binaries, no source builds: Dependency resolution — no conflict with the existing 46 packages, on both installer paths. Note
Seccomp — a representative geospatial workload (rasterio + pyproj + geopandas/pyogrio + shapely + Filter enforcement was verified rather than assumed — against This is the onnxruntime concern noted at Resource envelope — 2.46 s against the 30 s
Not covered
Excluded from this PR
|
|
@codex review |
The first version guarded on ^[0-9.-]+, copied from test_statsmodels. That regex matches -74.006, so a to_crs that silently returned unprojected lon/lat would have passed the test. Assert exit code 0, a strictly numeric unsigned easting, and a plausible UTM range instead.
packages_ready() gates package-init.sh on sentinel site-packages directories. On an upgrade over an existing /pkgs volume, PIL, markitdown, chdb and statsmodels are all already present, so the check passed and the script exited before reaching the pip install. The geospatial packages would never have landed on existing deployments without a manual FORCE_REBUILD=true. Add rasterio as a sentinel so stale volumes rebuild. build-packages.sh needs no equivalent change: it clears .package-installed and reinstalls unconditionally.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 137e29de52
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| @@ -0,0 +1 @@ | |||
| {"timestamp":"2026-07-26T15:20:44.917Z","type":"agent-turn-complete","thread_id":"019f9f01-a0f6-7cf1-b1d0-10892fb4290f","turn_id":"019f9f01-a155-7fe3-8a91-7b2462764325","input_preview":"Review the single commit on this branch (git show HEAD, or diff against origin/main). It adds geospa","output_preview":"**Findings**\n\n1. Medium: [test-sandbox.sh](/home/danny/ch-code-interpreter-worktrees/geospatial-packages/test-sandbox.sh:182) does not actually validate “numeric UTM 18N easting” the way the message c"} | |||
There was a problem hiding this comment.
Remove committed OMX session artifacts
Remove the entire .omx runtime-state directory from this commit and ignore it: these files contain session-specific thread/turn IDs, timestamps, prior prompt/output previews, and a developer workstation path unrelated to the geospatial feature. On subsequent OMX-assisted work, the metrics, logs, and state files will be rewritten and leave contributors with a dirty worktree while continuing to expose local session data in repository history.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Correct, and fixed — thank you, this was a genuine mistake on my part (a git add -A swept the directory into the second commit).
Because the files were already in published history, deleting them at the tip would not have removed them. The branch has been rewritten instead and force-pushed: .omx/ is gone from all three commits, not just the tip.
Verification:
git ls-tree -ron the branch head: 0.omxpaths- across every commit in
origin/main..HEAD: 0.omxpaths - PR file list is now exactly the 4 intended files (
api/README.md,build-packages.sh,docker/package-init.sh,test-sandbox.sh) - the rewritten tree is byte-identical to the reviewed version outside
.omx, so no review feedback was lost in the rewrite - all three checks green on the new head
c626725
On the dirty-worktree point: .omx/ has been added to the repository's local info/exclude rather than .gitignore, since it is contributor-side tooling and not something this repo should carry an ignore rule for. Working tree is clean.
137e29d to
c626725
Compare
|
@codex review |
|
Codex Review: Didn't find any major issues. What shall we delve into next? Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Adds a geospatial stack to the sandbox Python image so agents can do DEM/terrain and routing work — read raster tiles, reproject, run least-cost paths, and export results.
rasteriorioxarraygeopandaspyogriopyprojosmnxfoliumgpxpynumpy,scipyandscikit-imageare already installed —scikit-imagesuppliesMCP_Geometricfor least-cost paths, so no addition was needed there.Why bake them in
The sandbox runs under
clone_newnet: true(api/config/sandbox.cfg:25), so there is no network at execution time and nothing ispip install-able by the user. A package is either in the image or unavailable.Wheel availability
Every package resolves to a
cp314manylinux wheel on both x86_64 and aarch64, or is pure Python — no source builds are introduced, so thepip installininstall_python_packagescannot start compiling GDAL and fail the image build.richdemwas considered and excluded: it publishes an sdist only, with no wheels for any Python version. It would compile from source against GDAL headers and setINSTALL_FAILED=true.Size
Marginal installed cost is ~263 MB, concentrated in three packages that each vendor their own native stack:
rasteriolibgdal27.5 MB + sqlite + cryptopyogriolibgdal76.8 MBpyprojlibproj+libcurl+ datum gridsThe two independent GDAL copies are unavoidable with manylinux wheels, which cannot share system libraries.
numpy,pandas,networkx,requestsandjinja2are already in the image and add nothing.Changes
build-packages.shanddocker/package-init.sh— the two copies of the package list, kept in synctest-sandbox.sh— addstest_geospatial, which reprojects a point to EPSG:26918. This deliberately exercises pyproj's bundled PROJ data and GDAL loading under NsJail, which are the parts most likely to break in the sandbox rather than on a build hostapi/README.md— mentions the geospatial packages in the runtime listTesting
bash -nclean on all three shell scriptstest_geospatialhas not executed against a live sandbox. That is the one thing worth confirming in CI.