# How to Write Custom Whitebox Geoprocessing Tools for the GeoLibre Python Sidecar

> Learn to write custom Whitebox geoprocessing tools for the GeoLibre Python sidecar. Extend GeoLibre's toolbox using the whitebox-workflows API and register custom tools easily.

- Repository: [Open Geospatial Solutions/GeoLibre](https://github.com/opengeos/GeoLibre)
- Tags: how-to-guide
- Published: 2026-08-02

---

**You can extend GeoLibre's Whitebox toolbox by writing Python functions that use the `whitebox-workflows` API, registering them as FastAPI endpoints in the sidecar, and adding metadata to the Whitebox catalog JSON.**

GeoLibre ships with a WebAssembly (Wasm) implementation of the Whitebox geoprocessing toolbox for browser-based analysis, but heavy processing tasks require the full-featured **Python sidecar**. This FastAPI service, located in `backend/geolibre_server`, can execute custom Whitebox tools that you author yourself. Learning how to write custom Whitebox geoprocessing tools for the Python sidecar lets you add bespoke raster processing logic while maintaining full integration with the GeoLibre user interface.

## Prerequisites

Before creating custom tools, ensure your development environment includes the **Python sidecar** and its dependencies.

- **Python sidecar**: Set up the FastAPI server from `backend/geolibre_server`. Install dependencies with `pip install -e .` after creating a virtual environment.
- **Whitebox-Workflows**: The sidecar automatically installs this package on first run, providing the `Whitebox` Python class and CLI bindings.
- **FastAPI knowledge**: Familiarity with APIRouter and Pydantic models is helpful, as the sidecar uses these for the existing `/whitebox/run` and `/whitebox/status` endpoints.

## Write the Custom Whitebox Tool

A custom tool is a Python function that accepts a `WhiteboxJob` payload and returns a `WhiteboxStatus` dictionary. The function should validate inputs, execute the processing logic via the `whitebox-workflows` API, and package the results for the UI.

Create a new module at [`backend/geolibre_server/geolibre_server/custom_whitebox.py`](https://github.com/opengeos/GeoLibre/blob/main/backend/geolibre_server/geolibre_server/custom_whitebox.py):

```python
from fastapi import HTTPException
from whitebox_workflows import Whitebox
from geolibre_server.types import WhiteboxJob, WhiteboxStatus

def run_my_custom_tool(job: WhiteboxJob) -> WhiteboxStatus:
    """
    Example custom Whitebox tool implementation.
    
    Parameters
    ----------
    job : WhiteboxJob
        Contains input raster path (`job.input`), output path (`job.output`),
        and UI parameters (`job.params`).
        
    Returns
    -------
    WhiteboxStatus
        Dictionary with keys `output`, `log`, and `duration`.
    """
    if not job.input:
        raise HTTPException(status_code=400, detail="Missing input raster")
    
    factor = float(job.params.get("factor", 1.0))
    
    try:
        result = Whitebox.run(
            tool="my_custom_tool",
            input_raster=job.input,
            output_raster=job.output,
            factor=factor,
        )
    except Exception as exc:
        raise HTTPException(status_code=500, detail=str(exc))
    
    return {
        "output": job.output,
        "log": result.stdout,
        "duration": result.elapsed,
    }

```

The **tool name** (`my_custom_tool` in the example above) must match the entry you will add to the Whitebox catalog. The function receives the same `WhiteboxJob` model that the UI sends when users click **Run**, and it must return a dictionary conforming to the `WhiteboxStatus` schema.

## Register the Endpoint in the FastAPI Router

Expose your function through the sidecar's existing Whitebox router in [`geolibre_server/app/whitebox.py`](https://github.com/opengeos/GeoLibre/blob/main/geolibre_server/app/whitebox.py). Add a dedicated route that forwards requests to your custom implementation:

```python
from fastapi import APIRouter, Depends
from .custom_whitebox import run_my_custom_tool
from ..types import WhiteboxJob

router = APIRouter()

@router.post("/run/my_custom_tool")
async def run_my_custom_tool_endpoint(job: WhiteboxJob = Depends()):
    """Execute the custom Whitebox tool via the Python sidecar."""
    return run_my_custom_tool(job)

```

Using a dedicated path like `/run/my_custom_tool` keeps the sidecar's OpenAPI documentation tidy and simplifies routing logic compared to the generic `/run` endpoint that accepts a `tool_id` parameter.

## Add the Tool to the Whitebox Catalog

The GeoLibre UI populates the toolbox from a JSON catalog snapshot. To make your tool visible, add its metadata to [`backend/geolibre_server/geolibre_server/whitebox_catalog.json`](https://github.com/opengeos/GeoLibre/blob/main/backend/geolibre_server/geolibre_server/whitebox_catalog.json):

```json
[
  {
    "id": "my_custom_tool",
    "name": "My Custom Tool",
    "category": "Custom",
    "description": "User-defined raster processor with scale factor.",
    "parameters": [
      {
        "name": "factor",
        "type": "float",
        "default": 1.0,
        "description": "Scale factor for raster values."
      }
    ]
  }
]

```

After updating the JSON file, regenerate the TypeScript menu catalog used by the UI:

```bash
node scripts/gen-whitebox-menu-catalog.mjs

```

This script outputs to [`apps/geolibre-desktop/src/lib/whitebox-menu-catalog.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/lib/whitebox-menu-catalog.ts), which the UI imports to build the toolbox menu. According to the source code in [`packages/processing/src/wasm-client.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/wasm-client.ts) (lines 172-180), the sidecar merges this catalog with Wasm-only tools at runtime.

## Test the Custom Tool

Start the sidecar to validate your implementation:

```bash
cd backend/geolibre_server
uvicorn geolibre_server.app.main:app --reload

```

Send a test request using `curl` or any HTTP client:

```bash
curl -X POST http://127.0.0.1:8765/whitebox/run/my_custom_tool \
     -H "Content-Type: application/json" \
     -d '{"input":"/data/input.tif","output":"/tmp/out.tif","params":{"factor":2.5}}'

```

Expect a JSON response containing `output`, `log`, and `duration` fields. Open GeoLibre Desktop, navigate to *Processing → Whitebox*, and verify that **My Custom Tool** appears under the **Custom** category. Running it on a raster should display results on the map and populate the processing dialog with logs.

## Advanced Configuration

Consider these enhancements when deploying custom tools to production:

- **Parameter validation**: Use Pydantic models for complex parameter structures, leveraging the sidecar's existing type system.
- **Multiple outputs**: Return a list of raster paths in the `output` field; the UI will add each as a separate layer.
- **Streaming logs**: The sidecar supports Server-Sent Events for real-time log streaming. See `fetchWhiteboxJob` in [`packages/processing/src/sidecar-client.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/sidecar-client.ts) for implementation details.
- **Unit testing**: Mock `Whitebox.run` in [`backend/geolibre_server/tests/test_custom_whitebox.py`](https://github.com/opengeos/GeoLibre/blob/main/backend/geolibre_server/tests/test_custom_whitebox.py) to test logic without heavy raster I/O.

## Summary

Writing custom Whitebox geoprocessing tools for the GeoLibre Python sidecar involves four key steps:

- **Implement** the processing logic in a Python module using the `whitebox-workflows` API and `WhiteboxJob` types.
- **Register** a FastAPI endpoint in the sidecar router to expose the function via HTTP POST.
- **Catalog** the tool by adding metadata to the JSON manifest and regenerating the TypeScript menu file.
- **Test** the endpoint locally before committing changes to the repository.

This workflow allows you to extend the Whitebox toolbox with domain-specific raster operations while maintaining seamless integration with the GeoLibre user interface.

## Frequently Asked Questions

### What is the Python sidecar in GeoLibre?

The **Python sidecar** is a FastAPI service located in `backend/geolibre_server` that provides heavy-duty geoprocessing capabilities beyond what the browser-based WebAssembly implementation can handle. It runs the `whitebox-workflows` package and other Python dependencies, exposing them through REST endpoints that the GeoLibre desktop and web applications consume.

### Do custom tools work in the browser?

Custom tools written for the Python sidecar require the sidecar to be running, as they execute Python code and potentially call underlying C++ binaries. They do not run in the browser's Wasm sandbox. However, the GeoLibre UI treats them identically to built-in tools once they are registered in the catalog, providing a seamless experience for end users.

### How do I validate parameters for my custom tool?

Validate parameters using Pydantic models or manual checks at the start of your function. The `WhiteboxJob` model passed from the UI includes a `params` dictionary containing user inputs. Raise `HTTPException` with appropriate status codes (such as 400 for bad input or 500 for processing errors) to communicate failures to the client, which will display them in the processing dialog.

### Can I stream logs while the tool runs?

Yes. While the basic implementation returns logs after completion, the sidecar supports streaming Whitebox `stdout` line-by-line via Server-Sent Events. Implement this by modifying the client-side code in [`packages/processing/src/sidecar-client.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/sidecar-client.ts) to handle streaming responses from your endpoint, allowing users to see progress updates in real time.