Introduction

This course covers agentic coding workflows specializing in geospatial data science. You will get hands-on experience setting up your agent and understand how to use skills and MCP servers to augment domain-specific capabilities. We cover best practices for using coding agents to rapidly solve complex problems - grounded in established science and human-in-the-loop validation. We cover hands-on examples using Claude Code - including crime hotspot mapping, route optimization, and object detection from aerial imagery. You will also learn how to use agents to manage a personal knowledge base and create a website that automatically updates with new information.

View Presentation

Google Slides ↗ PDF ↗

Get the Course Videos

The videos for this course are currently being edited. We expect them to be available by end of November 2026.

Get the Data Package

The code examples and reference materials used in this course are supplied to you in the agentic_coding_geospatial.zip file. Unzip this file to a directory - preferably to the <home folder>/Desktop/agentic_coding_geospatial/ folder.

Download agentic_coding_geospatial.zip.

Note: Certification and Support are only available for participants in our paid instructor-led classes.

Installation and Preparation

Sign up for GitHub

Visit GitHub.com and create a free account. If you already have an account, skip this step.

Install Git and GitHub CLI

Follow our Git and GitHub CLI Installation Guide to install and configure Git and GitHub CLI.

Install Conda and Set up an Environment

We will use conda to install the required Python packages and manage local development environments.

Follow our step-by-step Conda Installation Guide to install Miniconda for your operating system. Once you have a working conda installation, follow the steps below.

  1. (Windows users): Search for Anaconda Powershell Prompt and launch it. (Mac/Linux users): Launch a Terminal window. Run the following commands to create a fresh environment and activate it.
conda create --name claude_code_workshop -y
conda activate claude_code_workshop
  1. Now your environment is ready. We will install the required packages from conda-forge.
conda install -c conda-forge pandas geopandas matplotlib jupyterlab rioxarray gdal rio-cogeo ipykernel uv

Your local development environment is now ready.

Install Visual Studio Code

We recommend Visual Studio Code (VS Code) editor for this course.

Follow our step-by-step Visual Studio Code Installation Guide to install and configure VS Code on your system. Make sure to complete the steps to set VS Code as your default editor.

Install Claude Code

Follow our step-by-step Claude Code Installation Guide to install and configure Claude Code on your system.

Note that you will need a Claude Pro subscription (or higher) to use Claude Code. The concepts apply to any coding agent, but the hands-on exercises are built around Claude Code, and commands and workflows differ a lot from one agent to the next. Having a Claude subscription lets you follow along step by step. Once you’ve learned the fundamentals of agentic coding, you will be able to use any coding agent of your choice (Codex, Copilot, OpenCode, etc.).

Install Obsidian

Obsidian is a free app for creating and managing notes. We will be using Obsidian for setting up your personal knowledge base using Claude. Visit Obsidian Download page and install Obsidian for your platform.

Sign up for OpenRouteService API

OpenRouteService (ORS) provides a free API for routing, distance matrix, geocoding, route optimization etc. using OpenStreetMap data. To obtain an API key, visit the HeiGIT Sign Up page and create an account. Once your account is activated, you can visit the Dashboard and copy the long string displayed under Basic Key.

Install QGIS

We will configure and use the QGIS MCP server to allow Claude Code to use QGIS directly. Please follow our QGIS-LTR Installation Guide to install QGIS. If you already have a recent QGIS version (3.40+ or 4.0+) installed on your computer, you can skip this step.

Get Familiar with the Terminal

Our primary interface for this course will be the Terminal. We will now cover basic terminal commands that will help you get comfortable with the environment.

(Windows users): Search for Anaconda Powershell Prompt and launch it. (Mac/Linux users): Launch a Terminal window.

The following are some of the common terminal commands we will need to browse and manage files.

Command Description Example
cd Change directory cd Desktop
cd .. Change to the parent directory cd ..
ls List files in the current directory ls
rm Delete a file rm test.txt
rm -R Delete a directory (Mac/Linux) rm -R test
rm -Recurse Delete a directory (Windows) rm -Recurse test
mkdir Create a directory mkdir test
cat Print the contents of a file cat test.txt
clear Clear screen clear

1. Agentic Coding Basics

1.1 Introduction to Agentic Coding

View Presentation

Google Slides ↗ PDF ↗

1.2 Setting up your Agent

A good practice is to always set up a CLAUDE.md file for your project. This file contains instructions and rules to be followed when working inside the project directory. If you already have a directory with some code or have cloned a Git repository, Claude Code can automatically create the CLAUDE.md file using the /init command. Here we are starting with a blank project, so we will create a new CLAUDE.md file with instructions.

  1. We will first navigate to the project directory and start Claude Code. (Windows users): Search for Anaconda Powershell Prompt and launch it. (Mac/Linux users): Launch a Terminal window. Use the cd command to change the current working directory to the project directory.

Windows

cd Desktop\agentic_coding_geospatial

Mac/Linux

cd Desktop/agentic_coding_geospatial

  1. Once you are inside the project folder, launch Claude Code by entering the following command. The first time you start Claude Code inside a directory, there will be a security notification. You can choose Yes, I trust this folder.
claude

  1. Invoke the /memory command to set up the project CLAUDE.md
/memory

  1. Select Project instructions and press Enter.

  1. Your default editor (Visual Studio Code) will now open with a new CLAUDE.md file. Paste the following content and save the file. Close the file once saved.
# CLAUDE.md

## Geospatial Stack Preferences

- Prefer Python-based approaches
- Use existing packages instead of building solutions from scratch
- My preference for geospatial packages are below
  - Pandas for tabular data
  - GeoPandas for vector geospatial data
  - XArray ecosystem (rioxarray, xarray-spatial etc) for raster geospatial data
  - Scikit-learn for Machine Learning
  - GeoAI (geoai-py) for Deep Learning
  - Matplotlib/Folium/Lonboard for data visualization in notebooks

## Other Preferences

- Write code that is simple to understand and explain
- Always install python packages in a conda environment. Never install anything in the base environment. Ask the user for confirmation on their preferred conda environment before installing anything.
- Do not use emojis

  1. Make sure you now have a CLAUDE.md file in your <home folder>/Desktop/agentic_coding_geospatial/ folder.

  1. You can also use the /context command to check if the file contents have been loaded into the current context.

Note: Learn more about Managing Context

/context

  1. Verify that you have the Memory file in the context.

  1. At the prompt, you can invoke several commands for configuration. You can type /help to see all available commands. Let’s run a few commands. First enable Plan mode by entering the /plan command. Next choose the model using the /model command. The default model choice is good for now, and you can change the model at any time.

Now we are ready to use Claude Code for our first data analysis task.

1.3 Exploratory Data Analysis (EDA)

We will now use Claude Code to do some data exploration, cleaning and analysis. This will give you a feel of how agents work and how to guide them. We will take the Police.uk data on street-level crime for the City of London (The Square Mile area) and identify crime hotspots.

  1. Enter the following prompt into Claude Code and press Enter. Make sure the Plan mode is on. This will ensure Claude Code will first make an implementation plan and wait for your approval before diving into coding.
I would like to do an exploratory data analysis of crime data in the folder data/london_crime_2024. 

* Give me a summary of the rows, columns and any missing data. 
* Flag any data quality issues. 
* Create charts showing different types of crime and monthly patterns.

Produce the output as a Python script and PNG images.

  1. As the project-level CLAUDE.md states, all the work needs to be done in a conda virtual environment. Claude Code will prompt you to choose an environment. Choose the claude_code_workshop environment created for this class and press Enter.

  1. For the Output format, choose Python script + saved PNGs.

  1. Review the answers and select Submit answers. Press Enter.

Note: Depending on your operating system, Claude Code version, and selected model, you may see a slightly different set of questions.

  1. Now Claude Code will go through the data and come up with a plan for building the required script for exploratory data analysis. You can review the plan and edit it as per your requirements. Use the Ctrl+G shortcut to open an editor with the plan and make any necessary edits. Once you are satisfied, confirm the execution by selecting Yes, and use auto mode.

  1. Claude Code will write the Python script and run it using the installed packages in the conda environment.

  1. Once done, it will print the summary of its findings.

  1. The analysis will also produce some charts in the outputs/ subfolder.

1.4 Data Cleaning and Spatial Analysis (Mapping Crime Hotspots)

Now that we have a good understanding of the data structure, we can ask Claude Code to help us with analyzing the data. In this section, we will go through the workflow of identifying theft hotspots. Starting with data cleaning, we will iteratively improve our analysis and learn how we can use existing references (research papers, manuals etc.) to ground the behavior of the model.

  1. Back in Claude Code, switch to Plan mode. You can press Shift+Tab until you see plan mode on. Enter the following prompt. Claude Code will ask you clarifying questions. You can read through the explanation and select the options that make sense for the analysis.
I want to analyze theft hotspots. 
Help me select the categories for theft crimes and filter the data.

  1. For the merge goal, select Align to official ONS groupings.

  1. Select Submit answers and press Enter.

  1. Review the plan and make any adjustments if required. Select Yes, and use auto mode to proceed.

  1. Claude Code will produce a merge script and the output CSV file.

  1. This is the cleaned version of our original dataset. We can use this for mapping hotspots. Switch to Plan mode (Shift+Tab) and enter the following prompt.
I want to map the theft hotspots. 
Suggest what would be the best technique for the analysis.

  1. Answer the clarifying questions and select the Kernel Density Estimation (KDE) as the technique. Select Submit answers and press Enter.

  1. Once the analysis is planned, enter the following prompt to build the script.
Create a static visualization using matplotlib using gaussian_kde.

  1. Claude Code will produce a script and a map with hotspot visualization.

  1. While this is a good starting point, we can improve it by providing well-known and high quality reference material to guide the implementation. We have an extract of a research report Mapping Crime: Understanding Hot Spots that contains useful tips and best practices for crime mapping. We can improve our analysis by using this reference. Switch to Plan mode (Shift+Tab) and enter the following prompt.
I have some reference material for crime mapping at
https://github.com/spatialthoughts/courses/releases/download/documents/hotspots.pdf
Incorporate suggestions from that and give me an updated plan.
Follow the reference exactly and report any deviations in the plan.

  1. Select the option to use the Quartic kernel and deny option to extend the analysis beyond the scope of the original request.

  1. Once the plan is ready, review it. We can be explicit about the desired output, so you can select Tell Claude what to change.

  1. Ask for the following change.
Save the updated script and chart with the _v2 suffix.

  1. Claude Code will build the required script and produce the new hotspot visualization.

  1. The new map is much more interpretable and based on a scientifically validated technique. Let’s extract the hotspots. Enter the following prompt.
Use the criteria "Greater than 5x mean" to extract hotspots and convert them to polygons.
Save the results as a GeoJSON london_theft_hotspots.geojson.

  1. The raster hotspots will be vectorized using the given threshold and saved as a GeoJSON file.

  1. We can visualize and explore the results in GeoLibre. Open https://web.geolibre.app/ in a browser. Drag and drop the GeoJSON file and verify the results.

Useful Commands

  • /usage: Check your plan utilization in the current session and how much quota is left.

2. Building Complex Workflows

2.1 Using Web APIs (Network Analysis and Route Optimization)

In this section, we will learn how to use Claude Code to build Jupyter notebooks for data analysis and interactively guide the agent to reach the desired solution and validate the results. We will be implementing a real-world scenario of optimizing delivery routes based on a route optimization algorithm.

In your data package, you will find the following files in the data/route_optimization/ folder.

  • Delivery_Locations.geojson: A set of 100 addresses in Washington DC area representing delivery locations.
  • Grocery_Store_Locations.geojson: A set of 14 grocery store locations which need to fulfill the delivery to these locations.

We will use Claude Code to build a Jupyter Notebook that builds an end-to-end workflow that loads the data, finds optimal delivery routes and writes PDF manifests with delivery schedule for each store.

View Presentation

Google Slides ↗ PDF ↗

2.2 Using Claude Code in VS Code

Let’s install the Claude Code for VS Code extension.

  1. Click the Extensions button on the left-hand panel. Search for Claude and select the Claude Code for VS Code by Anthropic extension.

  1. Click Install.

  1. Once installed, it can be invoked from the Toggle Chat button and selecting the Claude Code tab.

2.3 Building Notebooks

Now that we have Claude Code running inside VS Code, we can prompt it to build a Jupyter notebook for us.

  1. Ensure the course folder agentic_coding_geospatial is open in VS Code. Enter the following prompt.
I want to build a notebook to find optimal delivery routes. 
Create a new notebook scripts/route_optimization.ipynb
Read the .geojson files in data/route_optimization/ folder and
display the data on an interactive map.

  1. This is a simple and straightforward task. Our project level CLAUDE.md already has preferences listed for how to set up the environment and what packages to use. Claude Code will start creating the notebook and will pause periodically for confirmation. You can choose Yes to proceed.

  1. Once the task finishes, a new notebook route_optimization.ipynb will be created in the scripts/ folder as instructed.

  1. Locate the notebook in the Explorer tab and double-click to open it. The notebook will have the datasets visualized on an interactive map.

2.4 Interactive Data Analysis

Now, let’s build the core of our data analysis to find the optimal delivery routes. This is a complex problem that requires a lot more context and direction. We will use the Plan mode and guide Claude Code towards building the code that solves the problem.

  1. Make sure the notebook route_optimization.ipynb is open. Open Claude Code from the Toggle Chat button.

  1. Switch to Plan mode.

  1. Enter the following prompt.
I want to use OpenRouteService API. 
Give me options on different approaches to plan for the most optimal delivery routes from each store. 

Here are the constraints:

- A single trip will consist of 10 deliveries at maximum.
- The delivery will originate at a grocery store and end at the same delivery store.
- All stores are capable of fulfilling the order but can do a maximum of 5 delivery trips each day.

The goal is to minimize the total distance traveled.

The output is the assignment and delivery schedule for each store along with a GeoJSON of the optimal delivery routes for visual inspection.

  1. Claude Code will trigger the AskUserQuestion tool to collect more information. For the Vehicle Routing Problem (VRP) approach, select the ORS Optimization API (VROOM).

  1. We need to enter our API key. Select Other and enter the API key in the response below, replacing the <your-api-key> with your actual API key. If you do not have your key handy, you can login to your HeiGIT Account and copy the long string displayed under Basic Key.
Yes, I have a key. Save the API key in a separate cell in the notebook.

ORS_API_KEY='<your-api-key>'

  1. For the Conda env, select the claude_code_workshop conda environment that we have set up. You can then click Submit answers.

  1. As we are asking for delivery schedules, you may be prompted to choose store operating hours. We keep things simple and choose Trip order per store listing.

  1. After obtaining the necessary information, Claude Code will kick-off an agent to do the planning. Approve any permissions it may need.

  1. The OpenRouteService API has limits on how many Origin-Destination pairs it can solve. If you get prompted to choose for an approach, choose Two-stage: assign + batch, then ORS Optimization per trip approach.

  1. Once the plan is ready, it will be opened in VS Code. Review the plan and suggest any changes by adding comments. You can select any text and enter comments on what you would like changed. For example, in the initial plan that Claude Code came up with - it wanted to use the openrouteservice Python package. We can instead ask it to use the API directly instead of a client library by adding a comment like below.
Instead, use the REST API directly.

  1. After adding the comment, choose Send feedback and keep planning.

  1. Once the plan is modified and you are satisfied, choose Yes, and auto-accept.

  1. Claude Code will now start implementing the plan.

  1. Once the notebook is built, it will also test it to ensure it runs without any errors. Once everything is done, it will print a summary.

  1. Open the notebook and review the results. You will see the map with the planned routes for all the delivery locations.

2.5 Validation and Export

When building with AI - you need to spend most of your time validating the results and guiding the model. Let’s learn some techniques for validation.

  1. When reviewing the initial output of the delivery route, you will notice that some of the routes are very long and does not look optimal. We can ask Claude Code to fix this using the following prompt.
I see that some stores are not assigned any deliveries even if they are quite close to an address. 
The assignment tries to assign 10 deliveries in each route - 
making some of them quite long while nearby stores end up without any deliveries.
Update the plan to address this problem.

  1. Claude Code will go through the notebook and come up with a fix. Give your approval to apply the fix.

  1. Your prompt will also force Claude Code to do a more thorough validation of the results.

  1. The updated routes look much better, but we still need to do a closer inspection. We can export the results in any vector data format, so we can use a GIS to view and verify it better. Enter the below prompt.
Save the routes as a single GeoJSON file in the outputs/route_optimization/
folder so I can validate the results.

  1. A new file routes.geojson will be created. Locate it in the VS Code Explorer. Right-click and select Reveal in File Explorer to open the folder on your computer.

  1. We can visualize and explore the results in GeoLibre. Open https://web.geolibre.app/ in a browser. Drag and drop routes.geojson, along with the source data Delivery_Locations.geojson and Grocery_Store_Locations.geojson and verify the results.

  1. Once we are satisfied with the output, we can generate PDF manifests with the planned routes. These files are the output from our analysis that can be handed over to the operations team for implementation. Enter the following prompt. If prompted for a PDF library, choose Install reportlab and click Submit answers.
Generate PDF manifests in the outputs/route_optimization/ folder containing
delivery order and addresses for each trip.
1 manifest per store.

  1. The code will be added to the notebook and PDFs will be generated.

  1. The PDFs now contain delivery routes for each store.

Assignment

Now you are ready to put your agentic coding skills to test by solving a spatial analysis problem from scratch.

Problem Statement

You are a data scientist for a real-estate company who wants to enhance their property listings by assigning a livability score to each of their properties to help buyers pick properties that suit their lifestyle.

Your task is to calculate such a score for all the Apartment Buildings in your city. Consider the factors that are important to home buyers. You can design the score using metrics such as:

These are some examples and you can pick the criteria that make sense to you based on the knowledge of your city. You can use OpenStreetMap to obtain the data for apartment building polygons and the required amenities.

Required output

Below are example reports shared by participants of our live class for inspiration:

Tips

3. Building an AI Second Brain

An AI second brain is a persistent digital memory system that stores your notes and ideas. Andrej Karpathy popularized the idea of implementing such a knowledge base using the note taking app Obsidian and coding agents like Claude Code. In this section, we will take the core ideas behind the LLM-Wiki system and learn how to set up a simplified version to collect, organize and maintain an archive of your notes and bookmarks. We will also publish and host them as an auto-updating website on GitHub Pages so you can always find and recall items from your archive.

View Presentation

Google Slides ↗ PDF ↗

3.1 Setting up your Personal Knowledge Base

We will now create a new folder on your computer and set up a structure to create a personal knowledge base.

  1. (Windows users): Search for Anaconda Powershell Prompt and launch it. (Mac/Linux users): Launch a Terminal window. Create a new directory using the mkdir command.

Windows

mkdir Desktop\personal_knowledge_base

Mac/Linux

mkdir Desktop/personal_knowledge_base

  1. Next, switch to the directory using the cd command.

Windows

cd Desktop\personal_knowledge_base

Mac/Linux

cd Desktop/personal_knowledge_base

  1. Start Claude Code and when prompted, choose Yes, I trust this folder.
claude

  1. Invoke the /memory command to set up the project CLAUDE.md
/memory

  1. Select Project instructions and press Enter.

  1. Your default editor (Visual Studio Code) will now open with a new CLAUDE.md file. Paste the following content and save the file. Close the file once saved.
## Overview

A personal notes organizer maintained by Claude Code.

## Folder structure
   
```
- raw/ -- documents containing unprocessed notes
- processed/ -- documents containing processed notes
- notes/ -- markdown pages for the organized notes pages
- notes/index.md -- table of contents of all the notes pages
- notes/log.md -- append-only record of all operations
```

## Workflow

- Read the unprocessed notes in the `raw/` folder. Look at all files inside the `raw/` folder.
- Process each document and all notes inside using the processing instructions below. 
- Once processed, move it to the `processed/` folder.
- Add an empty file `New_Notes.md` in the `raw/` file to collect new notes.


## Processing Instructions

When the user adds a new note to `raw/` and asks you to ingest it

* Read the New_Notes.md and process all notes from it.
    * If the note has one or more URLs,  visit them and generate an accurate short description.
    * For notes with text upto 100 characters, add it verbatim. For longer notes, summarize it up to 100 characters.
* Read any other files added to the `raw/` folder and process each file as a separate note.
* Identify the core concepts/topic of the resource. 
* Identify the main topic and related topics. If the resource neatly fits into a single main topic - you do not have to have a related topic.
* Read `notes/index.md` first to find relevant topic pages.
* If there is no match, a new topic page can be added. See the list of topics below for additional topics of interest.
* Add a new item to the main topic page. Keeping the newer notes at the top.
* Add back-links ([[page-name]]) to connect related topics. If the related topic page does not exist, create the page.
* Update `notes/index.md` with new pages and one-line descriptions.
* Append an entry to `notes/log.md` with the date, source name, and what changed

## List of Topics

Here are some of the topics for the notes you may find. The topics can be Technology focused (i.e. Python, Xarray) or Theme focused (Climate Change, Agriculture). When deciding the main topic when a note covers both - use the theme focused topic as the primary topic.

Technology Topics
* Machine Learning
* Embeddings
* Deep Learning
* SQL
* Python
* Data
* Agentic Coding

Thematic Topics
* Climate Change
* Urban Planning
* Agriculture
* Remote Sensing
* Cartography

## Topic Page Format


Every note topic page should follow this structure:

```markdown
# Page Title


**Summary**: One to two sentences describing this page.
**Last updated**: Date of most recent update.

---

Main content goes here.
```

## Note Formatting Instructions

- Use Markdown format for each note.
- Use a bullet point for each note.
- For notes with URLs: 
      - Follow the format [title](url]): <description> <keywords>
      - Add a 1-2 line description from the URLs
   - For notes with just text:
      - Follow the format *Title*: <description> <keywords>
      - For notes with text upto 100 characters, add it verbatim. For longer notes, summarize it up to 100 characters.
- Add 3-6 keywords that best describe the note and will aid in recalling them later.
- Link to related topics using [[wiki-links]] throughout the text.

## Rules

- Keep page names Title Case with underscores (e.g. `Machine_Learning.md`).
- Write in clear, plain language.
- Always update the `log.md` after changes.

  1. Once the CLAUDE.md is set up, enter the following prompt.
Read CLAUDE.md and set up the folder structure for my notes

  1. Claude Code will set up the structure as per instructions in the CLAUDE.md file.

3.2 Populating Notes with Obsidian

Obsidian works with a folder of plain Markdown files called a vault. We will open our knowledge base folder in Obsidian, add a few notes and ask Claude Code to process them into linked topic pages. We will also learn how to clip web pages directly into the vault using the Obsidian Web Clipper.

  1. Launch Obsidian. Click Open and browse to the personal_knowledge_base folder to open it as a vault.

  1. You will see your personal_knowledge_base folder along with the subfolders created in the previous step. Select the raw/New_Notes.md file.

  1. Add some notes to this file. Each new line becomes a separate note. You can copy the following 3 notes to get started.
https://cloudnativegeo.org/blog/2026/02/the-technical-debt-of-earth-embedding-products/ Article comparing different earth embeddings

https://github.com/montimaj/agribound Python package for delineating field boundaries

https://zenodo.org/records/18647054

  1. In the Claude Code session, enter the following prompt.
Ingest new notes

  1. Claude Code will visit the URLs and populate each note with a summary, keywords and topics.

  1. You will see new files appear in your Obsidian vault. Open the notes/ folder to see the newly created pages. The index.md is the homepage for the knowledge base where all topics are listed.

  1. You can open individual topic pages to see the notes contained in them.

  1. Each note has links to different topics. You can visualize these connections using a graph view. Click on the Open graph view button.

  1. The default visualization includes all subfolders along with the index.md file. We can remove them from the view to see the actual shape of the notes. Click Filters and enter the following expression. You can also toggle the Existing files only and Orphans buttons.
path:notes  -file:log -file:index

  1. You will now see the connection between the notes clearly.

  1. To help collect and add notes from the web to your vault, you can use the Obsidian Web Clipper extension. Install the extension for your browser. Once installed, locate the icon in your browser’s extension area.

  1. The Web Clipper lets you extract text from any web page and save it directly to your Obsidian vault. Many websites - such as ones requiring user login - are not accessible by AI Agents. The extension makes it easy to add such pages as notes. Visit the following post from LinkedIn and click the Obsidian Web Clipper icon.

Note: If you do not have a LinkedIn account, you can use any other web page for this step.

https://www.linkedin.com/feed/update/urn:li:activity:7478690057026207745/

  1. The extension will populate a note. Change the folder name to be raw instead of the default Clippings. Click Add to Obsidian button.

  1. A new Markdown page will be added in the raw/ folder. Our vault is set up to process all the inputs from this folder, so we can now ask Claude Code to process this note.

  1. Enter the following prompt in Claude Code.
Ingest new notes

  1. The vault will be updated with the new note.

3.3 Publishing Your Notes Website

Claude Code can build, deploy and update websites. We will learn how to use these capabilities by turning our local Obsidian folder into a static website and host it for free on GitHub Pages. We will also configure it so it updates automatically every time we add new notes to our personal knowledge base. This allows you to always access and search your notes from anywhere.

  1. We will first verify and ensure you are logged in to your GitHub account in the Terminal. (Windows users): Search for Anaconda Powershell Prompt and launch it. (Mac/Linux users): Launch a Terminal window and enter the following command. If you get an error message, or do not see your account listed, follow our Configure GitHub CLI to complete the steps for logging in.
gh auth status

  1. We have provided a template for a website based on the MkDocs static site generator. Visit the template repository at https://github.com/spatialthoughts/personal-notes-website-template

  1. Copy the instructions for Claude Code from the README.md page.

  1. Paste it in your Claude Code session and press Enter.

  1. You will be prompted to enter a repository name for your website. Pick the repository name of your choice.

  1. Claude Code will now copy the relevant files from the template and set up your vault as a MkDocs website. Enter the following prompt to push your changes to GitHub and make the website live.
Push the changes

  1. GitHub provides free hosting service for public repositories via GitHub Pages. Select Yes, create public repo when prompted to choose what type of repository to set up.

  1. Claude Code will use the gh command to create and configure the repository. Once the deployment is complete, you can go to the URL of your website displayed in the output.

  1. You will see all your notes from the Obsidian vault published on the website.

  1. The website is set up to auto-deploy whenever a new change is pushed. Let’s test this. Enter a new note in your Obsidian vault.

Tip: You can indicate the main topic for the note by enclosing it in [[ ]]. This is the Obsidian syntax for indicating internal links.

https://www.geomermaids.com/cookbook/duckdb-spatial/ Optimizing DuckDB Spatial Queries [[SQL]]

  1. Ask Claude Code to Ingest new notes and it will update the vault and push updates to the GitHub repository.

  1. Wait for 1-2 minutes for the GitHub Action to deploy the updated site. You will see the new site with the updated note.

Useful Resources

4. Agent Skills

Skills are a set of instructions that teach an AI agent how to perform specific, multi-step workflows. Skills in Claude Code are defined by a SKILL.md containing natural-language instructions for the agent along with specific examples and patterns. You can also publish your skill on GitHub and make it available for others to download and use with their own agent.

View Presentation

Google Slides ↗ PDF ↗

4.1 Installing a Skill

There are multiple ways to install skills. The npx skills command provides an easy way to install skills for a wide range of coding agents. However this requires installation of Node.js on your system. For Claude Code, you can install skills directly as plugins. We will install Matt Pocock’s Skills for Real Engineers - which contain many widely used agent skills for engineering and productivity.

  1. (Windows users): Search for Anaconda Powershell Prompt and launch it. (Mac/Linux users): Launch a Terminal window. Activate the course environment and use the cd command to change the current working directory to the project directory. Run the following command to install the skills as a plugin. You will see a message confirming that the plugin was installed with the user scope, which makes the skills available in all your projects.
claude plugin install mattpocock-skills@claude-plugins-official

  1. Start Claude Code by entering claude. Type /skills and press Enter to list the available skills.
/skills

  1. You will see the skills installed by the plugin, with names starting with mattpocock-skills:. Use the arrow keys to scroll through the list, or type / to search. Press Esc to close.

4.2 Using a Skill (Earth Embeddings Research)

Skills can be triggered automatically when your prompt matches the task handled by a skill. Each skill has a description, and Claude Code uses it when the keywords in your prompt match the description. You can also invoke a skill directly by typing / followed by the skill name. We will use the research skill to investigate a question using primary sources.

  1. Enter the following prompt. It starts with the name of the skill, followed by the question we want to research.
/mattpocock-skills:research What earth embedding model is best suited for
mapping agriculture?

  1. Claude Code will follow the instructions in the skill. In this instance it started a background agent that worked from primary sources only, such as model papers, official model cards and benchmark papers. You can continue working in the main session while the agent is running.

  1. Research tasks can take a while. Once the agent has finished, Claude Code will summarize the findings, including a suggested next step and any gaps in the research.

  1. The full report will be saved as a Markdown file in the folder of your project. Open it in Visual Studio Code to read the recommendation along with the references.

4.3 Creating a Skill (Cloud-Optimized GeoTIFFs)

The real power of skills lies in automating custom workflows. We will learn how to create a new skill for your custom workflow and use it. We will create a new skill named create-cog for converting raster data into a Cloud Optimized GeoTIFF (COG) format.

  1. Enter the following prompt. Create a new skill from the following text: and paste the content below.
---
name: create-cog
description: Convert a raster to a Cloud-Optimized GeoTIFF (COG)
---

Use this skill when you need to convert any geospatial raster data to a
Cloud-Optimized GeoTIFF.

## Workflow

1. Activate the conda environment that has GDAL. Never use the base environment.
2. Check the GDAL version, since the conversion command differs by version.
3. Check if the input is already a valid COG. If it is, stop and report
   that. Do not re-convert.
4. Convert, using the compression settings and naming convention below.
5. Validate the output and report the result.

## Required Tools

* `gdal` Conda package. Install using `conda install -c conda-forge gdal`
* `rio-cogeo` Python package for validation. Install using `pip install
  rio-cogeo`

Both must come from a conda environment, not base. Check what is available
before installing:

    conda env list
    conda activate <env>
    gdal --version

If neither is installed, ask the user which environment to install into
before proceeding.

## Validating COGs

    rio cogeo validate <file>

Always validate the input before converting and the output after converting.

## Converting Raster to a COG

Check `gdal --version` first, then use the matching command.

GDAL version >= 3.11 (the `gdal` subcommand interface)

    gdal raster convert -f COG <input file> <output file>

GDAL version < 3.11 (the legacy utility)

    gdal_translate -of COG <input file> <output file>

Note the flag difference. The new `gdal raster convert` takes `-f` (or
`--format`). It does NOT accept `-of`, which is the legacy `gdal_translate`
flag, and fails with "Option 'o' is not a boolean option."

Creation options are passed with `--co KEY=VALUE` on the new interface,
`-co KEY=VALUE` on the legacy one.

If the output file already exists, the command errors out. Add
`--overwrite` only when you intend to replace it.

## Compression

The COG driver already applies LZW compression by default, so the output is
compressed even if you pass nothing. But the default uses no predictor,
which wastes a lot of space on continuous data. Set the compression and
predictor explicitly. Use DEFLATE as the default, since it is readable by
every GeoTIFF client.

    gdal raster convert -f COG --co COMPRESS=DEFLATE --co PREDICTOR=YES <input> <output>

Only exception - If the input data is JPEG compressed - typically used in
aerial/drone imagery), retain the same with COMPRESS=JPEG

## File Naming Convention

Append the text `_cog` to the converted filename. If the input is
`data.tif`, the output should be named `data_cog.tif`

## Remote Files

If the given file is a remote file, do not download it. Use GDAL Virtual
File Systems by prefixing the URL with `/vsicurl/`

    rio cogeo validate /vsicurl/https://example.com/data.tif
    gdal raster convert -f COG /vsicurl/https://example.com/data.tif data_cog.tif

A remote input gives no obvious output location. Write to the current
working directory unless a location is specified by the user.

In Windows Powershell, set the following environment variable `MSYS_NO_PATHCONV=1` 
to avoid errors when using paths starting with `/vsicurl`

  1. If prompted, install the skill as a project-level skill. This will be installed in the .claude directory in the current folder.

  1. Run the following command to reload the skills so the new skill is available.
/reload-skills

  1. Let’s test the skill. You have a regular GeoTIFF file in your data package. Let’s ask Claude Code to convert it. Enter the prompt below.
Convert the file data/chirps/chirps-v3.0.2025.tif to a Cloud Optimized GeoTIFF

  1. The skill will be invoked and a new file will be generated as per the instructions in the skill.

  1. Let’s test the skill with a remote file. Enter the following prompt.
Convert the file https://data.chc.ucsb.edu/products/CHIRPS/v3.0/annual/global/tifs/chirps-v3.0.2024.tif to a COG

  1. As specified in the skill, Claude Code will use the /vsicurl virtual file system to access the file instead of downloading it.

  1. Skills can also be invoked using commands. Let’s test the skill to ensure it follows the validation instructions. Enter the following prompt.
/create-cog Convert this file https://storage.googleapis.com/spatialthoughts-public-data/ntl/viirs/viirs_ntl_2021_global.tif

  1. As our input is already a COG, the skill will correctly stop and not convert the file.

Useful Skills

  • Anthropic Official Skills: Official skills repository by Anthropic. skill-creator, pdf, xlsx are useful skills for Data Science work.
  • Karpathy-Inspired Claude Code Guidelines: Improve Claude Code behavior, derived from Andrej Karpathy’s observations on LLM coding pitfalls.
  • Skills Leaderboard: Discover, install and manage skills using the skills CLI.
  • Geospatial Skills for Agents: A catalog of installable geospatial tools and capabilities designed for coding agents, covering raster/vector processing, satellite data, and interactive visualization.
  • SpatialThoughts AI Skills: Repository containing skills accompanied with Spatial Thoughts Courses.
  • GeoSQL: Skill for data scientists and analysts working with geospatial data on PostGIS, BigQuery, Snowflake, and Wherobots.

5. Using MCP Servers

The Model Context Protocol (MCP) is an open standard for connecting external tools to AI Agents. MCP Servers allow your Agent to carry out tasks on different applications. In this section, we will learn how MCP servers work and how to configure your agents to use them.

View Presentation

Google Slides ↗ PDF ↗

5.1 Installing and Using the QGIS MCP Server

The QGIS MCP server allows you to connect Claude Code to QGIS and provides tools to add layers, edit features, call processing algorithms and more. Configuring the MCP server is a two-step process:

  • Install the QGIS MCP plugin in QGIS.
  • Configure Claude Code with the QGIS MCP server.

We will go through each step and learn how to set up the server and use it from Claude Code.

  1. Open QGIS. Go to Plugins → Manage and Install Plugins….

  1. In the Plugin Manager, select the All tab, search and locate the QGIS MCP plugin. Click on the Install Plugin button to install it.

  1. Once installed, you may get a configuration pop-up. No need to change any settings here. Click Close.

  1. Start the MCP server from Plugins → QGIS MCP → Run MCP.

  1. You can also start the server from the Plugin Toolbar menu. Once started, the plugin button will turn green to indicate that the server is running.

  1. (Windows users): Search for Anaconda Powershell Prompt and launch it. (Mac/Linux users): Launch a Terminal window. Activate the course environment and run the following command to add the QGIS MCP server to Claude Code configuration.
conda activate claude_code_workshop
claude mcp add -s user qgis -- uvx --from https://github.com/nkarasiak/qgis-mcp/archive/refs/heads/main.zip qgis-mcp-server

  1. Start Claude Code. Run the following command for managing MCP servers.
/mcp

  1. Verify that qgis is connected. Press Esc to exit.

  1. Enter the following prompt to test the connection to the QGIS MCP server. If the connection is working fine, you will get a success return message.
ping qgis

  1. Let’s use the MCP server. Enter the following prompt.
Load the raster data/chirps/chirps-v3.0.2025.tif in QGIS

  1. Claude Code will use the tools provided by the MCP server to load the data layer in QGIS.

5.2 Setting up Project Instructions

Before we start asking our agent to perform tasks in QGIS, let’s update our CLAUDE.md file with QGIS best practices and preferences.

  1. Invoke the /memory command to update the project CLAUDE.md.
/memory

  1. Select Project instructions and press Enter.

  1. Your default editor (Visual Studio Code) will now open with the project’s CLAUDE.md file. Paste the following content after the first section. Save and close the file.
## QGIS Rules and Preferences

### Inputs and Outputs

- Never modify my input data sources and layers. Always create a new layer with your edits. 
- Create temporary memory layers for all intermediate outputs. 
- Always use GeoPackage as the format for saving the outputs, unless specified otherwise. 
  QGIS Projects can also be saved inside of a GeoPackage.

### Processing Algorithms

- Search the available algorithms and check if they can carry out the required tasks. 
  - If there are multiple algorithms, prefer the native QGIS algorithms.
- Always prefer built-in processing algorithms rather than writing your own.
  
### Spatial Index

- If you are running a processing algorithm that uses a spatial query or an overlay, check if the spatial index exists on the input layers, and if not, create one using the processing algorithm. `Create Spatial index`.
  - Check if the spatial index already exists first.
  - QGIS creates a spatial index for point layers automatically, so do this only for line and polygon layers. 
- When creating models, add the spatial index step to create a spatial index on intermediate layers where it is required.

5.3 Spatial Analysis with QGIS MCP Server (QGIS Multicriteria Overlay)

We will now use the QGIS MCP server to carry out a multicriteria overlay analysis. Our goal is to find suitable locations for new bicycle parking facilities based on several spatial criteria. We have a QGIS project with layers of bicycle theft hotspots, cycling routes, existing cycle parking and the borough boundary. We will ask Claude Code to design the workflow and run it in QGIS via the MCP Server.

  1. Make sure QGIS is open and the MCP server is running. Enter the following prompt to load the project. Claude Code will open the Bicycle_Theft_Multicriteria project stored in the multicriteria.gpkg GeoPackage and summarize the layers it contains.
Load the Bicycle_Theft_Multicriteria project from data/multicriteria_overlay/
in QGIS

  1. Switch to Plan mode (Shift+Tab) and enter the following prompt. We will ask Claude Code to suggest a workflow based on the layers we have, and will refine it to ensure it matches our expectation.
I want to do a multicriteria overlay analysis to find locations for new
bicycle parking facilities. Suggest the workflow to do this in QGIS with my
existing data layers.

  1. Claude Code will propose a workflow. Once the plan is updated, press Ctrl+G to open it in Visual Studio Code and review it.

  1. If you want to update the plan, close the file, and select Tell Claude what to change and enter what you want to change. For example, our initial plan excluded loading any intermediate layers and had questions about building a model. We can address these by entering the following prompt. Claude Code will update the plan. Press Ctrl+G to open it in Visual Studio Code and review it. When you are happy with the plan, save the file and close it.
Load all intermediate layers (turned off by default) so I can verify
the results. Also build a processing model with configurable distances.

  1. Back in Claude Code, select Yes, and use auto mode to proceed.

  1. Claude Code will run the analysis step by step using the MCP server, then run the new model with the same default distances and confirm both produce identical results. It will report the candidate zones ranked by the number of bicycle thefts inside each zone. In QGIS, you will see a Results group with the candidate_zones and candidate_sites layers.

  1. Expand the Intermediate group and turn on the layers one at a time to verify the analysis. For example, turning on 01_routes_buffer, 02_hotspots_buffer and 03_parking_buffer shows the areas near cycling routes, near theft hotspots and around existing parking. Checking the intermediate outputs visually is an important step in verifying the work done by an agent.

  1. Turn off the Intermediate group and turn on the candidate_sites layer. Each point is a suggested site for new bicycle parking, located inside one of the candidate zones.

  1. Once we have verified the results, we no longer need the intermediate layers. Read the Things to know section of the summary, which notes small differences between the plan and the model, such as the output names. Enter the following prompt to clean up the project.
Remove the intermediate layers from the QGIS project.

  1. The model created by Claude Code is a regular QGIS processing model that anyone can run without an agent. In the Browser panel, expand the multicriteria_overlay folder and double-click the Bicycle Parking Site Selection model to open it. The Parameters tab shows all the inputs we can configure. Let’s see what happens if we change one of them. Set Buffer around theft hotspots (m) to 0, Min distance from existing parking to 50 and Max distance from cycling route to 50. Click Run.

  1. A new set of candidate_sites and candidate_zones layers will be added to the project. Compare the new sites with the original ones. Changing the parameters resulted in a very different output. The results of a multicriteria overlay depend on the distance thresholds we pick, and these thresholds are often a judgement call. In the next section, we will test how sensitive our results are to these choices.

5.4 Sensitivity Analysis with QGIS Models

A sensitivity analysis tests how the results change when the input parameters change. Sites that are selected across a wide range of buffer values are reliable choices, while sites that appear only for certain values depend on our assumptions. Since we have a processing model with configurable distances, we can ask Claude Code to run it many times with different values and summarize the results.

  1. Enter the following prompt.
I want to do sensitivity analysis to test for the effects of different buffer
values. Use the QGIS model to run different variables of the analysis to
reliably detect candidate sites.

  1. Claude Code will describe its design before running the model. In this instance it decided to run the model 27 times, covering every combination of 3 values each for route_distance, hotspot_buffer and parking_distance, while keeping min_area fixed at 500 m2. It then counted how often each location falls in a candidate zone, using a 25 m point grid over Westminster. This gives the share of runs in which each location is selected.

  1. Once the runs are complete, Claude Code will report how often each of the original candidate sites was selected. Sites 4 and 2 were selected in all 27 runs and are marked as Robust. The other sites appear only for certain combinations of buffer values. Scroll down to read how each buffer affects the results.

  1. In QGIS, you will see a Sensitivity results group. The site_stability layer shows each candidate site styled by the percentage of runs in which it was selected. Turn on only the 82.4 - 100 category to see the 2 sites that are selected regardless of the buffer values. These are the most reliable locations for new bicycle parking. The group also contains a robustness_grid layer with the selection frequency for each grid point, a robust_zones_75pct layer with areas selected in at least 75% of the runs, and a run_summary table with the results of each run.

6. GeoAI

We will now build a notebook that uses a pre-trained model to detect buildings from aerial imagery, running on Google Colab so we can take advantage of its free GPU access. We will select an image from OpenAerialMap and use a pre-trained model to extract building polygons from it.

View Presentation

Google Slides ↗ PDF ↗

6.1 Configuring the Colab MCP Server

We will set up and configure a connection to the Google Colab MCP server which will allow Claude Code to create, modify and run Google Colab notebooks.

  1. Start Claude Code in the Terminal. (Windows users): Search for Anaconda Powershell Prompt and launch it. (Mac/Linux users): Launch a Terminal window. Use the cd command to change the current working directory to the project directory.
claude

  1. Enter the prompt below to set up the MCP server. In the world of agentic coding, you can point your agent to install instructions like these and it will configure itself instead of you doing this yourself.
Set up an MCP server according to the instructions at
  https://github.com/googlecolab/colab-mcp

  1. You can select the course conda environment when prompted to select an environment for installing dependencies.

  1. Claude Code will install the dependency and update the local configuration file .claude.json with the required information. Restart Claude Code for the changes to take effect. You can exit the session using Ctrl+C and start it again by typing claude.

  1. Once the session is restarted, enter the following command.
/mcp

  1. If everything went fine, you should see the colab-mcp server connected.

6.2 Building Notebooks in the Cloud

Now that we have configured the MCP server, we can prompt Claude Code to create cloud-hosted notebooks using Google Colab.

  1. Enter the following prompt.
Create a new colab notebook

  1. Claude Code will use the colab-mcp server to open a connection. Approve the execution requests.

  1. A new tab will open in Google Chrome and you will be prompted to connect to the Colab MCP server. Click Connect. Ensure that you are signed-in to your Google account.

  1. If this round-trip command was successful, a new notebook will be created. If you get errors, see the steps outlined in Debugging Colab MCP Connection.

  1. Next, let’s add some code and execute it. Enter the following prompt.
Add a cell to print "hello world" and run it

  1. The MCP server will add the cell and run the notebook in a cloud-hosted machine.

Debugging Colab MCP Connection

Colab MCP server can be a bit flaky and you may see errors when establishing the connection. Here are a few things you can try.

  1. Type /mcp and check whether the colab-mcp server is connected. If it is disconnected, select it and press Enter to reconnect.

  1. If you have a Google Colab tab open but the Claude Code is not able to connect to it, you can go to Tools → Command palette.

  1. Search for mcp and select Connect to a local Colab MCP server to connect that notebook to the MCP server.

6.3 Using Deep Learning Models (Building Detection)

With the Colab MCP server connected, we can now ask Claude Code to build a complete deep learning workflow. We will use a pre-trained building footprint extraction model from the GeoAI package, run it on a free GPU in Colab and verify the detected buildings against the source imagery.

  1. Enter the following prompt to build the notebook.
Create a new Colab notebook named "building_detection".

This notebook will use a pre-trained model for building footprint extraction from GeoAI and run it on the provided image. 

Structure the notebook following this example https://opengeoai.org/examples/building_footprints_africa/

The provided image can be large. So use the GeoAI package to split the input image into tiles 

Reproject the tiles to a suitable local UTM crs.

The model is trained on images around 50cm-1m resolution images. Check the resolution of the provided image and if it is higher resolution (i.e. 5cm, 10cm) - resample the tiles to 50cm resolution before running the inference. 

Save the results as a GeoJSON file in EPSG:4326 CRS.

Use this image from OpenAerialMap to test the notebook https://oin-hotosm-temp.s3.us-east-1.amazonaws.com/69493c8084a859b011c94266/0/69493c8084a859b011c94267.tif

  1. Claude Code will now build the workflow and populate the cells in the Colab notebook. Once done, we need to change the runtime to use a GPU.

  1. Open the notebook and click on the dropdown for Additional connection options and select Change runtime type.

  1. Select T4 GPU and click Save.

  1. Back in Claude Code, enter the following prompt.
Run the notebook

  1. The inference pipeline will be executed.

  1. View the notebook and you will get the detected building footprints as a polygon layer. Let’s download and view the results. Click on the Files tab from the left-hand panel in Colab.

  1. Browse to the directory where the output is saved and locate the building_footprint.geojson file.

  1. Click on the : button next to it and select Download.

  1. We can open the source imagery and the detections in GeoLibre Web for detailed QA. Visit https://web.geolibre.app/ and select Add Data → Raster Layer.

  1. Paste the URL of the image that we used for the notebook and click Load
https://oin-hotosm-temp.s3.us-east-1.amazonaws.com/69493c8084a859b011c94266/0/69493c8084a859b011c94267.tif

  1. Next, go to Add Data → Vector Layer. Click on the Drop file or click to browse panel. Browse to the downloaded GeoJSON file and select it and click Load.

  1. Check how well the model performed in detecting and extracting the buildings.

  1. Save the completed notebook by going to File → Save a copy in Drive.

  1. You can test the workflow on other aerial imagery from OpenAerialMap. Browse OpenAerialMap and find an image in your region. Make sure the image contains a few buildings. Replace the image used in this notebook with the URL of the new image and run the notebook.

If you want to use a sample notebook generated in this step, click the button below. Open In Colab

Data Credits

License

This course material is licensed under a Creative Commons Attribution 4.0 International (CC BY 4.0). You are free to re-use and adapt the material but are required to give appropriate credit to the original author as below:

Agentic Coding for Geospatial course by Ujaval Gandhi www.spatialthoughts.com

© 2026 Spatial Thoughts www.spatialthoughts.com


If you want to report any issues with this page, please comment below.