Tuesday, September 8, 2026

ArcGIS Pro, Claude Code, and a Loopback Bridge

Continuing the GenAI-with-a-GeoSpatial-twist thread I started a while back. Back then, I had a language model reason about geospatial logic. This time, I wanted it to actually do the work—on my open project, inside my running ArcGIS Pro session, while I watch.

The result is ProCowork, an experimental native ArcGIS Pro add-in that embeds the Claude Code engine in a dockable chat panel. I can ask it to list layers, add and calculate fields, select features, run a buffer, or write a more specialized ArcPy script. Claude generates the code, the add-in runs it against the live project, and the code and results come back into the same panel.

For example, I can type:

  • “List the layers in the current map.”
  • “Add a DOUBLE field POP_DEN to Parcels and set it to POP / AREASQMI.”
  • “Select parcels where POP_DEN > 5000 and zoom to them.”
  • “Buffer Roads by 100 meters and add the result to the map.”

The panel is useful, but the interesting part is not the chat UI. It is getting an external AI coding agent safely and reliably close enough to a live ArcGIS Pro project to be useful.

The constraint that shaped the design

arcpy.mp.ArcGISProject("CURRENT") only resolves inside ArcGIS Pro's own Python execution context on the foreground geoprocessing thread. Claude Code, however, runs as a headless child process. If it starts Python outside Pro, that process can work with datasets on disk, but it cannot see the open project as CURRENT.

My first design kept a long-running Python daemon inside Pro. It worked, and then it went stale in the ways long-running bridges tend to go stale. So I flipped the ownership around. A persistent C# bridge now lives inside ArcGIS Pro for the whole session. For each request it either uses the ArcGIS Pro .NET SDK directly or launches one fresh foreground ArcPy geoprocessing tool. The tool resolves CURRENT, performs the operation, returns JSON, and goes away. There is no Python daemon left behind to outlive its host.

ProCowork panel (WPF, inside ArcGIS Pro)
    -> Claude Code (headless child process)
        -> MCP over HTTP on 127.0.0.1:<ephemeral-port>
            -> C# BridgeService (inside ArcGIS Pro)
                -> .NET SDK on the CIM thread
                -> or one fresh RunScript.pyt call
                    -> live project, map, and data

MCP is the small door into the live map

The bridge exposes 14 tools through the Model Context Protocol (MCP). There are focused tools such as list_layers, get_field_list, feature_count, select_by_attribute, add_field, and run_geoprocessing. The centerpiece is run_python_current(code), which gives Claude a general ArcPy path when the curated tools are not enough.

Inspection calls and lightweight map interactions use the .NET SDK on Pro's CIM thread, without ArcPy. Data updates and arbitrary Python go through the fresh geoprocessing call. Those calls are serialized behind a semaphore because geoprocessing does not appreciate re-entrancy. Request and response data travel as geoprocessing string parameters, so there is no file-polling spool between C# and Python.

Everything stays local except the normal Claude model traffic. The MCP server binds only to loopback, chooses an ephemeral port at startup, and requires a new bearer token for the session. The add-in writes those details into a generated .mcp.json and starts Claude Code in streaming JSON mode. It can use the user's existing Claude Code login, an OAuth token, or an Anthropic API key; stored secrets are protected with Windows DPAPI.

There is also a very practical UI detail. Claude answers in Markdown, while ArcGIS Pro hosts a native WPF interface. ProCowork converts the Markdown with Markdig and renders headings, code, lists, links, and real tables using themed WPF controls. Tool calls can be shown or hidden, but I like keeping them visible: if an agent is changing my map, I want to see the code it ran.

A word of caution

By default, ProCowork runs in what I call YOLO mode. Generated code executes on the open project without an approval prompt. That immediacy is the point, and it is also exactly as dangerous as it sounds. ArcPy can edit or delete real data. The bundled instructions tell Claude to inspect fields first, use edit sessions, create backups before destructive operations, and report affected row counts. Those are useful working rules; they are not a security boundary.

So this is an MVP and an experiment, not an Esri product or a supported Esri solution. It currently requires Windows, ArcGIS Pro 3.7, the ArcGIS Pro SDK for .NET, and Claude Code. Keep backups and do not point it at the only copy of important data. The architecture can support an approval step, but the proper approval card is still future work.

What excites me here is not only that an LLM can write ArcPy. We already knew that. It is that a small, local bridge can give an agent useful context from a live desktop GIS, let it act through the correct execution path, and return the evidence to the same place where the request started.

The source code, build instructions, architecture notes, and current limitations are available in the ProCowork repository. The next step is the one I would want before using it on serious work: a clear review-and-approve experience for generated operations.

More to come :-)

No comments: