BLA
BLA (Blind LLM Agents) is the open-source Blue Defense MCP and CLI built to protect software artifacts against automated AI reverse-engineering workflows.
翻译准备中
Native macOS network monitor: every app's traffic to every domain, plus AI agent oversight with per-agent allowlists and tool/MCP server attribution. Free, open source (GPL-3.0), no telemetry.
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
Application-aware network monitoring for macOS, with focused visibility into AI agents.
A native macOS network monitor that attributes observed traffic to applications and destinations.
It highlights AI agent activity such as sensitive protocols, unfamiliar destinations, and large
uploads, with local history and explainable alerts.查看完整 README ↗Application-aware network monitoring for macOS, with focused visibility into AI agents.
A native macOS network monitor that attributes observed traffic to applications and destinations. It highlights AI agent activity such as sensitive protocols, unfamiliar destinations, and large uploads, with local history and explainable alerts.
Download for macOS · Website · Build from source · How it works
Your Mac now runs software that makes its own decisions. Coding agents read your files, run shell commands and call tools, and any of those tools can open a socket. Activity Monitor shows how much traffic there is. A firewall asks you to allow each connection. Neither answers the question that matters now:
What are my agents talking to, besides their model provider?
Flowlight answers that for observed application traffic, then provides additional context for recognized AI agents.
Flowlight recognizes 16 agents by name (Claude Code, Codex, Cursor, Windsurf, GitHub Copilot, Gemini CLI, Aider, Goose, Ollama, ZCode and more). It also classifies non-browser processes that contact one of 27 known LLM API providers. Provider contact is a classification signal, not proof that a process is autonomous or malicious.
For each agent you see which AI providers it uses, and everything else it contacted, including what its tools and MCP servers did:
Tools & MCP servers. Flowlight follows the process tree back to the agent that started each process, so the
curl, git push or npm install a Claude Code shell tool runs is counted as Claude Code's traffic, labelled
via curl. MCP servers are named from the agents' own configs (Claude Code, Claude Desktop, Cursor, Windsurf,
VS Code, Codex, Zed, Gemini CLI): via github MCP.
Allowlists. "Claude Code may talk to GitHub and npm, nothing else." Add domains (subdomains included), IPs or CIDR ranges, or start from a preset (GitHub, npm, PyPI, Homebrew, Docker Hub…). The agent's AI providers and your local network are always allowed; anything else raises an alert, and each destination has a one-click Allow.
Tool calls, from the model itself (optional). Turn on HTTPS inspection and Flowlight
reads every tool the agent offers the model, every call the model asks for (Anthropic, OpenAI, Gemini, and MCP
tools/call) and the result the agent sent back, then links each tool's request back to the call that caused it:
curl → paste.example ← Bash: curl -s https://paste.example/up. For MCP servers reached over HTTP it also records the
server's name and version and the tools it offers. Each agent's detail has Tool calls and MCP servers tabs.
What each agent is set up to do. With your say-so, Flowlight reads the agent configuration on this Mac — skills, subagents, slash commands, hooks (the shell commands they run on events), permission rules and MCP servers — and lists them per agent. A hook that posts to a webhook explains traffic you'd otherwise have to guess at. It looks only at the agent folders in your home folder, plus project folders you pick, and remembers the result instead of rescanning.
These rules watch every agent:
| Rule | Fires when an agent… | Severity |
|---|---|---|
| Allowlist violation | contacts anything not on its allowlist (when you've set one) | critical |
| Sensitive channel | uses email, file transfer, SSH or remote desktop, a tunnel or proxy, peer-to-peer, or a database connection | critical for email, file transfer, tunnels and P2P |
| Possible exfiltration | uploads more than 100 MB/hour to hosts that aren't AI providers | critical |
| Unnamed host | connects to a raw IP with no hostname on an unusual port | warning |
| Active while you're away | moves data after 15 minutes without keyboard or mouse input | warning |
| Fast learning | new destinations are flagged after a 1-hour learning period (24 hours for other apps) | info |
Every threshold is adjustable in Settings.
Off by default. When enabled, Flowlight runs a local proxy (127.0.0.1:8877) with a certificate authority created
on your Mac. For supported HTTP traffic routed through the proxy, it records headers, bodies, status and timing.
Answer a chosen host, path and method with your own status, headers, body and delay, to see how an agent copes when an API fails or returns something odd. Mock This… pre-fills retained, redacted headers and payloads: request data is reference-only, while the response can be edited as text/JSON or lossless hexadecimal for binary bytes. Saving persists only the matcher and authored response rule; it remains until removed even if captured traffic is cleared. The request is never sent. Mocked exchanges are recorded and clearly marked, so a session read later still shows what was real. Needs HTTPS inspection, since only decrypted traffic can be answered — and a mock changes the reply, not whether the connection can be made.
An allowlist warns by default. Turn on Refuse connections outside the list for an agent and Flowlight drops those connections as well, recording each one as an alert with Allow … from Now On to add it to the list in a click.
It needs the Network Extension — refusing a connection means being in its path, which the sampler can't do. Local traffic, DNS, essential Apple system services and Flowlight's own connections are never refused, and enforcement lapses a few seconds after the app stops running. When HTTPS inspection proxies an app, destination rules and enabled managed packs are decided against the original app before Flowlight opens the origin connection; agent allowlists still apply only on the direct Network Extension path.
An allowlist is one agent's idea of where it may go. A rule is the general version: it names a subject — an app, an agent, a destination, a URL, or a pairing of two of those — and says block or allow. Right-click any row in Live, Reports, AI Agents or Inspect to write one about what you're looking at; all of them land in the same editor on the Rules screen.
Flowlight includes three official hostname lists: Advertising, Cross-site tracking, and Privacy and telemetry.
Their baseline is built into the signed app for offline use and the app checks one fixed HTTPS source for newer
publisher-signed catalogs. Automatic checks are on by default and can be switched off in Rules › Packs; no traffic,
pack settings, or device identifier is sent. The server sees the Mac's IP address and Flowlight/<version> user agent.
All three packs are visible in Rules › Packs and off by default. A valid signature authenticates content but never grants enforcement consent: new packs remain off, and changed destinations disable that pack until you review the exact new version and press Save. A verified accepted catalog remains available as visible stale last-known-good during an outage; rollback, equivocation, revoked trust, or corrupt cached bytes fail closed. Enable a pack for every app or only selected apps; enforcement needs the Network Extension, because the sampler can observe connections but cannot refuse them.
Before enabling or broadening a pack, replay it against up to seven days of retained traffic to see which apps, destinations, connection counts and bytes would have changed. The activity feed groups repeated blocks instead of turning every ad request into a separate alert, while still naming the app, destination, matched list entry and pack. From any grouped event, add an exception for that app and destination in that pack. An ordinary allow rule remains the universal escape hatch, global Pause Blocking pauses packs too, and essential system traffic for accounts, push, updates, certificates and iCloud remains allowed.
These are hostname-level network blocks, not page or window cleaners. The tracking pack blocks documented dedicated
collection, replay and tracker-bootstrap hosts while keeping provider dashboards, login, billing, documentation and
administration reachable. When collection shares a product hostname—such as analytics.google.com/g/collect or a
Matomo tenant's /matomo.php—the hostname layer must allow it; HTTPS inspection may still apply an explicit URL rule
when the path is visible. First-party tracking proxies, ECH, QUIC, encrypted DNS, direct-IP connections and shared CDNs
can also limit coverage. Packs cannot remove first-party ads, DOM gaps, overlays, scripted popups or native app windows;
cosmetic filtering needs a browser extension that can see and change page content.
Which tools may this agent use is a different question from which hosts may it reach, so it gets its own tab in AI Agents: a switch on every tool the agent declares and every MCP server it reaches, presets (read-only, no shell, no writes), and a record of what has been taken away.
isError: true and a sentence, which is the
protocol's own shape for a tool that failed. resources/read gets a JSON-RPC error, which is its.Not all traffic goes to the internet. AirDrop, Handoff, AirPlay, Sidecar and Universal Control go straight to a device in the room over Apple Wireless Direct Link — no router, no internet, no address anyone else can reach. Flowlight was always counting those flows; it had no word for them, so an AirDrop of a 4 GB folder looked like a few megabytes to an address with no name.
Every flow now carries a channel: the network, peer-to-peer Wi-Fi, this Mac, or a tunnel. Narrow a report to one of them from the toolbar, and peer-to-peer rows are named by the feature that opened them — AirDrop and Handoff · nearby device — because a link-local address tells you nothing and the device has no name this Mac can learn.
The sampler reads the interface each socket is bound to, which is exact. The Network Extension is handed sockets rather than interfaces, so it judges by the address instead: link-local means peer-to-peer. That is the coarser of the two answers, and it says so.
macOS runs whichever build of the content filter was activated last, so after an app update the app and the extension can disagree — and then macOS refuses the connection between them. System Settings says Filter enabled, Flowlight says Extension connection invalidated, and neither changes its mind.
Flowlight climbs out of that on its own: redial twice, then ask macOS which build it has and reinstall the extension if it isn't this app's, then redial again — and if none of it works, capture with the nettop sampler so there is still data. It says which rung it is on and how long until the next one. Your chosen source isn't rewritten, blocking is switched off while the sampler stands in (the sampler can't refuse anything, and Rules shouldn't claim otherwise), and Try the extension again starts over.
A Mac sends and receives over more than TCP and UDP. The Devices screen covers the rest, with every channel off until you turn it on because watching more of your Mac should be a decision rather than something an update did.
Camera activity: whether each camera is active and when it started or stopped. Flowlight reads the public CoreMediaIO device state; it never opens a capture session, requests camera access, or reads frames. That signal does not identify the owning app, so Flowlight names the camera and does not guess. The sandboxed Mac App Store product carries Apple's camera hardware entitlement so it can see the device list, but still never asks for capture consent.
Bluetooth: which devices are paired, which are connected, when that changed, and which applications are built to use the radio. No byte counts — macOS keeps no per-app accounting for Bluetooth, and the traces that would give one need a profile an app can't read. The app list is who asked for Bluetooth, not who was granted it, and it says so.
USB and external storage: what is attached, what it is, and a drive's capacity, with the moment each arrived and left. Volumes arrive from the workspace the instant one is mounted; USB devices are read periodically. No throughput, for the same reason.
Ask in plain language and get an answer from what Flowlight recorded. What did Claude Code upload yesterday? Which app started talking to somewhere new this week? Summarise the last hour.
The model never gets your history. It is handed seven read-only queries it may call — totals, top apps, top destinations, new destinations, alerts, agents, a series over time — and nothing else. There is no query that takes SQL, and there will not be one. Flowlight runs whichever the model names, locally, and hands back the numbers.
It answers questions about Flowlight itself as well — how do I turn on HTTPS inspection?, why am I not seeing any traffic? — from the app's own guide to every feature and a snapshot of how this Mac is set up, never from the model's memory. And it draws a chart when the shape of the answer matters more than the numbers: a line for change over time, bars to compare, a pie for a split. Flowlight draws it from the rows the query returned, so the picture and the sentence come from one source.
Local first: the on-device model where macOS has one, or a server you already run (Ollama, LM Studio, llama.cpp). Both send nothing. Or bring your own key for Anthropic, OpenAI, Gemini or any OpenAI-compatible endpoint — the key lives in your login Keychain, the screen says when a question will leave the Mac, and every request is shown in full under the answer.
Every query is listed under the answer, and clicking one opens those rows in Reports. And Ask's own traffic shows up in Live like any other app's — including when the model is a server on this same Mac.
A third mode in Reports, beside the breakdown and the charts. It compares the apps in a report with each other and points at the ones whose destinations don't look like the rest — many more places than their peers, addresses that never resolved to a name, hostnames that look generated, far more sent than received, protocols that are a sideline rather than the app's purpose. Each finding shows its evidence; clicking one narrows the report to that app.
It's Worth a look, not Suspicious: the data supports "unusual next to the other apps here", and a backup tool talks to a lot of places for good reasons.
Flowlight keeps recording with its window closed and costs almost nothing while idle. Settings › General › Run in the background drops the Dock icon and the Cmd-Tab entry; the menu bar keeps the rates and offers Show Dock Icon to undo it. Quitting stops the sampler — it does not stop the Network Extension, which runs on its own until you disable it in Capture.
The window reopens where and how you left it; a first run fills the screen. Hostname setup is offered a little after launch and only while a window is open, rather than meeting a first run with a password prompt — and it returns next launch until taken or dismissed.
Pick a few apps and destinations and every screen shows only those — Live, Reports, Alerts, AI Agents and Inspect, plus the menu bar rates. It's for watching one agent work without the rest of the Mac in the way.
example.com covers api.example.com). IP addresses work; ranges don't.Per-app baselines (EWMA + z-score) for hourly volume and daily destination counts, 99th-percentile upload checks, first contact with a new domain, non-standard ports, and uploads from apps you haven't touched. Every alert names the app, the destination and the number that tripped it.
Off until you configure it, with no Flowlight-operated endpoint to send to — you name your own collector. OTLP over HTTP (rollups as metrics, alerts as logs) or newline-delimited JSON. The Settings panel lists every field that leaves and previews a real payload built from your own data first. Auth headers live in the Keychain. Nothing from HTTPS inspection can be exported — the payload types have nowhere to put a header or a body. What Flowlight sends appears in Live and Reports like any other app's traffic, including a collector on localhost.
No account, no cloud, no telemetry. Everything stays in a local SQLite database. Packet capture reads only DNS answers and TLS ClientHellos (a kernel filter drops everything else), and packet contents are never stored. Naming who owns an IP with no known hostname is on by default: it sends those public IPs (never private ones) to Team Cymru's DNS service, and you can turn it off in Capture. Release and official rule-pack checks make standard HTTPS requests with no traffic or pack settings; each has its own off switch in Settings or Rules › Packs. To attribute tools and MCP servers, Flowlight reads process command lines and your agents' MCP config files on your Mac; none of it leaves your Mac. HTTPS inspection is off unless you turn it on, and what it records stays in the same local database.
With Homebrew:
brew install --cask xinbetween/tap/flowlight
Or download Flowlight.dmg, open it, and drag Flowlight into Applications.
Releases are signed and notarized, so it opens straight away.
Prefer an installer? Every release also has a .pkg.
Launch Flowlight. Traffic appears within a second, and the ↓↑ rates live in your menu bar. After a clean quit and relaunch, Flowlight checks GitHub for a new release and opens its update window when one is available; it also checks daily. The check is optional in Settings, and any download is verified before Flowlight asks to quit and install it (Flowlight › Check for Updates…). Updating by hand? Quit Flowlight before dragging the new version in.
On first launch, Name Your Traffic offers the one-time setup that lets Flowlight read hostnames (it asks for your password once). Network-owner lookups are on by default and can be turned off there or in Capture.
Try it without your own data:
open /Applications/Flowlight.app --args -FLDemo YESlaunches with 90 days of synthetic traffic, including an inspected Claude Code session. That's what the screenshots show.
brew install xcodegen # project regeneration requires exactly 2.46.0
git clone https://github.com/xinbetween/flowlight.git && cd flowlight
scripts/check_xcode_project.sh --write # regenerate the committed shared Xcode project
scripts/check_xcode_project.sh # verify it still matches project.yml
scripts/build-local.sh # ad-hoc signed, no Apple account needed
open build/Build/Products/Release/Flowlight.app
scripts/build-dmg.sh # optional: drag-to-install disk image (build/Flowlight.dmg)
scripts/build-pkg.sh # optional: installer package
Requirements: macOS 15 or later, Xcode 16 or later. Internals and the Network Extension path are in docs/DEVELOPMENT.md.
flowchart LR
subgraph Capture
N[nettop sampler<br/>per-process byte counts, 1 s]
E[Network Extension<br/>NEFilterDataProvider, audit tokens]
end
P[BPF packet capture<br/>DNS answers + TLS SNI only] --> H[Hostname cache]
N --> B[Per-second batches<br/>app · host · IP · port · protocol]
E --> B
H --> B
B --> DB[(SQLite<br/>1 s → 1 min → 1 h → 1 day)]
B --> A[Anomaly + agent rules]
A --> AL[Alerts + notifications]
DB --> UI[SwiftUI + Swift Charts]
Two capture engines produce the same per-second summaries:
| nettop sampler (default) | Network Extension | |
|---|---|---|
| Needs | nothing | The Network Extension entitlement (paid developer account), app in /Applications, your approval |
| Attribution | process → app bundle | audit token → code-signing identity |
| Hostnames | TLS SNI + DNS from packet capture, reverse DNS, network owner | SNI, HTTP Host, system hostname, DNS |
| Short-lived flows | a connection that opens and closes between two readings is missed entirely | every flow, however brief |
| Byte counts | exact for anything alive across two readings — it compares running totals, so bursts aren't lost | from the filter's own statistics |
| Energy | starts a process every second | no polling |
What the sampler misses is whole connections, not bytes. It reads macOS's running counters once a second and records the
difference, so a long transfer is counted exactly however bursty it was. What never appears is anything that starts and finishes
between two readings — a quick DNS lookup, a fast API call, a script that runs curl and exits. For an agent that makes many short
requests, that is the difference between the two engines. The extension is called as each connection is made, so it sees those;
in exchange, traffic from before you enabled it isn't there and some system traffic is exempt from content filters.
Storage rolls per-second rows into minute, hour and day tables. Week, month and year views read the daily table, so a year of history stays fast.
Flowlight tells you what software on your Mac is sending and where. It is not a defence against an attacker who already controls the machine: anything running as root can unload its extension or stop the app. Blocking is real — the Network Extension refuses the connection before it is made — but it is control over software you already trust rather than a barrier against software you don't, and an agent that can run a shell can do by hand what a refused tool would have done. The threat model says what is defended, what is not, and why.
Shipped:
brew install --cask xinbetween/tap/flowlight, from 0.2.1)Planned, in order:
1.0 — What an agent did off the network. Flowlight can say that Claude Code uploaded 40 MB to an
unfamiliar host. It cannot say that it read ~/.ssh/id_rsa first, and that second half is the exfiltration
story: a file leaving is a read followed by a send, and only the send is visible today. This would record
what an agent's tools opened, wrote and spawned, and line it up against the connections that followed —
read the private key, then talked to paste.example as one finding rather than two screens.
It is not a resource monitor. CPU, memory and energy per process are Activity Monitor's job, done well and built into the Mac already; the only number of that kind worth having here is "this agent was busy while you were away", which belongs beside the away-activity alert rather than in a tab of its own.
Two things gate it, both stated here rather than discovered later. Per-process file attribution on macOS needs the EndpointSecurity framework, whose entitlement Apple grants on request and review — not a checkbox — and which only works from a system extension. And it would put far more sensitive material in Flowlight's hands than network metadata ever did, so the inspection budget in 0.9.3 stops being a nicety and becomes the thing that has to exist first. A tool that asks you not to monitor it has to deserve that twice over when it can see every file you open.
Later, no version yet:
/proc;
SwiftUI doesn't exist there.GetExtendedTcpTable. A bigger
commitment than Linux: three capture backends to maintain, and a thinner Swift ecosystem.Issues and PRs are welcome. Adding an agent, an LLM provider or a protocol is a one-line change plus a test. See CONTRIBUTING.md for local setup and contribution guidance.
Releases are deliberately not ordinary merges. main represents published software, while a release branch carries the
new version and generated site until a downloadable, verified build exists. Every release follows this order:
feature branch → release branch → reviewed green PR → immutable tag → signed dry run → publish and verify → merge to main
main, test it, and rebase it onto current main rather than merging main into it.release/<version> and make one final release commit containing the version bump,
release entry in site/pages/releases.html, and regenerated docs/ website output.main. Do not tag until it has been reviewed and every required check is
green.v<version> tag on that exact release commit. Tags are immutable: never retag, move or
force-push one. If it is wrong, issue the next patch release instead.SHA256SUMS.txt assets/checksums. Only then merge the release PR into
main, allowing GitHub Pages to advertise the downloadable release.The full commands, signing prerequisites and CI behavior live in CONTRIBUTING.md and docs/DEVELOPMENT.md.
Shared/ models, XPC contract, protocol classifier + catalog, SNI/HTTP/DNS parsers
FlowlightExtension/ NEFilterDataProvider system extension
Flowlight/
Capture/ nettop sampler, extension client, installer
Enrichment/ BPF packet capture, network-owner lookup
Storage/ SQLite store, rollups, queries
Analysis/ anomaly engine, AI agent catalog + rules
Inspection/ opt-in HTTPS inspection: local CA, proxy, HTTP parser, tool-call reader
UI/ Live · AI Agents · Reports · Alerts · Inspect · Capture
FlowlightTests/ 105 unit tests: parsers, BPF filter, rollups, charts, agents, MCP, allowlists, inspection, updates
docs/ website (GitHub Pages) and developer guide
Flowlight is free software under the GNU General Public License v3.0. You can use, study, share and modify it, and if you distribute a modified version, you must release its source under the same license.
Flowlight isn't affiliated with Apple or with any AI provider named here. Product names are trademarks of their owners.