# agent-zed — Privacy Hardening agent-zed is a private, **no-phone-home** fork of Zed. It drives vendors' own logged-in agent CLIs (Claude Code, Gemini) over ACP plus a local vLLM backend. It must never establish a Zed identity, send telemetry, upload crashes, check for updates, or make any unprompted network call to Zed-operated (or Zed-adjacent) infrastructure. This document records what was removed/neutralized and how it was verified. ## Threat model / goal - No automatic sign-in; no Zed account is ever established. - No telemetry, analytics, or usage events leave the machine. - No crash/minidump upload. - No auto-update or contact with release servers. - No unprompted startup fetches to Zed-operated endpoints. - Expected, allowed traffic: the federated agent processes the user explicitly drives (e.g. `npx` ACP agents) and the local vLLM backend on localhost. These are the vendor's processes, not agent-zed phoning home. ## Changes ### A — Sign-in removed - `crates/zed/src/main.rs`: `authenticate()` is a no-op — no automatic sign-in/connect at startup, so no Zed identity is established (this was the real phone-home). - `crates/title_bar`: removed the Sign In button + now-unused bindings. - `crates/onboarding`: removed the Zed-cloud "Zed Agent" promo + `SignIn` action. The dangling `onboarding::SignIn` keybindings were also removed from the three default keymaps (a removed action left bound = startup keymap-validation panic). - The `client` crate stays compiled but signed-out; collab/CRDT is retained for later self-hosting against a non-Zed server. ### B — Auto-update removed entirely Updates are a wholesale uninstall + reinstall; there is no in-app updater. - Deleted the `auto_update`, `auto_update_ui`, and `auto_update_helper` crates and all usages (menus, title-bar affordance, activity indicator, init). - This closed a **residual egress** that the earlier poll-neuter missed: `auto_update` still contained live calls to Zed release servers (`download_remote_server_release` / `get_release_asset`), reachable via "Check for Updates" and the SSH remote-server download path. - `remote_connection`: remote-server auto-download is stubbed to a clear "disabled in agent-zed" error instead of silently fetching from Zed. - Windows packaging was updated to match: `script/bundle-windows.ps1` no longer builds/copies/signs `auto_update_helper`, and `zed.iss` drops the `{app}\tools` and `{app}\updates` directories (auto-update installer artifacts). ### C — Telemetry neutralized - `crates/client/src/telemetry.rs`: `send_event()` is a no-op, so every `telemetry::event!` call site across the tree is inert with a single edit. Nothing is queued, recorded, or sent. ### D — Crash upload disabled - `MINIDUMP_ENDPOINT` is forced to `None` (ignores build/runtime env), so the upload paths in `reliability.rs` are unreachable. Local minidump capture is unaffected. (Runtime log confirms: "Minidump endpoint not set".) - `RefreshLlmTokenListener` is inert (no sign-in event to trigger a Zed cloud token refresh). ### E — ACP agent-registry auto-fetch disabled The federation feature auto-fetched the ACP agent registry from `cdn.agentclientprotocol.com` at startup (registry index + icons). This is not Zed telemetry, but it is an unprompted launch-time request to Zed-adjacent infrastructure — exactly the egress this build avoids. - `crates/project/src/agent_registry_store.rs`: removed the startup auto-refresh in `init_global`, and made `refresh_if_stale()` a no-op (this was the path that actually fired, via agent-settings load and registry-agent connect). - The registry still loads from the on-disk cache, and the explicit, user-initiated `refresh()` (e.g. opening the Agent Registry page) still works. Only the automatic, staleness-driven fetch is gone. ### F — Egress backstop Belt-and-suspenders: even if some code path survived the removals above, it cannot reach a Zed host. - `crates/http_client/src/http_client.rs`: the four Zed-host URL builders (`build_zed_api_url`, `build_zed_cloud_url`, `build_zed_cloud_url_with_query`, `build_zed_llm_url`) now `bail!` instead of returning a URL. Any surviving caller fails loudly rather than contacting `api.zed.dev` / `cloud.zed.dev` / `llm.zed.dev`. ### Extensions - `assets/settings/default.json`: `auto_install_extensions` is empty by default (was `{"html": true}`), so the extension registry/CDN is not contacted at startup. Users opt in to extensions explicitly. ## Verification Method: launch the built `agent-zed` against a fresh `--user-data-dir`, then observe outbound connections with `lsof -nP -i -p ` and capture TLS SNI hostnames with `tshark -i en0 -Y 'tls.handshake.type == 1'` (Wireshark's ChmodBPF grants capture access without sudo). IP-based inference is unreliable here because Zed and the ACP CDN both sit behind Cloudflare anycast; SNI is authoritative. Findings across the hardening passes: - Zero connections to `*.zed.dev` (Zed's own infra) at any point. - The one persistent startup egress observed (~36 connections) was conclusively identified by SNI as `cdn.agentclientprotocol.com` — the ACP registry fetch, fixed in **E** above. - After E: **agent-zed makes zero outbound connections at idle startup** (0 established across repeated samples; no `cdn.agentclientprotocol.com`, no `*.zed.dev` in the SNI capture). Startup is network-silent. Re-run the check after any change touching networking: ```sh cargo build --bin agent-zed tshark -i en0 -f 'tcp port 443' -Y 'tls.handshake.type == 1' \ -T fields -e tls.handshake.extensions_server_name -a duration:26 | sort | uniq -c & ./target/debug/agent-zed --user-data-dir /tmp/azed-check . # expect: no agent-zed connections to *.zed.dev or *.agentclientprotocol.com ```