Self-hosting

Self-hosting

CLI can run with no CLI-hosted component in the loop. There are three levels, from least to most isolated:

OptionWhat leaves your processWhat leaves your networkNeeds
Hosted service with a CustomBackendcontext, instructions, and evidence (probabilities, samples)the sameAn API key
Self-hosted service in your VPCrequests to your own deploymentnothingEnterprise deployment
Offline engine (cli_sdk.stats)nothingnothingpip install cci-sdk

Running the service inside your VPC

The self-hosted deployment runs the same components as the hosted service — API gateway, evaluation service, calibration service, monitoring service, and the calibration store that holds profiles, examples, audits, and monitor state — inside your own network. It exposes the same /v1 API, so SDK code does not change; point the client at it:

export CLI_BASE_URL=https://cli.internal.example.com/v1
export CLI_API_KEY=...        # issued by your deployment
from cli_sdk import CLIClient, VLLMBackend
 
backend = VLLMBackend(
    model="meta-llama/Llama-3.3-70B-Instruct",
    base_url="http://vllm.internal:8000",     # reachable from the CLI service
    engine_version="0.11.0",
    quantization="fp8",
)
 
with CLIClient(backend=backend) as client:
    print(client.list_backends())
  • API keys. The SDK sends a key whenever one is configured. It only allows a missing key when base_url is on localhost, 127.0.0.1, 0.0.0.0 or ::1 (for a deployment running next to your code, or a port-forward during development). Any other hostname needs a key.
  • Model backends. Hosted backends (VLLMBackend, SGLangBackend, and the closed-API classes) are called by the service, so their base_url and credentials must be reachable from where the service runs. A self-hosted service next to self-hosted vLLM or SGLang keeps every model call inside the VPC.
  • Proxies and TLS. Pass your own httpx.Client for corporate proxies or a private certificate authority: CLIClient(http_client=httpx.Client(verify="/etc/ssl/internal-ca.pem")).
  • Engine version. Guarantee cards report stats_version. Keep the deployment and any offline cci-sdk installs on the same version so audit trails can be compared if a workload moves between them.

Self-hosted deployment artifacts and installation instructions come with the Enterprise plan.

Zero-retention mode

In zero-retention mode, the calibration store keeps only calibration statistics — quantile tables, thresholds, e-process state, audit results — and no example content: no contexts, labels, or model outputs are stored after a request or an upload is processed. Zero-retention is a property of the workspace or deployment, not a request parameter, so no SDK code changes.

WorksUnavailable
evaluate with every primitive and guaranteeAnything that re-reads stored examples: recomputing a threshold after a method change, reproducing a guarantee card from the stored calibration set
add_examples (examples are folded into statistics, then discarded)Inspecting or exporting stored examples
audit against fresh examples you sendAudits that need to re-score previously uploaded examples
Drift monitors

Because the stored examples are gone, keep your own copy of every calibration set you upload if you may need to recalibrate, and run audits locally when examples cannot be sent at all (audit_coverage, or cli calibration audit-local).

Air-gapped offline engine

The statistics engine is a pip-installable package with no network dependency. cli_sdk.stats, cli_sdk.LocalMonitor, and the audit and label-efficiency helpers in cli_sdk.calibration never import the HTTP client or open a connection. They need only NumPy.

Install from a wheelhouse built on a connected machine:

# on a connected machine
pip download cci-sdk -d wheelhouse/
 
# inside the air-gapped network
pip install --no-index --find-links wheelhouse/ cci-sdk

Then calibrate, predict, audit, and monitor with no service at all:

import json
 
import numpy as np
from cli_sdk import LocalMonitor
from cli_sdk.calibration import audit_coverage
from cli_sdk.stats.conformal import aps
 
cal_probs, cal_labels = np.load("cal_probs.npy"), np.load("cal_labels.npy")
q_hat = aps.calibrate(cal_probs, cal_labels, alpha=0.10, seed=0)
 
with open("support-routing-v3.json", "w") as handle:      # your own versioned "profile"
    json.dump({"method": "APS", "alpha": 0.10, "q_hat": q_hat, "n": len(cal_labels)}, handle)
 
sets = aps.predict(np.load("test_probs.npy"), q_hat)
audit = audit_coverage([y in s for y, s in zip(np.load("test_labels.npy"), sets)], target=0.90)
monitor = LocalMonitor(type="coverage", target=0.88, false_alarm_rate=0.05)

The offline calibration guide walks through a full run, including Venn-Abers intervals, group-conditional thresholds, and the local drift monitor.

Offline, you own the pieces the hosted calibration store normally enforces: minimum-nn checks (minimum_calibration_size), versioning of thresholds, audits, and backend fingerprints. Calibrate on the exact artifact you deploy — same weights, quantization, prompt template, and decoding settings — because any change to the scoring pipeline breaks exchangeability.