> For the complete documentation index, see [llms.txt](https://docs.anthriq.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.anthriq.com/bxi-studio/developer/overview/backend-services/connect.md).

# Connect to the services

`@anthriq_dev/services` connects to the four BXI backend service servers: the executor, the operator and pipeline registries, and recording. `BxiServicesClient` manages all four together; each also has a standalone client.

## Connect

{% tabs %}
{% tab title="Node.js" %}

```typescript
import { BxiServicesClient } from "@anthriq_dev/services";

const services = new BxiServicesClient({
  onLog: (entry) => console.log(`[${entry.service}] ${entry.level}: ${entry.message}`),
});

const statuses = await services.initialize();

for (const status of statuses) {
  console.log(status.name, status.running ? "running" : status.error);
}
```

{% endtab %}

{% tab title="Python" %}

```python
from anthriq_services import BxiServicesClient

services = BxiServicesClient(
    on_log=lambda entry: print(f"[{entry['service']}] {entry['level']}: {entry['message']}")
)

statuses = await services.initialize()

for status in statuses:
    print(status.name, "running" if status.running else status.error)
```

{% endtab %}
{% endtabs %}

A service that is down without `autoSpawn` reports why instead:

`initialize()` health-checks every service, spawns any that are not running when `autoSpawn` is set, connects all sockets, and starts the log subscriber. It throws when a service fails to become reachable, listing each failure.

`connect()` opens the sockets without the health check or spawn step.

| Member                      | Client                   | Reference                                                                                       |
| --------------------------- | ------------------------ | ----------------------------------------------------------------------------------------------- |
| `services.executor`         | `ExecutorClient`         | [Run pipelines](/bxi-studio/developer/overview/backend-services/pipelines.md)                   |
| `services.operatorRegistry` | `OperatorRegistryClient` | [Manage operators and pipelines](/bxi-studio/developer/overview/backend-services/registries.md) |
| `services.pipelineRegistry` | `PipelineRegistryClient` | [Manage operators and pipelines](/bxi-studio/developer/overview/backend-services/registries.md) |
| `services.recording`        | `RecordingClient`        | [Record and play back](/bxi-studio/developer/overview/backend-services/recording.md)            |

## Configure

| Field                      | Type                     | Default                   | Purpose                             |
| -------------------------- | ------------------------ | ------------------------- | ----------------------------------- |
| `executorEndpoint`         | `string`                 | Resolved per backend mode | Executor request socket             |
| `operatorRegistryEndpoint` | `string`                 | Resolved per backend mode | Operator registry socket            |
| `pipelineRegistryEndpoint` | `string`                 | Resolved per backend mode | Pipeline registry socket            |
| `recordingEndpoint`        | `string`                 | Resolved per backend mode | Recording socket                    |
| `logEndpoints`             | `Record<string, string>` | Defaults below            | Log publisher sockets               |
| `timeout`                  | `number`                 | `15000`                   | Request timeout in milliseconds     |
| `onLog`                    | callback                 | None                      | Receive service-level log entries   |
| `debug`                    | `boolean`                | `false`                   | Enable debug logging                |
| `binaries`                 | object                   | None                      | Server binary paths for `autoSpawn` |
| `recordingStoragePath`     | `string`                 | None                      | Passed to the recording server      |
| `autoSpawn`                | `boolean`                | `false`                   | Spawn servers that are not running  |

The 15-second default covers pipeline initialization against real hardware, where device stream setup runs about 12 to 13 seconds end to end. Lower it only for workloads that never create a pipeline.

## Find the endpoints

Endpoints are IPC sockets, derived at construction from the resolved backend installation so a bundled backend and a CLI-installed one do not collide.

| Service           | Request socket                          | Log socket                                   |
| ----------------- | --------------------------------------- | -------------------------------------------- |
| Executor          | `ipc:///tmp/bxi-executor.sock`          | `ipc:///tmp/bxi-executor-logs.sock`          |
| Operator Registry | `ipc:///tmp/bxi-operator-registry.sock` | `ipc:///tmp/bxi-operator-registry-logs.sock` |
| Pipeline Registry | `ipc:///tmp/bxi-pipeline-registry.sock` | `ipc:///tmp/bxi-pipeline-registry-logs.sock` |
| Recording         | `ipc:///tmp/bxi-recording.sock`         | `ipc:///tmp/bxi-recording-logs.sock`         |

On Windows the base is `%TEMP%` with forward slashes, which ZeroMQ IPC requires.

A CLI-installed backend gets a version suffix so several versions can run side by side, such as `ipc:///tmp/bxi-executor-0.1.0.sock`.

| Backend mode                            | Versioned endpoints |
| --------------------------------------- | ------------------- |
| `installed`                             | Yes                 |
| Any mode with `BXI_BACKEND_VERSION` set | Yes                 |
| `bundled`                               | No                  |
| `development`                           | No                  |
| `override`                              | No                  |

{% tabs %}
{% tab title="Node.js" %}

```typescript
import { getServiceEndpoints, getEndpointInfo } from "@anthriq_dev/services";

console.log(getEndpointInfo());
```

{% endtab %}

{% tab title="Python" %}

```python
from anthriq_services import get_service_endpoints, get_endpoint_info

print(get_endpoint_info())
```

{% endtab %}
{% endtabs %}

A CLI-installed backend reports `installed (v0.1.0)` and versioned socket names instead.

> **Warning:** A client and server that disagree on an endpoint fail as a **timeout**, not a connection error, because ZeroMQ queues messages to an absent peer. Print `getEndpointInfo()` first when every request times out.

## Use one service alone

{% tabs %}
{% tab title="Node.js" %}

```typescript
import { ExecutorClient } from "@anthriq_dev/services";

const executor = new ExecutorClient({ endpoint: "ipc:///tmp/bxi-executor.sock" });
await executor.connect();

// ...

await executor.disconnect();
```

{% endtab %}

{% tab title="Python" %}

```python
from anthriq_services import ExecutorClient

executor = ExecutorClient("ipc:///tmp/bxi-executor.sock")
await executor.connect()

# ...

await executor.disconnect()
```

{% endtab %}
{% endtabs %}

All four share the same lifecycle:

| Method         | Description                                               |
| -------------- | --------------------------------------------------------- |
| `initialize()` | Health check, spawn when `autoSpawn` is set, then connect |
| `connect()`    | Open the request socket and start the log subscriber      |
| `disconnect()` | Close sockets, leaving spawned servers running            |
| `shutdown()`   | Disconnect and stop any server this client spawned        |

## Stream service logs

{% tabs %}
{% tab title="Node.js" %}

```typescript
import { BxiServicesClient, type LogEntry } from "@anthriq_dev/services";

const services = new BxiServicesClient({
  onLog: (entry: LogEntry) => {
    console.log(`[${entry.service}/${entry.source}] ${entry.level}: ${entry.message}`);
  },
});
```

{% endtab %}

{% tab title="Python" %}

```python
async with ExecutorClient("ipc:///tmp/bxi-executor.sock") as executor:
    await executor.list_pipelines()
```

{% endtab %}
{% endtabs %}

| Field       | Type                                     | Description                                                          |
| ----------- | ---------------------------------------- | -------------------------------------------------------------------- |
| `type`      | `"log"`                                  | Always `"log"`                                                       |
| `service`   | `string`                                 | `executor`, `operator_registry`, `pipeline_registry`, or `recording` |
| `level`     | `"debug"`, `"info"`, `"warn"`, `"error"` | Severity                                                             |
| `source`    | `string`                                 | Emitting component                                                   |
| `message`   | `string`                                 | Log text                                                             |
| `timestamp` | `number`                                 | Unix milliseconds                                                    |
| `data`      | `Record<string, unknown>`                | Optional structured payload                                          |

These are service-level logs: lifecycle, and pipeline create and destroy. Node output arrives on a per-pipeline socket instead. See [Run pipelines](/bxi-studio/developer/overview/backend-services/pipelines.md).

## Spawn the servers

`ServiceProcessManager` health-checks servers and spawns them detached. `BxiServicesClient` uses it when `autoSpawn` is set; use it directly for finer control.

{% tabs %}
{% tab title="Node.js" %}

```typescript
import { ServiceProcessManager } from "@anthriq_dev/services";

const manager = new ServiceProcessManager({
  autoSpawn: true,
  services: [
    {
      name: "executor",
      binaryPath: "/opt/bxi/bin/executor_server",
      endpoint: "ipc:///tmp/bxi-executor.sock",
      logEndpoint: "ipc:///tmp/bxi-executor-logs.sock",
    },
  ],
});

const statuses = await manager.ensureRunning();
await manager.stopAll();
```

{% endtab %}

{% tab title="Python" %}

```python
from anthriq_services import BxiServicesClient

services = BxiServicesClient(
    on_log=lambda entry: print(
        f"[{entry['service']}/{entry.get('source')}] {entry['level']}: {entry['message']}"
    )
)
```

{% endtab %}
{% endtabs %}

| Field                | Default  | Purpose                              |
| -------------------- | -------- | ------------------------------------ |
| `services`           | Required | Service definitions                  |
| `autoSpawn`          | `false`  | Spawn servers that are not reachable |
| `healthCheckTimeout` | `750`    | Per-probe timeout in milliseconds    |
| `spawnReadyTimeout`  | `20000`  | Budget for spawn to reachable        |

The 20-second readiness budget accommodates cold start on Windows, where on-access virus scanning routinely adds 3 to 8 seconds before a server binds. A server that exits immediately is reported with its stderr rather than waiting out the budget.

`stopAll()` terminates only the processes this manager spawned.

## Manage backend versions

{% tabs %}
{% tab title="Node.js" %}

```bash
bxi-backend list
bxi-backend info 0.1.0
bxi-backend install backend-0.2.0.tar.gz --suffix dev --set-default
bxi-backend default 0.2.0_dev
bxi-backend uninstall 0.1.0
```

{% endtab %}

{% tab title="Python" %}

```python
from anthriq_services import ServiceProcessConfig, ServiceProcessManager

manager = ServiceProcessManager(
    auto_spawn=True,
    services=[
        ServiceProcessConfig(
            name="executor",
            binary_path="/opt/bxi/bin/executor_server",
            endpoint="ipc:///tmp/bxi-executor.sock",
            log_endpoint="ipc:///tmp/bxi-executor-logs.sock",
        ),
    ],
)

statuses = await manager.ensure_running()
await manager.stop_all()
```

{% endtab %}
{% endtabs %}

| Environment variable  | Effect                                   |
| --------------------- | ---------------------------------------- |
| `BXI_BACKEND_VERSION` | Select a version, overriding the default |
| `BXI_BACKEND_PATH`    | Override path resolution                 |

> **Warning:** `bxi-backend clean` clears the registry but leaves installed files on disk. Backends removed that way keep consuming space and are no longer tracked for uninstall.

## Shut down

{% tabs %}
{% tab title="Node.js" %}

```typescript
try {
  // Use the services.
} finally {
  await services.shutdown();
}
```

{% endtab %}

{% tab title="Python" %}

```python
try:
    ...  # Use the services.
finally:
    await services.shutdown()
```

{% endtab %}
{% endtabs %}

`shutdown()` disconnects every client and stops servers this process spawned. Use `disconnect()` to leave a shared backend running for other clients.

## Next steps

* [Run pipelines](/bxi-studio/developer/overview/backend-services/pipelines.md)
* [Manage operators and pipelines](/bxi-studio/developer/overview/backend-services/registries.md)
* [Record and play back](/bxi-studio/developer/overview/backend-services/recording.md)
