# CLI-Anything Software-Specific Backends: Blender, OBS-WebSocket, Python, and QGIS

> Control Blender, OBS-WebSocket, Python, and QGIS with CLI-Anything. Translate uniform CLI commands into native API calls for your favorite software.

- Repository: [✨Data Intelligence Lab@HKU✨/CLI-Anything](https://github.com/HKUDS/CLI-Anything)
- Tags: deep-dive
- Published: 2026-05-18

---

**CLI-Anything supports four software-specific backends—Blender (bpy), OBS-WebSocket (obs-websocket), generic Python (py), and QGIS—that translate uniform CLI commands into native API calls for each target application.**

CLI-Anything, developed by HKUDS, is an open-source framework that exposes complex desktop and server applications through a standardized command-line interface. The project achieves this abstraction through **software-specific backends**, which are Python modules that handle process spawning, IPC channel management, and API translation. Each backend implements a consistent protocol in the HKUDS/CLI-Anything repository, allowing AI agents and users to interact with diverse software without learning individual native APIs.

## Overview of Supported Software-Specific Backends

CLI-Anything currently ships with four dedicated backends, each targeting a specific software ecosystem. The following table summarizes how each backend connects to its target application and where the implementation resides in the source tree.

| Backend | Target Application | Implementation File | Selection Method |
|---------|-------------------|---------------------|------------------|
| **Blender (bpy)** | Blender's embedded Python interpreter | [`cli_anything/blender/utils/blender_backend.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/blender/utils/blender_backend.py) | `--backend bpy` or auto-detection |
| **OBS-WebSocket** | OBS Studio via obs-websocket plugin (v5) | [`cli_anything/obs_studio/utils/obs_backend.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/obs_studio/utils/obs_backend.py) | `--backend obs-websocket` |
| **Python (py)** | Arbitrary Python scripts and libraries | [`cli_anything/python/utils/python_backend.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/python/utils/python_backend.py) | `--backend py` (default) |
| **QGIS** | QGIS Python API (qgis.core, qgis.gui) | [`cli_anything/qgis/utils/qgis_backend.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/qgis/utils/qgis_backend.py) | `--backend qgis` |

Each backend module is responsible for locating its target software, establishing the necessary communication channel (whether it is Blender's `bpy` module, a WebSocket connection, or a headless QGIS process), and mapping generic CLI verbs to native API operations.

## How Backend Selection Works

Backend discovery and selection are centralized in [`cli_anything/common/runtime.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/common/runtime.py) through the `RuntimeContext` class. When you invoke a CLI-Anything command, the system follows this resolution flow:

1. **Explicit selection**: The `--backend` flag accepts `auto`, `bpy`, `obs-websocket`, `py`, or `qgis`
2. **Auto-detection**: If set to `auto`, `RuntimeContext.detect_backend()` iterates through known backends and calls each module's `is_available()` method
3. **First match wins**: The first backend returning `True` (indicating the target software is installed and reachable) becomes the active backend

The entry point in `cli_anything/<software>/<software>_cli.py` (e.g., [`blender_cli.py`](https://github.com/HKUDS/CLI-Anything/blob/main/blender_cli.py)) exposes this flag:

```python
@click.command()
@click.option(
    "--backend",
    type=click.Choice(["auto", "bpy", "obs-websocket", "py", "qgis"]),
    default="auto",
)
def cli(backend, ...):
    if backend == "auto":
        backend = RuntimeContext.detect_backend()
    ctx = RuntimeContext(backend=backend, ...)

```

Every backend implements a uniform protocol consisting of `is_available()`, `run_command()`, and `cleanup()` methods, allowing the generic harness to treat them interchangeably.

## Blender (bpy) Backend

The Blender backend provides direct access to Blender's scene graph, objects, materials, and rendering capabilities through the embedded `bpy` Python module. When selected, [`cli_anything/blender/utils/blender_backend.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/blender/utils/blender_backend.py) launches a headless Blender process and exposes operations like `render`, `object list`, and `material create`.

**Key implementation details:**
- **Discovery**: Checks for Blender installation in standard system paths
- **IPC**: Direct Python module import within the Blender interpreter
- **File**: [`cli_anything/blender/utils/blender_backend.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/blender/utils/blender_backend.py)

**Usage example:**

```bash

# Render a scene using the bpy backend

cli-anything ./blender --backend bpy render --output scene.png

```

*What happens*: The backend starts a headless Blender interpreter and executes `bpy.ops.render.render(write_still=True, filepath="scene.png")`.

## OBS-WebSocket Backend

The OBS-WebSocket backend controls OBS Studio remotely via the `obs-websocket` plugin (WebSocket v5 protocol). Implemented in [`cli_anything/obs_studio/utils/obs_backend.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/obs_studio/utils/obs_backend.py), this backend manages scene switching, source manipulation, and streaming state by sending JSON requests to `ws://localhost:4455`.

**Key implementation details:**
- **Discovery**: Probes `ws://localhost:4455` to verify the obs-websocket plugin is listening
- **IPC**: WebSocket connection over port 4455
- **File**: [`cli_anything/obs_studio/utils/obs_backend.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/obs_studio/utils/obs_backend.py)

**Usage example:**

```bash

# Switch to the "Gameplay" scene

cli-anything ./obs-studio --backend obs-websocket scene switch --name Gameplay

```

*What happens*: The backend opens a WebSocket connection and sends the JSON request `{ "request-type": "SetCurrentScene", "scene-name": "Gameplay" }`.

## Python (py) Backend

The Python backend serves as the generic fallback when no dedicated backend exists for a target application. Located in [`cli_anything/python/utils/python_backend.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/python/utils/python_backend.py), this backend loads user-provided Python modules and introspects public functions, generating thin wrapper commands that forward CLI arguments to Python function calls.

**Key implementation details:**
- **Discovery**: Always available (requires Python only)
- **IPC**: Direct function invocation within the same process
- **File**: [`cli_anything/python/utils/python_backend.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/python/utils/python_backend.py)

**Usage example:**

```bash

# Execute a function from a custom module

cli-anything ./my-tool --backend py --module ./my_tool.py add --a 5 --b 7

```

*What happens*: The backend imports [`my_tool.py`](https://github.com/HKUDS/CLI-Anything/blob/main/my_tool.py), discovers the `add` function, and invokes `add(a=5, b=7)`.

## QGIS Backend

The QGIS backend enables scripting of geographic information systems through the QGIS Python API (`qgis.core` and `qgis.gui`). Implemented in [`cli_anything/qgis/utils/qgis_backend.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/qgis/utils/qgis_backend.py), it searches for QGIS installations via the `QGIS_PREFIX_PATH` environment variable or standard install locations, then spawns a headless QGIS process to handle layer management, processing algorithms, and map exports.

**Key implementation details:**
- **Discovery**: Checks `QGIS_PREFIX_PATH` environment variable or standard installation directories
- **IPC**: Headless QGIS process with Python API access
- **File**: [`cli_anything/qgis/utils/qgis_backend.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/qgis/utils/qgis_backend.py)

**Usage example:**

```bash

# Export the current project to PDF

cli-anything ./qgis --backend qgis project export --format pdf --output map.pdf

```

*What happens*: The backend spawns a headless QGIS instance, loads the active project, and executes `QgsProject.instance().write()` with the appropriate PDF driver.

## Backend Architecture and Protocol

All software-specific backends in CLI-Anything conform to a lightweight protocol defined in the runtime system. This standardization ensures that the CLI harness in [`cli_anything/common/runtime.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/common/runtime.py) can initialize and invoke any backend without software-specific logic.

**The three required methods:**

1. **`is_available()`**: Returns `True` if the target software is installed and ready for communication
2. **`run_command(command, **kwargs)`**: Executes the native API call and returns standardized results
3. **`cleanup()`**: Releases resources, closes sockets, and terminates spawned processes

This architecture allows CLI-Anything to treat Blender's `bpy` module, OBS Studio's WebSocket API, and QGIS's processing algorithms as interchangeable command targets, abstracting implementation differences behind a uniform command-line surface.

## Summary

- CLI-Anything provides **software-specific backends** for Blender, OBS-WebSocket, Python, and QGIS, located in `cli_anything/<software>/utils/<software>_backend.py`.
- Backend selection uses the `--backend` flag or `RuntimeContext.detect_backend()` auto-detection logic in [`cli_anything/common/runtime.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/common/runtime.py).
- Each backend implements `is_available()`, `run_command()`, and `cleanup()` to provide uniform interaction with native APIs.
- **Blender (bpy)** offers direct scene manipulation via the embedded Python interpreter.
- **OBS-WebSocket** controls streaming software via WebSocket v5 protocol on port 4455.
- **Python (py)** serves as the generic backend for arbitrary Python modules and functions.
- **QGIS** enables geospatial scripting through headless QGIS processes with full access to `qgis.core`.

## Frequently Asked Questions

### How does CLI-Anything automatically detect which backend to use?

When you run a command without specifying `--backend`, CLI-Anything invokes `RuntimeContext.detect_backend()` from [`cli_anything/common/runtime.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/common/runtime.py). This method iterates through the list of known backends (bpy, obs-websocket, py, qgis), imports each module, and calls its `is_available()` method. The first backend returning `True` is selected automatically, making the tool work out-of-the-box when target software is installed.

### Can I use the Python backend to wrap any arbitrary Python library?

Yes. The Python backend ([`cli_anything/python/utils/python_backend.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/python/utils/python_backend.py)) is designed as a generic fallback. Use `--module <path>` to specify your Python file, and CLI-Anything introspects all public functions, creating CLI commands that map directly to function signatures. This allows you to expose any Python API—whether standard library, third-party package, or custom code—through a uniform command-line interface without writing a dedicated backend.

### What is required for the OBS-WebSocket backend to function?

The OBS-WebSocket backend requires OBS Studio with the obs-websocket plugin (version 5) installed and enabled. The backend attempts to connect to `ws://localhost:4455` to verify availability. If OBS Studio is running and the WebSocket server is active on that port, the backend can switch scenes, control sources, and manage streaming state remotely.

### How does the QGIS backend locate the QGIS installation?

The QGIS backend ([`cli_anything/qgis/utils/qgis_backend.py`](https://github.com/HKUDS/CLI-Anything/blob/main/cli_anything/qgis/utils/qgis_backend.py)) checks the `QGIS_PREFIX_PATH` environment variable first. If not set, it probes standard installation locations for QGIS binaries and Python libraries. Once located, it launches a headless QGIS process that imports `qgis.core` and `qgis.gui`, enabling CLI commands to manipulate layers, run processing algorithms, and export maps without opening the QGIS GUI.