Served locally at http://localhost:51234. By minute 60 you should see the Broad Street pump and the death-density choropleth on screen.
The vocabulary, the surfaces, and the loop — so we share a language before we share a keyboard.
You type, it replies. The model sees only your message. Useful, but you copy-paste everything.
The model gains a code interpreter, file uploads, web search. Still a single turn, single surface.
The model reads your filesystem, runs commands, edits code, opens a browser — and reports back.
Today's lab assumes the third column. If you are still living in the first, the gap is mostly muscle memory — not capability.
You describe the feel of what you want — the shape, the behavior, the audience — and let the agent produce, run, and refine the code.
Coined by Andrej Karpathy, 2025. Useful for prototypes, demos, internal tools, and any disposable code where shipping fast beats writing it yourself.
First drafts. UI iteration. Throwaway scripts. "Can we visualize this?" moments. Today's storymap.
A substitute for code review on anything that handles PHI, runs in production, or makes clinical decisions.
The discipline of building software through an agent: setting up context files, naming reusable skills, version-controlling prompts, and treating the model as a teammate with a job description.
| Surface | Best For | Examples |
|---|---|---|
| Desktop LLM apps | Chat + artifacts | Claude Desktop · ChatGPT (Codex) · Perplexity Comet |
| CLI agents | Filesystem access | Claude Code · Codex CLI · Gemini CLI |
| AI-native IDEs | In-editor flow | VS Code (+ Copilot) · Cursor · Antigravity (Google) |
The prompts in today's lab are platform-neutral. Use whichever surface you already know — the workflow transfers.
Where agents already plug in — and where you, the analyst, still have to do the thinking.
geopandas, rasterio, shapely · gdal, ogr2ogr, pyproj. The agent writes, runs, and debugs in your shell.
Reachable through Model Context Protocol servers (QGISMCP) — the agent drives the GUI for layer styling, processing, atlases.
Petabyte-scale satellite catalog, JS & Python APIs. Agents are excellent at boilerplate ingestion and reducer chains.
Plain HTML / CSS / JS. The fastest path from "I have a GeoJSON" to "share this link." Today's deliverable.
The CLI tools the geo community has used for thirty years are now the agent's preferred plumbing. They are well-documented, deterministic, and easy to verify.
Your job shifts from man gdalwarp to specifying inputs, outputs, and expected CRS.
# Prompt: reproject every shapefile in data/raw/ # to EPSG:4326 and save as GeoJSON in data/clean/. for f in data/raw/*.shp; do name=$(basename "$f" .shp) ogr2ogr \ -f "GeoJSON" \ -t_srs EPSG:4326 \ data/clean/"$name".geojson \ "$f" done # Verify with one line of geopandas: python -c \ "import geopandas as gpd; print(gpd.read_file('data/clean/cases.geojson').crs)"
Model Context Protocol is the standard plug for "tool" servers — and the geo community already shipped one for QGIS.
The petabyte-scale public satellite catalog. The agent is excellent at generating boilerplate: collection filters, cloud masks, reducers, exports.
What you still own: choosing the right collection, defining the temporal window, sanity-checking the output against ground truth.
# Prompt: monthly NDVI for Pima County, # 2024, Sentinel-2 Surface Reflectance. import ee ee.Initialize() aoi = ee.FeatureCollection( "TIGER/2018/Counties") \ .filter(ee.Filter.eq( "NAME", "Pima")) s2 = (ee.ImageCollection("COPERNICUS/S2_SR") .filterBounds(aoi) .filterDate("2024-01-01", "2025-01-01") .map(ndvi))
Tile-based, tiny API, every public health JS map you've seen in the wild. Today's lab uses it.
~42 KB · works everywhere
Open fork of Mapbox GL. WebGL-rendered vector tiles, smooth interaction, full styling spec. Reach for it when Leaflet hits a wall.
vector tiles · 3D terrain · MIT
Both are plain HTML / CSS / JS. No bundler, no framework — which means the agent's output is a single file you can read, edit, and host on any static server.
Four steps. Ninety minutes. One scrolling map of a 175-year-old outbreak — built end-to-end by directing an agent.
The founding dataset of modern epidemiology. Geocoded cholera deaths, pump locations, and the spatial argument that broke the miasma theory.
Small enough to load in a browser. Famous enough that every public health professional in this room has seen the map — but probably never built one themselves.
geodacenter.github.io/data-and-lab/data/snow.zip
Public domain · Wellcome Collection
Drop in the three .md files that tell the agent how this workspace operates.
Folder tree, dataset download, unzip, sort GeoJSONs into map/.
A scrolling Leaflet storymap, choropleth on deaths, served on a local port.
Critique. Approve. Then a one-shot reveal: the same workflow, compressed to one prompt.
We will walk steps 0 — 3 together. Step 4 is yours to try in a fresh chat.
Stack (Python 3.10, Leaflet, no bundlers). Conventions (code/, data/, map/). Guardrails (confirm destructive actions, never fabricate sample data).
/scaffold, /fetch-snow, /storymap, /critique — named macros the agent can invoke.
Field names (deaths, deathdens). Labels on polygons, not points. PI's stylistic preferences.
This is the moment you stop treating the agent as a chatbot and start treating it as a teammate with a contract.
TASK
1. Create folders:
data/, map/, code/, prompts/
2. Download
geodacenter.github.io/data-and-lab
/data/snow.zip
into data/
3. Unzip in place, delete the .zip
4. Move every *.geojson from the
unzipped folder into map/.
Ignore __MACOSX, non-geojson.
5. Save script as code/setup.py.
Confirm each step.
The agent should announce each step and stop on the first failure. If it silently "succeeds" with no files in map/, your Filesystem MCP isn't running.
Grab the zip via your browser, drop it into data/, and re-run from step 3.
TASK Create map/snow_storymap.html using Leaflet (HTML/CSS/JS). Layout: - Scrolly story-map - Layers appear on scroll, fade past - Short caption per layer Data styling: - Choropleth on 'deaths', 'deathdens' - Labels on polygons only (NOT points) Serve: - python -m http.server 51234
If deathdens isn't in the GeoJSON, ask the agent to compute it from deaths divided by polygon area.
TASK Open map/snow_storymap.html. Critique colors, fonts, and scroll feel. Propose up to 3 improvements. Wait for my approval, then apply them in place.
This is the most cuttable step if we're running short. The point is just to feel the iteration loop once.
We just walked four steps. The pedagogical point of step 4 is to paste it all as one prompt and watch the agent execute end-to-end.
Yes, the prompt has typos. The numbering jumps. "Chloropleth" is misspelled. Both are preserved on purpose — modern agents handle messy real-world prompts surprisingly well.
Compare this output to the artifact you built across Steps 1–3. Where did the agent do better with all-at-once context? Where did it cut corners?
"Build a scrolling story telling map…
using Leaflet, HTML, CSS, and
JavaScript…
• layers appear on scroll
• chloropleth on 'deaths' and
'deathdens'
• death count labels on polygons,
not points"
Agents will invent plausible-looking sample data when a real fetch fails. Your guardrail: never fabricate — surface failures and stop.
The script ran. No files appeared. Check the Filesystem MCP is actually connected, and ask the agent to ls map/ after every step.
Treat the prompt window like a public Slack channel. Strip identifiers before pasting. Use synthetic or geocoded-out datasets for development.
Two deeper reads on the iterate-with-an-agent loop you just used in Step 3.
Replace the cut PDF-summary step. Extend the storymap with retrieval over the cholera primary sources.
Prompt logging, session automation, the agent loop framed end-to-end.
Rebuild the layers in QGIS via MCP. Deploy the map as a public static site.
Bring your storymap to the 1:00 PM AI Maker Space. We'll re-aim the workflow at a dataset of your choosing.