Health and speed

Why something can't connect, speed tests, stutter, route history, outages and reports for your provider.

When something can't connect

kilobat why <host> (MCP: diagnose_connection) checks one host layer by layer from this Mac, without running curl or nc, so a strict profile can't block the check itself. It tries IPv4 and IPv6 separately, so a network whose IPv6 is broken, a common cause of agents that hang or keep reconnecting, gets a plain answer. It names the interface used, such as Wi-Fi, a phone hotspot or a VPN, and tries each one when there are several. It reports the proxy the system or its PAC file picks, and with --app, the HTTPS_PROXY in that app's environment, without passwords. With a VPN or proxy on, it compares the direct path with the tunnel. A private name sent to a VPN's own resolver says which one, and whether it answers. Code in a container, VM or remote machine has its own network: pass --context and the report ends with a command to run there. When a hosted service makes the request from its own servers, as Warp does for a custom inference endpoint, --context provider says when the target is private (localhost, a LAN or Tailscale address) and so out of their reach, even though it works from the Mac.

Give it the exact URL that fails, query included: it requests that URL, but every output shows query values as [redacted], so a signed download link stays private. It sends the request the way the app would: through the app's HTTPS_PROXY, the system proxy, or with --proxy <url>, a proxy address the app sets in its own settings. When that proxy works and direct connections don't, as on many company networks, it says so instead of failing; when direct connections work and the request through the app's proxy fails, it says the network is fine and the app's path isn't. A setting it can't read or go through, such as LM Studio's Hugging Face proxy switch for huggingface.co downloads, gets its own note citing what users reported, and the verdict then says the network reaches the host, not that the app's request works. Kilobat never changes another app's settings. A server that refuses HEAD gets one GET for a single byte, never a download. It follows up to five redirects, names the hop that fails and checks IPv4 and IPv6 for the host the redirects end at. With --app, it lists the app's open connections to that host or its proxy, says when they use another IP version or server than the fresh check, and looks again a few seconds later: a transfer that went quiet is reported as quiet, never as finished. The report records the app's name and version, the method it sent, the path it took and, with --failed-at, when the app failed beside when the check ran. A passing check means this request works from this Mac over that path now; it can't see how a transfer already under way is doing, so watch that with kilobat bandwidth <app>.

When the host or the app belongs to a service with a public status page, such as slack.com or GitHub, the check ends with a Status page layer saying what that page reports. If the page reports an outage and nothing on this Mac failed, the verdict leads with it: “Slack is down for everyone, not you”, with the incident’s title and a link. If this Mac’s own network failed, the outage is a side note. A green page is said as such. See Is it them or me? When the failure could be this network itself, a Network block layer says whether it blocks the site, and when the service refuses where your connection appears to be, a Region layer says so; either leads the verdict. See Blocked here, not down.

Why speed tests disagree

Kilobat's speed test sends one HTTPS connection at a time to Cloudflare's nearest data center, 8 seconds each way and 80 MB at most, and pings 1.1.1.1 before and during the transfers. Speedtest by Ookla, fast.com and macOS's networkQuality open several connections at once and pick their own servers, so on fast or distant links they usually show more. Choose 4 connections beside the test button in the Speed tab, or run kilobat speedtest --parallel, to see how much that matters on your connection. Each saved test keeps the Cloudflare data center, the number of connections, the link (Wi-Fi band, channel, signal and link rate, or Ethernet), the VPN it went through and how much other traffic this Mac moved meanwhile. History › Speed-test comparison, kilobat speed-compare and MCP compare_speed_tests set two tests side by side and list what differed, each with a note on how it changes a result. They list differences, not causes: other devices on your network compete too, and Kilobat can't see them.

Route history

Tools › DNS & LAN › Trace 3 times, or kilobat trace <host> --rounds 3, traces a route three times with three probes a hop and saves each trace. History › Saved routes combines every saved trace to a host hop by hop, like mtr: loss, best, average, worst and last delay, which hops changed routers and where lasting delay starts. A hop that skips replies while later hops answer is a router rate-limiting probes, not loss. For the local network alone, kilobat lan-test <device> runs five seconds of iperf3 against a device running iperf3 -s; install iperf3 yourself, Kilobat never installs anything.

Stutter test

Calls, game streaming and remote desktops can stutter while speed and loss look fine, because a ping spike of a few hundred milliseconds disappears in an average. The stutter test in Health pings your router (or the internet) every 50 ms for 20 seconds and draws every reply, spikes in rose, with the median, p95, p99 and worst ping. It tells you whether the spikes repeat at a regular interval, which often points to AirDrop/AWDL scanning, or come at random, which points to a busy network, interference or a weak signal. Many routers answer only about ten pings a second; Kilobat recognizes that pattern and doesn't count it as loss. With Pro, Compare with low-latency on runs the test again with AirDrop/AWDL paused and says whether it helped.

The low-latency pause turns off AirDrop, Sidecar and Universal Control for 15 minutes, 1 or 2 hours, or until an app such as your game or call quits, 4 hours at most. It always restores when the time is up, the app quits, Kilobat quits or the network changes, and on the next launch if the Mac crashed. macOS asks for administrator approval. Health’s Nearby panel also shows whether AirDrop’s radio is active and what uses it, your AirDrop visibility, and, when you ask, the Bluetooth devices that share the 2.4 GHz band with Wi-Fi.

The Wi-Fi menu lists your Bluetooth devices under the networks: click one to connect or disconnect it. A 2.4 GHz tag marks connected headphones, keyboards and mice that share the band with your Wi-Fi, with a shortcut to a known 5 GHz network. Below them is AirDrop, with its visibility, what is using the link and the low-latency pause. Bluetooth appears only after you choose Show Bluetooth devices, so macOS asks for access only then.

Is it them or me?

When Slack, Zoom or GitHub won’t load, the question is whether it’s your connection or theirs. Kilobat reads the public status pages of over seventy services people use on a Mac, AI providers included (see AI agents below):Zoom, Slack, Microsoft Teams Free, Outlook.com, OneDrive, Google Meet, Gmail, Google Drive, Docs, Calendar and Chat, Discord, GoTo Meeting, FaceTime, iMessage, iCloud, the App Store, Apple Music and Apple TV, Dropbox, Box, Notion, Airtable, Proton, 1Password, Figma, Canva, Miro, Linear, Asana, Jira, Confluence, Trello, Grammarly, Claude, ChatGPT, Perplexity, Cursor, GitHub, GitLab, Bitbucket, npm, Docker, Postman, Vercel, Netlify, Supabase, Cloudflare, Tailscale, Epic Games and Reddit. It maps each app by its bundle ID and each site by its domain. kilobat down --list shows every page and the address Kilobat reads.

It asks only when there’s a reason: when you open Health and your own line checks out, for the apps in front or moving data; when a connection check names a host or app with a status page; when a call froze beyond the router; and, once a minute, when an app with a status page keeps failing to open connections (connections stuck waiting for the server’s answer in two samples in a row) while your line is fine. Then it notifies you once per incident, such as “Slack is having an outage”, with a button that opens the status page. Each page’s answer is kept for three minutes, and it waits five seconds at most. Turn the notifications off in Settings › Monitoring › Tell me when a service I use is down. Outages show at the top of Health and in a Services row in the menu and the Overview, which appears only while a service you use has a problem.

Kilobat only repeats what the page says. It says a service is down for everyone only when its page reports an outage, and “not you” only when your own line checked out; when the page is green, it says the page reports no problems, and a page it can’t read is never taken as an outage. Some services publish no public status: Webex, Teams for work or school (its status is shown to admins), Spotify, Steam, WhatsApp, Telegram and Signal. Calls and sites in a browser are checked through a connection check, since Kilobat doesn’t see which site a browser tab is on. In the terminal, kilobat down slack, kilobat down github.com or kilobat down for the apps running now; agents use service_status. It’s free.

AI agents and model providers

Many AI status pages are split into parts, and Kilobat reads the part each app uses: Anthropic’s page has claude.ai, the Claude API and Claude Code, so a claude.ai outage doesn’t count against Claude Code, and an API incident that names Claude Code does. OpenAI’s page splits ChatGPT, Codex and the API; GitHub’s has Copilot apart from the rest; Cursor’s has the IDE and its CLI. When a page has none of the parts named, the whole page counts. Covered: Claude, Claude Code and the Claude API; ChatGPT, Codex and the OpenAI API; GitHub Copilot; Cursor and its CLI; Gemini Code Assist (which the Gemini CLI uses when you sign in with Google) and Vertex AI, from Google Cloud’s feed; Mistral, Groq, Cohere, Fireworks AI, Together AI, Hugging Face and Perplexity; Windsurf, Zed, Warp, Replit, Lovable, Bolt and v0.

Coding agents are matched by process (claude, codex, gemini, cursor-agent, copilot), and any app is matched by the API it connects to: Kilobat looks up the addresses of api.anthropic.com, api.openai.com, api.githubcopilot.com, api.mistral.ai, api.groq.com and the other providers’ API hosts once a connection is stuck, and keeps them for ten minutes. So an agent such as Aider, which uses whichever provider you set up, or an editor calling the Claude API, is caught too. When one keeps failing to connect while your line is fine and the provider reports trouble, the notification names both: “Claude Code: Anthropic reports an outage — not your connection.” An agent stuck on errors can ask for itself: kilobat down claude-code, kilobat down api.openai.com, or the MCP tool service_status; kilobat down claude and kilobat down openai list every part of that page.

Not covered, for want of a public feed Kilobat can read: Grok and the xAI API (its page refuses non-browser requests), DeepSeek, OpenRouter, Replicate (its status is now part of Cloudflare’s page), JetBrains AI, Kiro and Amazon Q (behind an AWS sign-in) and the Gemini API in Google AI Studio. Ollama and LM Studio run on your Mac.

Blocked here, not down

A green status page and a site that still won’t load can mean the network you’re on blocks it: a hotel or airport Wi-Fi, a school or office network, a mobile operator or a country’s rules. When a connection check, kilobat down or a failing app points that way, Kilobat measures it and says so, for example “Slack looks blocked on this network, not down: its name doesn’t resolve here, while a secure resolver returns its real address.” It names the kind of network (your home network as marked in Devices, mobile data or a phone’s hotspot, a public Wi-Fi that showed a sign-in page, or plain Wi-Fi) and suggests only neutral options: another network, mobile data or roaming, or asking whoever runs this one. Kilobat measures blocks; it doesn’t help get around them, and never suggests a way to.

What counts, and the control each needs:

  • DNS tampering. This Mac’s DNS says the name doesn’t exist, gives no answer, answers with an address no public service uses (0.0.0.0, 127.0.0.1 or a private address), gives the same address it gives a made-up name, or sends it to a server that can’t show a valid certificate for the name, while one DNS-over-HTTPS question to your trusted resolver returns a public address that can. A different address that shows a valid certificate, or sits in the same block of addresses, is a CDN choosing a nearby server, not tampering. A name that doesn’t exist for the trusted resolver either, DNS that fails for every name, a VPN’s or company’s split DNS for the domain, and names only private networks know are never counted.
  • A cut secure connection. The connection opens, then the TLS handshake is reset or goes silent as soon as the site is named, twice, while the same server answers when named as another site. A server that doesn’t answer any name, a second try that goes through, or a connection that never opens is an ordinary failure.
  • Nothing connects. None of the service’s addresses connect while the trusted resolver itself answers. This counts only when the service’s status page reports no problems, and the verdict says that an outage the page hasn’t reported yet would look the same.
  • Block pages. A plain-HTTP request answered with HTTP 451 or a redirect off the service’s own domain backs up one of the findings above; on its own it proves too little.

A Wi-Fi sign-in page, Kilobat’s own rules, Protection or kill switch, and an outage on the status page each explain a failure better, so none is reported as a block. With a VPN on, the checks go through it and the verdict says so: the block is on the VPN’s path, not necessarily this network.

Privacy. The DNS-over-HTTPS question goes only to your trusted resolver, Cloudflare (1.1.1.1) unless you pick Quad9 (9.9.9.9) in Settings › Monitoring or with kilobat settings block-check-resolver quad9, by its address, and only while a failure is being diagnosed: one question for the one failing name. The handshakes go to the service’s own addresses, and the made-up name is under example.com. Kilobat never checks lists of blocked sites and never scans in the background.

When an app with a status page keeps failing while its page reports no outage, Kilobat checks once an hour at most per service and network, lists the block under Services and sends one notification per service, network and day; turn it off with Settings › Monitoring › Tell me when a service looks blocked on this network, or kilobat settings block-alerts off. kilobat down slack makes one connection to each service you name and, when it fails, runs the same check; kilobat why slack.com or kilobat doctor slack.com add it as a layer. Agents get the same in the block field of service_status and diagnose_connection. It’s free, like the status pages.

Not available in your region

Some services, and some features such as AI tools in parts of the EU, aren’t offered everywhere, and the service itself refuses by where your address appears to be. That isn’t an outage and isn’t this network blocking it. Kilobat says so only from the service’s own answer over a verified connection: HTTP 451, or wording it was seen to use, such as OpenAI’s unsupported_country_region_territory, claude.ai’s regional page, Anthropic’s API error about unsupported countries, regions or territories, and the Gemini API’s “User location is not supported”. The verdict reads like “OpenAI says its service isn’t available in your region. Your connection currently appears to be in Germany,” with the country your public address is registered in (looked up the way kilobat ip --public does, through any VPN). When a VPN or a roaming eSIM puts that exit in another country, or this Mac’s time zone is set to another country, it says so. It states facts only and never suggests a way around a regional restriction, which can break a service’s terms; the options are the service’s list of supported countries and its support. Paste the error an app got with kilobat why api.openai.com --error '…', or error in diagnose_connection, to have it recognised.

A report for your provider

When the connection is bad, your provider or IT desk wants proof. In Health, the report button makes one from what Kilobat recorded on this network over the last 24 hours or 7 days. It covers outages, latency at the router and beyond it, ping loss, and speed tests against your plan, plus a check of the site that fails if you add one. Each finding says what was measured and where, never whose fault it is. Copy it as text for a support chat, or save or share it as a PDF. It leaves out your network’s name, every local IP and hardware address, device names and which apps used the network. In the terminal, run kilobat support-report --host github.com, or --html --output report.html for the page. Site names, URLs and their paths are left out by default, including those in redirects. Tick Include site names, or pass --include-sites in the CLI or include_site_names: true to MCP create_support_report, only when you want those names in the report. Public IP measurements from the site check remain.

Outage credit

Many providers owe a credit after a long outage, and some pay it without being asked. History › Outage credit adds up the month’s outages that Kilobat can show were on the provider’s side and checks them against your provider’s published rule. An outage counts only when your router kept answering Kilobat’s checks while two internet servers and an HTTPS check all failed, or when a Starlink dish logged it as Starlink’s network (no satellite, no reply). Outages at your own router or Wi-Fi, time a hotel or café Wi-Fi’s sign-in page held the connection, ones without enough checks to tell, and any time the Mac was asleep are left out and shown apart. The card shows the longest outage and the month’s total beside the rule’s threshold, and when a rule Kilobat has verified applies, what it may qualify for.

Pick your provider, or press Detect: Kilobat asks Cloudflare for your public address and RIPE NCC which network it belongs to, then matches that network to its list. Enter what you pay a month for internet for the estimate. The rules are bundled with the app, each with its source and the date it was checked: Ofcom’s automatic compensation for BT, EE, Plusnet, Sky, Virgin Media, Vodafone, TalkTalk and Hyperoptic (£10.34 a day once a reported fault isn’t fixed within two full working days), Germany’s § 58 TKG for every provider there, Spain’s Real Decreto 899/2009 and Italy’s AGCOM indemnities, and the published terms of Xfinity, AT&T Fiber and Internet Air, Orange and Free. For a provider without a rule Kilobat could verify, such as Spectrum, Verizon, Cox, T-Mobile Home Internet or Starlink, the card says you can still ask, with the same evidence.

Copy claim gives you a message in the app’s language with a placeholder for your account number, each outage’s date and length, what Kilobat measured, the rule and the amount; Open claim page takes you to where your provider takes it, and Save provider report attaches the measurements as a PDF. When a rule has a deadline to ask, such as Xfinity’s 120 days, Remind me sets a notification before it. Kilobat never sends anything. It counts from when an outage started, while providers count from when you report it and decide what qualifies, so it only ever says “may qualify”. With Settings › Monitoring › Tell me when an outage may qualify for a credit, Kilobat notifies once per outage, at most once a day. The card’s estimate, claim and notification are part of Kilobat Pro. In the terminal, kilobat credit shows the month, --draft prints the claim and credit providers lists the rules; agents read it through get_outage_credit.

Plan check

Find out whether you get the speed you pay for. Type your plan’s download speed for this network in Settings › Network › Plan speed, or under a speed test result. The Speed tab then compares the last 30 days of tests on that network with it: “You got 61% of your 500 Mbps”, the median, the evening median beside the rest of the day, and how often a test got under half the plan. Each network keeps its own plan, so the café doesn’t count against your home plan. With Kilobat Pro, turn on Settings › Network › Plan check and Kilobat runs a light test up to three times a day, at a different time each day and always one in the evening peak (7 to 11 pm), when providers are most often slow. A check uses 25 to 80 MB over four connections, about two seconds at your plan’s speed. It waits until no call is going on, no VPN carries the traffic, the Mac’s other traffic is low and it’s on power or above 50% battery, and it never runs on a metered network. The provider report leads with the month: “Over 30 days, 41 scheduled checks: median 305 Mbps of the 500 Mbps you pay for (61%); evenings 180 Mbps.” In the terminal, kilobat plan shows the same, and agents get it through get_plan_check.

Service speed

A speed test measures the way to a nearby test server. The services you actually download from, such as GitHub, iCloud, Steam, npm, Docker or Hugging Face, sit at the end of other routes, and your provider can have a congested link to one of them while the rest of the internet is fast. Kilobat measures the downloads you already make: every download of 5 MB or more, one service’s connections together, over the seconds they were moving. It names each by the site the app asked for (when the network filter runs), the app, a reverse DNS name, or the network its address belongs to, from the published address lists of GitHub, Apple, Valve, Dropbox, Akamai, Fastly, Cloudflare, Amazon CloudFront, Google and Microsoft bundled with the app. Nothing extra goes over the network. Video, music and calls are never counted, since they move at the pace they play, and nothing counts while a VPN carries your traffic.

Speed › Services lists each service on this network: its typical speed over 30 days, the latest download and its share of the line. The line is the latest speed test on this network, or the fastest download Kilobat saw there, whichever is higher. With Kilobat Pro, Health speaks up only when it’s clear: at least three downloads from one service in the last day under a third of the line, each with another site or a speed test at least three times as fast within the same hour, most of that service’s downloads that day slow, and the service not slow on every other network you use. Downloads crowded out by your own other downloads don’t count. “Your provider’s route to GitHub is slow tonight. 3 downloads from GitHub ran at about 7 Mbps while other sites got 267 Mbps within the same hour. The slowdown is between your provider and GitHub, not your Wi-Fi or this Mac.”

The evidence follows. When the service’s status page reports a problem, it says it’s likely them. Otherwise it traces the route to the service’s server once and says at which hop the delay jumps. With enough history it finds the hours it’s slow, such as every evening from 7 to 11 pm, the classic sign of a congested link between two networks at the busiest hours. Then what to try: a VPN or another DNS, which reach the service another way; telling your provider, as the provider report includes a section on it; or trying later.

Test this service downloads up to 25 MB from a public file the service offers for download, such as a GitHub release, Apple’s macOS restore image, an npm or PyPI package, or Cloudflare’s speed test, once, only when you press it, and never on a metered network. In the terminal, kilobat service-speed shows the table and the finding, --test github runs a test and --list shows the files; agents get the history through get_service_speed.