Skip to content

Desktop app polls raw.githubusercontent.com every ~10 minutes, downloading 25–145 MB to refresh a 1.9 MB models.json (~21 GB/day, 24/7) #26068

Closed as not planned

Description

@fodurrr

Description

The OpenCode Desktop app (ai.opencode.desktop v1.14.29) downloads 25–145 MB from raw.githubusercontent.com every ~10 minutes, 24/7, while only writing a 1.9 MB local file (~/.cache/opencode/models.json). On a residential connection this is roughly 21 GB/day, ~630 GB/month of effectively wasted egress — mine, GitHub Pages/Fastly's, and my ISP's.

The pattern starts when the Desktop app is launched and stops when it is killed. Closing the app (no other config changes) made the rhythm vanish from my gateway chart within ~10 minutes.

I noticed this because the periodic load was visible as a clean 10-minute sine wave on my router's WAN throughput chart for the last few days. I traced it through packet captures and process inspection.

Evidence

1. Identified process and live connection

While the rhythm was active, lsof -nP -i 4 showed (PID + username redacted):

OpenCode  <pid>  <user>  TCP 10.x.x.x:62092 -> 185.199.108.133:443 (ESTABLISHED)

The destination IP is in GitHub's documented Fastly range 185.199.108–111.x, which serves both GitHub Pages and raw.githubusercontent.com. DNS confirms raw.githubusercontent.com resolves to exactly that IP set.

2. Per-burst pcap (gateway WAN, 40-sec window)

Top conversations during one captured burst (post-NAT WAN view):

Local         <-> Remote                   Bytes IN    Time slice
192.168.1.1   <-> 185.199.110.154           25 MB     t+30 -> t+40 sec
192.168.1.1   <-> 185.199.108.153            7 MB     t+25 -> t+28 sec

Bytes/sec timeline showed the line idle (~10 KB/s) for ~25 sec, then sustained ~2.5 MB/s (≈20 Mbps) for 10+ seconds to those IPs. Pure download, ~309 Kbps reciprocal upload (TCP ACKs only). No other host on my LAN had any conversation with 185.199.108–111.x during the window — definitively the OpenCode Desktop process.

3. Per-cycle volume (gateway 5-min site WAN counters)

Bucket (UTC)   WAN-RX MB
12:55          170.7
13:00           10.6   <- trough
13:05          145.0   <- peak
13:10           35.6
13:15          143.3
13:20           18.9
13:25          138.0
13:30           20.3
14:05          135.9
14:10           18.1
14:15          147.4
14:20           21.1
14:25          134.0
... (continues for 24+ hours unchanged)

Period: ~10 min. Peak buckets average ~140 MB. Trough buckets ~25 MB.

4. Disk artifact

Inside ~/.cache/opencode, the only file modified during the active period was:

~/.cache/opencode/models.json   1.9 MB
  size      = 1,884,486 bytes
  mtime     = May 6 16:12 local
  birthtime = Apr 11 (when OpenCode was first launched)

All other ~6,991 files in the 84 MB cache directory had old mtimes (one-time downloads of LSP servers, language tooling, etc.). Only models.json is being refreshed periodically.

models.json contains the registry of 117 LLM provider entries (Anthropic, OpenAI, Alibaba, AWS Bedrock, Azure, Perplexity, Scaleway, Siliconflow, etc., each with id / env / npm / api / name / doc / models fields) — the upstream appears to be the models.dev registry, also maintained by anomalyco (anomalyco/models.dev).

This is worth highlighting because anomalyco controls both ends of this loop — both the producer (models.dev) and the consumer (opencode). The fix can land on either side or both.

5. models.dev already has cache-revalidation built in, but OpenCode is bypassing its own CDN

https://models.dev/api.json is Cloudflare-fronted and returns proper headers:

HTTP/2 200
content-type: application/json
cf-cache-status: HIT
cache-control: public, max-age=0, must-revalidate
etag: "8bfd6079fcad9656d242d5d1ee8be061"

That ETag + must-revalidate pair is exactly the contract designed for If-None-Match → 304 Not Modified flows. A client that sends a conditional request gets a few-hundred-byte revalidation response when nothing has changed, instead of the full 1.9 MB body.

But OpenCode is not hitting models.dev — the pcap and DNS lookup show it hitting raw.githubusercontent.com directly (Fastly IPs 185.199.108–111.x). That bypasses anomalyco's own Cloudflare-fronted CDN entirely and goes to GitHub's raw-file endpoint, which:

  • is more expensive for GitHub/Fastly (no aggressive Cloudflare-side caching of mirrored content),
  • still supports If-None-Match if the client sends it (raw.githubusercontent.com does return ETag), but apparently OpenCode isn't sending it,
  • and is generally discouraged for high-volume polling — there are GitHub docs cautioning against using raw URLs for production traffic at all.

6. The damning ratio

  • Downloaded per cycle (peak): ~145 MB
  • Persisted on disk: 1.9 MB

That's a ~76× amplification between bytes-on-the-wire and bytes-actually-kept. Plausible mechanisms:

  • The app fetches per-provider blobs for all 117 providers and consolidates client-side into a single 1.9 MB digest, discarding the per-provider payloads.
  • The app re-downloads the same content with no cache validation, getting 200 OK every time instead of 304 Not Modified.
  • The poll interval (10 min) is far more aggressive than the data could possibly need (the registry changes maybe once a day at most).

7. A/B confirmation

Closing the Desktop app (no config changes) caused the rhythm to vanish from the gateway chart within ~10 minutes. (Screenshots of the before/after gateway chart can be supplied on request.)

Why this matters

  • Users: ~21 GB/day on residential connections — invisible bandwidth waste, and on metered/throttled connections (or struggling ISPs, or those using SQM that is forced to deprioritize this churn) it actively degrades other traffic.
  • Project: GitHub Pages / Fastly egress is being burned on cache-miss responses that could trivially be 304 Not Modified.
  • GitHub: they are paying Fastly egress for this. Multiplied across the user base, it is non-trivial.

Suggested fixes (in rough order)

  1. Switch the fetch URL from raw.githubusercontent.com/anomalyco/models.dev/... to https://models.dev/api.json (or whichever endpoint already exists on the Cloudflare-fronted host). That site is yours, has the right cache headers, and is the documented public API for the registry.
  2. Honor HTTP cache validators. Send If-Modified-Since / If-None-Match on the periodic refresh; treat 304 as success. With models.dev's ETag this would eliminate >99% of the bytes — and even on the current raw.githubusercontent.com path it would help substantially.
  3. Lengthen the poll interval. 10 minutes for a registry that changes daily-at-most is wildly aggressive. Hourly or daily would be plenty for the UX of "model list is fresh".
  4. Make the interval configurable in opencode.json (something like "modelsRegistry": { "refreshInterval": "1h" } or "never"). Currently the config docs only document a startup-time autoupdate flag with no equivalent for this background poll — the behavior is not documented at all.
  5. Don't refetch unchanged per-provider blobs. If the consolidated registry's hash hasn't changed, skip per-provider fetches.
  6. Document the behavior in the config docs so users at least know it exists.

Plugins

None.

OpenCode version

Desktop bundle ai.opencode.desktop v1.14.29 (embedded CLI also 1.14.29). Standalone CLI installed via mise is v1.14.39 — I have not verified whether the same loop exists there.

Steps to reproduce

  1. Install OpenCode Desktop on macOS (/Applications/OpenCode.app, ai.opencode.desktop v1.14.29).
  2. Open it and leave it running. No other interaction needed.
  3. Observe WAN throughput on a network monitor (e.g. UniFi).

A near-perfect 10-minute periodic envelope appears, peaking at ~4 Mbps averaged across 5-min buckets (≈20 Mbps line-rate during the actual ~10-second burst), continuing 24 hours per day for as long as the app is running.

Screenshot and/or share link

Screenshots of the WAN throughput chart showing the periodic envelope (and the same chart flattening after I quit the app) can be attached on request — they come from a gateway dashboard with some private info I haven't yet cropped out.

A 40-sec gateway WAN pcap during one full burst is also available on request.

Operating System

macOS 26.3.1 (Tahoe), Apple Silicon

Terminal

Ghostty (incidental — the bug is in the Desktop app, not a terminal session)

Activity

  1. github-actions commented on May 6, 2026

    @github-actions
    Contributor

    This issue doesn't fully meet our contributing guidelines.

    What needs to be fixed:

    • This issue does not use one of the required issue templates (Bug Report, Feature Request, or Question). Please re-submit using the appropriate template.
    • The issue was explicitly noted as being filed via an AI tool ("Filed via Claude Code"). AI-generated walls of text are not acceptable per our contributing guidelines. Please rewrite this in your own words, keeping only the essential reproduction steps and evidence.

    Please edit this issue to address the above within 2 hours, or it will be automatically closed.

    If you believe this was flagged incorrectly, please let a maintainer know.

  2. github-actions commented on Jul 8, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions