Everything Mockingbyrd measures stays on your Mac, stored as plain JSON you can read, and nothing it measures is ever sent anywhere. Two requests can leave, both switchable off in Settings. The update check fetches a static file from the download site to compare version numbers and carries no identifier. Crash reporting is off by default — not started, not sampled, not pinged — and sends a stack trace only once you turn it on.
What it does
Install
Apple silicon, macOS 14 or later.1
Download it
mockingbird.marcobuhlmann.com — the button on that page serves the current build. The line beneath it reads the version, size and build straight from the published file, so what it says is what you get.
2
Open the disk image
Drag Mockingbyrd onto Applications. It is signed with a Developer ID and notarized, so it opens on a double-click — no trip to System Settings, and no clicking past a warning.
3
Apply the guard fix
Open Doctrine and apply the fix beside The T0 guard hook is installed. Until you do, Mockingbyrd measures your Mac but enforces nothing.
If you would rather check the file than trust the page:
/download/latest.json carries the version, commit, byte count and SHA-256 of the image being served. shasum -a 256 Mockingbyrd.dmg should match it, and spctl -a -t open --context context:primary-signature -v Mockingbyrd.dmg should answer source=Notarized Developer ID.From source
Requires a Swift toolchain (Xcode 16 or later).make-dmg.sh signs the app and the image with a Developer ID, submits them to Apple and staples the ticket, when a certificate is in the keychain; without one it still builds, and says so. The build stamps the repository into the bundle: the commit count as the build number, the short hash as the thing that identifies a build exactly. Settings shows both, along with whether the guard hook on disk matches the app that installed it.
Headless use
You can run Mockingbyrd from a shell or a cron job:--context prints the allow-listed JSON a copilot may see, --projection-script prints the P2 narrowing without installing it, --price-routine writes the script that checks public price lists, --prune-log strips payloads from older audit entries, and --restore-pack resets built-in rules while keeping your custom ones. Run --help for the full list.
Trial and licence
Mockingbyrd runs for seven days with nothing held back. After that it needs a licence.What stops, and what does not
When the trial ends the app keeps showing everything it has already measured — the score, every control and its evidence, the roster, the ledger — and stops being able to change anything on the Mac. Scans, fixes, rule edits, enforcement changes and cap changes are locked, and each refusal says what still works rather than failing quietly.The guard keeps enforcing. The T0 guard is a hook on disk that Claude Code invokes directly. It keeps blocking exactly what it blocked yesterday whether or not this app is licensed, running, or even installed. Nothing on your Mac becomes less safe because a date passed.
Activating
There is no activation server. A licence is a small signed file, checked against a key compiled into the app, so activation works offline and keeps working when nothing is reachable.1
Find your machine code
Settings → Licence shows a code like
BE6A-8F77-FE96. It is a digest of this Mac’s hardware identifier, not the identifier itself — a tool that reported machine identifiers in the clear would be the sort of thing this app exists to catch.2
Ask for a code
Use the form at mockingbird.marcobuhlmann.com — it asks for an email address and nothing else. Settings → Request a code opens it for you. Reply to the mail you get back with the machine code above and the licence is tied to that Mac; without one it runs anywhere.During the test phase codes are issued by hand, so allow a day. There is no checkout, no account and no payment flow in the app.
3
Paste it in
Paste the licence into Settings → Licence and click Activate. A licence that does not verify is refused and changes nothing, so a bad paste cannot displace one that works.
A modified copy cannot be activated
macOS already refuses to launch a Developer ID build whose bundle has been edited, and nothing an app does about itself improves on that. What Mockingbyrd adds is narrower: re-signing a build with a different certificate is the ordinary way to get a modified one past Gatekeeper, and a copy signed by anyone other than the publisher will not accept a licence. It still runs, still measures, still shows everything it can see, and says plainly why it will not activate. If that check cannot run at all, the copy is treated as genuine. This layer must never be the reason somebody cannot use a licence they paid for.From a shell
--scan, --roster, --ledger and the rest keep working after the trial ends. --preset, which writes caps, does not, and exits 3 saying so.
Checking it
scripts/check-licence.sh runs the shipping binary against a throwaway home directory — 30 checks covering the trial arithmetic, a clock wound backwards, a lost trial record, a forged payload, a licence issued for another Mac, an expired one, rubbish input, what an expired trial does and does not stop, and what a re-signed copy refuses.
Updates
Mockingbyrd asks the download site once per launch whether a newer build exists. That request is a GET for a static JSON file. It carries no licence, no machine code, no version and no identifier of any kind, and it downloads and installs nothing — it compares two version numbers and offers a link. It is a switch in Settings, and turning it off makes the app silent on the network again — unless you have also turned on the other one.Crash reporting
A signed build that falls over on somebody else’s Mac leaves nothing behind to read. Mockingbyrd can report a crash to Sentry so it can be fixed, and this is the one part of the app that sends anything about what happened on your machine — so it is off, and off means not started. Once it is on, a report carries the error and its stack trace, this build’s version and commit, your macOS and hardware version, and basic performance timings. What it does not carry, and why that took verifying:
The first two were found by sending a real error and reading what arrived, not by reading the SDK’s documentation — both were present despite
sendDefaultPii being off.
One thing cannot be removed from the app side. Sentry sees the address a report arrives
from, as any web request does, and derives an approximate country from it. Switching that off
is an organisation setting in Sentry — Security & Privacy → Prevent Storing of IP
Addresses — not something the SDK controls. The switch in Settings says so rather than
claiming more privacy than the app delivers.
The eight screens
Grouped in the sidebar as Posture, Control and Spend.Overview
Coverage, then Start here — the three controls worth doing next, each marked whether Mockingbyrd can apply it or it needs you. Below that the doctrine’s sections in order: §0’s numbers measured live, §2’s direction of travel, N1–N7 and P0–P5 at a glance, and every open finding ranked by what it costs.
Doctrine
Every control, filterable. Each one shows its evidence, its editable probe, its proposed fix and its results from the last 24 scans.
Monitor
Score over time, config fingerprints, and a timeline of drift, fixes, drills and enforcement changes.
Enforcement
Install and register the guard. Enforce, pause or stop it, switch individual layers, and view the end of the audit log.
Drills
The six P5 exercises and their pass conditions. Recording a run here satisfies the rules that depend on drills.
Token Ledger
What your agents would have cost at API rates, by model, project and week. Rebuilt from session files already on your Mac.
Agent Roster
Who can reach what. A map of every agent around a hub, wired to the capabilities it actually holds, with a matrix behind it.
Settings
Interface mode, scan cadence, what happens when the guard refuses something, the projection scope and the rule pack — plus your licence, the update check, crash reporting, and a way to reopen the tour.
Two modes
The same data, twice.Nerd Mode
The screens above — probes, evidence, weights, and the full roster matrix.
Intuitive
Plain language over identical numbers: areas instead of invariants, a card per finding, and the roster map without the matrix.
Fixes are scripts, deliberately
The doctrine’s N3 says an agent’s output is only a proposal, and you are the one who applies it. Mockingbyrd follows the same rule:1
Prepare script
Writes the change to
~/agent/work/mockingbird/fix-<rule>-<timestamp>.sh and shows you the whole script.2
Apply
Runs that same file after you confirm. Nothing is written until you press it.
sudo, timeout 30, an absolute path or -c. It keeps the spelled-out commands that N5 tells you to keep. Moving outbound network access to ask leaves narrow WebFetch(domain:…) grants alone. No fix deletes anything: removing the guard renames it with a timestamp.
Enforcement in one paragraph
Settings alone are not a real boundary on a single-user Mac. The one control Mockingbyrd actually holds is aPreToolUse hook at ~/.claude/hooks/t0-guard. It checks each tool call for T0 paths and destructive commands like rm -rf, DELETE FROM, DROP TABLE and --force, no matter which interpreter would run them. It reads the command and the paths the call touches, not the file contents the call carries. Registering the guard adds it alongside your existing hooks. The guard reads ~/.config/mockingbird/enforcement.json on every call, so pausing works right away and a timed pause ends by itself.
Read the enforcement guide
Storage
Plain JSON, stored locally. Nothing Mockingbyrd measures leaves the machine.~/.claude/projects and ~/.codex/sessions and writes nothing back to either. Its cache holds token counts only, keyed by file size and modification time — prices are applied on read, so editing prices.json re-prices your history immediately.
The rule pack is written once, on first launch, and Mockingbyrd never reads it from the app binary again. That way your edits survive upgrades. To pick up new built-in rules after an update, use Settings → Restore built-in pack. Your custom rules are kept.
Limits
Mockingbyrd runs as your user. An agent with a general-purpose interpreter can reach anything your user can reach, including this app. What the controls buy you is that a mistake takes more separate steps, and you can see each one. That lowers the risk, but it is not a boundary. For a real boundary, use a second macOS user account that owns~/agent/, or a virtual machine.
Mockingbyrd also can’t stop context from leaving your Mac. Anything an agent reads is sent to a model provider. Narrowing the screenpipe projection (P2) is the only control here that affects that, so take it seriously.
Next steps
Architecture
How scans run, how scoring and drift work, the projection scope, and how to write a probe.
Enforcement
Installing the guard, what it blocks, and how pausing works.
Rule reference
All 58 controls with their tier, weight, type and fix.
Agent Roster
Who can reach what, and where each cell’s evidence comes from.
Token Ledger
Token use and API-equivalent spend, and how prices stay current.
