Platform

Who can reach what, from evidence.

Every agent, subagent, scheduled job and connector on your Mac is a row. Every capability the doctrine cares about is a column. Each cell names the evidence it came from, because a permission list is a thing a tool wrote about itself.

Rows are what can act

The agents themselves, their profiles, subagent definitions, scheduled jobs and connectors — named for the tool rather than the activity, because the first question a roster answers is what this is.

Columns are what it costs

Files, shell, code runners, network, delete, secrets, originals, connectors — ordered by consequence, with originals and secrets first.

Cells name their source

A permission entry, a profile file, an agent definition, a launch agent, a connector declaration, an app's entitlements, or what macOS actually allowed.

Config is what a tool chose to say about itself

So the roster reads past it three ways, and the three disagree often enough to be worth reading separately.

Connectors

MCP is the common denominator and every tool keeps its list somewhere else. One scan covers Claude Desktop, Claude Code — including the per-project lists in ~/.claude.json — Cursor, Windsurf, Continue, Zed, VS Code and Codex. A server declared in two tools is one row that says so.

Entitlements

An app's code signature is readable with no permission at all and is vendor-independent: it says what the app may ask macOS for. These land as their own state — declared, not confirmed. An entitlement is a request, not a grant, and calling it granted would be a lie with a colour.

TCC

What macOS actually allowed. Read-only and immutable, so nothing is written beside a system database. Entitlements and TCC disagree in both directions, which is the reason to read both.

It reads what is loaded, not only what is declared

The gap between those two is where the interesting things live. A server running with no local declaration at all, started by an app whose connector list lives elsewhere, is listed, flagged and marked RUNNING. Candidates have to look like a package name or they are discarded — a command line carries tokens, paths and JSON — and the several spellings one server appears under collapse to a single row.

Three rules that keep a cell honest

  • A deny narrows a capability; it does not remove one that is also granted. Reporting shell: denied because Bash(tccutil:*) sits in the deny list would read as though the agent cannot run commands, when it plainly can.
  • An entry naming an original is about originals, however it is spelled. A Read() of the screen-history store is not a file permission.
  • A row nothing local can see reads “not visible here”, not blank. The ChatGPT app's tools and connectors are configured inside the app and on its maker's servers. An empty row would say reaches nothing, and the truth is the opposite.

The trade, stated rather than buried

Reading TCC needs Full Disk Access. Mockingbyrd has to hold the broadest read on the machine in order to report who else holds it.

It asks for nothing on its own. Without the grant every row stays at declared, not confirmed, and the app offers a button that opens the settings pane. Granting stays your act, because macOS does not let an app grant itself this — which is the point.