Last updated: 2026-08-03

Privacy & GDPR

Short version: your usage data stays on your Mac — we run no server that ever receives it. What does leave a device is narrow and named: crash reports (Sentry) and product analytics (PostHog) are off by default and start only if you switch them on, in the app or via the banner on this site; both are hosted in the US. Cloudflare hosts this site and counts page views without cookies or a visitor ID. All three are documented in full below — written to satisfy GDPR, CCPA, and basic human decency.

Data controller

The data controller is the independent developer of Cavemode, reachable at notsu@devpon.com. EU residents may contact this address to exercise their GDPR rights (see "Your rights" below).

Lawful basis (GDPR Art. 6)

  • Consent — you paste your claude.ai session key into Cavemode knowingly. No data processing happens before that action. You can withdraw at any time by quitting the app and deleting the Keychain entry (Keychain Access → search "cavemode" → delete).
  • Contract performance — license verification against api.polar.sh is necessary to deliver the product you purchased.
  • No legitimate-interest processing, no profiling, no automated decision-making.

What Cavemode stores

  • Your Claude session key — stored in the macOS Keychain under the service identifier app.cavemode.session. Never transmitted to any server owned by us. Used only to make requests to claude.ai on your behalf, the same way your browser does.
  • Usage snapshots — an hourly record of your session and weekly utilization percentages, saved locally in your Library/Application Support/Cavemode/ folder so Cavemode can draw the weekly devolution report and project your burn-rate forecast (when you'll reach your limit at the current pace). Capped to the last 7 days. Computed and stored entirely on your Mac, never uploaded.
  • Spend snapshots (pay-as-you-go accounts only) — for each usage poll on a per-token-billed account (e.g. a Codex CLI account), Cavemode appends a small local record — timestamp, cumulative token count, an on-device cost estimate, and the model id — to Library/Application Support/Cavemode/spend_history.json. These records let Cavemode show your spend since local midnight and your recent burn rate. They are computed and stored entirely on your Mac, never transmitted, and capped to the last 7 days. Lawful basis: legitimate interest (on-device usage insight you asked for by connecting a pay-as-you-go account). Cleared automatically when you disconnect the account, and removable any time via the erasure step in "Your rights" below.
  • App preferences — sound on/off, refresh interval, launch-at-login, floating-widget visibility / content toggles / window position. Stored in UserDefaults.
  • Widget snapshot — no longer written. Older versions with the Notification Center widget wrote a widget-snapshot.json into the App Group container group.app.Cavemode.desktop. The widget has been removed, nothing writes or reads that file anymore, and the erasure step below covers the leftover container from an older install.
  • Minigame best scores — stored locally. Not uploaded.
  • Funeral already-seen marker — when your usage hits 100%, Cavemode plays a short "funeral" animation once. So that quitting and reopening the app doesn't replay it for the same lockout, Cavemode records one timestamp per account under the UserDefaults keys funeral.seen.* — the reset time of the limit window you're waiting on, or, when the API doesn't report one, the time you dismissed it. A timestamp and nothing else: no usage figures, no account name. Lawful basis: contract performance (not repeating an animation you already dismissed). Never transmitted; clear by quitting Cavemode and running defaults delete app.cavemode.macos.
  • Polar license state — your license key and the Polar activation id are stored in the macOS Keychain under app.cavemode.license so Cavemode doesn't re-prompt on every launch.
  • Rating-prompt cadence (Mac App Store build only) — small counters under the UserDefaults namespace reviewPrompt.* (cold-launch count, first-launch date, last-asked timestamp + version, weekly-report view count, post-purchase primer flag, onboarding-completed timestamp, first-paid timestamp). Used only to throttle Apple's system rating sheet — see "App Store rating prompt" below. Never transmitted; clear by quitting Cavemode and running defaults delete app.cavemode.macos.

Codex CLI account (cavemode.app download only)

If you choose to add an OpenAI Codex CLI account in Settings, Cavemode reads files Codex CLI maintains on your Mac, both of which are owned by your user account:

  • ~/.codex/auth.json — read when you connect the account (and again if the access token later lapses) to learn your account id, plan tier (ChatGPT Plus / Pro / etc.), the email on file, and the OAuth access_token the Codex CLI already holds. Cavemode copies that access token into the macOS Keychain — one entry per connected account — so it can read your usage. It never writes auth.json and never touches a refresh token; token rotation and revocation stay the Codex CLI's job.
  • ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl — Codex CLI writes one of these per conversation. Every turn it appends a rate-limit snapshot (5-hour primary + 7-day secondary buckets, with percentages and reset timestamps) to the file. Cavemode tail-scans the newest file as a local fallback for the account you're currently viewing. Nothing is written, nothing is transmitted.

Reading your quota requires one outbound request: Cavemode sends the account's access token to OpenAI's ChatGPT backend (chatgpt.com/backend-api/wham/usage), tagged with that account's ChatGPT account id, to read back its remaining 5-hour and weekly usage — roughly once a minute while the account is connected. This is what lets two different ChatGPT logins each show their own separate numbers. No prompt, conversation, or file content is read or transmitted; the request goes only to OpenAI's own servers, never to a server we operate, and OpenAI's own privacy policy governs how it handles it.

Excluded entirely from the Mac App Store build — the sandbox cannot reach ~/.codex/, so the Codex option does not appear in the App Store download. Lawful basis: performance of the user-requested function (Art. 6(1)(b)) — you explicitly add the account in Settings so Cavemode can show you its usage, and the access token exists solely to fetch that number. Disconnect at any time from Settings; the file reads and usage requests stop the same second and the account's copied access token is deleted from the Keychain immediately (Cavemode does not, and cannot, revoke the Codex CLI's own sign-in).

Gemini CLI account (cavemode.app download only, beta)

If you choose to add a Gemini CLI account in Settings, Cavemode reads ~/.gemini/oauth_creds.json — a file the Gemini CLI itself maintains on your Mac, owned by your user account — to learn your access token, refresh token, and the email on file so the popover can label the card. Both tokens are copied into the macOS Keychain (one entry per connected account). Unlike the Codex CLI integration above, checking your quota requires outbound requests to Google:

  • Cavemode sends your access token to Google's Code Assist API (cloudcode-pa.googleapis.com) to read back your remaining usage for the connected Google account, roughly every two minutes while the account is connected.
  • When that access token expires, Cavemode exchanges the refresh token for a fresh one via Google's token endpoint (oauth2.googleapis.com/token) — byte-for-byte the same call the Gemini CLI itself makes on its next run, using the CLI's own public installed-app client id. This keeps the quota reads working without you re-signing-in.

No other file content, prompt, or conversation data is read or transmitted; these requests go only to Google's own servers, never to a server we operate, and Google's own privacy policy governs how it handles them. Personal Google accounts (free, AI Pro, AI Ultra) are not supported by the quota API as of mid-2026 — Cavemode shows an honest message instead of a usage number for those accounts; Workspace and Code Assist Standard/Enterprise accounts work normally.

Excluded entirely from the Mac App Store build — the sandbox cannot reach ~/.gemini/, so the Gemini CLI option does not appear in the App Store download. Lawful basis: performance of the user-requested function (Art. 6(1)(b)) — you explicitly add the account in Settings so Cavemode can show you its usage, and the tokens exist solely to fetch that number. Disconnect at any time from Settings; the file reads, quota requests, and token refreshes stop the same second and both copied tokens are deleted from the Keychain immediately (Cavemode does not revoke the Gemini CLI's own sign-in).

Claude account — three ways to connect

Cavemode offers three ways to connect a claude.ai account, all reachable from the same "Add account" flow. Only one needs to succeed; you pick whichever is easiest.

  • Sign in inside Cavemode (default). Cavemode opens claude.ai's real login page inside a sandboxed, in-app browser window (WKWebView) and, once you sign in, captures the resulting sessionKey cookie automatically — the same cookie your regular browser would receive, just read once at the moment login succeeds instead of you copying it from DevTools. The embedded browser talks only to claude.ai; Cavemode does not see your password, 2FA code, or anything you type into the page, only the cookie the page sets when login completes.
  • Import from Claude Code CLI. If you're signed in to the Claude Code CLI, Cavemode reads its OAuth credential — the Keychain item Claude Code-credentials, or failing that ~/.claude/.credentials.json, or the CLAUDE_CODE_OAUTH_TOKEN environment variable — the same credential store the CLI itself reads and writes, owned by your user account and never modified by Cavemode. This is a different token from the sessionKey cookie above and can't be converted into one, so checking its quota calls a different endpoint: api.anthropic.com/api/oauth/usage, sending the token as an Authorization: Bearer header the same way the Claude Code CLI itself does. Excluded from the Mac App Store build — the sandbox cannot reach ~/.claude/ or that Keychain item.
  • Paste a session key manually. The original flow — copy your sessionKey cookie from claude.ai's DevTools and paste it into Cavemode. Ships in every build.

Whichever way you connect, the resulting credential is stored in the macOS Keychain, used only to call claude.ai or api.anthropic.com on your behalf, and never transmitted to any server we operate. Lawful basis: performance of the user-requested function (Art. 6(1)(b)) — you take an explicit action (sign in, import, or paste) to connect each account, and the credential exists solely to fetch the usage numbers you asked to see. Disconnect any time from Settings; see "Your rights" below for the full erasure path.

Looking for sign-ins already on your Mac (opt-in)

Claude Code, Codex and Gemini each save their own sign-in on your Mac when you use them. Cavemode can look for those, so that connecting an account is one tap instead of a copy-and-paste. It asks first. The first time you open the connect screen, Cavemode shows a plain-language disclosure explaining what it would look at, and reads nothing until you answer. Declining is a complete answer — the manual paste and sign-in paths all still work.

If you allow it, Cavemode reads only these locations, all of which belong to your own user account and are written by those apps themselves:

  • The Keychain item Claude Code-credentials, or failing that ~/.claude/.credentials.json (Claude Code)
  • ~/.codex/auth.json (Codex)
  • ~/.gemini/oauth_creds.json (Gemini)

The read is read-only — Cavemode never writes to, moves, or signs out of another program's credential store, and never consumes the rotating refresh tokens those files hold. What it finds (which of the three is present, and the email or account label inside, where there is one) is shown to you on screen so you can confirm or deselect each one before anything is connected. None of it is transmitted anywhere — not to us, not to any third party. The result is held in memory while the screen is open and is gone when you close it; nothing about what was found is written to disk.

What is stored: exactly one value — your yes/no answer, as the string allowed or declined, under the connect.localSignInScan.decision preference key. It records whether we may look; it cannot record what was found. Lawful basis: consent (Art. 6(1)(a)), given by your explicit answer and withdrawable at any time in Settings → Privacy. Excluded from the Mac App Store build entirely — that build's sandbox cannot read another app's files, so it says so plainly instead of showing an empty result.

OpenRouter account

If you paste an OpenRouter API key in Settings, Cavemode stores it in the macOS Keychain (one entry per connected account) and calls GET https://openrouter.ai/api/v1/key with your key as an Authorization: Bearer header — roughly once a minute while the account is connected — to read back your remaining balance or rate limit. Nothing else is sent to OpenRouter; Cavemode never reads or transmits your prompts, model choices, or request history. Ships in every build (plain HTTPS, no filesystem access needed). Lawful basis: performance of the user-requested function (Art. 6(1)(b)) — you paste the key yourself so Cavemode can show you your own OpenRouter usage. Disconnect any time from Settings; the key is deleted from the Keychain immediately.

GitHub Copilot account (beta, cavemode.app download only for now)

If you connect a GitHub Copilot account, Cavemode starts GitHub's OAuth Device Flow (RFC 8628): it requests a device code from github.com/login/device/code, shows you a one-time code and a GitHub verification link, and polls github.com until you approve it in your own browser. GitHub then issues a bearer token, which Cavemode stores in the macOS Keychain and uses to call the undocumented GET https://api.github.com/copilot_internal/user endpoint every couple of minutes to read back your Copilot plan and quota. In plain terms: no password, no browser embedded inside Cavemode for this one — you approve the connection on GitHub's own site.

Honest disclosure: because GitHub does not offer a public OAuth client id for third-party Copilot-quota tools, this device flow authenticates using the OAuth client id GitHub's own VS Code Copilot Chat extension uses — the only client id GitHub's undocumented copilot_internal/* endpoints currently accept for this kind of read. It is not an app we registered ourselves, and GitHub could revoke or change that access at any time; a kill switch (FeatureFlags.copilotProviderEnabled) lets us pull the feature without an app update if that happens. This is disclosed here so you can make an informed call about connecting a Copilot account. Lawful basis: performance of the user-requested function (Art. 6(1)(b)) — you explicitly start and approve the device-flow connection so Cavemode can show you your own Copilot usage. Disconnect any time from Settings; the token is deleted from the Keychain immediately.

Cursor account (beta, cavemode.app download only for now)

Cursor offers two ways to connect, both landing on the same cookie: Cavemode can open cursor.com's real login page inside a sandboxed, in-app browser window (the same WKWebView capture described for Claude above) and read back the WorkosCursorSessionToken cookie once you sign in, or you can paste that cookie value yourself from DevTools. Either way, the cookie is stored in the macOS Keychain and used to call the undocumented GET https://cursor.com/api/usage-summary endpoint roughly once a minute to read back your included-plan usage and on-demand spend.

Honest disclosure: that endpoint is a private dashboard API, not a published Cursor API — its shape has changed before and could change again without notice, which is why this connection carries a "Beta" label in the app and defensive parsing that degrades to an honest "unavailable" state rather than showing a wrong number. A kill switch (FeatureFlags.cursorProviderEnabled) lets us pull the feature if Cursor's endpoint stops working entirely. Lawful basis: performance of the user-requested function (Art. 6(1)(b)) — you sign in or paste the cookie yourself so Cavemode can show you your own Cursor usage. Disconnect any time from Settings; the cookie is deleted from the Keychain immediately.

AI agent activity bubbles (cavemode.app download only)

The floating widget can show what your local AI coding agents are doing — working, finished, or waiting for your approval — and let you answer Claude Code permission prompts from the widget. To do this, Cavemode:

  • adds hook entries to ~/.claude/settings.json that point at a small helper bundled with the app. The helper forwards Claude Code's hook events (session id, working directory, tool name and input, the last assistant message excerpt) over a private local socket to the Cavemode app on the same Mac. Nothing is transmitted off the device, stored to disk, or added to analytics — the events live in memory only while the session runs.
  • tail-reads Claude Code transcript files and Codex CLI rollout files to show a short excerpt of the latest result in the bubble. Read-only, local-only.
  • while an agent is actively working and the widget is visible, checks how fast its transcript file is growing — a byte-count only, no file content is read for this — about once a second, so the character can “type along” and speed up when output flows fast. The count is used in memory to pick an animation and is never stored or transmitted. Turn off “Typing reaction” in Settings to stop this sampling.

This is on by default so the widget works out of the box, and the Settings pane discloses it next to the toggles. Turn off “Show AI coding activity” in Settings and Cavemode removes its hook entries from ~/.claude/settings.json the same second — that is also the full erasure path, since no agent data is ever persisted. Excluded entirely from the Mac App Store build (the sandbox cannot reach ~/.claude/). Lawful basis: legitimate interest (Art. 6(1)(f)) — narrowly scoped to rendering your own local agents' status on your own screen, with a one-click opt-out. The three related analytics counters (hooks installed / removed, approval decided) carry no content and ship only if you separately opt in to product analytics (off by default).

Accelerometer reads (Slap Attack minigame only)

On Apple Silicon MacBooks (M1 Pro and later), the Slap Attack minigame reads the laptop's built-in motion sensor so a real physical slap can trigger a hit. Data is processed locally and discarded after each sample — nothing is written to disk, nothing is transmitted, and the sensor is only opened while the minigame is on-screen. Desktop Macs and other Apple Silicon models without the sensor fall back to click input with no motion access.

Network requests

Every install makes at most three kinds of network requests out of the box. Connecting an optional provider account (Codex, Gemini CLI, OpenRouter, GitHub Copilot, Cursor, or the Claude Code OAuth import tier) adds the request kinds documented in that provider's own section above — usually a single usage read, though Gemini CLI also refreshes its access token against Google's token endpoint when it expires. Each one only starts after you explicitly connect that account, and stops the moment you disconnect it.

  1. To claude.ai — to read your own usage, every 60s, using the session key you provided during onboarding. Plus one immediate fetch the first time you paste a session key, so Cavemode can show your current devolution stage before you ever close the onboarding window. This is identical to what your browser does when you open Claude.
  2. To api.polar.sh — cavemode.app download only. Once at first launch to activate your license key, and a lightweight re-check roughly every 30 days so Polar can revoke refunded or shared keys. The request contains the license key, a device label (your Mac's hostname, e.g. Johns-MacBook-Pro), and an activation id; no user-identifying data beyond that. Excluded entirely from the Mac App Store build.
  3. To Apple StoreKit — Mac App Store build only. Standard Apple in-app purchase / restore flow, handled by the operating system. Cavemode reads Transaction.currentEntitlements locally to verify the lifetime unlock; Apple processes payment and card data under its own privacy policy. Excluded entirely from the cavemode.app download.

No default-on analytics, crash reporting, or telemetry. The two optional toggles in Settings → Privacy & diagnostics (described in the next section) are the only paths by which anything can leave your device — and both are off out of the box.

App Store rating prompt (Mac App Store build only)

On Mac App Store builds, Cavemode may ask the operating system to display Apple's standard rating prompt after positive in-app moments — a new Slap Attack personal best or a return visit to the weekly devolution report. The prompt is rendered and rate-limited by macOS (Apple caps it to 3 prompts per 365 days, system-wide); we do not transmit any rating data and have no way to observe whether you rated, dismissed, or how many stars you chose. Cavemode only knows that it asked the system to show the prompt.

You can also tap "Rate Cavemode on the App Store" in Settings at any time to open the App Store review page directly — useful when the automatic moments don't catch you, since the user-initiated path bypasses Apple's 3/365 cap. The prompt is excluded entirely from the cavemode.app download (which has no App Store listing to rate).

Feedback email

If you tap "Grunt at us" in Settings → About, choose "ME HAVE NOTES" on the occasional "How's it going?" card, or use the /feedback page on this site, Cavemode opens your own mail app with a prefilled message to notsu@devpon.com. Nothing is sent until you press send in your mail client, and the message travels through your email provider — never through a Cavemode server or web form.

From the app, the message includes a small, non-identifying context footer to help us act on bug reports: app version and build, build channel (Mac App Store or cavemode.app), your macOS version, the current devolution stage (0–5), how many accounts you've connected (a count, not identities), and your locale. It never includes your name, your Claude or Codex account, your session key, your license key, or any file path — and you can edit or delete any of it before sending.

Lawful basis (GDPR Art. 6): consent — you choose to write and send the email. We process your email address and message only to read and reply, and keep it no longer than needed to resolve your point. Erasure: reply asking us to delete the thread, or email notsu@devpon.com, and we'll remove the correspondence.

Software updates (Polar.sh distribution only)

The cavemode.app download channel needs its own update path because it ships outside the Mac App Store. We use Sparkle — the open-source macOS update framework — and serve a signed appcast at https://cavemode.app/appcast.xml.

  • Off by default. Settings → Updates → "Automatically check for updates" is the toggle. Until you turn it on, Cavemode never fetches the appcast on its own. Pressing "Check for Updates…" performs exactly one request, and is the only request that runs while the toggle is off.
  • What gets sent. A standard HTTP GET to the appcast URL with a User-Agent string identifying the app, its version, and the Sparkle library version (format: Cavemode/1.0.0 Sparkle/2.x.y). No analytics, no identifiers, no usage data, no IP-derived profile. Cloudflare Pages serves the file and keeps standard access logs (IP, timestamp, status code) under its own privacy policy; we do not query or correlate them.
  • Lawful basis. Explicit consent (Art. 6(1)(a)) — you flip the toggle. Disable it at any time and the requests stop the same second.
  • Mac App Store builds. The Updates section in Settings is informational only — it states that updates flow through the App Store and offers a "Check the App Store" button that hands off to Apple's Mac App Store app. Cavemode itself makes no update-related network requests on the App Store binary; Sparkle is not compiled into it and the appcast URL above is never contacted from that build.

Optional diagnostics & product analytics (opt-in, off by default)

Settings → Privacy & diagnostics exposes two toggles, both defaulting to off. Turning them on is the only way any diagnostic or product event leaves your device. Toggle them off at any time and the outbound pipe stops immediately.

  • Anonymous crash reports — when on, Cavemode routes symbolicated crash traces, main-thread hang reports, and error breadcrumbs to a crash-reporting processor. Every outbound payload passes through an on-device redaction pass that strips /Users/<your-name> paths, URL query strings, Claude session keys matching sk-ant-sid01-…, Polar license keys, and Authorization / Cookie header values. Each report is tagged with the same coarse, non-identifying context as product events — app version + build, build channel, macOS version, Mac model family, language/region, and entitlement tier — to help triage crashes. No email, IP, or device serial is sent.
  • Anonymous usage stats — when on, Cavemode sends a small set of typed product events (onboarding completed, paywall viewed, minigame started, share exported, stage changed, …) to a product-analytics processor. Each event is tagged with a random device UUID generated locally on first opt-in and reset the moment you opt out. Event properties are typed enums only — no free-form strings, no file paths, no license keys, no session keys. Each event also carries a few coarse, non-identifying context fields — app version + build number, build channel (App Store vs direct), macOS version, Mac model family (e.g. MacBookPro18,3), system language/region (e.g. en_US), how many accounts you've added, and your entitlement tier (free vs paid). No precise location, no serial number, no hostname.

Active processors: Sentry (US region, ingestion at *.ingest.us.sentry.io) for crash + error reports; PostHog (US cloud, ingestion at us.i.posthog.com) for product analytics. Both operate under signed Data Processing Agreements (GDPR Art. 28). Sentry Inc. and PostHog Inc. are both U.S.-based, so telemetry — when you opt in — is transferred outside the EEA. We rely on each vendor's published transfer mechanism (Standard Contractual Clauses and/or EU–U.S. Data Privacy Framework certification) for that transfer; current status for each vendor is on their respective processor pages. Every outbound payload first passes through a local redactor (PrivacyScrubber) that strips file paths, Claude session keys, Polar license keys, and URL query strings — audited rule-by-rule in the open-source test suite.

The macOS toggles default OFF. While off, the SDKs never start and zero outbound calls are made. Flipping a toggle on lets the corresponding SDK initialize within the running process; flipping it off calls SentrySDK.close() + PostHogSDK.optOut() so mid-session changes take effect immediately. The toggles persist as booleans under UserDefaults keys diagnostics.crashReportingEnabled / diagnostics.productAnalyticsEnabled.

After a successful purchase, we identify the now-paid user with SHA-256(license key) — never the raw key, never email — so events from a known-paid install can be grouped without storing PII. The same hash is set as Sentry's user.id for crash deduplication. Anonymous installs use a UUID stored in macOS Keychain under service app.cavemode.analytics.

Lawful basis: consent (GDPR Art. 6(1)(a)). Withdraw at any time by flipping the toggle off. Retention (planned): crash reports 90 days, product events 12 months. Right to erasure (GDPR Art. 17): email notsu@devpon.com with the anonymous device UUID shown under Settings; we submit deletion requests to both processors within 30 days and reply when they confirm.

Cookies + third-party services on this website

This site (cavemode.app) is a pure static SvelteKit build hosted on Cloudflare Pages. It loads no fonts from external CDNs. Your browser's localStorage stores two keys — theme (light/dark preference) and cavemode_consent_v1 (your cookie-banner decision: {analytics:bool, decided:bool}). The language switcher also stores a functional first-party PARAGLIDE_LOCALE cookie so your selected language wins over browser auto-detection on future visits. These stay on your device.

On first visit you see a cookie banner. Clicking Reject leaves the site with zero outbound observability requests. Clicking Accept activates the same two processors used by the macOS app: PostHog (autocapture clicks/forms, page views — all text content and element attributes masked before send) and Sentry (error reports plus performance traces sampled at 10%; replays activate only when an error is captured, with all text masked and media blocked). PostHog stores a first-party cookie (ph_*) plus localStorage entries for distinct_id continuity. Both SDKs send to US endpoints (us.i.posthog.com, *.ingest.us.sentry.io) under the EU–U.S. Data Privacy Framework adequacy decision. You can revoke at any time by clicking Reject in the banner (re-summon it via DevTools → Application → Local Storage → delete cavemode_consent_v1).

Clicking a "Download" button on this site pulls the macOS DMG directly from dl.cavemode.app/Cavemode-latest.dmg — a Cloudflare R2 object-storage subdomain we operate alongside the marketing site (dl. is a CNAME we control inside the same Cloudflare account; no third-party CDN is involved). The same Cloudflare access-log disclosure above covers it. Before the click, the button performs a cross-origin HEAD probe to confirm the DMG is reachable; if the probe fails (a deploy gap, a network error), the button relabels itself and points at Apple's Mac App Store listing instead. The app is free on both routes — this site has no checkout, and no button on it can send you to a payment page.

Following the App Store link opens apps.apple.com in a new tab, where Apple's own privacy policy applies. Nothing about you is passed in that link beyond the app id, and the website loads no Apple code, fonts, or pixels — the "Download on the Mac App Store" badge is an SVG we host ourselves.

Cloudflare Pages, our static host, processes standard IP-level access logs for DDoS protection and diagnostics under their processor agreement (cloudflare.com/privacypolicy). These logs are not correlated with any Cavemode-specific data.

Cloudflare Web Analytics. We use Cloudflare's privacy-first Web Analytics to count aggregate page views per URL — for example, how many people open cavemode.app/from/death after a friend shares a death certificate. It is cookieless: it sets no cookies, writes nothing to localStorage, assigns no visitor ID, and builds no cross-site or cross-visit profile. Because it runs entirely on Cloudflare — already our hosting processor under the agreement above — it introduces no new data exporter: the same edge that serves the page does the counting, and the IP is used transiently to derive a bot-filtered visit count, never stored against you. On that basis (data minimisation, no device identifier) it runs under legitimate interest without the consent banner, separate from the opt-in PostHog/Sentry processors described earlier. Cloudflare's analytics privacy notes: cloudflare.com/web-analytics.

Share links and attribution

When you tap a Share button inside Cavemode (death certificate, weekly report, current-usage snapshot, or Slap Attack receipt), the link embedded in your caption is a cavemode.app URL decorated with ?utm_source, utm_medium, utm_campaign, and ref query parameters. The ref value is an 8-character random token generated on your Mac the first time you share. The token is opaque and contains no personal data. The website does nothing with it: there is no checkout for it to flow into (the app is free), so the parameters are simply ignored, and the only measurement of a shared link is the cookieless, aggregate page-view count Cloudflare keeps for the /from/… URL itself.

The share image itself carries a small QR code and a printed cavemode.app address in its footer, so a screenshot or a caption-stripped repost can still lead someone back to the app. The QR encodes exactly the same cavemode.app/from/<card> URL with the same opaque ref token and utm parameters described above (its medium is tagged card) — it is generated entirely on your Mac with Apple's built-in QR generator, contains no personal data, and adds nothing new that leaves your device. Those links now open a matched landing page (for example /from/death) instead of the generic homepage, which is the same static site covered above.

When a visitor lands on cavemode.app carrying those query parameters, the site stores nothing. It used to stash them in the browser's sessionStorage under the key cavemode_ref so a checkout could carry the attribution; with the app free there is no checkout, so the stash had no purpose and was removed — a store with no use is exactly the kind of collection data minimisation forbids. No cookies and no sessionStorage entries are written for attribution, and nothing about the visit is transmitted to us.

You can reset your own ref token any time by running defaults delete app.cavemode.Cavemode app.cavemode.shareId in Terminal. The next share regenerates a fresh token. The Instagram mechanic also writes share images to ~/Pictures/Cavemode/ on your Mac so you can AirDrop them to your phone — drag them to Trash any time to delete.

Adaptive menu bar — what runs locally

To survive the MacBook notch on small screens, Cavemode reads NSScreen.safeAreaInsets on launch and observes the NSWindow.didChangeOcclusionStateNotification stream for the menu-bar icon's window. Both signals are read-only system APIs scoped to your own user session — nothing about your display configuration leaves your Mac. When Cavemode detects the icon is clipped, it locally posts a macOS notification and narrows the menu-bar title; no event is sent anywhere unless you have opted into product analytics, in which case a single menu_bar_auto_compacted event records that the heuristic fired.

Cavemode also registers a system-wide keyboard shortcut (⌃⌥⌘C by default) so you can open the popover even when the menu-bar icon is hidden. The shortcut is registered via macOS's Carbon RegisterEventHotKey API and is processed entirely on your Mac. No accessibility permission is requested.

Cavemode ships a small companion process — CavemodeMenuBarHelper (app.cavemodeapp.menubar) — embedded inside the main app bundle at Cavemode.app/Contents/Library/LoginItems/. It runs alongside the main app and owns the actual menu-bar icon. The split exists because macOS's menu-bar slot allocator can deny new icons for an entire bundle-id prefix; routing the icon through a separate prefix is the only reliable workaround. The helper is registered as a Login Item via macOS's SMAppService API on first launch (you may see an approval prompt in System Settings → General → Login Items). It communicates with the main app entirely through a local NSXPCConnection (mach service group.app.cavemode.shared.menubar) — no network access, no Keychain access, no file access. The connection is scoped to your own login session via a shared App Group entitlement. If you decline the Login Item, the main app continues to run; only the menu-bar icon goes away.

Your rights (GDPR Art. 15–22)

  • Right of access & portability — Cavemode stores nothing on any server. The data on your device (Keychain + local files) is already in your possession; export it via macOS tools at any time.
  • Right to rectification — re-enter your session key in Cavemode's settings.
  • Right to erasure ("right to be forgotten") — quit Cavemode, delete the Keychain entries app.cavemode.session and app.cavemode.license, and drag ~/Library/Application Support/Cavemode — plus, if you ever used the old Notification Center widget, the leftover App Group container ~/Library/Group Containers/group.app.Cavemode.desktop — to the Trash. Deleting the app removes them automatically. Nothing remains. For Polar order data, contact Polar directly.
  • Per-account erasure, without deleting the app. Every connected provider account (Claude, Codex, OpenRouter, GitHub Copilot, Cursor, Gemini CLI) keeps its credential in its own Keychain entry. Removing that account from Cavemode's account list — "Remove account" in Settings or the account rail — deletes its Keychain entry immediately, the same second, with no further action needed. This is the in-app deletion path for any single provider connection; you don't need to uninstall Cavemode or contact us to disconnect one account.
  • Erasing your answer about looking on this Mac. Settings → Privacy has a "Look for sign-ins on this Mac" switch and a "Forget my answer about looking on this Mac" button. The switch withdraws consent — Cavemode stops looking immediately. The button goes further and deletes the stored answer outright, so afterwards the app holds no record that the question was ever asked and will ask again next time. That one preference value is the only thing this feature ever writes, so removing it is a complete erasure; accounts you already connected are unaffected and are removed separately, per the bullet above.
  • Right to object, right to restrict processing — stop using the app; no processing continues.
  • Right to lodge a complaint — with the supervisory authority in your EU member state.

Data transfers

The app calls claude.ai (Anthropic PBC — USA) and api.polar.sh (Polar Software Inc. — USA) using your authenticated session. These are direct peer-to-peer calls from your Mac; Cavemode does not proxy, log, or observe them. Both providers have published data-transfer mechanisms (SCCs) for EU↔US flows.

Retention

Local files rotate according to your usage history settings (default: 7 days of snapshots). All retention happens on your device. The app never sends retention metadata anywhere.

Children

Cavemode is a developer tool. We do not knowingly collect or process data from anyone under 16.

What Cavemode never does

  • Send your prompts, conversations, or responses anywhere
  • Log what you type into Claude
  • Read Claude's web interface DOM
  • Share your session key with anyone, ever
  • Install kernel extensions, system services, or anything else invasive

Changes to this policy

Material changes (new data categories, new third parties, new retention periods) will be announced in the in-app release notes and on the changelog at least 14 days before taking effect. Minor wording updates bump the "Last updated" date above.

Questions?

Email notsu@devpon.com — replies within 72 hours on weekdays. GDPR data-subject requests are honoured within 30 days (Art. 12).