Skip to main content

Qbrix

Python SDK for the qbrix platform.

License Coverage Python 3.10+ Pydantic v2 Transports


Typed sync and async clients for Qbrix — pool/experiment/gate management and the agent select/feedback loop.

Installation

The SDK speaks to the qbrix proxy over either HTTP/JSON or gRPC — pick a transport (or install both):

pip install qbrix[http]   # HTTP/JSON transport (httpx)
pip install qbrix[grpc]   # gRPC transport (grpcio)
pip install qbrix[all]    # both

pip install qbrix with no extra installs only the models and config layer — constructing a client then raises a clear ImportError naming the extra to add.

Quick Start

Set your credentials as environment variables and call resources directly — no client instantiation needed:

export QBRIX_API_KEY="optiq_xxx"
export QBRIX_BASE_URL="http://localhost:8000"
import qbrix

# 1. Create a pool of arms (variants)
pool = qbrix.pool.create(
    name="homepage-buttons",
    arms=[{"name": "blue"}, {"name": "green"}, {"name": "red"}],
)

# 2. Create an experiment with a bandit policy
exp = qbrix.experiment.create(
    name="button-color-test",
    pool_id=pool.id,
    policy="BetaTSPolicy",
)

# 3. Select an arm for a user
result = qbrix.agent.select(
    experiment_id=exp.id,
    context={"id": "user-123", "metadata": {"country": "US"}},
)
print(result.arm.name)       # "green"
print(result.is_default)     # False (bandit selected)

# 4. Send feedback (reward) after observing the outcome
qbrix.agent.feedback(request_id=result.request_id, reward=1.0)

The system learns from every reward and adjusts future selections automatically.

Self-hosted qbrix

qbrix is open source. Run it with the self-hosting guide: bin/selfhost-init and docker compose up -d from the repository, or the Helm chart. Then register in the console and create an API key under Settings → API keys.

QBRIX_BASE_URL is the address of your install, not of the API path: the SDK adds /api/... itself.

Install QBRIX_BASE_URL
Docker Compose quickstart http://localhost:8000 (or your CONSOLE_URL once it's on a real host)
Helm chart your ingress origin, e.g. https://qbrix.example.com
Managed hosting https://cloud.qbrix.io

The compose gateway and the chart's default ingress serve HTTP only, so use qbrix[http]. gRPC needs a direct route to the proxy's gRPC port (50050), for example from a service in the same cluster.

Transports

The same Qbrix client, resources, and Pydantic models work over either wire format — only the transport differs:

from qbrix import Qbrix

# HTTP — your install's gateway or ingress
client = Qbrix(transport="http", base_url="http://localhost:8000")

# gRPC — a directly-reachable proxy (local dev shown; or an in-cluster address)
client = Qbrix(transport="grpc", base_url="grpc://localhost:50050")

When transport is omitted it's resolved in this order: the transport= kwarg → the QBRIX_TRANSPORT env var → the base_url scheme (grpc:// / grpcs:// → gRPC) → HTTP.

gRPC needs a directly-reachable proxy gRPC endpoint. The hosted cloud at cloud.qbrix.io is served over HTTPS behind a CDN and does not expose gRPC — use transport="http" for it. Reach for gRPC against a local proxy (grpc://localhost:50050) or a service deployed alongside the proxy.

The gRPC transport covers pool, experiment, gate, agent, and policy operations. The runtime resource is HTTP-only (the proxy doesn't expose it over gRPC) — calling it on a gRPC client raises NotImplementedError. Install qbrix[all] and use transport="http" if you need it.

Explicit Client

For full control over configuration or lifecycle (e.g. closing the transport connection, using a context manager), instantiate the client directly:

from qbrix import Qbrix

with Qbrix(api_key="optiq_xxx", base_url="http://localhost:8000") as client:
    pool = client.pool.create(
        name="homepage-buttons",
        arms=[{"name": "blue"}, {"name": "green"}, {"name": "red"}],
    )
    result = client.agent.select(experiment_id="exp-uuid", context={"id": "user-123"})
    client.agent.feedback(request_id=result.request_id, reward=1.0)

Async

from qbrix import AsyncQbrix

async with AsyncQbrix(api_key="optiq_xxx") as client:
    result = await client.agent.select(
        experiment_id="exp-uuid",
        context={"id": "user-456"},
    )
    await client.agent.feedback(request_id=result.request_id, reward=1.0)

Configuration

Constructor kwargs take priority over environment variables, which take priority over defaults.

export QBRIX_API_KEY="optiq_xxx"
export QBRIX_BASE_URL="http://localhost:8000"
from qbrix import Qbrix

client = Qbrix()  # picks up env vars automatically
Env Var Default Description
QBRIX_API_KEY None API key (optiq_xxx)
QBRIX_BASE_URL http://localhost:8000 Your install's origin, without /api (the compose quickstart's gateway by default)
QBRIX_TRANSPORT (auto) http or grpc — overrides URL-scheme detection
QBRIX_TIMEOUT 5.0 Request timeout / gRPC deadline (seconds)
QBRIX_MAX_RETRIES 0 Retry count on transient failures (429/5xx, gRPC UNAVAILABLE)

gRPC-only knobs: QBRIX_GRPC_KEEPALIVE_TIME_MS (30000), QBRIX_GRPC_KEEPALIVE_TIMEOUT_MS (10000), QBRIX_GRPC_USE_TLS (false).

timeout and max_retries can also be overridden per call on every resource method — useful for hot-path calls like agent.select() that need a tighter budget than the rest of the client:

result = qbrix.agent.select(
    experiment_id=exp.id,
    context={"id": "user-1"},
    timeout=0.3,
    max_retries=0,
    fallback={"id": pool.arms[0].id, "name": pool.arms[0].name, "index": pool.arms[0].index},
)
if result.is_fallback:
    # proxy was unreachable/unhealthy — arm was resolved locally, no learning signal
    ...
qbrix.agent.feedback(result.request_id, reward=1.0)  # no-op when request_id is None

fallback only kicks in for availability failures (timeout, connection error, 429, 5xx) — a 4xx caller error still raises even with fallback set, so it doesn't get hidden behind a fabricated selection. See examples/handling_outages.py for a runnable version, and qbrix.io/docs/handling-outages for the full contract.

Feature Gates

Attach a feature gate to control rollout before the bandit kicks in:

import qbrix

qbrix.gate.create(
    experiment_id=exp.id,
    enabled=True,
    rollout_percentage=80.0,
    default_arm_id=pool.arms[0].id,
    rules=[
        {"key": "plan", "operator": "==", "value": "enterprise", "arm_id": pool.arms[1].id},
    ],
)

# Gate-matched selections return is_default=True
result = qbrix.agent.select(
    experiment_id=exp.id,
    context={"id": "user-789", "metadata": {"plan": "enterprise"}},
)
print(result.is_default)  # True

Error Handling

import qbrix
from qbrix import NotFoundError, RateLimitedError

try:
    exp = qbrix.experiment.get("nonexistent-id")
except NotFoundError as e:
    print(f"Not found: {e.detail}")
except RateLimitedError as e:
    print(f"Retry after {e.retry_after}s")

Supported Policies

Policy Type Best For
BetaTSPolicy Stochastic Binary rewards (clicks, conversions)
DiscountedTSPolicy Stochastic Binary rewards that drift over time
GaussianTSPolicy Stochastic Continuous rewards
DirichletTSPolicy Stochastic Categorical / multi-outcome rewards
LogisticTSPolicy Contextual Binary rewards with features
UCB1TunedPolicy Stochastic Theoretical regret guarantees
KLUCBPolicy Stochastic Binary rewards with tight bounds
KLUCBPlusPolicy Stochastic Tighter KL-UCB for long horizons
MOSSPolicy Stochastic Fixed horizon problems
MOSSAnyTimePolicy Stochastic Unknown horizon
EpsilonPolicy Stochastic Simple, predictable exploration
LinUCBPolicy Contextual Linear reward models with features
LinTSPolicy Contextual Linear models with uncertainty
GLMUCBPolicy Contextual Generalised linear reward models
EXP3Policy Adversarial Non-stationary environments
EXP3IXPolicy Adversarial EXP3 with lower-variance estimates
FPLPolicy Adversarial Follow the perturbed leader
RandomPolicy Baseline A/B-style control for benchmarking
MetaBanditPolicy Meta Delegates to policy="auto"

Pass policy="auto" to let qbrix pick and tune a policy for you (backed by MetaBanditPolicy). client.policy.list() is the runtime source of truth.

License

MIT

Metadata

Release files for qbrix 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for qbrix 0.3.0
File Size Uploaded
qbrix-0.3.0.tar.gz 220.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for qbrix 0.3.0
File Interpreter ABI Platform
qbrix-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 278.3 kB

Release files / qbrix-0.3.0.tar.gz

Download URL qbrix-0.3.0.tar.gz
Size 220.2 kB
Tags Source
SHA-256 checksum
How to use checksums
2dbfd1e7739a92793b73de823b16f0a05987fc094ee144541983604434c87c64
BLAKE2b-256 checksum
How to use checksums
e5704e91b6a531809eb4dcc94c9cc4a57d04186f6cf1218cf9624a9f479f2cdc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / qbrix-0.3.0-py3-none-any.whl

Download URL qbrix-0.3.0-py3-none-any.whl
Size 58.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2ea65d605364eb66b40701fecd33e34c0156f8fa8edc8c839fc4192f48bf3586
BLAKE2b-256 checksum
How to use checksums
b7559d40e876a7ecfbca3b5b4275c7d067765e2735f40c09d0231a4138dadac6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.11

2 release files

0.2.10

2 release files

0.2.9

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page