Skip to content
EyeSpeakEyeSpeak.

Privacy policy

What leaves your Mac, and what never does.

Effective date
10 September 2026
Applies to
EyeSpeak for macOS 0.2.8 and later on the beta and stable channels, the EyeSpeak gateway at api.eyespeak.ai, and the website at eyespeak.ai.

This policy is written from the source code, not from a template. Every statement of the form “we do X” or “we never do Y” below corresponds to a specific file in the application or server, and Appendix B names that file so the claim can be checked. Where the code does not do something, this policy does not promise it.

EyeSpeak is provided by [LEGAL ENTITY NAME], [REGISTERED ADDRESS] (“EyeSpeak”, “we”, “us”). Contact: privacy@eyespeak.ai.

Amber brackets mark fields still to be filled in before publication (legal entity, registered address, EU/UK representative).

1The short version

  • EyeSpeak is a voice-driven assistant that acts on your Mac. The microphone is open only while you physically hold the push-to-talk key, or during a dictation session you started and can see running. It never listens otherwise.
  • To carry out a command, the content of that command — your speech, what is on your screen, and anything a step reads (a document, a web page, a connected email) — is sent through our gateway to the AI providers named in §7. Our gateway does not log, store, or forward that content to anyone else. It records only counts: who, which model, how many tokens, how long, and whether it worked.
  • Your account is your Google identity. We store your Google account ID, email address, display name, and per-device version information.
  • Usage analytics and crash reports are on by default, disclosed during setup, and can be turned off in Settings. Neither ever contains what you said, what was on your screen, a window title, a file path, or a URL. You can open the exact file that would be sent before it is sent.
  • Bug reports are sent only when you press Send after reading a preview of the exact report. They do contain transcripts and window titles, which is why they require that step.
  • We do not sell personal information, do not use it for advertising, do not use your content to train models, and do not access your camera.

2Definitions

TermMeaning
AppThe EyeSpeak application installed on your Mac: a Python core and a native macOS overlay (“HUD”).
GatewayOur server at api.eyespeak.ai. It authenticates you, enforces usage allowances, proxies model requests, relays transcription audio, receives analytics and bug reports, and serves updates.
Websiteeyespeak.ai, including the waitlist, beta download page, and the operator console at eyespeak.ai/admin.
CommandOne push-to-talk utterance (or typed prompt, or brush gesture) and everything EyeSpeak does to carry it out.
ContentAnything that originates from you or your screen during a command: audio, transcripts, accessibility structure, screenshots, document text, page text, clipboard text, and data returned by a service you connected.
Structural dataCounts, categories from a fixed list, durations bucketed into ranges, and version numbers. Never content.

3When the microphone is on

The App records audio in exactly two situations, and no others:

  1. Push-to-talk. From the moment you press and hold the trigger key (Right Option by default) until you release it.
  2. Dictation. From the moment you start a dictation session — by pressing ⌘\ or by saying “scribe”, “dictate”, or “transcribe” — until you stop it with the same keys, or until ten minutes have elapsed, whichever comes first. While dictation is running the overlay shows Transcribing… for the whole session.

An audio cue plays when the microphone opens. There is no wake-word listener, no background recording, and no audio buffer retained after the key is released or dictation ends.

Audio is not stored. It is streamed as it is captured, over an authenticated WebSocket, to the Gateway’s transcription relay, which forwards it to OpenAI’s gpt-live-transcribe model and returns the transcript. The Gateway meters the audio in 30-second blocks against your voice allowance and does not retain audio. No audio file is written to your disk by the App.

Transcription bias is off. The App can send a list of vocabulary terms and on-screen words as hints to the transcriber. This is disabled by default and can only be enabled by a developer environment variable (EYESPEAK_VOICE_CONTEXT=1); it is not exposed in Settings and is not enabled in released builds.

Camera. EyeSpeak does not request or use camera access. The application bundle declares no camera usage description and no camera entitlement, and a packaging test fails if one is added. A gaze-tracking feature that once existed has been removed and is not in any released version.

4What EyeSpeak sees to carry out a command, and where it goes

This section is the heart of this policy. When you give a command, EyeSpeak gathers what it needs to understand the screen and act on it. That material is Content, and it leaves your Mac only to be processed by the AI providers in §7, only through our Gateway, and only for the duration of the request.

4.1What may be collected during a command

Depending on the command and the application in front, some or all of the following may be read:

  • Your words: the transcript of what you said, or the text you typed into the overlay.
  • The accessibility tree of the frontmost application: the names, roles, values, and positions of visible controls, the window title, and the menu bar. This is how EyeSpeak finds a button without a screenshot.
  • Page structure of a Chromium-based browser or Electron application via the Chrome DevTools Protocol, or of Safari via its scripting interface: the URL, title, and text and link structure of the page.
  • Screenshots of the display, downscaled to 1280 pixels wide and JPEG-encoded, taken only when the accessibility path cannot see enough to act (the “vision” fallback) or when you use the magic brush.
  • A native-resolution crop of the region you circled with the magic brush. Text in the crop is first read on-device by macOS Vision.framework; the image itself is sent to a model only when the region is not text (a chart, a diagram, a photo) or when the command needs to act on it.
  • Selected text in the frontmost application, when the command refers to it.
  • Document contents when a command reads or edits a file directly (.txt, .csv, .xlsx, .docx, .pdf, .pptx), and the statistical profile of a spreadsheet.
  • Output of file commands (move, copy, find, trash) run on your behalf.
  • Data returned by a connected service you have authorised (§6): for example, the subject lines and snippets of matching emails, upcoming calendar events, or file names in Drive.
  • Facts carried across the steps of one long command (a scratchpad of what earlier steps established). It is discarded when the command ends.
  • Your home directory path, the name of the frontmost application, and the name of your assistant and your first name from Settings, if you set them.

4.2Where it goes

  1. The App assembles the request and sends it over HTTPS to the Gateway with your session token. The App refuses to send Content over any connection that is not HTTPS (loopback excepted for development), and refuses to follow redirects with your token.
  2. The Gateway checks that you are signed in and within your allowance, validates that the request body matches a reviewed shape, and forwards it to one of the model providers in §7 using our provider credentials. The Gateway fixes which models can be reached; the App cannot choose an arbitrary provider or model.
  3. The provider returns a plan or an answer. The Gateway records the usage figures listed in §4.3 and returns the response to the App.
  4. The App carries out the plan locally and verifies each step against your screen.

The Gateway never logs a request body, never persists one, and never sends one to an error tracker. This is enforced by there being no code path on the Gateway that writes a body anywhere — not by a redaction step that could miss one. The Gateway’s unhandled-error reporter (§9) is configured so that request data, headers, exception messages, local variables and breadcrumbs are structurally excluded.

4.3What the Gateway records per request

For each model or transcription request the Gateway stores one row containing: your user ID, device ID, timestamp, tier, provider, model, purpose (a fixed label such as plan, compose, identify, anki_generate), input and output token counts, cache-read and reasoning token counts, latency in milliseconds, status, and an internal cost estimate. For transcription it stores voice seconds. Daily totals of these are kept per user to enforce your allowance.

For requests to Anthropic that carry encrypted “thinking” blocks, the Gateway also stores a keyed hash (HMAC) of each block, together with the response’s admitted output ceiling, for 30 days. This lets it reserve the right budget when the block is sent back on a later turn. The hash cannot be reversed to recover reasoning text, and no reasoning text or encrypted block is stored.

The Gateway’s web server writes standard access logs: the connecting IP address, request method and path, status code, and timing. These logs are held by our hosting provider (§7) and do not contain request or response bodies.

4.4What never leaves your Mac

  • The full local trace (trace.jsonl): every event of every command, including transcripts, window titles, menu paths, plans and verdicts.
  • Your history (history.jsonl): the prompt, the response, the steps narrated, the target app, and outcome for each finished command, shown in the Recents screen.
  • Learned routes (transitions.json, prior_state.json, app_routes.json): which structural actions worked for which application.
  • Your vocabulary library (~/.eyespeak/vocabulary.txt).
  • Brush crops (/tmp/eyespeak-brush/, mode 0700), pruned after one hour.
  • Temporary screenshot files, deleted immediately after being read.
  • Generated outputs you asked for: Anki packages, figures, and add-on files under ~/.eyespeak/.

None of these files are uploaded by any code path in the App. A bug report (§10) is the only way any of this material can leave your Mac, and it requires you to read and send it.

4.5Approval before irreversible actions

By default, any step the planner marks as dangerous — deleting, sending, overwriting, running a shell command that mutates, calling a mutating API — shows an Approve/Deny prompt before it runs. You can change this in Settings to gate every step, or none. This is an action-safety control, described here because it also bounds what a command can do with your data.

5Your account

The distributed App requires an EyeSpeak account during the beta. You create it by signing in with Google.

5.1What we receive from Google at sign-in

The App runs Google’s Authorization Code + PKCE flow in your browser, on a one-shot loopback server on your Mac. The App sends Google’s ID token to the Gateway, which verifies it against Google’s published keys (issuer, audience, expiry, signature) and requires that Google marks the email as verified. From the verified token we store:

FieldPurpose
Google subject ID (sub)The stable identifier for your account. We key on this, never on email, so an email change does not create a second account.
Email addressBeta access gating (invitations are issued to an email), the account card in Settings, and support.
Display nameThe account card in Settings.

The Google access and refresh tokens obtained in that same flow are not sent to the Gateway. They stay in your macOS Keychain (§6) and are used only by the App on your Mac.

5.2Devices and sessions

At sign-in the App sends a randomly generated install ID (a 32-character hexadecimal string created on first launch and stored in ~/Library/Application Support/EyeSpeak/install_id), plus the App version, build number, and release channel. The Gateway records a device row: install ID, platform, OS version, App version, channel, CPU architecture, first and last seen. The install ID is random; it is not derived from any hardware identifier.

The Gateway issues a short-lived access token and a refresh token. Refresh tokens are stored hashed on the server and rotate on every use; reuse of a rotated token revokes the whole session family. On your Mac, the session (tokens, your email, name, and plan) is stored as a single item in the macOS Keychain under the service name eyespeak-gateway-session. It is never written to a plain file in a released build.

5.3Entitlements and usage

We store your plan (beta, dev, or a comp/paid plan), its limits, and your daily usage totals (§4.3). Operators can adjust group allowances; every such change is recorded in an audit trail with the operator’s identity and the before/after values.

5.4Signing out

Sign out in Settings asks the Gateway to revoke your refresh token, deletes the Keychain item, and deletes the local analytics outbox so the next person to sign in on the same Mac cannot inherit your pending events. A sign-out that cannot reach the server still clears the local session.

5.5Invitations and the waitlist

The beta is invitation-only. If you join the waitlist on the Website, we store your email address and, if you consented to Website analytics, a random visitor ID. When an operator invites you, we store the invitation code, the email it was issued to, its expiry, who issued it, an optional operator note (“label”), the plan it grants, and a hash of the download token. The raw download token is shown once and is not stored. When you redeem an invitation we record which account redeemed it and when.

6Connected services

6.1Google Gmail, Calendar and Drive

Signing in with Google presents one consent screen that requests both your identity and access to Gmail, Calendar and Drive, so you see the full scope of access before any command can use it. The scopes are:

  • openid, userinfo.email, userinfo.profile — identity (§5.1)
  • https://www.googleapis.com/auth/gmail.modify
  • https://www.googleapis.com/auth/calendar
  • https://www.googleapis.com/auth/drive

You may decline the Gmail, Calendar and Drive scopes on Google’s consent screen and still sign in; the corresponding commands will then be unavailable.

How the tokens are used. Google API calls are made directly from the App on your Mac to Google’s servers, using the access token in your Keychain. Requests are built from a fixed, reviewed list of endpoint templates; the planner can select an endpoint and supply argument values but can never compose a URL, choose a host, or see a token. Any endpoint that changes data (sending mail, creating an event, moving a file) goes through the Approve/Deny gate (§4.5).

What happens to Google data. Data returned by a Google API during a command (for example, matching message subjects, event titles and times, file names) becomes part of the Content for that command and is handled exactly as §4 describes: it may be included in the request to a model provider so the assistant can complete your command, it is not logged or stored by the Gateway, and it is not used for any other purpose.

Google API Services User Data Policy — Limited Use disclosure. EyeSpeak’s use and transfer to any other app of information received from Google APIs adheres to the Google API Services User Data Policy, including the Limited Use requirements. Specifically:

  • We use Google user data only to provide and improve the user-facing features you invoke in EyeSpeak.
  • We transfer Google user data to third parties only as necessary to provide those features (the model providers in §7, acting as our processors), to comply with law, or as part of a merger or acquisition with notice to you.
  • We do not use Google user data for advertising, and we do not sell it.
  • Humans do not read your Google user data except with your explicit consent for a specific support request, where necessary for security or to comply with law, or on data you have aggregated and anonymised.
  • We do not use Google user data to train or improve generalised AI or machine-learning models.

Disconnecting. Sign out in Settings best-effort revokes the grant at Google’s revoke endpoint and deletes the Keychain item. You can also revoke EyeSpeak’s access at any time at myaccount.google.com/permissions.

6.2Other services called from your Mac

The following are called directly from the App, not through the Gateway, only when a command needs them:

ServiceWhat is sentCredential
Wikipedia (en.wikipedia.org)Your search terms or an article title, with a User-Agent that identifies EyeSpeak.None
PubMed (eutils.ncbi.nlm.nih.gov)Your search terms.None
Google Places (places.googleapis.com)A place type and a coordinate.Only if a developer supplies a key; not shipped in the beta App.
Canvas LMSRequests to your institution’s Canvas host, or a read of the calendar feed URL you configured.A personal access token or feed URL you place in your own configuration file; never stored by us.

Each of these has a fixed host allowlist. A request whose host, scheme or path does not match its template is refused before it is sent.

6.3Local integrations

Anki (via AnkiConnect), Blender and FreeCAD are driven over loopback connections on your own Mac. Nothing is sent to any server other than the model requests already described in §4.

7Service providers (processors)

We use the following providers. Each receives only what the table states.

ProviderRoleWhat it receivesLocation
Anthropic (api.anthropic.com)Planning, composition, vision fallback (Claude models)Command Content (§4.1) for the request, via our GatewayUnited States
Cerebras (api.cerebras.ai)Fast planning and vision tiers (open-weight models)Command Content (§4.1) for the request, via our GatewayUnited States
OpenAI (api.openai.com)Speech-to-text (gpt-live-transcribe)Audio while the mic is open, via our Gateway relayUnited States
GoogleIdentity; Gmail/Calendar/Drive APIs when you use themID token at sign-in; API requests directly from your Mac (§6.1)Global
Neon (PostgreSQL, AWS us-east-2)Our databaseAccount, device, session, entitlement, usage, invitation, report metadata, analytics outboxUnited States
Render (Ohio)Hosts the GatewayAll traffic to the Gateway in transit; access logs (§4.3)United States
Cloudflare R2Private object storageBug report bodies you chose to send (§10); signed release downloadsUnited States (ENAM)
PostHog Cloud (US)Product analyticsStructural analytics events (§8) after the Gateway has re-filtered them, with IP geolocation disabledUnited States
SentryCrash reportingScrubbed crash events (§9)United States
VercelHosts the WebsiteWebsite requestsUnited States

Model providers and your Content. Anthropic, Cerebras and OpenAI receive Content only to generate the response for your request. They are engaged under their commercial API terms. Under Anthropic’s and OpenAI’s published API data policies at the time of writing, API inputs and outputs are not used to train their models by default; each provider may retain API data for a limited period for abuse monitoring under those policies. We have no code path that opts your data into training, and we do not use your Content to train anything ourselves. Their policies are at anthropic.com/legal/privacy, openai.com/policies/api-data-usage-policies, and cerebras.ai/privacy-policy.

We do not use any other analytics, advertising, attribution, or session-replay service. In PostHog, autocapture, session replay, heatmaps, console capture, and performance capture are disabled.

8Usage analytics (on by default; you can turn it off)

What it is for. To learn which kinds of things people automate, whether commands succeed, and whether the product is getting faster — in aggregate.

How it is disclosed and controlled. The sign-in screen states that usage analytics track categories and outcomes without your words and can be turned off in Settings. The switch is Settings → Privacy → Share usage data. Turning it off stops the uploader and deletes the local outbox file, so no record of your activity remains queued on disk.

You can read exactly what would be sent. Events are written to ~/Library/Application Support/EyeSpeak/analytics_queue.jsonl before anything is transmitted. Settings → Privacy → Open usage data file opens it.

What an event can contain — and nothing else. Every event is filtered through an allow-list on your Mac before it is queued, and filtered again by the Gateway before it is stored. A property that is not on the list is dropped, including properties that did not exist when the list was written. The complete list is in Appendix A. In summary an event carries:

  • an event name from a fixed set (e.g. app_launched, command_completed, onboarding_finished, update_installed);
  • categories from closed vocabularies: the kind of intent (e.g. edit_text, web_research), the category of the target app (e.g. browser, productivity), how the command was started (voice, typed, brush, …), which pipeline answered it, the outcome, a latency bucket (<250ms … >=5s), the names of the kinds of action taken (e.g. menu, click, type) and how many of each;
  • booleans such as whether the result was verified or undone;
  • bounded counts (actions, model calls, tokens, duration);
  • your onboarding persona and goals, chosen from a fixed list during setup (e.g. student, study), which are also set as properties on your PostHog profile;
  • the permission state of each macOS permission (granted / denied / …);
  • your App version, build, channel, macOS version and CPU architecture, and your install ID.

What an event can never contain. A transcript, a window title, a menu path, a file path, a URL, an element label, the identity of the target application (only its category travels), the arguments of any action, a precise duration, or a session identifier that links one command to the next. The name you typed for your assistant, your name, and your free-text persona detail are not on the allow-list and cannot travel.

Identity. Analytics events are stored and forwarded to PostHog keyed by your EyeSpeak user ID. If you joined the waitlist with Website analytics consent, the Gateway links your Website visitor ID to that user ID once, so a sign-up funnel can be counted end to end. IP-based geolocation is disabled on every event we forward.

Rate and retention. The outbox holds at most 5,000 events or 5 MB, is sent in batches of 100 over HTTPS with your session token, and retries on failure rather than discarding. Events older than 30 days at the time of receipt are rejected by the Gateway. See §13 for server-side retention.

9Crash reports (on by default; you can turn it off)

Switch: Settings → Privacy → Send crash reports.

When an unhandled error occurs in the App (or in the Gateway), an event is sent to Sentry. Before it is sent, the event is rebuilt from scratch to contain only:

  • event ID, timestamp, severity, platform (python);
  • the App or Gateway version and release channel;
  • for each exception: its type name (e.g. KeyError), the literal string [exception message omitted] in place of the message, and a stack trace limited to the module, function name and line number of frames inside EyeSpeak’s own code. Frames from libraries and the OS are dropped.

Sentry’s SDK is initialised with all default integrations disabled, personal data collection off, local variables off, breadcrumbs off, and performance tracing off. The result is that a crash report cannot carry a transcript, a window title, a file path, a URL, a request body, a header, or any variable value — there is no field left in the event for them.

Sentry’s ingestion servers necessarily see the IP address of the sending machine in transit; it is not attached to the event we send.

10Bug reports (only when you choose to send one)

A bug report is the one thing that can carry Content off your Mac, and it is designed so that this cannot happen without you reading it first.

What a report contains. For one command: what you said (the transcript), the response, the steps EyeSpeak narrated, which pipeline answered and why, the raw local trace events for that command (which include window titles, menu paths, element labels and plans), and the environment: App version, macOS version, the frontmost application, and which configuration overrides were set. Screenshots are not included.

Redaction. Before preview, the value of every configuration key whose name ends in a secret suffix is replaced with <redacted>, and the rendered text is swept for credential-shaped strings (API keys, JWTs, bearer tokens, URLs with embedded credentials, private key blocks). If a pattern match cannot be redacted, the upload is refused rather than sent. This sweep is a safety net; it does not guarantee that every secret is caught, which is why the preview exists.

Consent. The App always writes the report to ~/Library/Logs/EyeSpeak/reports/ first, whether or not you send it. It is sent only when you open the preview and press Send, and only the reviewed draft is sent. Sending requires being signed in and uses HTTPS.

Storage. The Gateway stores the report body as a private object in Cloudflare R2 under a key derived from your user ID, and a database row with the report reference (EY-…), your user and device IDs, the time, App version, channel, commit, and size. Report bodies are never written to the database and are never sent to an error tracker.

Deletion. Email privacy@eyespeak.ai with the EY- reference (shown in the App after sending) and we will delete the object and its row. Reports are in any case deleted no later than 90 days after submission (§13).

Limit. At most 20 reports per account per day are accepted.

11Software updates

The App checks for updates by requesting a signed manifest from the Gateway with your session token. The check sends your session token and nothing else in the request; the manifest returned may be gated by your install ID (a staged rollout compares a hash of install ID + version against a rollout fraction, on your Mac). Downloads are redirected to a short-lived (5-minute) private R2 URL; the App strips your session token before following that redirect. Downloaded bundles are verified with Apple’s notarization tools and an Ed25519 manifest signature before being installed. Up to 50 update downloads per account per day are accepted.

12The Website

Analytics. The Website sends a fixed set of events (landing_viewed, beta_viewed, waitlist_submitted, invite_created, download_started) to the Gateway only with your consent, identified by a random 32-character visitor ID that the Website assigns. No other properties are attached. These are forwarded to PostHog with IP geolocation disabled.

Waitlist. Your email address, the visitor ID if you consented, and the time.

Beta download. A download link is issued against a hashed invitation token; each token allows at most 20 downloads per day. If the invitation was issued to a consented visitor ID, a download_started event is recorded.

Operator console (eyespeak.ai/admin). Used only by EyeSpeak operators. Operators authenticate with an email code and an authenticator app; no codes or authenticator secrets are stored. The console shows, per person: email, name, plan, invitation history, sign-in and last-use times, App version and platform, and spend/usage totals. It never shows Content, request bodies, or report bodies. Every state change an operator makes is written to an audit table with the operator’s email and the before/after values.

13Retention

DataWhereKept
Command Content (audio, transcript, screen structure, screenshots, documents, page text, connected-service results)Gateway, in transit onlyNot stored. Held in memory for the duration of the request.
Per-request usage rows (§4.3)NeonFor the life of your account, then deleted with it (database cascade).
Daily usage totalsNeonFor the life of your account.
Thinking-block hashesNeon30 days from creation.
Account (Google sub, email, name), devices, entitlementsNeonUntil your account is deleted (§15).
Sessions (hashed refresh tokens)NeonUntil revoked or expired; deleted with the account.
Analytics eventsNeon outbox → PostHogDelivered outbox rows are kept in our database for up to 13 months, then removed. PostHog retains events under its standard project retention. Turning off Share usage data stops new events; it does not delete events already delivered — ask us (§15).
Crash eventsSentryUnder Sentry’s standard project retention.
Bug reportsCloudflare R2 + Neon rowUntil you ask us to delete them, and no later than 90 days after submission.
Invitations and waitlistNeonFor the duration of the beta programme. Invitation rows are kept as the record of who invited whom.
Operator audit trailNeonFor the duration of the service.
Gateway access logsRenderUnder Render’s standard log retention.
Everything in §4.4Your MacUntil you delete it. Uninstalling the App does not remove ~/Library/Application Support/EyeSpeak, ~/Library/Logs/EyeSpeak, ~/Library/Caches/ai.eyespeak.desktop, ~/.eyespeak, or the two Keychain items; see §15.3.

14Security

  • All App-to-Gateway and Gateway-to-provider traffic is HTTPS or WSS. The App refuses to send credentials or Content over plain HTTP anywhere but loopback, and refuses to follow redirects with a bearer token.
  • Released builds have their Gateway address, Google client, and update verification keys compiled in; an environment variable cannot redirect a released App’s traffic.
  • Provider API keys exist only on the Gateway. The App never holds one.
  • Session tokens and Google tokens are stored in the macOS Keychain via the Security framework, in-process — never passed on a command line.
  • Refresh tokens are stored hashed; reuse detection revokes the family.
  • Bug report and release storage use separate, bucket-scoped credentials; the Gateway credential cannot write releases and the release credential cannot write reports. Public bucket access is disabled.
  • The Gateway validates every proxied request body against a reviewed shape and rejects fields it does not recognise.
  • The Website-to-Gateway internal endpoints require a shared secret of at least 32 bytes.
  • The App runs without the App Sandbox (Accessibility control is incompatible with it) but with the hardened runtime and library validation enabled, so no unsigned code can be loaded into a process that holds Accessibility.
  • The local Unix socket between the App’s core and its overlay lives in a directory only your user can read (mode 0700).

No system is perfectly secure. If you believe you have found a vulnerability, email security@eyespeak.ai.

15Your rights and how to exercise them

These apply to everyone, regardless of where you live. Residents of the EEA/UK and California have specific statutory rights noted below; we honour the same requests from anyone.

15.1Controls in the App

To…Do this
Stop usage analytics and delete the local outboxSettings → Privacy → Share usage data → off
Stop crash reportsSettings → Privacy → Send crash reports → off
See what analytics would be sentSettings → Privacy → Open usage data file
Read a bug report before sending, or never send oneThe preview is mandatory; close it to decline
Revoke Google accessSettings → Sign out, or myaccount.google.com/permissions
Gate every action behind Approve/DenySettings → Approval mode → All
Choose which microphone is usedSettings → Input → Microphone
Revoke macOS permissionsSystem Settings → Privacy & Security → Accessibility / Microphone / Screen Recording / Automation

15.2Requests to us

Email privacy@eyespeak.ai from the address on your account, and we will act within 30 days (extendable once by 60 days where legally permitted, with notice). You can:

  • Access / export the data we hold about you: your account row, devices, entitlements, usage rows, analytics events, report metadata, and any bug report bodies. We will provide it in JSON.
  • Correct your name or email (these mirror your Google account; change them there and sign in again, or ask us).
  • Delete a bug report by EY- reference.
  • Delete your account. We will delete your user row and, by database cascade, your devices, sessions, entitlements, usage rows, thinking hashes and analytics outbox rows; delete your bug report objects; and delete your person profile and events in PostHog. Invitation rows keep the invited email as the record of the invitation but lose their link to your account. Crash events cannot be linked to you and are not affected.
  • Object to, or restrict, processing based on legitimate interests (analytics, crash reporting) — the Settings switches do this immediately; we will also honour an emailed request.
  • Withdraw consent for bug reports (they are per-report; simply do not send) and for Website analytics (your cookie/consent control on the site).
  • Complain to a supervisory authority. In the EEA/UK that is your national data protection authority; we would appreciate the chance to address your concern first.

We will not discriminate against you for exercising any right.

15.3Removing local data

Quit EyeSpeak, then delete: ~/Library/Application Support/EyeSpeak, ~/Library/Logs/EyeSpeak, ~/Library/Caches/ai.eyespeak.desktop, ~/.eyespeak, and the Keychain items eyespeak-gateway-session and eyespeak-google-oauth in Keychain Access. Brush crops in /tmp/eyespeak-brush are removed by macOS on reboot.

15.4California (CCPA/CPRA)

In the preceding 12 months we have collected the categories described in §4–12: identifiers (Google sub, email, name, install ID, IP address in logs), internet/electronic activity (structural analytics, usage rows), audio and visual information and electronic content (Command Content, in transit only, and bug reports you send), and inferences limited to the persona and goals you chose during setup. Sources: you, your device, and Google. Purposes: providing the service, enforcing allowances, security, product analytics, crash diagnosis, and support. Disclosed to the processors in §7 for those purposes only. We do not sell personal information and we do not share it for cross-context behavioural advertising. We do not use or disclose sensitive personal information for purposes beyond providing the service you requested. You have the rights to know, delete, correct, and opt out, and to non-discrimination, exercisable as in §15.2.

15.5EEA / United Kingdom (GDPR / UK GDPR)

Controller: [LEGAL ENTITY NAME]. Legal bases:

ProcessingBasis
Account, sessions, allowances, model and transcription requests, updates, supportPerformance of a contract (Art. 6(1)(b))
Gmail, Calendar and Drive accessYour consent on Google’s consent screen (Art. 6(1)(a)); withdrawable at any time
Usage analytics, crash reportsLegitimate interests (Art. 6(1)(f)) in understanding and improving a beta product, with an in-app off switch and structural-only data; you may object at any time
Bug reportsYour consent, per report (Art. 6(1)(a))
Website analyticsYour consent (Art. 6(1)(a))
Security logs, audit trail, abuse preventionLegitimate interests (Art. 6(1)(f)) and legal obligation

International transfers. We and all processors in §7 process data in the United States. Transfers from the EEA/UK rely on the EU-U.S. Data Privacy Framework where the recipient is certified, and otherwise on Standard Contractual Clauses (and the UK Addendum) in our agreements with those processors. Contact us for details.

Automated decision-making. EyeSpeak uses AI models to interpret your commands and act on your Mac. It does not make decisions producing legal or similarly significant effects about you. Usage allowances are enforced by fixed numeric limits, not by profiling.

16Children

EyeSpeak is not directed to children under 13 (or under 16 where that is the age of digital consent), and we do not knowingly collect personal information from them. The beta is invitation-only. If you believe a child has provided us personal information, contact privacy@eyespeak.ai and we will delete it.

17Changes to this policy

We will post any change here with a new effective date, and for material changes we will notify signed-in users in the App or by email to the address on the account before the change takes effect. Because this policy is generated from the code, a change in what the App or Gateway does that affects your privacy will be reflected here in the same release.

18Contact

[LEGAL ENTITY NAME]
[REGISTERED ADDRESS]
Privacy: privacy@eyespeak.ai
Security: security@eyespeak.ai
EU/UK representative (if required under Art. 27): [NAME AND ADDRESS, or “not required”]

AThe complete analytics vocabulary

Every analytics event is reduced to the following on your Mac (eyespeak/telemetry_schema.py) and again on the Gateway. Anything not listed here is discarded on both sides.

Event names (App): app_launched, app_active, app_quit, signed_in, signed_out, permission_state, onboarding_started, onboarding_step_completed, onboarding_skipped, onboarding_finished, try_prompt_shown, try_prompt_spoken, command_started, command_completed, command_corrected, limit_reached, update_offered, update_installed, update_failed, bug_report_submitted, dashboard_opened, feature_used.

Event names (Website): landing_viewed, waitlist_submitted, invite_created, download_started, beta_viewed.

Enumerated properties (value must be in the set):

PropertyAllowed values
personastudent, professional, creative, researcher, developer, engineer, other
intentnavigate, edit_text, document, data, communication, web_research, file_management, media, cad, study, system, query, other
app_categorycommunication, browser, productivity, document, data, media, cad, study, development, developer, system, other
source (renamed input_source on the server)voice, typed, brush, dashboard, app, web, hotkey, dictation
routefastpath, fast, prior, agent, plan, computer, dictation, direct, cached, unknown
outcomeok, failed, aborted, cancelled, blocked, unknown
kindcommand, correction
methodgoogle
stepsignIn, role, detail, goals, permissions, tryPrompt, ready, sign_in, persona, coach, name
pagehome, settings, welcome, setup, turn
kind_commands, model_calls, input_tokens, output_tokens, voice_seconds, tier, turn, spend, access, unknown
periodday, week, month
tierfast, standard, deep, vision, max
reasonquota, network, verification, download, install, unknown
featurebrush, dictation, command, dashboard, report, update
latency<250ms, <500ms, <1s, <2s, <5s, >=5s
accessibility, microphone, screen_recording, automationgranted, denied, not_determined, unknown, unavailable, restricted

Boolean properties: first_launch, skipped, fell_back_to_typing, verified, user_undo, corrective_rephrase, pack_stale, ok.

Bounded numeric properties: actions (≤10,000), model_calls (≤1,000), duration_ms (≤3,600,000), hands_free_seconds (≤3,600), matched_ratio (≤1), count (≤10,000), input_tokens and output_tokens (≤10,000,000).

List properties: goals (from: study, email_calendar, writing, research, three_d, cad, media, code, files, web); ops and op_counts (from: bind, open_app, open_url, navigate, menu, click, click_at, key, type, set_value, read, screenshot, scroll, wait, shell, script, api, doc_read, doc_write, doc_edit, save_as, blender, freecad, anki, drag, select, move, resize, focus, press, paste, copy).

Version property: to — a semantic version string.

Envelope (sent once per batch): version, build, channel, os, arch, install_id — each restricted to 64 characters of [A-Za-z0-9_.+-].

BWhere each commitment lives in the code

The EyeSpeak source is at github.com/EyeSpeakAI/EyeSpeak. Paths are relative to the repository root.

CommitmentEnforced in
Mic open only between key-down and key-up / dictation start and stop; ten-minute dictation ceilingeyespeak/voice.py, eyespeak/dictation.py, eyespeak/app.py
No camera permission or entitlement; test fails if addedpackaging/Info.plist.in, packaging/entitlements.plist, tests/test_packaging.py
Transcription bias off by default, env-onlyeyespeak/config.py (VOICE_CONTEXT)
Audio metered in 30-second blocks, not retained; model and upstream fixedserver/relay.py
Gateway never logs/persists/forwards a bodyserver/app.py (_proxy, _capture_unhandled), server/README.md (“The body policy”)
Per-request usage fieldsserver/schema.sql (usage_events, usage_daily)
Thinking-block HMAC, 30-day expiry, no reasoning textserver/schema.sql (thinking_receipts), server/app.py
Gateway proxies only reviewed model/provider setserver/app.py (ModelPolicy table)
HTTPS-only; no redirects with bearer token; released builds ignore env overrideseyespeak/gateway.py (_insecure, _NoRedirect, base_url), eyespeak/analytics.py (secure_endpoint), eyespeak/update.py (_SafeRedirect)
Local trace and history never uploadedeyespeak/trace.py (“Nothing here uploads anything”), eyespeak/history.py, eyespeak/debugreport.py
Structural projection allow-list (shared_view)eyespeak/trace.py
Analytics allow-list on both sides; unknown keys droppedeyespeak/telemetry_schema.py (properties, envelope), server/product.py (events)
Analytics off deletes the outbox; sign-out / account change resets iteyespeak/analytics.py (set_enabled, reset_account), eyespeak/gateway.py (sign_in, sign_out)
Outbox bounds: 5,000 rows / 5 MB / batches of 100eyespeak/analytics.py
Gateway rejects events older than 30 days; 20,000/day cap; PostHog $geoip_disableserver/product.py
PostHog host restricted to US/EU ingestionserver/product.py (deliver)
Onboarding and Settings disclosuresmacos/Sources/EyeSpeakHUD/OnboardingSignIn.swift, macos/Sources/EyeSpeakHUD/SettingsPage.swift
Crash events rebuilt: type + in-app frames only; message replaced; PII/locals/breadcrumbs offeyespeak/crashes.py (scrub, configure)
Bug report contents; secret-suffix redaction; no screenshotseyespeak/debugreport.py
Bug report credential sweep; refuse on failed redaction; preview-then-send; always saved locally firsteyespeak/reportupload.py, eyespeak/reportflow.py
Report body to R2 only; row without body; 20/day; server-side deleteserver/product.py (reports, delete_report), server/storage.py, server/schema.sql (reports)
90-day report lifecycle; 13-month analytics outbox trimserver/admin.py (retention)
Google ID token verified server-side; email must be verified; access/refresh tokens never sent to Gatewayserver/app.py (_verify_google), eyespeak/gateway.py (sign_in)
Google scopes and single consent screeneyespeak/google_auth.py (SCOPES)
Tokens in Keychain via Security framework, in-processeyespeak/keychain.py, eyespeak/google_auth.py, eyespeak/gateway.py
Google revoke on sign-outeyespeak/google_auth.py (sign_out)
Fixed endpoint templates; host allowlist; planner never emits a URL; mutating endpoints gatedeyespeak/webapi.py (_ALLOWED_HOSTS, render, Endpoint)
Approve/Deny gate for dangerous steps; user-selectable modeeyespeak/settings.py (approval_mode), eyespeak/plan.py (is_dangerous)
Install ID random, 0600eyespeak/analytics.py (install_id)
Refresh tokens hashed, rotated, family revocationserver/schema.sql (sessions), server/app.py
Update manifest signature, notarization check, 5-minute download URLs, 50/dayeyespeak/update.py, server/product.py (artifact), server/storage.py
Website events, waitlist, download endpoints and their limitsserver/product.py (web_events, waitlist, beta_download)
Operator console fields and audit trailserver/console.py (_person, audit), server/console_schema.sql
Local data locationseyespeak/paths.py, eyespeak/config.py, eyespeak/lasso.py, eyespeak/platform/darwin/screen.py
Separate R2 credentials; public access disableddocs/beta-readiness.md (Cloudflare R2 row), server/storage.py
No App Sandbox; hardened runtime; library validation keptpackaging/entitlements.plist
Runtime socket directory 0700eyespeak/paths.py (runtime_dir, ensure)

Site analytics

A random browser ID counts landing and beta page views. You can change this any time.