docs · internals
Architecture#
bite is three cooperating processes on your Mac. The control plane is Rust: the MCP stdio server, the CLI, setup, doctor and the config writers. The native work happens in Swift — a helper installed once at a stable path, and a detached crawl worker that indexes Mail.Diagram source (Mermaid)
flowchart LR
subgraph callers ["agent / human"]
A["MCP client\nClaude Code · ZCode · Codex · …"]
H["terminal"]
end
B["bite (Rust)\nMCP stdio server · CLI · setup · doctor"]
B -- "line-delimited JSON" --> C
C["bite-helper (Swift, stable path)"]
C -- EventKit --> CAL["Calendar · Reminders"]
C -- Contacts.framework --> CON["Contacts"]
C -- ScriptingBridge --> SB["Mail · Notes · Messages"]
B -- "spawn + batches" --> W["bite-crawl (Swift worker)"]
W -- "NSAppleScript (OSA)" --> MAIL["Mail"]
W -- "staged batches/*.jsonl" --> IDX["entity index (LanceDB)\ninstant local search"]
B -- ingest --> IDX
A --> B
H --> B
Native, not osascript#
Every call goes through Apple's own APIs: EventKit for Calendar and Reminders, Contacts.framework for Contacts, ScriptingBridge for Mail, Notes and Messages — and NSAppleScript (OSA) inside the detached crawl worker, where Mail's indexing needs the compiled-AppleScript transport. No osascript processes are spawned, nothing runs a shell, and no Python sits in between. That is a property claim with an exception named, not a slogan: the crawl worker compiles AppleScript through OSA because it must — see the next section.
OSA-mediated Apple Events#
From macOS 27, raw (non-OSA) Apple Event senders get silent empty replies. Every bite component that sends Apple Events goes through OSA — the helper via ScriptingBridge, the crawl worker via NSAppleScript — so events are answered normally and TCC behavior is unchanged. The crawl worker's port to NSAppleScript is exactly this fix (v0.4.0).
The stable helper path#
macOS ties permission grants to the binary that earned them. bite-helper lives at ~/Library/Application Support/bite/bin/bite-helper and never moves: refreshes update it in place, so Calendars/Reminders/Contacts grants survive every upgrade. An ad-hoc codesign signature is applied on each install, and because bite ships source-only, Gatekeeper never stands between users and the helper.
One registry, two faces#
MCP tools/list schemas and CLI verbs are generated from the same table, crates/bite-core/src/registry.rs. Each entry carries the tool's name, app, bridge method, agent-facing description, parameter specs, and two behavioral flags — destructive (confirm-gated) and replay_safe (whether a helper death may trigger a transparent retry). The tools page is that table in prose; a CI conformance test fails the build if the Swift handlers and the registry drift apart.
The bridge#
The control plane talks to the helper over line-delimited JSON on the helper's stdio: a handshake, request/response pairs correlated by id, and notifications. Errors carry a code and, when user action fixes them, a fix. The full contract — every method, every error code, every result shape — is on the protocol page and is pinned by tests on both sides (Rust conformance tests, Swift ProtocolTests, and golden conversations against a fake helper).
Agent-friendly errors#
A tool error is written for the agent to act on. A permission denial returns the exact fix — a command or a System Settings deep link the agent relays verbatim; a missing app says app_not_running ("launch Messages"); a mid-indexing Mail query returns deferred: true with the hint to retry or force live, instead of blocking for minutes. When the helper dies mid-call, read-only tools are retried transparently while mutating ones return a not-replayed error with a re-check hint — the first attempt may already have committed.
Confirm-before-destruct#
Deletes, moves and bulk operations return a preview until the caller passes confirm: true (the CLI: --yes). The preview states exactly what would happen — the event, the message, the selection count — so an agent can show a human, or a human can read the terminal, before anything irreversible starts. Bulk deletes go through Mail's Trash and are recoverable; that is the one softening the rule allows.
Local-only#
No server, no account, no telemetry, no crash reporting. The only network bite could ever touch is the planned, explicit bite install-helper --prebuilt download (roadmap) — which fetches a signed binary and none of your data. Everything your agents read and write through bite stays in the 0700 data dir or in Apple's own apps. The security and privacy page is the full statement.