SkyTwin is developed by Jay Zalowitz, an independent open-source contributor. Source code, including the entirety of the data-handling implementation, lives at github.com/jayzalowitz/skytwin under the Apache 2.0 license. There is no SkyTwin Inc., no cloud product, and no centralized data store. Contact: open an issue at github.com/jayzalowitz/skytwin/issues.
Which Google scopes SkyTwin can request depends on which OAuth client is in use. There are two tiers, and the difference matters:
A fresh desktop install uses an OAuth client owned by the SkyTwin project. That client is registered for identity and Calendar scopes only. It cannot request Gmail access — the code path that builds the authorization URL refuses to add Gmail scopes for the bundled client (resolveRequestedScopes in apps/api/src/routes/oauth.ts). The scopes it requests are:
openid + email + profile — to identify which Google account is connecting, used as the primary key for the local twin profile.https://www.googleapis.com/auth/calendar.readonly — to read your calendar so SkyTwin can spot conflicts, suggest times, and learn your scheduling preferences.https://www.googleapis.com/auth/calendar.events — to create, modify, and respond to calendar invites with your approval, or automatically for events that match patterns you have explicitly taught the twin.That is the complete list for the default install. If you never supply your own OAuth credentials, SkyTwin never asks Google for access to your mail.
Gmail's readonly and modify scopes are restricted scopes under Google's policy. Rather than put restricted scopes on a shared, project-owned client, SkyTwin requires you to create an OAuth client in your own Google Cloud project and paste its credentials into Setup (see Connect Gmail). Only then, and only if you explicitly opt in to Gmail during the connect flow, does SkyTwin additionally request:
https://www.googleapis.com/auth/gmail.readonly — to read incoming mail metadata and body content so SkyTwin can interpret signals (a newsletter just arrived; a friend asked for a meeting; a calendar invite needs response).https://www.googleapis.com/auth/gmail.modify — to apply labels and archive mail that you have taught SkyTwin to archive automatically, and to send Gmail replies or new messages after your approval or under autonomy rules you have explicitly enabled. SkyTwin does not permanently delete mail. Outgoing SkyTwin-sent emails include a small default-on footer linking to the open-source repo; you can turn that footer off in Settings.In this tier the OAuth client is yours; the grant is between you and Google, and the tokens are stored on your own machine exactly as described below.
SkyTwin can also connect Outlook mail and calendar via Microsoft Graph. There is no bundled Microsoft client — connecting Outlook means registering your own Microsoft Entra application and supplying its credentials, the same bring-your-own model as Tier 2 above. The Graph scopes requested are:
User.Read — to read the signed-in account's basic profile and email address, used as the account key for the local twin profile.Mail.Read — read-only access to Outlook mail so SkyTwin can interpret the same kinds of signals it reads from Gmail.Calendars.Read — read-only access to your Outlook calendar for conflict detection and scheduling context.offline_access — Microsoft's mechanism for issuing a refresh token so background sync survives a restart. It grants no additional data access of its own.The Outlook integration is read-only: SkyTwin does not request write scopes for Microsoft mail or calendar, so it cannot send Outlook mail or modify Outlook events. Microsoft user data is stored, used, and deleted on exactly the same terms as Google user data throughout this policy.
SkyTwin uses Google user data exclusively to provide the user-facing personal-assistant features visible in the SkyTwin desktop app. Specifically:
SkyTwin does not use Google user data for advertising, model training across users, lending decisions, or any purpose other than the personal-assistant features described above.
All data accessed via Google APIs — both raw API responses and any derived signals, decisions, preferences, and twin profile records — is stored exclusively in a CockroachDB database that runs locally on the device where SkyTwin is installed. The database files live in your operating-system-standard application data directory:
~/Library/Application Support/SkyTwin/crdb-data/%LOCALAPPDATA%\SkyTwin\crdb-data\~/.local/share/SkyTwin/crdb-data/Those files are protected by your operating system's normal file permissions — the same protection as the rest of your home directory. There is no additional SkyTwin-managed encryption layer over them by default.
dm-crypt on Linux. That is what actually protects your SkyTwin database if your machine is lost or stolen or its disk is imaged. We recommend enabling it before you connect an account.
SkyTwin ships a credential vault (@skytwin/credential-vault) that encrypts stored OAuth access and refresh tokens with AES-256-GCM, using a per-user key derived from a passphrase via scrypt. The key is derived on your device and never leaves it. We would rather be precise than reassuring about what this covers today:
oauthRepository.saveTokenForAccount, which stores access_token and refresh_token in plaintext columns — so setting a vault passphrase does not currently encrypt either existing or newly issued tokens. The vault is implemented and tested, but the key is not yet wired into the token save path. Assume your OAuth tokens are stored unencrypted and protect them with full-disk encryption.Your learned preferences (the preferences table), your twin profile (the twin_profiles table — inferences, communication style, risk tolerance, spend norms, routines, domain heuristics), and the textual memory the twin extracts from your correspondence (the brain_pages table — titles, body content, and metadata) are currently stored unencrypted in your local CockroachDB. The same is true of the derived search fields computed from them: the full-text index (content_tsv) and the semantic vector (embedding).
A column-level encryption schema and helpers for those three tables exist in the repository (migration 066-encrypt-high-value-tables.sql and packages/db/src/lib/vault-helper.ts), but they are not yet activated by any shipping code path — no running process supplies the vault key to them, so they operate in plaintext mode. Switching them on is tracked as issue #374. This page will be updated when that ships. Until then, treat those tables as readable by anyone who can read the files on your machine, and rely on full-disk encryption.
SkyTwin runs no analytics and collects no usage telemetry. No Google user data, no derived twin data, and no message or calendar content is ever sent to the SkyTwin developers or to any SkyTwin-operated server. The one exception is a cloud AI provider that you configure yourself — see Data sharing & transfers below, where prompts containing your data go to whichever provider you chose (including Google AI, if that is the one you picked). The default install makes no such calls.
The desktop app includes one optional, default-off diagnostic: “Send anonymous crash reports” in Settings. When — and only when — you turn it on, an unhandled crash uploads a small JSON report to https://crash.skytwin.dev/api/desktop/report containing the exception type, the error message, the stack trace, the app version, and your OS platform and CPU architecture. The message and stack are scrubbed before upload (redactPii in apps/desktop/src/crash-reporter.ts) to remove email addresses, home-directory paths, Bearer credentials, api_key= / token= / secret= / password= values, and bare keys carrying a recognizable vendor prefix (sk-, ghp_, xoxb-, AIza, and similar). Scrubbing is pattern-based, so a secret in an unrecognized format could still appear in a stack trace — which is part of why the setting is off by default. The report carries no account identifier, no signal or memory content, and no twin profile data. Leaving the setting off means no crash report is ever sent.
SkyTwin does not transfer Google user data to any third party for the developers' benefit — there is no analytics, advertising, model-training, or data-broker pipeline, and no SkyTwin-operated server ever receives it. The only network connections the app makes with your Google data are the ones below; note that item 2 (an optional, opt-in cloud AI provider you enable) is the single case where decision content is sent to a third party, and only then:
gmail.googleapis.com, calendar.googleapis.com, graph.microsoft.com) to fetch the data you authorized and carry out approved actions, including Gmail label/archive operations, Gmail sends, and calendar changes.llama.cpp runtime and makes no outbound LLM calls.getLlmClientFromConfig) now orders local providers (embedded llama.cpp, Ollama) ahead of cloud providers (Anthropic, OpenAI, Google) by default. A cloud key in your env no longer silently escalates that path to cloud-as-primary. Set SKYTWIN_LLM_PRIORITY=cloud-first on the API process to put cloud providers ahead of local — that's an explicit consent gate and the env var is the audit trail.
ai_provider_settings table, ordered by the per-row priority column. That path is NOT changed by this update; the user-facing toggle UI that unifies both ordering paths is tracked as a follow-up to the same issue. Until that ships, configure ai_provider_settings.priority via Settings to control your decision-pipeline ordering.
Separately from the list above, the desktop app can send an anonymous, PII-scrubbed crash report to crash.skytwin.dev if — and only if — you turn that default-off setting on. Crash reports contain no Google or Microsoft user data; see Telemetry and crash reports for the exact contents.
We do not sell user data. We cannot sell user data — we do not possess it.
The SkyTwin development team has no operational mechanism to read your Google or Microsoft user data. The data lives on your device, in files owned by your operating-system user account. The only people who can read it are:
SkyTwin's use of information received from Google APIs adheres to the Google API Services User Data Policy, including the Limited Use requirements. Specifically:
DELETE /api/users/:userId?confirm=delete-my-data) and underlying purge function (userPurgeRepository.purgeUser in packages/db/src/repositories/user-purge-repository.ts) execute the delete inside a CRDB serializable transaction, so a failure rolls back cleanly. The cascade list is exhaustive — every table backed by a user_id → users(id) foreign key carries ON DELETE CASCADE (see migration 061-cascade-cleanup.sql from #413), and the chained children (e.g. candidate_actions.decision_id, twin_profile_versions.profile_id, execution_plans.decision_id) are deleted explicitly first. Your linked Google account stays connected at Google's end; SkyTwin just stops seeing it and forgets what it learned.SkyTwin is not designed for or directed at children under 13. We do not knowingly collect data from children.
Material changes will be announced in the project CHANGELOG on GitHub (CHANGELOG.md) and reflected here. This page is versioned in git alongside the source code; previous revisions are available in the repository history.
Privacy questions, security disclosures, or data-handling concerns: open an issue at github.com/jayzalowitz/skytwin/issues or, for security-sensitive matters, follow the disclosure process described in SECURITY.md.