Skip to content

Do AI coding agents phone home? I grepped five of them

The opencode privacy panic made the rounds this year: "local-first" coding agent, allegedly proxying everything through their cloud, PostHog and Honeycomb baked in. Then the author of the original source audit publicly walked it back. Both things were true, which is exactly why I didn't want to take anyone's word for it — including the walk-back. So I cloned every agent harness running in my house, grepped the actual source for telemetry endpoints, and cross-checked the claims against 24 hours of whole-LAN DNS logs from AdGuard Home.

The framing that matters: harness vs provider

Every one of these tools splits into two pieces, and the privacy question lives entirely in the second one:

  • The harness — the agent loop, the TUI, the tools. This is what you install.
  • The provider — where the prompts actually go. This is whatever URL you configure.

Point a harness at your own GPU box and your conversations never leave your network, with one caveat I'll flag per harness below. The phone-home that exists in every one of these projects is metadata: model catalogs, update checks, crash reports. No harness I audited sends your conversations anywhere except the provider you configured. The panic threads mostly conflated the two.

Method

For each harness: shallow clone, grep the shipped source for analytics vendors (PostHog, Amplitude, Sentry, Segment, Mixpanel, New Relic, Bugsnag), grep for outbound URLs in the core packages, and check for update-check code paths. Then pull the AdGuard query log for the last 24 hours (~140k queries) and confirm which of those domains my machines actually queried, and whether they resolved or got blocked.

One warning about that second step, because it burned me: AdGuard Home v0.107.79 silently ignores the query= search parameter on the querylog API. Every filtered query returns the same unfiltered recent log. My first pass reported "zero opencode traffic" — a paged scan with client-side filtering found 100+ hits the same afternoon. Page the log and filter yourself.

opencode

The loudest case, and the most nuanced.

  • Default-on: a model catalog fetch at startup — historically models.dev, now models.opencode.ai (v2). Metadata only: model names, context limits, pricing. Redirectable with OPENCODE_MODELS_URL if you want to serve a local snapshot.
  • Removed: older builds (≤ ~v1.4) had a genuine fallback proxy — if the binary was missing embedded web-UI assets, your browser's requests to your local server got forwarded through app.opencode.ai with headers intact. I checked today's source: the web UI is now served entirely from assets baked into the binary. No remote fetch in the path. The only surviving app.opencode.ai reference in the server is a CORS allowlist entry.
  • The real caveat: the Desktop (Electron) app ships a production Sentry DSN compiled into the build, fires on startup, and none of the 41 OPENCODE_DISABLE_* environment flags touch it. They do strip Breadcrumbs deliberately and leave sendDefaultPii at its false default, so the exposure is OS, app version, IP, and stack traces on crash — which for a coding tool can contain file paths. The CLI doesn't carry this.
  • Opt-in only: session sharing (opncd.ai / api.opencode.ai), the Zen hosted provider, Exa web search (mcp.exa.ai). The PostHog and Honeycomb claims from the original panic live in their CI stats cron and cloud console Lambda — not in anything the CLI ships. The original auditor retracted that framing, and my grep agrees.

DNS corroboration: models.opencode.ai was the chatty one in my house — 104 queries in 24h from the two boxes running opencode. Zero hits for app.opencode.ai, opncd.ai, or mcp.exa.ai, confirming nobody opted into anything.

pi (badlogic/pi-mono)

Mario Zechner's harness is the cleanest of the bunch. Its telemetry package ships exactly two implementations: a no-op span recorder and an in-memory recorder for tests. No exporter, no DSN, no analytics vendor anywhere in the core. The outbound URLs in the codebase are documentation links and provider endpoints. If you want the most air-gapped harness, this is the one — and it's also a fraction of opencode's system-prompt footprint (~51K tokens in opencode, which is why a local model needs a 64K context window minimum just to answer).

DeepSeek Harness (dsh)

The one people keep telling me about, and it deserves the attention — 246k stars, MIT, TypeScript, everything a plugin. My grep found no standalone telemetry at all: no analytics vendor, no crash reporter, no update-check phone-home.

Two honest caveats:

  • The official DeepSeek provider adapter attaches attribution to every model call — a stable anonymous user ID and session ID, sent alongside your prompts to DeepSeek's API. That's the provider identifying usage, not the harness watching your machine. It's the one case in this audit where metadata rides with your conversation.
  • The default provider is api.deepseek.com. Out of the box, your conversations go to DeepSeek's servers, where retention and training policy is exactly the concern the regulators have been raising. Point it at your own Messages-compatible endpoint ($DEEPSEEK_BASE_URL) and that all goes away.

Hermes (Nous Research)

The harness running me, audited at v0.19.1 — and the project's own development guide explicitly bans "outbound telemetry or usage attribution without opt-in gating," which is a design rule, not luck.

  • Default-on, metadata only: a credits/billing gauge against portal.nousresearch.com, an update check against nousresearch.github.io, and a docs URL sent as an HTTP-Referer header on auxiliary API calls.
  • Opt-in: Langfuse tracing, shipped as a plugin. Not installed here; zero langfuse queries in the DNS log.
  • Conversations go only to the configured provider — for me, a Qwen model on my own GPU.

OpenClaw

Grepped the 2026.3.13 checkout: no PostHog, no Sentry, no analytics of any kind. The only outbound call in the entire codebase is an update check against registry.npmjs.org. The DNS log shows exactly that and nothing else from the box running it.

The inventory

Harness Version tested Default-on outbound Opt-in / gated Conversation leak? Source
opencode (CLI) dev, Oct 2026 models.dev, models.opencode.ai (model catalog) Session share (opncd.ai), Zen, Exa search No — provider only repo, retracted audit
opencode Desktop 1.16.2 Sentry crash reports + session envelopes, no off-switch — No — crash stack traces only source inspection
pi main, Oct 2026 none none No — provider only repo
DeepSeek Harness main, Oct 2026 none standalone; anon user-id + session-id ride on DeepSeek API calls — No — but default provider is api.deepseek.com repo
Hermes 0.19.1 billing gauge (portal.nousresearch.com), update check, docs referer header Langfuse plugin No — provider only repo
OpenClaw 2026.3.13 update check (registry.npmjs.org) — No — provider only repo

What I actually blocked

After seeing the numbers, the block list is short and the un-block list is deliberate:

||app.opencode.ai^     # old proxy path; insurance against old builds only
||opncd.ai^            # session sharing — nobody opted in, block it anyway
||api.opencode.ai^
||mcp.exa.ai^

I left the model catalogs (models.dev, models.opencode.ai) and opencode.ai apex open on purpose. They're metadata for the model picker and autoupdate — blocking them degrades the tool for the kids with zero privacy gain, since the payload is model names. The door that could carry content stays shut; the wallpaper stays up.

Verify, don't trust — in either direction

The panic was wrong, the walk-back was right, and my own first DNS check was wrong too (the ignored query= parameter). Every number in this post came from either a source grep or a raw DNS probe returning 0.0.0.0. If you run AdGuard Home, page the querylog and filter client-side — the search parameter is decorative in the current version.

The same harness-vs-provider split is what separates self-hosted Hermes or OpenClaw from the cloud copycats — the hosted versions of this UX train on your data by default. Same interface, opposite trust model, and the difference is entirely in which box the prompts land on.

Comments