What Ciency sends over the network, what it keeps on the Mac, and what never leaves it. Written from the code as of 2026-10-10. Where this file and the code disagree, the code is right and this file is out of date.
Ciency has no analytics, no telemetry and no crash reporting: after a crash it reads the report macOS wrote, on the Mac, to tell the user what happened, and sends it nowhere (section 2, "Crash reports"). It has no account unless the user sets up iPhone & Cloud (Ciency Cloud, below), which is off until they do and absent from a build without a backend. Its only dependency outside Apple's frameworks is Sparkle, with system profiling switched off. Every network request below is started by something the user does, or by a setting the user can turn off. In this build the update feed, share-link, price-list and Ciency Cloud URLs are empty, so those four never make a request. Almost everything Ciency stores lives in its preferences and in one private folder, ~/Library/Application Support/Ciency/; section 2 lists the rest.
| Request | Host | When | Off switch | State in this build |
|---|---|---|---|---|
| Ciency's own update check | The CIENCY_FEED_URL host (planned: Cloudflare) | Hourly, 6 s after launch, and when Ciency becomes active, if the last check is over 15 min old. Also on Check for Updates | Settings → Updates → "Automatically check for updates" | Off: feed URL empty, updater never created |
| Online lyrics | lrclib.net | Once per song, while the lyrics pane is open | Opt-in: "Look up lyrics online" (off by default) | Works once the user opts in |
| Internet speed test | speed.cloudflare.com | Only when the user presses Run Test | Don't press it | Works |
| Share links | The CIENCY_SHARE_URL host (planned: Cloudflare Worker + R2) | Only when the user makes a link from a capture or recording, deletes one, or asks self-removal to delete them | "Shareable links that expire", plus a device token the user must paste | Off: URL empty, link controls hidden |
| AI price list | The CIENCY_PRICES_URL host (planned: Cloudflare) | At most once a day while AI Agents runs, or on "Check now" | AI Agents → "Keep prices current" | Off: URL and key empty |
| Codex account and resets | OpenAI, through Codex's own command-line tool | While the AI page's Banked resets card is on screen (at most every 5 min), on Retry, and on Spend a Reset | Hide the card, switch Codex off in AI Agents, or turn AI Agents off | Works in release builds |
| App Updates | uclient-api.itunes.apple.com, itunes.apple.com, each app's declared feed host, formulae.brew.sh, and whatever brew contacts | When the App Updates list opens and the last check is over 10 min old, on a manual check, on a source change, or on the optional schedule (off by default) | The three source switches, and the schedule | Works in release builds |
| Homebrew | Whatever brew contacts, and formulae.brew.sh | When the Homebrew page is used | Don't use the page | Works in release builds |
| Site icon for a radial menu link | The link's own host | Only when the user presses Fetch Icon | Don't press it | Works |
| Ciency Cloud (iPhone & Cloud) | The CIENCY_API_URL host (planned: Cloudflare) | Only after the user pairs an iPhone or signs in, and then only for the categories they switch on: when something they share changes | Each category's switch, Pause syncing, Sign Out This Mac… | Off: URL empty, the page isn't shown |
The rest of this section describes each one. The file and line where each request is made are listed so this file can be checked against the code.
App/Sources/UpdaterController.swift (startUpdater, checkForUpdatesInBackground, checkForUpdates). Configuration: App/Info.plist keys SUFeedURL, SUPublicEDKey, CiencyFeedToken, filled from the build settings CIENCY_FEED_URL, CIENCY_SPARKLE_PUBLIC_KEY and CIENCY_FEED_TOKEN in project.yml.scripts/release.sh refuses to make a release without both.SUScheduledCheckInterval 3600), about 6 s after launch if the last check is stale, and whenever Ciency becomes active and the last check is over 15 min old. A manual Check for Updates always asks. If an update is accepted, Sparkle downloads the archive the appcast points to.com.ciency.Ciency.feed-token, or the build setting), it goes in an Authorization: Bearer header. SUEnableSystemProfiling is false, so no hardware or system profile is sent. The host sees the IP address and Sparkle's request headers, which name the app and its version.Packages/CiencyKit/Sources/CiencyPlatform/Lyrics/LyricsLookup.swift:67. The query is built in CiencyCore/Island/IslandLyricsRules.swift (LyricsQuery.url).feature.islandLyrics.onlineLookup, off by default. The lyrics pane shows what turning it on sends before it is on. Turning it off cancels a lookup in flight.GET https://lrclib.net/api/get with the track title, artist, album (when known) and duration in whole seconds. A song with no artist, no duration (a live stream) or an oversized field is never sent. The User-Agent is Ciency/<version> (macOS lyrics, opt-in).lrclib.net; body capped at 128 KiB.Packages/CiencyKit/Sources/CiencyPlatform/Metrics/BandwidthCheck.swift:168 (latency), :178 (download), :189 (upload). Shown in the Network section of the System Monitor.https://speed.cloudflare.com/__down?bytes=0, then about 5 s of downloads from __down, then about 5 s of uploads of zero-filled bodies to __up. No data about the user or the Mac is sent. Ephemeral session, no cache.Packages/CiencyKit/Sources/CiencyPlatform/Sharing/LinkClient.swift (create :81, upload and complete :164/:166, delete :146, the HEAD check :155); CiencyFeatures/Tools/Screenshot/Links/LinkService.swift; self-removal step in CiencyPlatform/Removal/LiveRemovalSystem.swift.CIENCY_SHARE_URL is empty, so ShareEndpoint.url is nil and every link control stays hidden. Nothing is ever sent.feature.screenshot.links.enabled, on by default), and a device token has been pasted into Settings (stored in the Keychain as com.ciency.Ciency.share-token). Even then, nothing is uploaded until the user makes a link for a specific capture or recording.POST /v1/links with the kind, content type, byte size, SHA-256 of the file, and the expiry (1 hour, 1 day or 7 days), with the device token as a bearer token;PUT or in parts, then a complete call;DELETE /v1/links/<id> with the link's own delete token, when the user deletes a link, when a link is no longer wanted by the time its upload ends, or when self-removal is asked to delete links;HEAD on each deleted link's public URL, with no token, to confirm it is gone.Capture/links.json (each link's URL, expiry and delete token), pruned as links expire.Packages/CiencyKit/Sources/CiencyPlatform/Agents/PriceBookUpdater.swift:80; scheduling in CiencyFeatures/DynamicIsland/Agents/AgentsService.swift (checkPrices).CIENCY_PRICES_URL and CIENCY_PRICES_PUBLIC_KEY are empty, so nothing is ever requested. The list built into the app (CiencyCore/Agents/BuiltInPriceBook.swift) is used..sig file, with only a Ciency/<version> User-Agent. Ephemeral session, no cookies or cache, redirects only to the same host over HTTPS, 512 KiB cap. The list must carry a valid Ed25519 signature and be newer than the one kept, or it is refused.Agents/PriceBook.json and Agents/PriceBook.json.sig.feature.islandAgents.updatePrices, on by default).Packages/CiencyKit/Sources/CiencyPlatform/Agents/CodexAppServer.swift:117 starts the tool; AgentsService.swift (checkCodex, spendCodexReset) decides when.codex -c features.plugins=false app-server, found inside the Codex or ChatGPT app, in ~/.local/bin, /opt/homebrew/bin or /usr/local/bin. It talks to it over a pipe: initialize (client name ciency and Ciency's version), account/read, account/rateLimits/read, and, only after the user confirms Spend a Reset, account/rateLimitResetCredit/consume with a random idempotency key and the credit's ID.PATH is set to the usual tool folders), because Codex needs the user's own configuration, such as CODEX_HOME, proxies and certificates. Unlike the Now Playing host below, it is not given an empty environment, so anything in Ciency's environment is visible to Codex.Agents/codex-pending-reset.json (the idempotency key and its date) for 10 minutes after a reset gets no answer.-CiencyDebugRealCodex YES.Packages/CiencyKit/Sources/CiencyPlatform/Apps/UpdateNetwork.swift (feeds :115, App Store :138, catalog :146); URLs in CiencyCore/AppUpdates/UpdateSources.swift and UpdateFeeds.swift; flow in CiencyFeatures/Tools/AppUpdates/AppUpdateChecker.swift.feature.appUpdates.schedule) is Off by default.| Source switch | Host | What it receives |
|---|---|---|
| App Store apps | uclient-api.itunes.apple.com | Store item IDs of App Store apps, in batches of 20, and the Mac's region code |
| App Store apps | itunes.apple.com | Bundle IDs of those apps, in batches of 20, with the region code, then without it |
| Other apps | Each app's own feed host (its Sparkle SUFeedURL, or an electron-builder latest-mac.yml, which can be on github.com) | A plain GET of the URL as the app declares it |
| Other apps | formulae.brew.sh (/api/cask.json) | One download of the whole public cask catalogue; nothing about the Mac's apps |
| Homebrew apps | Whatever brew contacts | brew info --installed and brew outdated --cask --greedy; see Homebrew below |
-CiencyDebugRealUpdateChecks YES.Packages/CiencyKit/Sources/CiencyPlatform/Homebrew/BrewRunner.swift (brew runs; popularity download :202).brew itself: Ciency runs /opt/homebrew/bin/brew or /usr/local/bin/brew (through arch -x86_64 for an Intel prefix). Reads (info, outdated, search, cleanup --dry-run) happen when the Homebrew page or App Updates is used. Changes (install, upgrade, uninstall, update, autoremove, cleanup, trust) happen only when the user asks. brew contacts Homebrew's servers and GitHub as it normally does, including Homebrew's own analytics, which follow the user's Homebrew setting.-l -i -c, then -l -c, for at most 10 s) and passes on only HOMEBREW_* variables and the proxy variables curl and git read. It adds HOMEBREW_NO_ENV_HINTS=1 and nothing else.formulae.brew.sh (/api/analytics/install-on-request/homebrew-core/30d.json or /api/analytics/cask-install/homebrew-cask/30d.json), at most once a day per kind, kept in memory. The request carries no search term.-CiencyDebugRealBrewReads YES.Packages/CiencyKit/Sources/CiencyFeatures/Tools/RadialMenu/RadialSettingsPage.swift:722 (SiteIconFetcher)./favicon.ico on the link's own host, with no credentials and an Accept: image/* header. Ephemeral session, no cache, 5 s timeout, same-origin redirects only, 2 MB cap.CiencyFeatures/Cloud/Sync/ (CloudSyncHost, CloudAgentSink, MacStatusProducer, CompanionEventRelay), CiencyFeatures/Cloud/Remote/ (RemoteActionHost, RemoteCommands, RemoteActionNotices) and CiencyFeatures/Cloud/Backup/ (CloudBackupModel), over CiencyCore/Sync/ (SyncEngine, KeyEngine, CloudClient, and Backup/: CloudBackups, BackupSeal, CloudBackupSchedule). What each doc holds, field by field, is in CiencyCore/Sync/Payloads/. Spec: specs/companionSync.md, specs/cloud.md.CIENCY_API_URL is empty, so there is no page, no key, no account and no request. A debug build reaches a backend only inside a sandbox with -CiencyDebugCloud, and then keeps its keys in files in that sandbox, never in the Keychain.What leaves, by category (each is a switch on the page; off, nothing of it is sent, and what it had put on the server is deleted):
| Category | What is sent, sealed | When |
|---|---|---|
| AI agents | A glance: for each agent, its plan's name, its limit windows (how long, percent used, when it resets, when and how that was read) and when it was last active; a keyed tag of the agent's account, never the account itself; the running tasks (agent, start time, model, tokens so far, value so far, and the project folder's name); today's value and tokens; the date of the price list. History: one doc per day: token counts, requests, web searches and OpenCode's reported cost, by hour, agent, model, project and price class. No prices, no prompts, no replies, no file names, no session IDs | The glance within 2 s of a change a person would notice, otherwise at most every 5 minutes (every minute while the iPhone has this Mac open), and in Low Power Mode only when it matters. History at most every 10 minutes on the power adapter and 30 on battery, and not in Low Power Mode, with one exception: after the account's key changed (a device was removed), the days the server holds are sealed under the new key and sent again at once, whatever the power state |
| Include project names (shown while AI agents or Notifications is on; on by default) | Off: every project is sent as "Project" in the glance and the history and left out of notifications, and the days already on the server are deleted and sent again without names | — |
| Live Activity (needs AI agents) | The Lock Screen's content: the running tasks (agent, start time, model, the project folder's name, or "Project" with project names off), the ones that finished while it ran and when, and each working agent's tightest limit (its window, percent used, when it resets). No token counts, no values. Beside it, in clear for Ciency's server: whether a task is running and whether one just finished. Only if the account switched "Show Without Encryption" on (on an iPhone, off by default): also, in clear, which agents are working, when each task started and each limit's percentage, nothing else | When something on the Lock Screen would change: a task starts or finishes, a project or a limit's whole percent changes. Never for token counts, never on a timer |
| Mac status | Battery level to the nearest 5%, charging, on the power adapter; thermal state; Low Power Mode; free disk space to the nearest 5%; whether Keep Awake is on and until when; whether the Mac is awake | When charging, Keep Awake, Low Power Mode or sleep changes; otherwise at most every 2 minutes, and only when a 5% step is crossed |
| Notifications | An event with its words, written on the Mac: "Claude Code is done" and "14m · $3.20 · project" (the project only with project names on); a limit running low or renewed; the daily budget reached; "Homebrew finished" or "Homebrew failed" (never which package); "Export finished", "Link copied" or "Link ready" (never the file's name, never the link); "Timer" and "Finished"; "Low battery" and the level; "Mac too hot"; "Keep Awake ended". Which of them are sent, and how urgently, follows the choices made on the iPhone | When it happens. Nothing is watched for it: each is said where Ciency already says it on the Mac, and the battery and the heat are read with the Mac status's readings |
| Cloud backup (off by default; the only category offered without an iPhone) | A settings backup: exactly what Export Settings writes (below, Settings backup): every portable setting, including text snippets, radial menu profiles, Command Bar links and rules, shortcuts and lists of app bundle IDs, with this Mac's computer name, the date and Ciency's version. A label: the backup's date, Ciency's version and build, its sizes and the hash of its sealed body. Both are sealed with the account's key and signed by this Mac. Nothing else is in either: no key, no token, no file, no path, no clipboard history, no notes, and none of the cloud's own switches | On Back Up Now. With "Back up automatically" on (Daily or Weekly): after a setting that travels changed, at most once a day or a week, on the power adapter only, never in Low Power Mode. Nothing is sent while nothing changed |
Remote actions (Keep Awake from your iPhone, Lock Screen from your iPhone; each off by default, and only with an iPhone paired):
Cloud/producers; Clear empties the list, and signing out deletes both.Sent by any paired Mac, whatever the switches (sealed like the rest):
device.status): the version and hash of the list of trusted devices it holds, and whether a new recovery key waits to be saved on it. This is how two devices notice that they were given different lists.mac.meta): which categories are on, whether project names are included, whether Keep Awake and Quick Toggles are installed, and Ciency's version.What Ciency's server can see (the full table is specs/cloud.md §4.5): an opaque account ID and Apple's identifier for the Apple Account (no name, no email: neither is asked for); each device's ID, kind (Mac or iPhone), OS and Ciency versions and public keys; when each device connects, sends and sleeps, and its IP address; which kind of thing a sealed doc is (a glance, a day of history, a status), its size and when it was written; that an event was sent, when, how urgent, how long it stays valid, and which of three sizes it has (events are padded to a fixed size before they are sealed, so the size doesn't follow the words); each iPhone's push token, and which of Apple's two push services it belongs to; for each backup, which Mac uploaded it, when, how big it is, and when it was fetched or deleted and by which device (a backup is padded to steps of 16 KB before it is sealed, so its size says roughly how much it holds and not the length of a snippet that was added; its label is one length for every backup); and that the account has a doc of vouches for removed Macs' backups, how long it is and when it changed (inside, sealed: device IDs, backup IDs and hashes, no name and no setting). It can't see agent names, plans, limits, token counts, values, models, projects, device names, an event's words, which day a history doc is for, or anything in a backup: no setting, no snippet, no app list, not the Mac's name, not Ciency's version, not the date the Mac wrote into it. With Live Activity on, it also sees when a task is running on a Mac and the moment one finishes (which push to send, at which priority), which iPhones take Live Activities and which Macs each left out; and only if the account switched "Show Without Encryption" on, which agents are working, when each task started and each limit's percentage. A day doc's size grows with how much the day held, and how many day docs exist says how many days had AI use.
Ciency Cloud's own counts, and when it holds back (specs/cloud.md §11.2). The server runs at https://ciency.omniciency.com, on the owner's Cloudflare account, and keeps that account inside the allowances its plan includes:
A Start Over without the recovery key (specs/cloud.md §4.6). When a device that has only the account's key (from the iPhone's iCloud Keychain copy) asks to start the account over, Ciency's server holds it for 48 hours before it takes it, so the user's other devices can cancel it. Meanwhile it keeps, beside the sealed request it will store, which device asked, its kind, when, until when, and, after a cancel, which device cancelled it and when, how many requests in a row were cancelled, and until when no other is held (a week, doubled with each cancel in a row up to 30 days). A Start Over made with the recovery key carries that key's signature over the new list, which the server keeps with the reset and hands only to the devices it removed; it can neither make nor read anything from it. Each trusted iPhone gets a time-sensitive notification with the same words for every account ("Ciency is being started over from another device…"): Apple sees that one was sent, and nothing about which device or account. The name of the device that asks is inside the sealed request, which only the user's devices open.
What a notification's push shows, and to whom (specs/cloud.md §8.2). Ciency's server hands each event that should buzz to Apple's push service, for each of the account's iPhones. What travels is the event still sealed, with the same text for every event ("Ciency", "Update from your Mac"), and the labels the server already sees beside it: the Mac's and the event's opaque IDs, the time, how urgent, how long it stays valid, and a tag that lets a newer event replace an older one. Apple sees that and the iPhone's push token; neither Apple nor Ciency's server can read a word of the event. The iPhone opens it itself.
specs/cloud.md §4.5 has the table). The size of an event no longer helps tell them apart.What a Live Activity's push shows, and to whom (specs/cloud.md §8.4). For each iPhone that takes Live Activities, Ciency's server hands Apple a start when a task begins, an update when the Lock Screen changes (at most once a minute) and an end when the last task finishes. Each carries the Mac's Live Activity content still sealed and padded to one of three sizes (so its length says little about how many tasks there are or how long their names are), with the Mac's opaque ID, a version number and the key's number, whether the Mac is asleep, and for a start the words "Ciency" and "Your Mac is working". Apple sees that, the iPhone's tokens, and so when tasks run on that Mac; it can't read a task, an agent or a project, unless the account switched "Show Without Encryption" on, in which case Apple and Ciency's server both see which agents work, since when, and their limits' percentages.
What stays on the Mac for it (section 2): the keys, the outbox (what waits to be sent, and the last content sent of each doc, unsealed as the AI ledger is), the producer's notes of which days were sent, and its notes about backups (when this Mac last backed up, a digest of the settings in that backup, the newest backup it has seen of each Mac, a digest of the name it last saw each Mac under (to notice a name that changed; not the name), and, while it waits to be written, which backups a Mac it removed had; never a setting).
Restoring a backup downloads it, checks that it is the backup that was listed and that the Mac named beside it signed it, and then goes through Import Settings: the same validation of every setting, the same question, a safety copy of the current settings first (Backups/), then the relaunch. A backup that Ciency's server altered, cut short or swapped for another restores nothing. Ciency's server can't change a backup or pass an old one off as new; it can fail to list one, and the page says when a backup this Mac saw before is no longer listed (a Mac that never saw a backup can't tell an empty list from that).
What a backup's signature can't say, and what the page does about it:
Taking it back:
Cloud/ here. Its backups stay on the server for the other Macs unless "Sign Out and Delete Backups" is chosen. Delete Account… deletes everything the server holds for the account, every backup included.codesign --verify and spctl -a -t exec on it. Gatekeeper's assessment may ask Apple's notarization service about that app. Ciency sends nothing itself.Some buttons open a web page or app link: a meeting's Join link in Calendar, an App Store page, a package's homepage, a typed web address in the Command Bar, a radial menu link, a local port in Port Manager. These open in the default browser or app, which makes the request. Ciency only hands over the URL, and only when the user clicks.
These use no network at all:
nettop -n (no name lookups), system_profiler SPPowerDataType, local IP addresses. The only network use is the speed test above.system_profiler SPBluetoothDataType and Core Bluetooth reads of paired accessories' battery levels (Bluetooth LE only, opt-in).NWPathMonitor), which sends nothing. Its only network use is the price list and Codex, above.Development builds keep the real network off for App Updates, Homebrew, Codex, the price list and share-link deletion during removal, unless launched with the matching -CiencyDebugReal… argument. Tests never reach the network. The speed test, the lyrics lookup (once opted in) and Fetch Icon behave the same in every build.
Settings live in the com.ciency.Ciency preferences domain (~/Library/Preferences/com.ciency.Ciency.plist), as JSON values.
feature.<feature>.<name>, for example feature.islandLyrics.onlineLookup.updates.* (update preferences) and backup.reviewPermissions. Two lists stay on this Mac and are in no backup or export: backup.unreviewedItems, digests (SHA-256) of imported items that wait for review, and backup.reviewedItems, digests of items allowed here. They hold no names and no paths. When AI Agents last checked the price list is a feature setting that stays on this Mac (feature.islandAgents.lastPriceCheck); builds before Phase 10 M1 kept it as islandAgents.lastPriceCheck, outside the settings store, and that old value is no longer read.feature.textSnippets.items), radial menu slices (with fetched site icons), Command Bar links and rules, and the names of the screen recorder's saved looks (feature.screenRecorder.presets; their pictures stay in Recordings/Presets/ and never travel in a backup).feature.islandWatch.resumable) for a one-click resume. The typed text or number it waits for is not saved.feature.downloadsCleaner.kept, .unsorted), on this Mac only.Everything else lives in ~/Library/Application Support/Ciency/. Ciency creates its folders there as 0700, so other accounts on the Mac can't reach anything inside, and writes most files 0600 through CiencyCore/Files/OwnerOnlyFile.swift. The full list is declared in CiencyCore/Removal/RemovalFootprint.swift, and a test fails if code writes to an area missing from it.
| Path | Feature | What it holds | Time Machine |
|---|---|---|---|
Scratchpad/notes.json | Scratchpad | The notes | Backed up |
Shelf/ | Shelf | Item list, copies of the files put on the Shelf, pending deletions | Backed up |
Clipboard/history.json, Clipboard/Images/ | Clipboard History | Copied text, images and file references | Backed up |
Capture/Recent/ | Screenshot | Recent captures and their index | Excluded |
Capture/Copied/, Capture/Drag/ | Screenshot | Work files for copy and drag; drag files are swept regularly | Excluded |
Capture/links.json | Screenshot | Share-link records: URL, expiry, delete token | Excluded |
Recordings/Take-<id>/ | Screen Recorder | The movie, pointer path (motion.bin), key-press times (keys.json), camera layout, edits (including caption text), take state, and Overlays/ (private copies of pictures laid over the recording) | Excluded |
Recordings/Presets/ | Screen Recorder | Private copies of the pictures saved in named looks | Excluded |
Recordings/Uploads/ | Screen Recorder | Compressed copies made only to upload a share link; emptied at launch | Excluded |
Backups/ | Settings Backup | Up to 5 safety snapshots of all settings, taken before an import | Backed up |
CommandBar/learning.json, learning.key | Command Bar | Keyed digests of what was picked, and the key | Backed up |
ColorPicker/history.json | Color Picker | Picked colours | Backed up |
DownloadsCleaner/sorted.json, undo.json | Downloads Cleaner | Which files the sorter moved, and what Undo needs | Backed up |
NowPlaying/, NowPlaying/Queue/ | Now Playing | A verified private copy of Ciency's own Now Playing adapter (file 0500) | Backed up |
Wallpaper/Index-before-Ciency.plist | Wallpaper | A copy of macOS's wallpaper settings from before Ciency changed them | Backed up |
Agents/ledger.sqlite (and -wal, -shm) | AI Agents | Usage counters (see section 5) | Excluded |
Agents/Status/claude-status.json | AI Agents | The status-line relay's output (see section 5) | Excluded (the folder) |
Agents/ other files | AI Agents | Price list and signature, Codex pending reset key, the status-line relay script, its state and the original statusLine value | Backed up |
PointerAcceleration/journal.json | Pointer Acceleration | The pointer settings to put back | Backed up |
MachineState/ | Shortcuts | Which system shortcuts Ciency took over | Backed up |
Removal/journal.json | Self-removal | Progress of a removal, deleted last | Backed up |
Cloud/sync/ | Ciency Cloud | The sync engine's outbox and cursors: what waits to be sent and the last content sent of each doc (the glance, the status), not sealed; what was read from other devices, sealed as it came | Excluded |
Cloud/producers/ | Ciency Cloud | Which days of AI history were sent, as fingerprints, and how far the ledger was read | Excluded |
Cloud/backups/ | Ciency Cloud | Notes about cloud backups: the ID and date of this Mac's last one with a digest of the settings in it; the ID and date of the newest backup seen of each Mac; a digest (SHA-256) of each Mac's name as last seen, and when it changed; and, until it is written to the server, the IDs and label hashes of the backups a Mac this Mac removed had. No setting and no key | Excluded |
CrashHandling/run.json | Crash handling | The run marker: this run's process ID and launch time, the build's version label, and whether to reopen after a crash. Deleted on every orderly quit | Backed up |
CrashHandling/crashes.json | Crash handling | Up to 20 recent crashes: when, which build, which signal, whether Ciency was reopened, and the file name of macOS's report. Never the report's contents | Backed up |
CrashHandling/instance.lock | Crash handling | An empty file whose lock says a Ciency is running on this folder | Backed up |
An early build kept Scratchpad notes in ~/Library/Application Support/com.ciency.Ciency/; they are moved into the private folder on first use.
~/Library/Caches/com.ciency.Ciency/: Sparkle's downloads and staged updates. Ciency's own requests all use ephemeral sessions, so they keep no URL cache there.~/Library/HTTPStorages/com.ciency.Ciency (and .binarycookies): may be created by Sparkle or by macOS; Ciency's own requests keep no cookies.$TMPDIR/com.ciency.Ciency/: short-lived work files, such as Shelf drops.com.ciency.Ciency.share-token and com.ciency.Ciency.feed-token, stored "this device only" (not synced to iCloud Keychain). Ciency refuses to write any other name, and never shows a Keychain prompt when reading.specs/companionSync.md): this Mac's device keys (com.ciency.Ciency.cloud.device), the account's keyring (.cloud.keys), the account record (.cloud.account), a trust change in flight (.cloud.pending), a recovery key not yet saved (.cloud.recovery) and, on a device restored with the recovery key until it is confirmed, that key's Start Over proof and countersigning seed (.cloud.restore). None is synced to iCloud Keychain; a Mac keeps no copy of the keyring there.statusLine member of ~/.claude/settings.json and keeps up to 3 timestamped settings.json.ciency-backup-… copies next to it. See section 5.com.ciency.Ciency.FanHelper, with recovery files in /var/run) and the closed-lid sleep rule in /etc/sudoers.d. Both are added only when the user turns those features on, with administrator approval.macOS writes a report for every crash of every app, by itself, in ~/Library/Logs/DiagnosticReports/ (Ciency-<date>-<time>.ips). Ciency writes nothing there. After it crashed, it reads its own report on the Mac to show a notice at the next launch (specs/crashHandling.md), and nothing leaves the Mac: this feature has no network code.
Ciency….ips, changed since the crashed run began, the newest eight at most. One is taken as the run's report only when it names that run's process ID and Ciency's bundle ID.CrashHandling/crashes.json. Its contents are never copied into Ciency's folder, its preferences or the unified log./usr/bin/open). It reads and writes only CrashHandling/, and exits as soon as the app has ended. Before opening anything it looks at the Mac's process table once (and so does the instance it opened): the names of running processes, and the executable and launch arguments of the user's own, to see whether a Ciency is already starting and whether Sparkle's installer is still at work. Nothing from that look is kept or logged. It is not a login item or a launch agent. Settings → General → "Reopen Ciency after a crash" turns the reopening off.docs/PLAN.md → Crash handling, step 3).The settings backup exports a .cienbackup JSON file to a place the user picks.
Self-removal ("Remove Ciency from This Mac…", also offered when Ciency finds itself in the Trash) first puts back every system change it made, then:
statusLine exactly and moves Ciency's settings.json backups to the Trash;Many features also offer "Also delete its data" when uninstalled on their own. Uninstalling AI Agents takes the status-line relay out and puts the previous status line back.
Based on what the code does today:
skipSecrets).keys.json is a list of numbers), to drive typing zoom. Text Snippets matches what is typed in memory.| Permission | Why |
|---|---|
| Accessibility | Read and arrange windows, react to keys and clicks, type snippets, read notification banners |
| Screen Recording | Screenshots, recordings, Watch, screen text and live window previews |
| System Audio Recording | Per-app volume, the equalizer and recording what the Mac plays |
| Microphone | The user's voice in screen recordings |
| Camera | Camera Preview and the recorder's camera bubble |
| Calendars (full access) | Upcoming events in the Dynamic Island |
| Notifications | Telling the user when something needs attention, such as an update or a scheduled App Updates result |
| Full Disk Access | Finding leftovers and caches in protected folders (Cleaner, Uninstaller) |
| Files and Folders | Folders the user picks, such as Downloads |
| App Management | Installing, updating and removing apps in Applications |
| Automation: Finder | Moving files and emptying the Trash |
| Automation: System Events | Switching settings such as dark mode when no direct way exists |
| Automation: Terminal | Opening Terminal to run commands the user chose |
| Automation: Music or Spotify | Reading and controlling playback, and Apple Music's own lyrics |
| Bluetooth | Battery levels of Bluetooth LE accessories, only if turned on |
| Speech Recognition | Dictating annotation text, on the Mac only |
Input Monitoring is listed in the code but not needed: Ciency uses Accessibility instead.
AI Agents is off until the user turns it on. It reads only files already on the Mac and uploads nothing. Code: CiencyCore/Agents and CiencyPlatform/Agents. CLAUDE_CONFIG_DIR, CODEX_HOME, XDG_DATA_HOME (OpenCode) and COPILOT_HOME are honoured.
| File | Fields used | What happens to the rest |
|---|---|---|
Claude Code logs: ~/.claude/projects/**/*.jsonl, ~/.config/claude/projects/, $CLAUDE_CONFIG_DIR/projects/ | Timestamps, model, token counts (input, cache write and read, output), request and message IDs, session and parent session IDs, working folder (reduced to a project folder name), stop reason, sidechain flag, Bash tool-call IDs (to know a shell is still running), web-search count, service tier and speed, inference region | Prompt and reply text is never stored. Text the person typed is looked at in memory only to spot an interruption marker |
Codex logs: ~/.codex/sessions/, ~/.codex/archived_sessions/ | Timestamps, model, token counts (including reasoning), session and parent thread IDs, working folder (reduced to a project folder name), rate-limit readings, plan type | Same as above |
~/.claude.json | oauthAccount.organizationUuid, organizationType, organizationRateLimitTier, userRateLimitTier, billingType | The file also holds the person's name and email; they are parsed in memory and dropped |
~/Library/Application Support/Claude/plan-usage-history.json (Claude app) | Sample times, organisation, usage percentages | Nothing else is read |
~/.claude/sessions/<pid>.json | Session ID, process ID, process domain, status, entry point, working folder | Used to tell running tasks from finished ones |
Ciency's relay output, Agents/Status/claude-status.json | rate_limits (five-hour and seven-day used percentage and reset time) | See below |
~/.claude/settings.json, managed settings, a project's .claude/settings.json | The statusLine value only | Read to show whether the relay is installed or overridden |
OpenCode database: ~/.local/share/opencode/opencode.db (or under $XDG_DATA_HOME/opencode/), opened read-only (immutable when OpenCode is closed and no -wal exists, checked before anything read is stored). Changes are noticed by one vnode source on opencode.db-wal and one on its folder's own entries, never a recursive watch. Like any SQLite WAL reader, Ciency updates its read marks in opencode.db-shm while OpenCode runs; it never writes OpenCode's data | From the session table: session ID, parent session ID, working folder (reduced to a project folder name), the OpenCode version that made the session. From the message table: row number, message ID, session ID, creation and update times, the data's length, and from its JSON only the role, the prompt a reply answers, the model, token counts, the cost OpenCode recorded, the finish reason, the completion time, the working folder, and whether it is a summary or holds an error. From the part table, inside the query only: whether a reply still has a pending or running tool call, and whether a summary's prompt is an automatic compaction (each part's type, state.status and auto) | Prompt and reply text, tool input and output, titles and error messages stay inside SQLite: the query pulls single values out of the JSON, so they never reach Ciency's memory. Nothing else in OpenCode's folder is opened |
Copilot sessions: ~/.copilot/session-state/<session>/events.jsonl only (a regular file in a real session folder; symlinks are skipped). Watched with one vnode source on session-state, one on each recently changed events.jsonl, and one on a new session folder's own entries until its log appears; never recursively | Each event's top-level type, time and subagent ID. Decoded for some kinds only: session ID, selected and changed model, working folder and repository root (reduced to a project folder name), each reply's model, call and message IDs, whether it requested tools, and its phase; at shutdown, per-model request and token totals | Prompts are never decoded; reply text is parsed in memory and dropped. Other files in a session folder (workspace files, checkpoints, a checkout) are never listed, opened or watched; only a new session folder's own entries are watched, briefly, for its log to appear |
Status-line relay (opt-in). Only after the user presses the button and confirms the shown change, Ciency writes Agents/claude-status-relay.sh and points Claude Code's statusLine at it. Each time Claude Code refreshes its status line, the script saves the full input Claude Code gives status lines into Agents/Status/claude-status.json (mode 0600, replaced each time, in a folder excluded from Time Machine), then runs the user's previous status line unchanged. Ciency reads only rate_limits from that file. The script saves the whole input because it must stay a few lines of POSIX sh (no jq, under 5 ms) and can't pick fields out of JSON; that input includes the session ID, the working folder, the model and Claude Code's cost estimate. A relay installed by an earlier build is rewritten to use the excluded folder the next time AI Agents starts.
Codex. See "Codex account and limit resets" above. The account answer gives the plan type and whether it is a ChatGPT sign-in; the limits answer gives percentages, reset times and banked resets.
The ledger (Agents/ledger.sqlite, 0600, excluded from Time Machine) keeps:
Show on the finish notice. To offer Show, Ciency walks up from the task's process ID to its parent processes (kernel process records, no permission) until it finds an ordinary app, such as Terminal or an editor. Only that app's bundle ID and name are used, in memory, and Show only brings it forward.
History older than the chosen range (90, 400 or 730 days) is dropped. Prompts, replies, tool input and output, file contents and code are never stored, logged or sent.
| Tool | When | Network |
|---|---|---|
/usr/bin/perl | Hosts Ciency's own signed Now Playing adapter, because since macOS 15.4 the system answers Now Playing reads only for Apple-signed processes. Perl must be root-owned and Apple-signed; the adapter is verified against Ciency's signature before and after it is copied. The child gets an empty environment apart from LANG and PATH, a fixed command line, no inherited files, and its responsibility disclaimed, so it borrows none of Ciency's permissions. It exits when Ciency does | None |
codex app-server | AI Agents, Banked resets card. Inherits Ciency's environment (Codex needs the user's own configuration) | Codex talks to OpenAI |
brew (and arch) | Homebrew page, App Updates | brew uses the network |
| The user's login shell | Once per launch, to read Homebrew's environment | Whatever the user's startup files do |
codesign, spctl, hdiutil, ditto | Disk image installer | spctl may ask Apple's notarization service |
system_profiler | Bluetooth devices, battery health | None |
nettop, lsof, netstat, ps | System Monitor, Port Manager, Process Killer | None |
mdfind | App Updates scan | None |
pmset, sudo, visudo, osascript | Keep Awake's closed-lid rule (asks for an administrator password once) | None |
launchctl | Fan helper, file actions | None |
hidutil, diskutil, tccutil, killall, pgrep, /bin/sh | Key remapping, disk info, permission reset, restarting Finder or the wallpaper agent, relaunch and removal | None |
Ciency's own executable, as the crash watcher (--ciency-crash-watch) | Started at every launch; waits for the app's process to end and exits with it | None |
/usr/bin/open | The crash watcher, to reopen Ciency after a crash | None |
Not released; this describes what is built (Phase 10, specs/iphone.md). The iPhone app only reads what the user's Macs chose to share, through Ciency Cloud, and writes one thing: the notification choices.
Library/Application Support/Cloud/<environment>/sync), written with complete file protection (unreadable while the iPhone is locked) and left out of backups.…/local) holds this iPhone's own choices: which Mac Home shows, limits as remaining or used, and whether "Hide Ciency in the App Switcher" was switched off.specs/cloud.md §4.4).-CiencyDebugSharedKeys YES, a throwaway account's record and keyring are files in the Simulator's app group folder, removed at the next launch.)https://<Ciency's API host>/pair#…, which opens Ciency for iPhone (a universal link: only the app Ciency's server names can open it). Everything that matters is after the #, which no browser or server ever sends; the page at that address, for a browser without the app, says to open the link with Ciency for iPhone and runs no script. A debug build against this Mac's test server uses ciency://pair#… instead.Update this file in the same change whenever a feature adds or changes a network request, a stored file or folder, a preference that holds user content, a Keychain item, or a tool it launches. New container areas and Keychain names must also be added to RemovalFootprint.swift, which the tests enforce.