All docs ▾
Getting started
Using Vex
Privacy
What stays on your machine, what leaves it, and what is opt-in.
Vex has no account, no sync and no server-side copy of your data. Your conversations, missions, memories, portfolio history and embeddings live in a database on your own machine. The traffic Vex generates is the traffic the work requires: public chain RPC, protocol APIs, your own model provider, and the activity lane described below.
Everything is local
The app manages a per-install Docker Compose stack for its own data plane. Two services, both published on loopback only:
| Service | What it holds | Published on |
|---|---|---|
| Postgres 18 + pgvector | Sessions, transcripts, approvals, activity, knowledge entries and their vectors. Digest-pinned image, SCRAM-SHA-256 auth, password supplied as a file secret rather than an environment variable. | 127.0.0.1 |
| Embeddings runtime | EmbeddingGemma 300M running locally under llama.cpp, producing 768-dim embeddings over an OpenAI-compatible endpoint. Your text is embedded on your machine. | 127.0.0.1 |
Neither service is reachable beyond loopback, and neither is shared between installs: the Compose project name and both named volumes carry a per-install id. The model file (~333 MB) is downloaded once, SHA256-verified, and cached in a named volume. See Requirements.
Inference is the one part of the agent loop that leaves: prompts go to OpenRouter under your own account and key, so the provider’s policies are the ones that apply, and the cost is yours. Nothing routes through Vex infrastructure.
Crash reporting is opt-in
Sentry crash reporting is off unless you turn it on: the stored preference defaults to disabled, and the consent checkbox appears on the Review step of the first-run wizard (First run). If the build has no DSN configured, the card says so and there is nothing to consent to. When it is enabled, a before-send hook scrubs the event and an allowlist limits breadcrumbs before anything is transmitted.
Bug reports are a separate, local path. The in-app report-issue dialog assembles a redacted report on your machine: field names that look sensitive are replaced wholesale, then every string is scrubbed in two tiers, hard-redacting mnemonics, private keys, API keys and JWTs and masking addresses and transaction hashes. You decide what to do with the result.
The AgentScan lane
AgentScan names two different things, and the difference matters.
In the app, AgentScan is a read-only screen over your own history: every activity row the agent produced across your wallets, filterable and paginated, read from your local Postgres. That screen sends nothing anywhere.
Outside the app, AgentScan is also a public activity explorer, and Vex ships a reporting lane pointed at it. The ingest URL is a config value (services.agentscanApiUrl) and it ships set to https://agentscan.projectvex.ai, so on a default install the lane is live. There is no in-app toggle for it. Here is exactly what that means.
- What it sends. One event per committed activity row, drained from a local outbox on a 30-second tick: kind, status, protocol, chain ids, token addresses and symbols, requested and executed amounts, USD estimates, the transaction hash, a failure code from a closed list, and timestamps.
- What it cannot send. Each event is assembled field by field from a named allowlist, with no spread and no passthrough, so your wallet address, the sending address, the session id, the nonce, free-text failure reasons and route provenance have no line that reads them. Prompts, transcripts and memories are not part of the contract at all.
- Who you are to it. The install identity is a random value, never derived from key material. Binding is a signed challenge rather than a blind message: the trading key signs a server-issued nonce to prove the install owns the wallet addresses it binds, which does mean the server learns those addresses at binding time even though individual events never carry them.
- How it behaves. HTTPS only (localhost is the single exception, for local development). It is off the money path: no handler waits for it, a dead server just accumulates outbox rows, and it never sends a transaction or spends anything.
A transaction hash is public on chain and resolves to the address that sent it. So treat a reported activity as public: the event body carries no address, but the chain does.
What actually leaves your machine
| Traffic | When | Why |
|---|---|---|
| OpenRouter | Every agent turn | Inference, on your own key |
| Chain RPC and protocol APIs | Reads, quotes and broadcasts | The work itself: 11 protocol integrations, listed on Protocols & tool counts |
| AgentScan ingest | Every 30 s, when there is committed activity to report | The public activity explorer, on the allowlisted contract above |
| Tavily / Rettiwt | Only when research tools run | Web and X research, on your own keys |
| HuggingFace and container registries | First run, and on image updates | Pulling the pinned images and the embedding model |
| GitHub Releases | Update checks | See Verify a build |
| Sentry | Only if you opted in | Scrubbed crash reports |
Not on that list, and never on it: your master password, your private keys, your vault, your transcripts, or your memories. See Keys & encryption for how the first three are protected at rest.