Build on it, don't just buy into it
Every solution in this portfolio is a developer product first. Import a single map control into an application you already ship, describe a whole map app in YAML, call the REST APIs from any language, or license the source and run the entire thing yourself.
Four ways in, depending on how much you want to own
Mix them freely — most teams start with the library and add the REST layer later.
TypeScript library
Tree-shakeable npm package with 40+ map controls and a headless client behind each one. Import one class or the whole surface, with full types.
Python CLI
Declare a full map application in YAML and build it into a portable static page — with the COOP/COEP headers DuckDB WASM requires already set.
REST APIs
OpenAPI 3.1 with Swagger UI and ReDoc, auto-generated record CRUD, realtime SSE, and standards-compliant Esri and OGC geospatial contracts.
Source-code licence
The repository, not just the bundle. Self-host it, fork it, extend it on your own roadmap — with no dependency on our release schedule.
What each solution exposes
Eight products, four developer surfaces, one licensing conversation.
| Solution | Language / runtime | Developer surface |
|---|---|---|
| Land Intelligence — Zoning & CRE Analysis | TypeScript, Python | npm library (40+ controls, headless clients), YAML config schema, Python CLI with init, validate, build, serve and convert |
| Execution Layer | Rust (TrailBase), TypeScript | Auto-generated record CRUD per table, realtime SSE subscriptions, custom domain endpoints, JSON-schema form definitions |
| Parcel Federation Proxy | Python (FastAPI) | Esri FeatureServer contract, OGC API Features, unified search, admin registry API, OpenAPI 3.1 document for client generation |
| Opportunity Pipeline | Python (DuckDB) | YAML jurisdiction schema with validated config models, a staged CLI you can run whole or one stage at a time, canonical role and column catalog, and a manifest contract for the map client |
| Geospatial CMS In development | TypeScript (Next.js, ArcGIS SDK) | Versioned REST API under /api/v1 for auth, feature retrieval and spatial analysis; a serialisable workflow-graph format; Zod-validated boundaries; self-hosted via Docker Compose |
| County Tax Search Gateway | TypeScript (Express, Playwright) | OpenAPI 3.0 document with bundled Swagger UI that works offline, one result envelope across every outcome, a named error-code taxonomy, and a CLI with pipeline-friendly exit codes |
| Zoning Code Intelligence | Python (FastAPI, DuckDB) | OpenAPI 3.1 with the AI-dependent endpoints separated from the key-free text endpoints, answers returning their own source passages, a staged SQL extraction pipeline, and CSV / GeoJSON / PostGIS export |
| Geospatial AI Assistant | Python (FastAPI), TypeScript | Unified geospatial API across ESRI/OGC/WFS with CQL filter conversion, a natural-language SQL surface with generation and execution split apart, and an MCP server exposing 20+ tools plus a Python client |
| AI Analyst backend | Python (FastAPI) | Chat and session endpoints, natural-language to read-only SQL, ArcGIS FeatureServer query proxy, layer catalog |
Enough to see the shape of the thing
Full reference documentation ships with SDK access.
// npm install maplibre-arcgis maplibre-gl import maplibregl from 'maplibre-gl'; import { ArcGISAuthManager, ArcGISLoginControl, EsriFeatureServiceControl } from 'maplibre-arcgis'; import 'maplibre-arcgis/style.css'; const map = new maplibregl.Map({ container: 'map', style: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json', center: [-98.5, 39.8], zoom: 4, }); const auth = new ArcGISAuthManager({ portalUrl: 'https://www.arcgis.com', authMethod: 'oauth2', clientId: 'YOUR_CLIENT_ID', }); map.addControl(new ArcGISLoginControl({ auth }), 'top-right'); map.on('load', () => { map.addControl(new EsriFeatureServiceControl({ id: 'parcels', url: 'https://services.arcgis.com/.../FeatureServer/0', auth, })); });
import { ArcGISAuthManager } from 'maplibre-arcgis'; // OAuth2 / PKCE — recommended for user-facing apps new ArcGISAuthManager({ portalUrl: 'https://www.arcgis.com', authMethod: 'oauth2', clientId: 'ID' }); // Static API key — ArcGIS Location Platform / developer accounts new ArcGISAuthManager({ portalUrl: 'https://www.arcgis.com', authMethod: 'apikey', apiKey: 'KEY' }); // generateToken — ArcGIS Server / Enterprise new ArcGISAuthManager({ portalUrl: 'https://my.portal.com', authMethod: 'token', username: 'user', password: 'pass' }); // App credentials — server to server new ArcGISAuthManager({ portalUrl: 'https://www.arcgis.com', authMethod: 'app', clientId: 'ID', clientSecret: 'SECRET' }); // One manager, passed to every control that needs a token.
version: 1 title: Industrial Site Selector auth: portal_url: https://my.portal.com method: oauth2 client_id: abc123 view: center: [-98.5795, 39.8283] zoom: 6 controls: login: true duckdb_loader: true style_admin: true layers: - { id: zoning, type: feature_service, url: https://…/FeatureServer/0, opacity: 0.7 } - { id: dem, type: cog_s3, url: s3://my-bucket/dem.tif, colormap: terrain } - { id: lidar, type: copc_lidar, url: https://…/cloud.copc.laz } - { id: parcels, type: duckdb, url: https://…/parcels.fgb, render_type: fill } # maplibre-arcgis validate map.yaml # maplibre-arcgis build map.yaml → portable static page # maplibre-arcgis serve map.yaml → with COOP/COEP headers set
import { FeatureServiceEditor, geoJsonFeatureToEsri } from 'maplibre-arcgis'; const editor = new FeatureServiceEditor({ url: 'https://services.arcgis.com/.../FeatureServer/0', auth, }); const features = await editor.queryFeatures({ where: "ZoningCode = 'M1'" }); await editor.applyEdits({ adds: [geoJsonFeatureToEsri(newParcel, spatialReference)], updates: [updatedFeature], deletes: [staleFeature], }); // Or give end users the editing panel directly: // map.addControl(new FeatureEditorControl({ url, auth }), 'top-right');
# Esri FeatureServer contract GET /parcels/FeatureServer # service descriptor GET /parcels/FeatureServer/0 # layer descriptor GET /parcels/FeatureServer/0/query # Esri /query contract # OGC API Features contract GET /parcels/ogc/collections/parcels # collection metadata GET /parcels/ogc/collections/parcels/items # ?bbox=… &limit=… # Unified cross-jurisdiction search GET /parcels/search?parcel_id=010-001234&state=OH GET /parcels/search?address=1+main+st+columbus+oh GET /parcels/search?owner=acme+holdings&state=TX # Registry admin — not exposed to mapping clients GET /admin/registry GET /admin/health POST /admin/reload
# 1. Describe the jurisdiction. Keys are canonical names, # values are whatever the county happened to call them. sources: parcels: url: https://services.arcgis.com/…/FeatureServer/0 layer_name: austin_parcels srid: 2277 attribution: "Travis Central Appraisal District" field_map: parcel_id: PROP_ID lot_size: SQ_FT owner: OWNER_NAME output: dir: data/austin_tx queries: - { query: underbuilt_parcels, file: 15_underbuilt.geojson } - { query: assemblage_candidates, file: 16_assemblage.geojson } - { query: composite_opportunity_score, file: 17_composite.geojson } # 2. Run it — whole, or one stage at a time. python -m opportunity_pipeline.run jurisdictions/austin_tx.yaml python -m opportunity_pipeline.run jurisdictions/austin_tx.yaml \ --stages extract,convert python -m opportunity_pipeline.run jurisdictions/austin_tx.yaml \ --stages analyze -v # 3. Read the manifest from your own client. curl '…/data/austin_tx/manifest.json' # layers + styles curl '…/data/austin_tx/opportunities/15_underbuilt.geojson'
Three ways to take delivery
Pick the one that matches how much of the system you want to run yourself. All three include developer documentation and integration support.
Managed service
We run it. You get accounts, endpoints and an SLA, and the parcel registry stays current without your team maintaining it.
- Fastest path to a working pilot
- No infrastructure on your side
- Registry and upstream maintenance included
SDK licence
Take the library, CLI and API clients into your own product. Your UI, your branding, your deployment — our engine underneath.
- Tree-shakeable — ship only what you use
- Full TypeScript types and reference docs
- Versioned releases with upgrade notes
Source-code licence
The repository itself — backend, frontend, migrations, deployment configuration. Run it in your own environment and extend it without waiting on us.
- Docker Compose deployment included
- Air-gapped and on-premises friendly
- Your roadmap, your release schedule
* Third-party data sources — ATTOM, Regrid, ESRI GeoEnrichment, Google Maps, MapTiler and county tax portals — require their own credentials or licences and are billed by those providers, not by us. ArcGIS GeoEnrichment consumes ArcGIS credits at ESRI's published rates.
Get the SDK and a technical walkthrough
Tell us what you are building and which parts you would want to own. We will scope the integration on the call rather than after it.