macOS 15+ · Swift 6 · local capture and index · optional AI · MIT
Download current stable release · Build from source · Product details
ZBS Eye is a tiny native recorder for people who want a searchable memory of their Mac without sending their life to somebody else's cloud. It quietly captures screen moments, accessible text, OCR fallback, microphone and optional system audio. Everything is indexed locally and can be explored in the Timeline, opened as a call, searched in Ask, or read by your own agent over localhost.
Release status: the public stable release is 0.8.0 (build 22), Developer ID signed and Apple-notarized.
The example above is synthetic. No personal history, real meeting, URL, transcript, or participant name is stored in this repository.
Eye records useful evidence and gives it back. It is not a CRM, a calendar manager, or a meeting bot.
- Timeline combines screen frames, extracted text, app context, audio density, call spans, and bookmarks in one scrubbable view. A seven-image filmstrip makes nearby visual moments immediately reachable.
- Calls keeps meetings out of the all-day activity stream. Microphone and system audio remain separate; a bookmark schedules a checkpoint transcript without interrupting the recording.
- Search combines FTS5 with local multilingual semantic retrieval, so a query in one language can find evidence written in another.
- REST and MCP let local agents retrieve bounded, typed evidence instead of scraping the UI. The server
binds to
127.0.0.1; everything except/healthrequires a Keychain-backed Bearer token. - Storage stays yours. Fresh installs use a 5 GB media budget. You can choose another cap, keep media forever, move the data root to an external SSD, or create consistent compressed backups.
- Browser Bridge optionally adds rendered text from the active Chromium tab when Accessibility cannot see it. It is off by default, authenticates the local app before extracting text, and never sends page data beyond this Mac.
Screen capture is adaptive: Accessibility text is the cheap first path, while Vision OCR handles apps whose UI trees are empty. Images use HEIC and perceptual-hash deduplication. Static screens do not become thousands of duplicate files. One low-rate stream always notices app switches and, when macOS already permits listen-only input observation, clicks, the end of scrolling, and a pause after typing; Eye never asks for a new permission for these signals. A three-second tick remains the fallback, followed by one sparse minute tick after sustained inactivity. The input observer retains only the kind of activity. It never stores keys, entered text, pointer coordinates, scroll contents, or clipboard data. Heavy work remains latest-wins, with at most one current and one pending moment, and frequent input cannot start it more than once per 1.5 seconds.
With listen-event access already available, Eye sees native screenshot shortcuts early, cancels pending heavy work, and rejects any in-flight result that crosses the screenshot boundary; those shortcuts never create an Eye moment. Otherwise the screenshot-helper fallback yields as soon as macOS exposes it. Already-running synchronous AX or Vision work may finish in the background, but cannot be saved as an Eye frame. Eye never requests a new permission for this and does not stop or rebuild its stream.
Timeline resolves every selected time to the nearest real image at or before that time—never a future frame. It keeps two earlier, the current, and four later images close at hand, loads at most two files concurrently, and caps decoded-image memory at 128 MB. Missing or retained-away files fall back only to an earlier image. Activity cards lazily show a representative 160×90 frame when one still exists and keep their app-only layout when it does not.
Any eligible external application using the microphone starts one local Call immediately. This includes
native apps, browsers, ChatGPT, and unknown microphone owners; several owners and device or helper changes
stay inside the same Call. Krisp is treated as an audio relay: it may join an existing Call, but cannot start,
name, or keep one alive by itself. Eye also excludes its own processes, a narrow system list, and ChatGPT's
codex_chronicle capture helper. Known Zoom, Meet, and Teams signals may improve the saved source context, but
they never decide whether recording is allowed to start. Detection, recording, and saving do not require
internet access.
Eye requests separate microphone and system-audio tracks. If one track is unavailable, the Call remains
recording and reports the missing track instead of silently hiding the gap. Audio Off, privacy pause,
critically low disk, and storage relocation remain hard stops.
The main Record Timeline / Pause Timeline control governs ordinary screen and Timeline audio capture; it does not disarm microphone-triggered Calls. Choose Audio Off or start a privacy pause when no automatic Call should begin. Privacy pause remains available from the menu bar even while Timeline capture is paused.
Eye itself and a narrow list of macOS system daemons are always excluded. Settings → Audio → Don’t auto-record these apps adds user-selected bundle identifiers to a separate audio exclusion list; this does not change the existing Private apps list for screen capture. While a Call is recording, Never auto-record [App] adds that app to the audio list and saves the current Call.
When microphone activity disappears, Eye keeps the same Call open for a 30-second grace. End & save finishes it immediately; This wasn’t a call stops and permanently deletes the whole automatic Call. If the microphone returns during the grace, the timer is cancelled and the same Call continues. With no action, Eye saves once after 30 seconds. There is no post-save Undo; saved Calls can be opened or deleted in Calls.
Detection is local. Call context may retain a normalized service host and an opaque fingerprint hash, but not the full URL or path, meeting code, window title, or participant names; detector diagnostics log neither private form. The ordinary Timeline capture still records visible screen content and may locally retain browser URL, title, and text.
Optional Whisper Large V3 Turbo can produce a whole-call transcript after the call. Optional local diarization creates anonymous per-call speaker lanes; you may name or correct them for that call. Eye does not keep a reusable voiceprint and does not show a live transcript.
Chrome, Dia, Arc, Edge, Brave, Vivaldi, Chromium, and compatible Chromium browsers can add visible rendered page text to Timeline. Install ZBS Eye Browser Bridge from the Chrome Web Store, or use the bundled unpacked fallback from Settings → Browser Capture. Copy the separate write-only token, then explicitly enable the extension. Safari is not supported.
The extension checks an HMAC proof from the real local Eye process and confirms recording is active before it extracts DOM text. It ignores background tabs, password and form values, hidden elements, scripts, and styles. Requests go only to loopback. See the Browser Bridge privacy details.
Recording, indexing, Timeline, Calls, search, REST, and MCP do not require an AI provider. AI starts off. On qualified Apple Silicon hardware, one click can download the pinned ZBS Eye Local model. You may instead connect a local server, signed-in CLI, or cloud API provider.
That choice changes only generation features such as Ask and Daily Insights. Before any non-local provider receives a prompt excerpt, Eye names the recipient and asks for scoped consent. Raw recordings, the database, and storage never become provider uploads. API credentials live in the macOS data-protection Keychain.
- Open the current stable release, download the notarized ZIP,
move ZBS Eye.app to
/Applications, and launch it. - Grant Screen Recording and Accessibility. Microphone is optional; system audio has its own switch.
- Press Record Timeline. Open Timeline and change windows once to see the first moments appear.
ZBS Eye is distributed outside the Mac App Store because cross-app Accessibility and continuous capture are
incompatible with the App Sandbox. Release artifacts use Developer ID, Hardened Runtime, Apple notarization,
and a stapled ticket. Exact artifact verification is documented in docs/NOTARIZE.md.
Maintainers must use the exact ZIP and matching .manifest.json path printed by the script, never select a
release asset by wildcard, and run scripts/verify-release-artifact.sh before installation or publication.
The app pauses on lock, display sleep, and system sleep. It resumes only after macOS reports a real unlocked
console session; loginwindow and screen-saver shells are rejected again at the final write boundary.
The installed binary can serve MCP over stdio:
"/Applications/ZBS Eye.app/Contents/MacOS/ZBS Eye" --mcp-read-onlyUse that command in Codex, Claude Code, Claude Desktop, or another MCP client. Read-only mode exposes Timeline,
search, calls, bookmarks, source health, and paginated transcript evidence. Frame-image access and the global
capture toggle require the separate --mcp-full mode. For localhost integrations, inspect GET /health,
then use the authenticated REST surface described by the app's MCP & AI Tools settings.
xcodegen generate
xcodebuild -project ZBSEye.xcodeproj -scheme ZBSEye -configuration Debug buildThe codebase is Swift 6 with strict concurrency, SwiftUI, ScreenCaptureKit, Vision, GRDB/SQLite, sqlite-vec, whisper.cpp, FluidAudio, FlyingFox, and the Swift MCP SDK. Start with AGENTS.md for architecture, data-safety invariants, and review risks; use BUILD.md for the complete build path.
Privacy and data-loss review matter more here than feature count. Capture has one writer, every live
data-root path is resolved through StorageLocation, live SQLite is never copied directly, and the HTTP
surface is localhost-only with authentication. iCloud snapshots and user exports are intentional
out-of-root exceptions.
MIT © 2026 zbs-gg.