Privacy & GDPR
Short version: Cavemode keeps your data on your Mac. There is no server. There is no analytics. There is no tracker. Long version 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 toclaude.aion 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 (macOS widget only) — when you add the Cavemode
widget to Notification Center or the desktop, Cavemode writes a small JSON file
(
widget-snapshot.json) into a shared App Group container (group.app.Cavemode.desktop). The widget runs as a separate sandboxed process that cannot reach the network or your Keychain, so this file is the only way it can draw your current devolution stage, usage %, reset time, account name, and (pay-as-you-go only) today's spend. It holds only what the widget shows — no session key, nothing beyond the account label you set. Written entirely on your Mac, never transmitted. Lawful basis: contract performance (showing you your own usage). Removed when you delete the app; see the erasure step in "Your rights" below. - Minigame best scores — stored locally. Not uploaded.
- Polar license state — your license key and the Polar activation
id are stored in the macOS Keychain under
app.cavemode.licenseso Cavemode doesn't re-prompt on every launch. - Rating-prompt cadence (Mac App Store build only) — small
counters under the
UserDefaultsnamespacereviewPrompt.*(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 runningdefaults 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 two files Codex CLI maintains on your Mac, both of which are owned by your user account and never leave your device:
~/.codex/auth.json— read once when you connect the account, to learn your account id, plan tier (ChatGPT Plus / Pro / etc.), and the email on file so the popover can label the card. Cavemode never calls OpenAI's servers with these tokens; refresh + 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 each poll to surface that snapshot on the menu bar. Nothing is written, nothing is transmitted.
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: consent (Art. 6(1)(a)) — you explicitly add the
account in Settings. Disconnect at any time from Settings; the file reads stop
the same second.
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.jsonthat 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
Cavemode makes at most three kinds of network requests:
- 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. - 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. - To Apple StoreKit — Mac App Store build only. Standard Apple
in-app purchase / restore flow, handled by the operating system. Cavemode reads
Transaction.currentEntitlementslocally 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).
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 matchingsk-ant-sid01-…, Polar license keys, andAuthorization/Cookieheader 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}). Both 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
click falls back to Polar's hosted checkout at polar.sh, which has its own privacy policy
(polar.sh/legal/privacy).
You only reach polar.sh on a deliberate purchase — either from the in-app paywall when you decide to unlock the paid features, or via the fallback path described above if a deploy mishap leaves the DMG unreachable. Polar is the Merchant of Record and data controller for your purchase, email, and payment info — we receive only the email and license key Polar issues. The website itself does not load any Polar code, fonts, or pixels.
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.
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, contains no personal data,
and exists so that if someone clicks a link you posted and buys, Polar's checkout
record keeps a note of which link they came from — useful for us to measure whether
Cavemode's share buttons actually convince anyone and, in future, to reward people
whose links drive purchases.
When a visitor lands on cavemode.app carrying those query parameters,
we stash them in the browser's sessionStorage under the key cavemode_ref for up to 30 days so that the ref can flow through to
Polar's checkout if the visitor buys. No cookies are set for this,
no identifier links the token to your Apple ID, payment, or device hostname, and
nothing is transmitted to our servers outside of the Polar checkout URL the
visitor deliberately opens.
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.sessionandapp.cavemode.license, and drag~/Library/Application Support/Cavemodeand the App Group container~/Library/Group Containers/group.app.Cavemode.desktop(the widget snapshot) to the Trash. Deleting the app removes both automatically. Nothing remains. For Polar order data, contact Polar directly. - 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).