# GeoLibre Python Sidecar (FastAPI) Architecture: A Complete Guide to Geoprocessing Tools and Implementation

> Explore the GeoLibre Python sidecar architecture. Learn how FastAPI securely exposes geoprocessing tools like WhiteboxTools, GDAL, GeoPandas, and more via an async API.

- Repository: [Open Geospatial Solutions/GeoLibre](https://github.com/opengeos/GeoLibre)
- Tags: architecture
- Published: 2026-08-03

---

**The GeoLibre Python sidecar is an optional FastAPI server running on `127.0.0.1:8765` that hosts heavyweight geoprocessing libraries—WhiteboxTools, GDAL/Rasterio, GeoPandas, Apache Sedona, and SamGeo—behind a secure, token-gated API with asynchronous job queuing.**

The **GeoLibre Python sidecar** bridges the gap between browser-based GIS workflows and computationally demanding geoprocessing tasks. According to the `opengeos/GeoLibre` source code, this FastAPI application runs locally as a trusted companion to the desktop client, executing operations that cannot safely run inside the Tauri sandbox or browser environment. This guide examines its architecture, security model, router organization, managed runtime system, and the complete set of geoprocessing tools it exposes.

## FastAPI Application Structure and Entry Point

The sidecar's foundation lives in **[`geolibre_server/app/main.py`](https://github.com/opengeos/GeoLibre/blob/main/geolibre_server/app/main.py)**, where the FastAPI instance is created and configured with modular routers for each tool category.

```python

# backend/geolibre_server/geolibre_server/app/main.py

app = FastAPI(title="GeoLibre Server", version="0.8.0")
app.include_router(whitebox_router)
app.include_router(conversion_router)
app.include_router(raster_router)
app.include_router(vector_router)
app.include_router(postgis_router)
app.include_router(sql_router)
app.include_router(ml_router)

```

This router-based organization keeps each geoprocessing domain isolated and testable. The application follows standard FastAPI patterns: **Pydantic** models for request validation, dependency injection for shared services, and explicit path prefixes for API versioning.

## Security Architecture and Request Gating

The GeoLibre sidecar implements defense-in-depth for a local service that handles file system paths and subprocess execution.

| Security Layer | Implementation | Source Location |
| -------------- | -------------- | --------------- |
| **Per-launch token authentication** | Desktop shell generates `GEOLIBRE_SIDECAR_TOKEN`; middleware validates `X-GeoLibre-Token` or `Authorization: Bearer` headers; exempted only when unset for local testing | [`main.py`](https://github.com/opengeos/GeoLibre/blob/main/main.py) lines 37–84 |
| **Trusted host validation** | `TrustedHostMiddleware` restricts to loopback addresses (`localhost`, `127.0.0.1`, `testserver`) | [`main.py`](https://github.com/opengeos/GeoLibre/blob/main/main.py) lines 87–97 |
| **CORS policy** | Limited to Vite dev server (`:5173`) and Tauri webview origins; credentials disallowed | [`main.py`](https://github.com/opengeos/GeoLibre/blob/main/main.py) lines 98–110 |
| **Health endpoint exemption** | `/health` skips token checks for readiness probes via `_TOKEN_EXEMPT_PATHS` | [`main.py`](https://github.com/opengeos/GeoLibre/blob/main/main.py) line 53 |

The token middleware aggressively rejects requests from unexpected origins, mitigating DNS rebinding attacks against local services. As implemented in `opengeos/GeoLibre`, the environment variable escape hatch (`GEOLIBRE_SIDECAR_TOKEN` unset) exists solely for `pytest` automation, not production deployments.

## Router Modules and Geoprocessing Tool Groups

Each router encapsulates a specific geoprocessing domain. The GeoLibre sidecar provides seven primary tool groups:

### WhiteboxRouter (`/whitebox`)

**WhiteboxTools** integration via **[`geolibre_server/app/whitebox.py`](https://github.com/opengeos/GeoLibre/blob/main/geolibre_server/app/whitebox.py)**. This router wraps the WhiteboxTools CLI, automatically bootstrapping a managed virtual environment on first use. Heavy geomorphometric and hydrologic analyses execute in isolated subprocesses with streaming output capture.

### ConversionRouter (`/conversion`)

The most complex router, implemented in **[`geolibre_server/app/conversion.py`](https://github.com/opengeos/GeoLibre/blob/main/geolibre_server/app/conversion.py)**, handles format conversion across the geospatial stack:

- Vector → **GeoParquet** (Hilbert-sorted for spatial performance)
- Vector → **FlatGeobuf**
- Vector → **PMTiles** (via **freestiler**)
- CSV (lon/lat) → **GeoParquet**
- Raster → **Cloud-Optimized GeoTIFF**

This router implements **uv-managed runtime bootstrapping**, job queuing, and persistent result storage.

### RasterRouter (`/raster`)

Lightweight wrapper in **[`geolibre_server/app/raster.py`](https://github.com/opengeos/GeoLibre/blob/main/geolibre_server/app/raster.py)** for **rio-cogeo** Cloud-Optimized GeoTIFF generation. Delegates to the conversion runtime for actual execution.

### VectorRouter (`/vector`)

Placeholder utilities in **[`geolibre_server/app/vector.py`](https://github.com/opengeos/GeoLibre/blob/main/geolibre_server/app/vector.py)**: bounding box extraction, buffer operations, and reprojection. Future iterations will integrate full GDAL/GeoPandas workflows.

### PostGISRouter (`/postgis`)

Remote **PostGIS** connection management with strict host whitelisting via `GEOLIBRE_POSTGIS_HOSTS`. See **[`geolibre_server/app/postgis.py`](https://github.com/opengeos/GeoLibre/blob/main/geolibre_server/app/postgis.py)** for connection registration and status monitoring.

### SQLRouter (`/sql`) — Apache Sedona Integration

**Apache Sedona** spatial SQL via the Rust SedonaDB engine. The **[`geolibre_server/app/sql.py`](https://github.com/opengeos/GeoLibre/blob/main/geolibre_server/app/sql.py)** router exposes:

- `GET /sql/status` — Engine availability probe
- `POST /sql/run` — Execute spatial SQL over registered layers

### MLRouter (`/ml`) — SamGeo Proxy

Reverse-proxy design in **[`geolibre_server/app/ml.py`](https://github.com/opengeos/GeoLibre/blob/main/geolibre_server/app/ml.py)**. The sidecar **never loads PyTorch**; instead, it forwards requests to an external **SamGeo** server running the Segment Anything Model 3. This architecture keeps the sidecar lightweight while enabling AI-powered segmentation.

## Managed Runtime System with uv

The conversion and raster tools require heavy native dependencies (**DuckDB**, **rio-cogeo**, **freestiler**) that cannot bloat the base sidecar installation. The GeoLibre sidecar solves this with an **on-demand virtual environment** managed by **uv**.

### Bootstrap Flow

1. **Interpreter resolution** — `GEOLIBRE_CONVERSION_PYTHON` environment variable takes precedence; otherwise `_ensure_managed_runtime()` creates a venv under `~/.cache/geolibre/conversion-runtime`

2. **Package installation** — `_run_runtime_setup_command` installs locked dependency versions

3. **Verification and caching** — `_check_runtime_import` validates imports; path cached in `_CHECKED_RUNTIME_PYTHON`

All runtime management functions reside in **[`conversion.py`](https://github.com/opengeos/GeoLibre/blob/main/conversion.py)** lines 461–735: `_runtime_python`, `_ensure_managed_runtime`, and `_check_runtime_import`.

This design ensures native wheels download once, remain isolated from the sidecar process, and can be rebuilt independently when dependency versions change.

## Asynchronous Job Queue Architecture

Conversion and raster operations are **long-running and CPU-bound**. The GeoLibre sidecar implements a lightweight async job system without external message queues.

### Job Lifecycle

```python

# Simplified flow from conversion.py

def submit_conversion(request: ConversionRequest) -> JobState:
    job_id = str(uuid.uuid4())
    state = JobState(id=job_id, status="pending", ...)
    _JOBS[job_id] = state
    
    threading.Thread(
        target=_run_conversion_job,
        args=(job_id, request),
        daemon=True
    ).start()
    return state

```

The background thread:

1. Spawns the managed runtime subprocess
2. Streams stdout for progress messages
3. Parses `__GEOLIBRE_CONVERSION_RESULT__` or `__GEOLIBRE_CONVERSION_ERROR__` markers
4. Updates `_JOBS[job_id]` with status, messages, and final result

Memory is bounded via `MAX_RETAINED_JOBS = 100`; completed jobs evict oldest entries first.

### Polling-Based Client Interaction

Clients poll `/conversion/jobs/{job_id}` for state transitions:

```bash
curl http://127.0.0.1:8765/conversion/jobs/$JOB_ID \
  -H "X-GeoLibre-Token: $GEOLIBRE_SIDECAR_TOKEN"

```

Response schema includes `status` (`pending|running|succeeded|failed`), `messages` (progress log), and `result` (final output metadata on completion).

## Optional Dependencies and Extras Installation

The sidecar's **[`pyproject.toml`](https://github.com/opengeos/GeoLibre/blob/main/pyproject.toml)** defines modular extras for selective capability enablement:

```toml
[project.optional-dependencies]
conversion = ["duckdb>=1.1.0", "rio-cogeo>=5.0.0", "freestiler>=0.1.0", ...]
vector = ["geopandas", "shapely"]
raster = ["rasterio"]
sedona = ["apache-sedona[db]"]
ml = ["samgeo-api"]  # client-only; model server external

whitebox = ["whitebox-workflows"]

```

Install patterns:

```bash

# Core sidecar only

pip install -e .

# With conversion tools

pip install -e ".[conversion]"

# Full geoprocessing stack

pip install -e ".[conversion,vector,raster,sedona,whitebox]"

```

Router endpoints dynamically respond to availability; the UI queries `/conversion/status`, `/sql/status`, and `/ml/status` to enable or disable features.

## Complete Endpoint Reference

| Method | Path | Description | Router |
| ------ | ---- | ----------- | ------ |
| `GET` | `/health` | Service readiness | Core |
| `GET` | `/algorithms` | Placeholder algorithm registry | Core |
| `POST` | `/shutdown` | Graceful termination | Core |
| `GET` | `/conversion/status` | Runtime availability | Conversion |
| `POST` | `/conversion/vector-to-geoparquet` | Shapefile/GeoJSON → GeoParquet | Conversion |
| `POST` | `/conversion/vector-to-flatgeobuf` | ZIP shapefile → FlatGeobuf | Conversion |
| `POST` | `/conversion/csv-to-geoparquet` | CSV with lon/lat → GeoParquet | Conversion |
| `POST` | `/conversion/vector-to-pmtiles` | Vector → PMTiles via freestiler | Conversion |
| `POST` | `/conversion/raster-to-cog` | GeoTIFF → Cloud-Optimized GeoTIFF | Conversion |
| `GET/POST` | `/conversion/jobs/{id}` | Job status polling and control | Conversion |
| `GET` | `/whitebox/status` | WhiteboxTools runtime check | Whitebox |
| `POST` | `/whitebox/run` | Execute WhiteboxTools command | Whitebox |
| `GET` | `/raster/status` | rio-cogeo availability | Raster |
| `POST` | `/raster/to-cog` | Raster COG conversion | Raster |
| `GET` | `/postgis/status` | Connection pool health | PostGIS |
| `POST` | `/postgis/connect` | Register whitelisted PostGIS server | PostGIS |
| `GET` | `/sql/status` | SedonaDB engine availability | SQL |
| `POST` | `/sql/run` | Execute spatial SQL | SQL |
| `GET` | `/ml/status` | SamGeo proxy reachability | ML |
| `POST` | `/ml/segment/*` | SAM 3 segmentation endpoints | ML |

## Typical Usage Flow

1. **Desktop launcher** spawns `geolibre-server` with `GEOLIBRE_SIDECAR_TOKEN` set; binds to `127.0.0.1:8765`

2. **Health probe** — UI polls `/health` until `{"status":"ok"}`

3. **Capability detection** — Parallel queries to `/*/status` endpoints determine enabled features

4. **Job submission** — POST to conversion endpoint returns `job_id` immediately; work continues in background thread

5. **Progress monitoring** — Client polls `/conversion/jobs/{id}` at interval, updating UI with `messages` array

6. **Result retrieval** — On `status: succeeded`, client reads `result.output_path` for generated file location

7. **Cleanup** — Desktop app calls `POST /shutdown` on exit; sidecar terminates cleanly

## Summary

- The **GeoLibre Python sidecar** is a FastAPI application providing secure, local access to heavyweight geoprocessing libraries that cannot run in browser or Tauri contexts

- **Security layers** include per-launch token authentication, trusted host validation, and restricted CORS—implemented in [`main.py`](https://github.com/opengeos/GeoLibre/blob/main/main.py) lines 37–110

- **Seven router modules** organize tools by domain: WhiteboxTools, conversion, raster, vector, PostGIS, Apache Sedona SQL, and SamGeo ML proxy

- **uv-managed runtimes** isolate heavy dependencies (DuckDB, rio-cogeo, freestiler) in cached virtual environments, bootstrapped on demand via [`conversion.py`](https://github.com/opengeos/GeoLibre/blob/main/conversion.py)

- **Asynchronous job execution** uses in-memory state with background threads, bounded retention, and polling-based client interaction

- **Optional extras** in [`pyproject.toml`](https://github.com/opengeos/GeoLibre/blob/main/pyproject.toml) enable selective installation; routers degrade gracefully when dependencies are absent

## Frequently Asked Questions

### What is the default port for the GeoLibre Python sidecar?

The sidecar binds to `127.0.0.1:8765` by default. This loopback-only binding, combined with `TrustedHostMiddleware`, prevents external network access. The port is not currently configurable without source modification.

### Why does the sidecar use a reverse proxy for SamGeo instead of loading PyTorch directly?

The ML router in [`geolibre_server/app/ml.py`](https://github.com/opengeos/GeoLibre/blob/main/geolibre_server/app/ml.py) forwards requests to an external SamGeo server to keep the sidecar memory footprint small and startup time fast. Loading PyTorch and the SAM 3 model would add gigabytes to the runtime and complicate cross-platform distribution. This architecture lets the SamGeo server run on GPU hardware while the sidecar remains CPU-only.

### How does the conversion job queue handle failures and retries?

Failed jobs capture `__GEOLIBRE_CONVERSION_ERROR__` markers from subprocess stderr, storing the error message in `JobState.messages`. The sidecar does not implement automatic retry; clients receive `status: failed` and must resubmit. Successful and failed jobs persist in `_JOBS` until `MAX_RETAINED_JOBS` eviction, allowing post-hoc debugging.

### Can I run the sidecar without the GeoLibre desktop application?

Yes. Set `GEOLIBRE_SIDECAR_TOKEN` to any value for development mode where token checks are skipped, or provide a consistent token via environment variable for scripted access. The README in [`backend/geolibre_server/README.md`](https://github.com/opengeos/GeoLibre/blob/main/backend/geolibre_server/README.md) documents manual startup with `python -m geolibre_server.app.main` or `uvicorn`.