add-chart
Renamed → /portaljs-add-chart. This alias will be removed next minor release.
Auto-ingest a geospatial file (GeoJSON, Shapefile, GeoPackage, KML/KMZ, FlatGeobuf, CSV-with-geometry) into a PortalJS portal — on your own machine, no server. Normalizes CRS to EPSG:4326, derives a PMTiles render tier + a GeoParquet query tier, pushes all three to R2 via Git
> /plugin marketplace add datopian/portaljs > /plugin install portaljs@datopian-portaljs
How it fires
How this command gets triggered: by you, by Claude, or both.
/portaljs-add-geoContext preview
What this command does when you run it.
Auto-ingest a geospatial file (GeoJSON, Shapefile, GeoPackage, KML/KMZ, FlatGeobuf, CSV-with-geometry) into a PortalJS portal — on your own machine, no server. Normalizes CRS to EPSG:4326, derives a PMTiles render tier + a GeoParquet query tier, pushes all three to R2 via Git
description: Auto-ingest a geospatial file (GeoJSON, Shapefile, GeoPackage, KML/KMZ, FlatGeobuf, CSV-with-geometry) into a PortalJS portal — on your own machine, no server. Normalizes CRS to EPSG:4326, derives a PMTiles render tier + a GeoParquet query tier, pushes all three to R2 via Git LFS, and emits one dual-tier datasets.json entry the showcase renders with <MapPreview> + <GeoQuery>. allowed-tools: Read, Write, Edit, Bash, WebFetch
Turn one geospatial upload into a **dual-tier** PortalJS dataset entirely on the user's machine — **no server-side container compute**, keeping the zero-backend bet end-to-end. From a single source file this produces two derivatives plus the preserved original:
with MapLibre GL over HTTP range requests: any dataset size pans/zooms with no tile server.
Hilbert-sorted) `<GeoQuery>` runs spatial SQL over in place via DuckDB-Wasm.
artifact.
All three land on Cloudflare R2 (via Git LFS → Giftless), and the skill appends **one** `datasets.json` entry whose `resources[]` are exactly the shape the showcase auto-renders (PR #1647 / the `@reference/world-boundaries` demo): a `pmtiles` resource → `<MapPreview>`, a `geoparquet` resource → `<GeoQuery>`, and the original as a download. No page edits — the dynamic showcase route `pages/[owner]/[slug].tsx` renders each resource by its `format`.
This automates the manual `tippecanoe` / `duckdb` recipes documented in the template README (the interim ingest path). Use it whenever the source is a **vector geo format**; for plain tabular data use `/portaljs-add-dataset`, and for a Leaflet view over small GeoJSON use `/portaljs-add-map`.
This runs **native CLIs on the user's machine** (locked direction, 2026-07-08 — overrides po-6sr §7's server-compute sketch). No container, no cloud job. tippecanoe has no mature WASM build, so the PMTiles tier fundamentally needs the native binary; skills already shell out to git-lfs and npm, so native geo deps fit the model. Three tools:
| Tool | Role | Why this tool | |------|------|---------------| | **GDAL** (`ogr2ogr`, `ogrinfo`) | Read **every** vector input; reproject → EPSG:4326; emit the normalized GeoJSON intermediate | Widest driver set (SHP, GPKG, KML/KMZ, FGB, CSV-geom) | | **tippecanoe** | normalized GeoJSON → PMTiles (render tier) | The de-facto tiler; no WASM equivalent | | **duckdb** (+ `spatial`) | normalized GeoJSON → GeoParquet 1.1 with covering `bbox` + Hilbert sort (query tier) | The **proven** writer — PR #1647 verified `<GeoQuery>` against duckdb output; ogr2ogr's Parquet driver won't cleanly emit the covering-bbox column + Hilbert ordering the bbox-first query needs to prune |
(GeoJSON), `.zip` (zipped Shapefile), `.gpkg`, `.kml`/`.kmz`, `.fgb`, `.csv` with a geometry/lat-lon column. Raster (`.tif`/`.tiff`) is **out of scope** (COG is a later phase).
for `'owner'` portals).
**If the source is missing, ask for it — never dead-end.** The user can say "use defaults".
Extract:
from `datasets.json`, else `reference`)
If `SOURCE` is missing, ask (one focused prompt) and wait:
To add a geospatial dataset I need: 1. Source: a local geo file path or public URL (required) — GeoJSON, zipped Shapefile (.zip), GeoPackage (.gpkg), KML/KMZ, FlatGeobuf (.fgb), or a CSV with a geometry/lat-lon column. 2. Portal directory (Enter for current directory) 3. Dataset name (Enter to use the filename) 4. Namespace value — the group this dataset belongs to (subject if the portal is "theme" mode, publisher if "owner" mode; Enter to reuse the catalog's existing namespace)
Read `NAMESPACE_TYPE` from `PORTAL_DIR/lib/datasets.ts` so you can phrase the namespace question correctly ("subject" vs "publisher").
Do this **before touching data**. Missing tools stop the run with a one-line install — never silently skip a tier.
MISSING="" for t in ogr2ogr tippecanoe duckdb; do command -v "$t" >/dev/null 2>&1 || MISSING="$MISSING $t" done
If `MISSING` is non-empty, print the install for the user's OS and STOP:
ERROR: [add-geo] MISSING_TOOLS Missing:<MISSING>. Install then re-run:
macOS: brew install gdal tippecanoe duckdb
Debian/Ubuntu: sudo apt-get install -y gdal-bin duckdb # tippecanoe: apt where available,
else build from source — https://github.com/felt/tippecanoe
Windows: not supported natively — use WSL (Ubuntu) and follow the Debian steps.Detect Windows-native (`$OSTYPE` = `msys`/`win32`, or `uname` shows MINGW/MSYS) and print the WSL note prominently — this is a documented first-cut limitation, not a bug.
Verify the duckdb `spatial` extension can load (it auto-installs on first use, needs network once): `duckdb -c "INSTALL spatial; LOAD spatial; SELECT 1;"` — if this fails, report it as `MISSING_TOOLS` (duckdb spatial) with the same stop behavior.
🌀 AI-native framework for building data portals. Scaffold a full portal from a brief and load datasets in minutes with agentic skills — any backend (CKAN, GitHub, Frictionless).
Repo: datopian/portaljs
Renamed → /portaljs-add-chart. This alias will be removed next minor release.
Renamed → /portaljs-add-dataset. This alias will be removed next minor release.
Renamed → /portaljs-add-map. This alias will be removed next minor release.
Renamed → /portaljs-add-resource. This alias will be removed next minor release.
Migrate a whole ArcGIS Hub site (opendata.arcgis.com or a Hub Premium custom domain) into a PortalJS Arc portal end-to-end. Harvests the Hub /data.json…
Renamed → /portaljs-architect. This alias will be removed next minor release.