Zhivra Privacy Policy
Last updated: 2026-08-17 (added: how Zhivra’s own endpoints rate-limit by a daily-rotating keyed IP pseudonym — never the raw IP — and the expiry scrub that clears it, plus your free-text note, from expired diagnostic reports)
This is the privacy policy for Zhivra in its current state (pre-launch / early access). It describes what the extension does today. Before a public marketplace release we will revise this document — in particular, a future managed-cloud tier will introduce optional server-side features (covered below) that do not exist yet.
Zhivra is a VS Code extension that routes each of your requests to the best-suited “agent persona” (a model + system prompt + tool set) and runs an AI coding agent on your behalf. Here’s where your data goes — and, more importantly, where it doesn’t.
Where your data goes (and where it doesn’t)
-
Your code, files, prompts, and commands. When you use Zhivra’s AI features, the relevant files, your prompts, and the conversation context are sent to the AI model provider you have configured (e.g. OpenRouter, Anthropic, or whichever provider the routed persona’s model lives on) so the model can respond. Zhivra has no cloud proxy — your code and prompts go directly from your machine to that provider. We (the Zhivra developers) do not receive, store, or process your code, prompts, or commands. The AI provider you chose handles that data under their privacy policy.
-
API keys and credentials. Any API key you enter is stored locally on your device (in VS Code’s secret storage / settings) and is sent only to the provider it belongs to. It is never sent to us or any third party.
-
Telemetry / usage analytics — gated by consent, no data leaves until you acknowledge the prompt. Zhivra is forked from Roo Code, which shipped a PostHog analytics client; that has been removed (no analytics key is bundled, no PostHog sink is registered). Zhivra has its own, narrower telemetry: on first activation you see a one-time consent dialog. No telemetry leaves your machine until you click “Yes” on that dialog. (Zhivra does make a small number of non-telemetry housekeeping requests that carry no prompts, code, or telemetry — they are enumerated in “Every network request Zhivra makes” below, so nothing is undisclosed.) If you opt in, Zhivra uploads behavioral routing signals — which persona handled each turn, accept/reject, latency, cost — the signal base for routing improvements (ranking changes are human-reviewed today). Answer “No thanks” and nothing is uploaded — ever: declining also switches the upload setting itself off, so the decline is enforced by configuration, not just remembered. (Turning the setting back on yourself later is a new, explicit opt-in.) The dialog never re-asks after a “No”. (Closing the dialog without answering is not treated as a “No”: it will ask again on a later activation until you answer.) No prompts, no code, no API responses are uploaded under the anonymous-telemetry channel; a second, separately opt-in channel (routing-improvement uploads) can upload prompt and response text and is off unless you explicitly enable it. Whichever way you answer, your decision is recorded locally on your machine (the choice, when you made it, and which version of the dialog text you saw) — we keep an auditable record of your consent without that record itself leaving your device. Full detail in “Contributing anonymous telemetry (opt-in)” below.
-
Routing-improvement uploads — separate opt-in, off by default. A second, distinct channel (
zhivra.routingImprovement.enabled) opts you into uploading your full prompt + the agent’s full response so a third-party judge LLM can grade routing quality. This is a meaningful privacy step beyond anonymous telemetry, which is why it is its own setting and starts off. Full detail in “Routing-improvement uploads (opt-in, off by default)” below. -
Routing-classifier fallback (on by default). Zhivra’s router classifies each request with a fast, local, deterministic classifier first. When that classifier can’t categorize a request, Zhivra sends the text of that prompt to a small, cheap classification model (default
google/gemini-2.5-flash) via your own configured OpenRouter key — the same key your main requests already use; no Zhivra server is involved. This is a second model seeing your prompt beyond the persona that answers it, so we disclose it explicitly. Controlled byzhivra.llmClassifierFallback.enabled(on by default;zhivra.llmClassifierFallback.modelpicks the model). If you run Zhivra against a local model provider and want strictly nothing to leave your machine, turn this setting off. -
Marketplace / model-list / metadata requests. Zhivra may make network requests to fetch the list of available models from your configured provider’s public catalog (e.g. OpenRouter’s
/modelsendpoint), and it fetches OpenRouter’s public zero-data-retention provider list (openrouter.ai/api/v1/endpoints/zdr) at activation (cached up to 24 hours) so routing can respect data-policy constraints. These requests carry only what’s needed to fulfill them — no code, no prompts, no install id. For provider-specific catalogs that require authentication, your API key for that provider is sent to that provider (as any catalog query requires); the ZDR fetch sends no credentials or custom headers at all (the server necessarily sees standard web-request metadata like your IP, as with any HTTPS request). -
Capability-table fetch (only if capability-table routing is on). When
zhivra.routing.useCapabilityTableis on (off by default), Zhivra fetches a signed routing table from a Zhivra-operated endpoint (zhivra-cap-table.zhivra.workers.dev) on your first routed turn and then at most every 7 days (if the first fetch fails, it retries on subsequent turns until one succeeds). That request carries your anonymous install id (so we can count active installs and version the table) plus your Zhivra cloud API token if you’ve configured one — never prompts, code, or behavioral data. The response is cached at~/.zhivra/cap-table-cache.json. Heads up: this setting is window-scoped, so a workspace’s.vscode/settings.jsoncan turn it on for that workspace — if that matters to you, audit workspace settings in repos you don’t control.
Codebase indexing (off by default): if you turn on the optional “codebase indexing” feature, snippets of your code are sent to whichever embedding provider you configure (OpenAI, Ollama, Gemini, Bedrock, OpenRouter, Vercel) and stored in whichever vector database you point it at (a local Qdrant by default). Nothing is indexed or sent until you enable it and supply that configuration.
Files Zhivra writes on your machine
Zhivra keeps some data locally on your own device — nothing here is uploaded anywhere unless you explicitly choose to share it (see the next section):
-
Error log —
~/.zhivra/errors-<pid>-YYYY-MM-DD.log. A structured record of errors the extension hits, kept so that you (or we, if you choose to share a diagnostic bundle) can debug a problem. It contains the error type, the error message, a few lines of stack trace with file paths scrubbed (your home directory and workspace path are replaced with~/and<workspace>/so your username doesn’t leak), and a small set of scalar values (task id, persona id, token counts) — never your prompts, never your code, never file contents. Files older than 7 days are deleted automatically. On by default; disable with thezhivra.errorLog.enabledsetting. -
Routing & outcome logs (opt-in, off by default) —
~/.zhivra/dogfood/. When you turn on thezhivra.dogfoodLogger.enabledsetting, Zhivra writes per-turn routing decisions (which persona was picked and why) and behavioral signals (did you accept/reject a tool action, did you edit the agent’s code, did you abandon the task) to local CSV files. The routing log includes the first ~200 characters of your prompt (so the routing decision is interpretable); the outcome log contains no prompt or code content — only behavioral signals (tool names, persona ids, edit-distance buckets). This is off unless you explicitly enable it, and the files are kept until you delete them (no automatic expiry unless you setzhivra.dogfoodLogger.retentionDays). A subset of this data — minus the prompt prefix and the reasoning text — is uploaded only if you also opt in to “Contributing anonymous telemetry”. -
Task history — VS Code’s extension storage (
globalStorage). Zhivra stores your conversation history per task so you can resume a task later and so the agent has its context. This includes your prompts and the files the agent read or wrote during that task. It stays on your machine; it is deleted if you uninstall the extension. (You can also delete individual tasks from the history view.)
When the agent runs a shell command whose output is large, the full output is
written to a file under your VS Code global-storage task directory
(tasks/<id>/command-output/cmd-*.txt) so it can be referenced later. That file
is removed when the task is reset and does not survive uninstalling the extension.
If a command you run prints a secret (e.g. cat .env), that secret will be in that
file until the task is cleared.
Housekeeping files — for completeness, the extension also keeps these small state files (none contain prompts or code; none upload automatically):
~/.zhivra/install-id— your anonymous install UUID (file permissions restricted on macOS/Linux). Deleted/rotated byZhivra: Delete My Telemetry.~/.zhivra/cap-table-cache.json— the cached signed routing table (only written if capability-table routing is on). Delete it freely; it re-fetches.~/.zhivra/joint-scoring-v1-marker— a tiny migration marker.~/.zhivra/custody/— if you enable the custody evidence feature (zhivra.custody.enabled, off by default): a content-free, hash-chained log of which provider served each turn (provider names, token counts, cost — never prompt or response text) plus any reports you generate from it. Kept until you delete it; never uploaded and never included in diagnostic bundles.<dogfood dir>/.upload-cursor.json— bookkeeping for which telemetry rows were already uploaded.<dogfood dir>/pending-retention.json— a rolling list (max 500) of absolute file paths + content hashes of files the agent recently wrote, used to detect whether you kept or reverted the agent’s edits after 24h. Path names can reveal project/folder names, so note: this file is local-only, is never uploaded (only its entry count appears in Verify Install output), and entries older than 24 hours are swept shortly after each activation.<dogfood dir>/abandoned-emitted.json— task-id list (max 500) that prevents duplicate “task abandoned” signals.- VS Code storage: your consent token (
globalState) and, once minted, a per-install upload secret (VS Code SecretStorage) used to sign uploads.
Contributing anonymous telemetry (opt-in)
To make the auto-router better, Zhivra can upload a small, anonymous stream
of behavioral data. This is off by default. The consent dialog appears on
activation; you can also flip the upload any time via the
zhivra.telemetry.uploadEnabled setting. If you enable the local
routing/outcome logs yourself in Settings without ever answering the dialog,
Zhivra treats that as local-only: the upload setting is switched off for
you, and uploads start only if you explicitly turn
zhivra.telemetry.uploadEnabled on. Until you affirmatively opt in one of
those two ways, nothing is uploaded.
What is uploaded, if you opt in:
- Routing decisions — for each turn: which category the request was classified as, which persona and model were chosen, which personas were candidates, whether it was an exploration pick, whether you overrode the choice (and to what), the turn index, and the length of your prompt (a number — not the text). The raw ~200-character prompt prefix that’s kept in the local log is stripped before upload, and so is the router’s free-text “reasoning” string.
- Behavioral signals — whether you accepted or rejected a tool action, reverted a file, redid or abandoned a turn, the edit-distance “bucket” of the agent’s output, and which tool a signal relates to. When the auto-router escalates because you re-asked (“redo this” / repeated frustration), we also record which tier the ladder moved to (alt model → adjacent persona → premium model) and which persona ids the escalation moved between — persona ids only, no prompt content. For task-anchored routing, we also record the task’s anchor persona id, whether the turn was held to that anchor, and the effective routing category — persona ids and category tags only, no prompt content. These are tags and small numbers — no prompt or code content.
- Operational fields — alongside the above, each routing event can carry: which providers were considered for the turn and the scoring breakdown (persona/model ids and numbers), which provider actually served the turn and its reported cost (custody fields), whether the LLM-classifier fallback fired (category, outcome, latency, cost, cache-hit — not the prompt), which provider families you hold API keys for (provider names only — never the keys), and a deterministic per-row dedup id. All of these are ids, tags, and numbers — no prompt or code content. (The per-turn data-policy / anonymization-count fields recorded in the local CSV are not currently uploaded.)
- Attached to each event: an anonymous install id (a random UUID generated
on your machine — not your name, email, or any device identifier; a reinstall
gets a fresh one), the extension version, and a cohort tag. Outside the
private beta this is a coarse label like
"colleagues"or"beta". During the private beta it is a per-recipient ID — a random token unique to your invite. That token is pseudonymous, not fully anonymous: it carries no name or email, but we privately hold the mapping from it back to the person we invited, so we can group your sessions and trace a leaked build back to its recipient. Your.vsixbuild is also watermarked with the same recipient tag for that purpose (the watermark stays in the build and is never uploaded with telemetry).
What is never uploaded on this channel: your prompts, your code, file contents, API requests or responses, file paths, your username, or IP-derived data. (File paths can, however, appear in a diagnostic bundle you choose to send — task metadata includes your workspace folder name/path; see the diagnostic-reports section. Separately from the uploaded events themselves, the ingest endpoint rate-limits incoming requests using a daily-rotating keyed hash of the connecting IP, held in a rate-limit log that a daily job purges once rows are older than 24 hours — the raw IP is not stored; see “IP handling at Zhivra endpoints” for the scheme.) The only field that ties events back to you is the pseudonymous per-recipient beta ID described above — re-identifiable only by us, via the private invite mapping, never by a third party. The uploaded payload is the same scalar-only schema as the local CSV logs — minus the prompt prefix and the reasoning text.
Where it goes: a Supabase Postgres database hosted in the United States
(us-east-1). The write key the extension carries can only append events of
the allowed types — it cannot read raw events back. (The separate Verify
Install endpoint returns aggregate counts for your own install id; see its
section.) Self-hosters can point the
extension at their own Supabase via zhivra.telemetry.uploadEndpoint.
Turning it off: set zhivra.telemetry.uploadEnabled to false. Already-uploaded
events stay where they are; nothing further is sent.
Local signal-capture file (leaves your machine ONLY inside a FULL diagnostic bundle)
When an implicit behavioral signal fires (same-task re-ask, negative or positive language, time-to-accept, frustration escalation) and the dogfood logger is enabled (zhivra.dogfoodLogger.enabled, off by default — no captures are ever written without it), Zhivra writes a JSONL row to ~/.zhivra/dogfood/signal-capture-YYYY-MM-DD.jsonl on your machine (a new file each day). The row contains the full user message that triggered the signal, the matched prior message (for re-ask detection), and the last few prior user messages as context — enough to debug “why did the detector think these two messages were the same ask?”. Secret-looking strings (API keys, tokens) are scrubbed at write time.
The anonymous-telemetry uploader reads only dogfood-*.csv and outcomes-*.csv (scalar-only) — it never touches signal-capture files, so this content is never uploaded automatically. There is exactly one path by which it can leave your machine: if you run the diagnostic-report command and choose the FULL (sensitive) redaction level, the last 200 rows are included in the bundle — which you may then upload or keep local. Redacted and Skip bundles omit it entirely.
Retention: these files are rotated daily and soft-capped at ~5 MB (past the cap, further captures that day are silently dropped). While the dogfood logger is enabled, old files age out under zhivra.dogfoodLogger.retentionDays (default 0 = kept until you delete them). The moment the logger is disabled (or was never enabled), Zhivra deletes any existing capture files at the next activation — prompt-bearing files don’t outlive the opt-in. To stop captures: disable the dogfood logger (zhivra.dogfoodLogger.enabled set to false) — no capture is written while it’s off. (The signal detectors themselves keep running in memory, because routing escalation uses them — but nothing is written to disk or uploaded.)
Routing-improvement uploads (opt-in, off by default)
This is a separate channel from anonymous telemetry above. Anonymous telemetry tells our auto-router what happened (which persona was picked, did you accept it). Routing-improvement uploads add the request and the answer so a third-party judge LLM can grade quality. We split it out as its own setting because it’s a meaningfully larger privacy surface — and because plenty of users will reasonably want the first channel but not the second.
It is controlled by the zhivra.routingImprovement.enabled setting and is
off by default. You can also flip it via the Zhivra: Configure Routing Improvement Consent command. We may also ask you once, via a one-click
prompt, if you already have anonymous telemetry on. If you say “Not now,” we
re-ask at most once, 30 days later (or when you yourself toggle the telemetry
upload setting back on — your own toggle can re-open the question sooner), and
then never again — no dark patterns.
What is uploaded, if you opt in (per routed turn):
- Everything the anonymous-telemetry channel uploads (routing decision, persona id, model id, accept/reject signals, edit-distance bucket).
- The full text of your prompt for that turn, up to 32 KB.
- The full text of the agent’s response for that turn, up to 64 KB.
- The list of tools the persona had access to (tool names only — e.g.
read_file,apply_diff,execute_command). - The size in characters of each tool’s output — not the output content.
If the agent reads a 50,000-character file, we upload “
read_file, 50000”; the file contents stay on your machine. - The same anonymous install id, extension version, and cohort tag the anonymous-telemetry channel uses.
What is still not uploaded: file contents the agent read or wrote, the text of diffs the agent applied, command output, API keys, your name, email, IP, or any device identifier. The boundary on tool output content is the same in both channels — only the metadata changes.
Where it goes: the same Zhivra-operated Supabase Postgres database in the
United States (us-east-1). From there, every routed turn is forwarded to
a third-party LLM provider so a judge can score it. Which provider depends on
which persona ran — we apply a family-separation rule (a Claude judge never
scores a Claude persona’s output, and so on):
- Anthropic Claude (Haiku 4.5 for the bulk judge; Sonnet 4.6 for a 5% calibration sample). Retention: 7 days for commercial API traffic; up to 2 years for abuse-flagged content; classifier scores up to 7 years. Anthropic moved from 30-day to 7-day retention on September 14, 2025. Source: https://privacy.claude.com/en/articles/10023548-how-long-do-you-store-my-data. Zhivra does not currently have a Zero Data Retention contract with Anthropic; we will pursue one before the public beta.
- Google Gemini Flash on a paid API key. Retention: none at rest —
prompts and responses to
generateContentare not stored after the response and are not used for training on paid keys. (Free-tier Gemini behaves differently; Zhivra does not use a free-tier key.) - OpenAI gpt-4o-mini for a 5% calibration sample on non-Anthropic-persona turns (family separation blocks Claude from grading itself, so we need a third provider). Retention: 30 days for abuse monitoring; data not used for training by default on API calls. Zhivra does not currently have an OpenAI ZDR contract.
These are the providers’ policies, not promises we can enforce. If a provider
changes posture, we will update this section and docs/contributing-routing-data.md.
How to opt out: set zhivra.routingImprovement.enabled to false. From
the next turn onward, no prompt or response content is uploaded. Already-uploaded
data stays unless you also run Zhivra: Delete My Telemetry (next paragraph).
How to delete what you’ve already contributed: the Zhivra: Delete My Telemetry command cascades a deletion of your anonymous install id’s rows
across the Zhivra-controlled tables. Specifically, in this order:
- Storage objects — zip blobs from any diagnostic reports you’ve sent are removed from our Supabase Storage bucket.
diagnostic_reports— metadata rows for those diagnostic reports.judge_scores— every quality / routing-fit / tool-fit score the judge LLM produced for your turns.telemetry_events,routing_events,outcome_events— every dogfood routing decision + every behavioral signal (accept / reject / re-ask / frustration / etc.) we have for you, across all event tables.upload_attempts— the rate-limit log for your uploads (diagnostic, telemetry-ingest, consent, and Verify Install requests, including any IP pseudonyms on those rows) — andcap_table_fetches— the server’s log of capability-table fetches from your install id (yes, the server keeps one; it’s deleted here too).consent_grants— your consent row is marked withdrawn (granted = false) rather than deleted immediately. A daily reaper job sweeps withdrawn rows after 30 days, at which point the row itself is gone. The 30-day delay exists so we can prove to ourselves (in an audit) that the withdrawal was processed, not lost.
After the cascade completes, your local install id and consent token are rotated; future turns from this machine are treated as a fresh install.
What it deletes locally (exact scope): the dogfood/outcome CSV files and
the upload cursor, plus the install id, consent token, and upload secret
(rotated/cleared). It does not delete other local files — signal-capture
files, error logs, the custody evidence log, the cap-table cache, or the
housekeeping state files listed earlier. Those never uploaded anything by
themselves; delete ~/.zhivra/ manually if you want them gone too.
The delete cascade covers everything we store. It does not reach into the third-party LLM provider’s abuse-monitoring window described above — that data is held by Anthropic (7-day window), Google, or OpenAI under their own retention policies (the windows listed above) and we have no API to delete it. This is the documented gap; we’d rather state it honestly than imply we can wipe data we can’t.
Long version: see docs/contributing-routing-data.md
for the plain-English explainer, the trade-off in one paragraph, and pointers
into the source.
Verify Install command
Zhivra: Verify Install is a self-diagnostic command added in the pre-beta
build. Run it from the Command Palette to see a quick report on whether your
extension is configured correctly and whether your install id is registered
with Zhivra’s telemetry server. A one-time prompt offering to run it appears 30
seconds after activation — only after you’ve already answered the routing-
improvement consent dialog — with Yes / Not now / Don’t ask again choices.
“Not now” suppresses the prompt for 7 days; “Don’t ask again” turns it off
permanently. You can always invoke the command yourself afterwards.
One non-interactive call to the same endpoint: the first time a telemetry
upload actually runs (i.e. you opted in and local logs exist), the extension
calls this endpoint once in the background to mint the per-install upload
secret that signs subsequent uploads. That call sends the same two fields as
the command (install_id, extension version) and nothing else. It cannot
happen before consent, because it only fires as part of an upload flush that
consent gates.
What the command sends to Zhivra’s server: your anonymous install_id
(the same UUID the rest of Channel-D uses) and the extension version. That is
the entire request body. No prompts, no code, no settings, no behavioral data
are sent. The request carries the same publishable key any client carries;
once your install has an upload secret (previous paragraph), the request is
additionally signed with it so the server can tell your install’s requests
from someone merely replaying your install id.
What comes back: aggregate counts only, for your install id —
how many telemetry_events rows are recorded (today and all-time), whether
a consent_grants row exists and its granted state, the shape of the
consent token hash (sha256 / grandfather sentinel / null — never the hash
itself), aggregate counts for judge_scores and diagnostic_reports, and
the latest scored-at / received-at timestamps. The hash of your consent token
never leaves the server.
What the rendered report shows: the response above + your local settings
(telemetry.uploadEnabled, routingImprovement.enabled), the dogfood CSV
path (rendered with your home dir as ~/ so screenshots don’t leak your
username), the timestamp of the latest CSV write, and the count of
pending-retention.json entries. Your install id is truncated to the first
8 characters before display.
Where it goes: the same Zhivra-operated Supabase project in us-east-1
that hosts the rest of Channel-D, at the new
/functions/v1/verify-install Edge Function. Self-hosters can override via
the zhivra.verifyInstall.endpoint setting. The endpoint is rate-limited to
10 calls per install id per hour (it reuses the upload_attempts table); a
single rate-limit log row is inserted per call, no other writes happen.
How to opt out: don’t run the command, and pick “Don’t ask again” if the one-time prompt appears. The command never auto-fires after the first run.
Diagnostic reports — only if you choose to send one
If you hit a bug and want us to help, Zhivra has a Zhivra: Send Diagnostic Report command (Command Palette). Nothing uploads in the background. An
upload only happens when you run that command and pick “Send to Zhivra” in the
second dialog. This is one of three paths by which your prompts, code, or
behavioral data can reach Zhivra:
the other two are the opt-in anonymous routing telemetry
channel and the opt-in routing-improvement uploads
channel — both off by default. Diagnostic reports aren’t on/off; they just
run when you ask them to.
What the bundle contains:
dogfood/dogfood-*.csvandoutcomes-*.csv— routing decisions and behavioral signals (which persona was picked, accept/reject, edit-distance buckets), last 7 days. Only present if you had the local routing/outcome logs enabled. The redaction level you pick applies here too: in Redacted and Skip modes the ~200-character prompt-prefix and free-text reasoning columns are stripped from the CSVs; only the FULL (sensitive) level ships them verbatim. When shipped (FULL), those two columns are secret-scrubbed (API keys/tokens removed) but NOT PII-scrubbed — an email or name in the first ~200 chars of a prompt can be present.- If you selected FULL, the bundle also includes the last 200 rows of the local signal-capture file (full trigger messages — see that section above). Redacted/Skip omit it.
errors/recent.jsonl— the last 200 lines of the local error log (scrubbed stacks, file paths replaced with~/and<workspace>/). No prompt or code content.output-channel-tail.txt— the last 500 lines of the Zhivra Output panel. On private-beta builds this tail (andmanifest.json) includes the build’s per-recipient watermark tag, so a bundle identifies which beta build produced it — consistent with the watermark disclosure in the telemetry section.- An optional free-text note you can type when sending (max 2048 characters). It is sent as you typed it — don’t put secrets in it. It is stored with the report’s metadata and cleared when the report expires at 30 days.
tasks/<taskId>/for the last 10 task directories —history_item.json,task_metadata.json,ui_messages.json,api_conversation_history.json. These conversation files are redacted by default (see below).versions.json— extension, VS Code, OS, and Node versions.manifest.json— a listing of every file in the bundle and the redaction level you picked.
What’s NOT in the bundle by default: your prompts, your code, the model’s
completions, and the contents of any files the agent read or wrote — all
replaced with [REDACTED — len=N] placeholders, keeping only structural
metadata (timestamps, roles, tool names, token counts). The first dialog gives
you three task-history options:
- Redacted (recommended) — the default; placeholders only.
- FULL (sensitive) — includes raw prompts and code. Explicit opt-in, with a clear warning in the dialog. Pick this only when the bug needs the actual prompt or file to reproduce, and only if you trust where it’s going.
- Skip task history — omit the
tasks/directory entirely.
The second dialog then asks where to send it: Send to Zhivra (recommended),
Save locally instead (you get a .zip you can email yourself), or
Cancel.
Where it goes if you choose “Send to Zhivra”: a Zhivra-operated Supabase
project hosted in the United States (us-east-1). Stored privately in
Supabase Storage; access is restricted to Zhivra maintainers debugging the
report.
How long it’s kept: 30 days — a daily scheduled job then deletes the bundle and scrubs the report’s metadata row down to structural fields (versions, sizes, timestamps, reference code, and your anonymous install id — kept so deletion requests still work). The IP pseudonym described in “IP handling at Zhivra endpoints” below and your free-text note are cleared in the same scrub. Because the job runs once a day, a report can live up to a day past the 30-day mark. We don’t keep copies elsewhere.
Reference code: after a successful upload you’ll see a code like
ZD-XXXX-XXXX. Include it when you email us at support@zhivra.com — that’s
how we find your bundle on the server. Without it we have no way to match a
report to a person, by design.
How to opt out: don’t run the command. If you’ve already started it and
changed your mind, pick Cancel in the second dialog (nothing is uploaded
until you confirm). If you want the bundle for your own records but don’t want
us to have it, pick Save locally instead — you can then email the zip to
support@zhivra.com yourself, or attach it to a GitHub issue, on your terms.
IP handling at Zhivra endpoints
Like any HTTPS request, a request to a Zhivra-operated endpoint necessarily reveals your IP address to the server while it’s being handled. None of Zhivra’s Supabase endpoints store the raw IP. To rate-limit abuse (each endpoint has a per-install cap and a per-IP cap — e.g. 10 diagnostic uploads per install per hour, 50 per IP per hour), three of them — the diagnostic-upload initializer, the telemetry ingest, and the consent recorder — store a keyed, daily-rotating pseudonym of it instead: an HMAC-SHA256 of the IP computed with a server-held secret, with the UTC date mixed into the input. Because the secret never leaves the server, the hash can’t be reversed or brute-forced back to your IP — and hashes from different days can’t be linked to each other — by anyone who doesn’t hold that secret. If the server-side secret is not configured, no hash is stored at all (the per-IP limit simply goes inactive) — there is no fallback to a weaker scheme.
Where the pseudonym lives: a rate-limit log purged by a daily cleanup job
once rows are older than 24 hours (so a row lives at most about two
days), and — for diagnostic reports only — the report’s metadata row, where
it is cleared when the report expires (see “How long it’s kept” above).
Zhivra: Delete My Telemetry deletes both. (That command authorizes the
deletion with your consent token, so it needs the consent record that
telemetry opt-in creates; if you never opted in and want a diagnostic report
deleted, email support@zhivra.com with your reference code instead.)
One exception on raw-IP handling: the optional capability-table endpoint (off by default; see its section above) rate-limits with a short-lived raw-IP counter held at the infrastructure layer for up to an hour. It is never written to Zhivra’s database.
What we do not do
- We do not train any AI models on your data. (The judge LLM that scores routing-improvement uploads grades them; the providers we send those uploads to — Anthropic, Google paid Gemini, OpenAI — do not use API content for training by default. We don’t run our own training pipeline.)
- We do not sell or share your data with third parties — outside the two explicit, opt-in upload channels described above (anonymous telemetry and routing-improvement uploads), and the diagnostic-report path you trigger by hand. Routing-improvement uploads pass through a third-party judge LLM by design; that’s disclosed in its own section above.
- We do not upload your code, prompts, conversations, or diagnostics
anywhere automatically without an opt-in. A diagnostic report is only sent
when you run
Zhivra: Send Diagnostic Reportand pick “Send to Zhivra”; there is no automatic crash-report upload in the free fork. Background uploads happen only on the two opt-in channels above — both inert until you opt in.
Every network request Zhivra makes
The complete list, so you can audit the claim rather than trust it. (The
developer-grade version with source line references lives in
docs/architecture/privacy-data-flows.md.)
| Request | When | Carries | Off switch |
|---|---|---|---|
| Your configured AI provider | every agent turn | prompts, conversation, file context — the product working | use a local provider |
| Classifier fallback → your OpenRouter key | ambiguous turns only | that turn’s prompt text | llmClassifierFallback.enabled |
| Provider model catalogs | on demand | catalog query; for authenticated catalogs, your API key for that provider | — |
| OpenRouter ZDR provider list | at activation, cached up to 24h | nothing (bare GET; no credentials) | — (no identifiers sent) |
| Provider sign-in flows (OpenRouter “Connect”, OpenAI Codex) | only when you use them | the OAuth exchange those providers define | don’t use OAuth sign-in (paste keys instead) |
| Remote MCP servers | only if you configure MCP servers | whatever the tools you invoke send, to hosts you configured | don’t configure remote MCP servers |
| Codebase-indexing embedder + your vector DB | only if you enable codebase indexing | code snippets, to the providers you configured | leave indexing off (default) |
| Capability-table fetch (Zhivra endpoint) | first routed turn + every 7 days, only if routing.useCapabilityTable is on (off by default; window-scoped — a workspace can enable it) | anonymous install id (+ your Zhivra cloud API token if configured) | leave the setting off |
| Anonymous telemetry ingest | every 10 min, only after consent + local logs on | scalar routing/behavior rows | consent “No” / telemetry.uploadEnabled |
| Consent-grant record | when you click “Yes” on the routing-improvement consent dialog, or enable that setting yourself | install id + a hash of your consent token | don’t opt in |
| Upload-secret mint (verify-install endpoint) | once, on the first consented upload flush | install id + version | never fires without consent |
| Routing-improvement content | rides telemetry, only after the separate routing-improvement opt-in | that turn’s prompt (≤32 KB) + response (≤64 KB), secret-scrubbed | routingImprovement.enabled |
| Verify Install (command) | when you run it (one-time prompt offers it) | install id + version | don’t run it |
| Diagnostic report | only when you pick “Send to Zhivra” | the bundle you reviewed + optional note | pick “Save locally” |
| Delete My Telemetry | when you run it | install id + consent token (to authorize deletion) | — (it’s the delete button) |
Nothing else. If you find traffic not on this list, that’s a bug — report it.
Server-side note: three of the Zhivra-operated endpoints in this table (telemetry ingest, consent-grant record, diagnostic report) rate-limit by a daily-rotating keyed hash of the connecting IP — no Supabase endpoint stores the raw IP. Scheme and retention in “IP handling at Zhivra endpoints”.
Your controls
- Configure a local model provider to keep everything on your machine — and
also turn off
zhivra.llmClassifierFallback.enabledfor strictly-local operation (see the classifier-fallback bullet above). zhivra.errorLog.enabled— turn off the local error log.zhivra.dogfoodLogger.enabled— turn on (or leave off) the local routing/outcome logs.zhivra.telemetry.uploadEnabled— controls the anonymous telemetry upload. (The declared setting default istrue, but Zhivra switches it off for you when you decline the consent dialog — or when you enable local logging without ever answering it — so uploads only run after an affirmative “Yes” or your own explicit setting flip; the effective out-of-the-box posture is OFF.) Turn off anytime to halt uploads.zhivra.telemetry.uploadEndpoint— point it at your own Supabase if self-hosting.zhivra.routingImprovement.enabled— turn off (the default) or on the routing-improvement uploads (full prompt + agent response to a third-party judge LLM).Zhivra: Configure Routing Improvement Consentre-opens the prompt at any time.Zhivra: Delete My Telemetry— cascade-delete everything Zhivra holds about your install id (telemetry events, judge scores, consent record, diagnostic reports) and reset your install id locally.Zhivra: Send Diagnostic Report— a no-op until you run it. You upload only if you choose to; the same command has a “Save locally instead” option that never touches the network.zhivra.diagnostics.endpoint— point it at your own Supabase deployment if self-hosting.- Delete tasks from the history view, or
~/.zhivra/directly, at any time. - Uninstall the extension to stop all local data collection.
Website forms — enterprise waitlist & contact
Everything above is about the VS Code extension. This section is separate: it
is the collection notice for the waitlist / early-access form on the Zhivra
website (zhivra.com/enterprise). It satisfies the transparency duty under the
EU/UK GDPR (Arts. 13–14) and serves as the Personal Information Collection
Statement under the Hong Kong Personal Data (Privacy) Ordinance (DPP1) — the
framework Zhivra applies while operated from Hong Kong, pre-incorporation.
-
Who controls the data. Zhivra (incorporation in progress — the registered entity will be the formal data controller) controls waitlist submissions. Reach us at
support@zhivra.com. -
What we collect — only what you type. The form stores the fields you fill in: your work email and company, and (optionally) your role, team size, regulated vertical, and the free-text “biggest blocker” box. We also record a server timestamp and a derived flag noting whether the email is a free-mail domain (e.g.
gmail.com) so we can tell work addresses from personal ones. We do not store your IP address, user-agent, or any device fingerprint — the same “only what you submit” posture the extension takes. The blocker box is a “what’s slowing you down” field, not a support ticket; please don’t paste secrets or sensitive personal data into it. -
Why we collect it, and the legal basis. Two purposes only: (1) to contact you about Zhivra early access / enterprise availability, and (2) to gauge aggregate demand (e.g. how many regulated teams are interested) so we can prioritise. The legal basis is your consent — you tick the consent box before submitting — together with our legitimate interest in evaluating and responding to demand (GDPR Art. 6(1)(a) and (f)). We do not use waitlist data for anything else, and we do not sell or share it.
-
Where it’s stored & who processes it. Submissions are stored in a Cloudflare D1 database hosted in the Asia-Pacific region; Cloudflare is our infrastructure processor. To block spam the form uses Cloudflare Turnstile, which receives your IP address and a challenge token to confirm you’re human — that check happens at Cloudflare and the result is not stored by us. Turnstile is privacy-preserving and does not track you across sites. No other third party receives this data.
-
How long we keep it. Until the earlier of: (a) we’ve contacted you and the waitlist has served its purpose, or (b) you ask us to delete it. We purge stale entries periodically rather than holding them indefinitely.
-
Your rights. You can ask us to access, correct, or delete your waitlist entry, or withdraw consent, at any time — email
support@zhivra.comand we’ll action it. EU/UK residents may also object to processing and lodge a complaint with their supervisory authority; Hong Kong residents may complain to the Privacy Commissioner for Personal Data (PCPD). Withdrawing consent doesn’t affect anything we lawfully did before you asked.
Security & changes
We take reasonable measures to protect data on your machine, but no system is perfectly secure. If this policy changes materially, we will surface a notice in the extension.
Contact
For privacy questions, open an issue on the Zhivra project repository.
By using Zhivra, you agree to this Privacy Policy.