← All chapters

Privacy proxy

Personal data replaced with placeholders before a model provider sees it, images redacted by a redactor you run (one command, no open ports), and what it does not cover.

How it works

Garage → Settings → Limits → Privacy proxy. With the proxy on, every model call of the tron passes a stage of the gateway that replaces personal data it recognises with placeholders — [EMAIL_1], [PHONE_2], [NAME_1] — before the provider sees the request, and puts the real values back in the answer (text and tool arguments, streaming included) before the tron sees it: the tools receive the real values. Inside a chat session the same value always gets the same placeholder; the map is kept encrypted and expires with the session. The preview («this message would be sent as») shows the result without sending anything. Usage counts the replacements of every call.

What it recognises

Deterministic rules, no statistical model: email addresses; phone numbers (E.164, and Italian mobile and landline formats); IBANs (checked with mod 97); Italian tax codes (with their check letter) and VAT numbers (with their check digit); card numbers of 13 to 19 digits that pass Luhn; IPv4 and IPv6 addresses; and the names you declare (people or companies to protect, whole words, case does not matter), for the tron and for the company. A long number that fails its check is left alone. Under the switch, «What to hide» chooses which of these eight kinds are replaced (all of them by default; with none selected the proxy replaces nothing, and the preview says so); a company that enforces the proxy also sets the kinds for its trons, and its libraries use the company kinds.

Its limits, said plainly

It reduces the risk; it does not anonymise. Pseudonymised data is still personal data. Names you do not declare, and personal data written in a form the rules do not recognise, reach the provider. Embeddings and reranking are outside it, with one choice: a library with privacy_proxy on has its chunks (and the queries) pseudonymised before the embedding, with placeholders stable for that library — searching by a name in it becomes less precise. Plugins calling their own services (JEV) are outside it.

The image proxy

Images go to a redactor you run, which covers faces, text, licence plates and declared names before the provider sees them. Vibetron has no such model: it defines the contract vibetron.image-redactor/1.1 (schema at GET https://api.vibetron.ai/public/v1/image-redactor-schema). The main way is Connect to Vibetron: one command on any machine — a laptop, a server, behind a home router — and no open ports, certificates or tunnels, because the redactor opens the connection to Vibetron and receives the images on it. In the card choose Connect to Vibetron, generate the key (vbt_ir_…, shown once), start the redactor with it, and the status turns to «Your redactor is online» with its version and models; then press Test: a synthetic image with a line of text goes through the connection and the result is shown, Sent beside Returned. Test with your image does the same with a PNG, JPEG, WebP or GIF of yours (up to 20 MB) and the categories chosen in «what to cover»: it is read in the browser, never stored, and enters no chat and no usage record. Vibetron asks the redactor only for the kinds it declares a model for (the hello of the connection, or /health of an endpoint): a kind without a model is marked in the card and skipped, and if none is left the call is refused as before. Style chooses how a region is covered: Box (default) a solid rectangle, Blur a strong blur; the Test uses the same style. One connection per key: starting the redactor somewhere else takes over, and a new key disconnects the old one. If the redactor is offline or does not answer: block (default) refuses the call with image_redactor_unavailable («your image redactor is offline»); ask stops the turn in the site chat and the person chooses Send anyway or Drop images (bridges and the Tron API always block). Without an image proxy, images pass as they are and Usage counts them as unredacted.

# on your machine: connected mode, no open ports
VIR_KEY=vbt_ir_… vibetron-image-redactor --connect

# the connection the redactor opens
wss://api.vibetron.ai/redactor/connect
Authorization: Bearer vbt_ir_…
X-Vibetron-Contract: vibetron.image-redactor/1.1

# the signature of every answer
sha256=<hex HMAC-SHA256(key, request_id + "." + hex sha256(canonical JSON of the answer without signature))>

A remote endpoint instead

If the redactor runs on a server with a public address, Vibetron can call it instead: choose Remote endpoint, set the endpoint (https only, also on a private network), paste a TLS fingerprint if the certificate is self-signed, and press Test (POST /probe). The settings saved before connected mode existed keep working this way.

GET/healthOn your service, no authentication: { contract, status, models, version }.
POST/redactOn your service, Authorization: Bearer vbt_ir_…, X-Vibetron-Contract and X-Request-Id: { request_id, session_id, image: { mime_type, data_base64 }, redact, declared_names, style } → { request_id, image, regions, stats, models }, signed with X-Vibetron-Signature.
POST/probeSame shape as /redact, used by the Test button.
# the signature of a /redact answer
X-Vibetron-Signature: sha256=<hex HMAC-SHA256(key, request_id + "." + hex sha256(body))>

The reference package

vibetron-image-redactor is an open-source redactor (MIT) that follows the contract; its source is at https://github.com/aeratic/vibetron-image-redactor. Run without arguments, it opens a terminal screen to pick the models (face detector, text detector, optional OCR) with their CPU, memory and download size, then asks how Vibetron should reach it: Connect to Vibetron (recommended: the address of the API, default https://api.vibetron.ai, and the key) or Listen on an address (the TLS certificate, self-signed with the fingerprint to copy into Vibetron, or yours). It keeps images in memory only, logs no content, verifies Vibetron's certificate, and signs every answer. Python 3.12 or newer; the optional OCR that reads words (needed for declared names) runs on Python 3.12 to 3.14, the base service also on 3.15. It also runs as a Docker image, as a non-root user, with its settings in the /state volume and its models in /models: with VIR_API_URL and VIR_KEY set it starts in --connect mode, otherwise in --serve mode (docker-compose.yml in the repository).

pipx install git+https://github.com/aeratic/vibetron-image-redactor
vibetron-image-redactor

# or without the screen, connected to Vibetron
VIR_KEY=vbt_ir_… vibetron-image-redactor --connect

# or with Docker, connected to Vibetron (no published port)
docker run -d --name vibetron-image-redactor \
  -e VIR_API_URL=https://api.vibetron.ai -e VIR_KEY=vbt_ir_… \
  -v vibetron-image-redactor-state:/state -v vibetron-image-redactor-models:/models \
  ghcr.io/aeratic/vibetron-image-redactor:0.2.0

For a company

A company can set the default for its trons, enforce the proxy, protect names for every tron and provide one image proxy for all of them: Organization → Settings → Privacy proxy (see Organizations).

The routes

GET/trons/:id/privacyThe tron's settings, what the company imposes, and what counts; image_redactor.connection is the live connection of a connected redactor (since, last seen, address, version, models), or null.
PUT/trons/:id/privacy{ proxy, declared_names, image_redactor: { mode: connected | endpoint, endpoint, fingerprint_sha256, on_fail, redact, style: box | blur } }. Never the key.
POST/trons/:id/privacy/preview{ text } → { text, replacements, active }: nothing is written.
POST/trons/:id/privacy/image-redactor/keyA new key, returned once.
POST/trons/:id/privacy/image-redactor/probeThe Test: outcome, regions, the models of /health, the image sent and the one returned. Optional { image: { mime_type, data_base64 }, redact } tests your own image (20 MB, never stored); 10 tests a minute per person.