> ## Documentation Index
> Fetch the complete documentation index at: https://pomeroy.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# What leaves your Mac

> Every request Pomeroy makes, and everything that can reach it. Your calendar, mail, messages, contacts, notes and reminders never leave your Mac, and a test fails if this page and the code disagree.

Pomeroy reads your calendar, your mail, your messages, your contacts, your
notes and your reminders. **None of it ever leaves your Mac.** Not the text,
not the names, not the subjects, not a count of how many you have, not a hash
of any of it. Pomeroy has no server to send it to.

One exception, and it is yours rather than Pomeroy's. Pomeroy has a local
address an assistant can connect to, described under [What can reach
Pomeroy](#what-can-reach-pomeroy), and it answers only on this Mac. You can put
your own tunnel in front of it and reach it from somewhere else. Pomeroy ships
no tunnel, runs no relay, and publishes no recipes for one, so that route is
something you build rather than something Pomeroy offers. What it costs is worth
saying plainly: your app data then crosses whatever you pointed at it, and the
sentence above is a promise about what Pomeroy does, not about what you can
choose to do with your own Mac.

A short list of requests does go out, and this page is all of it.

## Where Pomeroy connects

| Host                      | Why                                 | What is sent                                                                     | Opened by   |
| ------------------------- | ----------------------------------- | -------------------------------------------------------------------------------- | ----------- |
| `api.lemonsqueezy.com`    | Licence check                       | The licence key you typed, and a random label for this Mac                       | Pomeroy     |
| `pomeroy.app`             | Update check                        | Nothing but the request                                                          | Sparkle     |
| `us.i.posthog.com`        | Four counts                         | See below                                                                        | posthog-ios |
| `us-assets.i.posthog.com` | The counting library's own settings | Nothing but Pomeroy's PostHog project token, in the address                      | posthog-ios |
| `weather-data.apple.com`  | Weather answers                     | The coordinates of the place you asked about, and the app's identity (see below) | WeatherKit  |

Nothing else. No crash reports, no error logs, no "usage statistics", no
heartbeat, no font list, no screen size, no serial number, no advertising id.

One more address appears when you click **Buy Pomeroy**: the store's checkout
page opens in your browser. That is your browser talking to the store, not
Pomeroy, which sends nothing and learns nothing about it.

Requests Pomeroy makes itself are checked against this list in code before a
connection is opened, and it refuses anything not on it. That is
`NetworkPledge`, and the test that drives every flow through a recorder is
`NetworkPledgeTests`. The update check and the counts are made by two libraries,
Sparkle and posthog-ios, which open their own connections. What holds those to
this page is described under each below.

### The licence check

Pomeroy sends two fields and no others:

* `license_key`, the key from your purchase email, exactly as you typed it.
* `instance_name`, which is `Pomeroy` followed by eight random characters,
  generated once on this Mac and kept. It is **not** your Mac's name, serial
  number, hostname or account. It exists so the store can show you which
  activation to free when you move to a new Mac.

After activation, re-checks send the key and the activation id the store
issued instead of the label. A check that cannot reach the server changes
nothing: a licensed Mac keeps working offline for as long as it stays offline
(ADR-0007).

### The update check

Sparkle asks `https://pomeroy.app/appcast.xml` for the list of released
versions. It is a plain GET: no identifier, no licence key, no count. The
answer is signed with an Ed25519 key whose public half is baked into the app,
and a download whose signature does not match the bytes is thrown away
(ADR-0009).

Turn it off in Settings → General and Pomeroy never asks.

### The weather question

Weather answers come from Apple's WeatherKit, the same source the Weather
app uses. When you ask about the weather, and only then, the framework
sends Apple the coordinates of the place you named, and enough about the
app itself (its identity and signature) for Apple to agree to answer. The
weather actions take place names, never your location; the coordinates sent
are "Clapham, London", not where your Mac is.

Apple's own words on it: "Location is used only to provide weather forecasts
and is not associated with any personally identifying information and is
never shared or sold."

Like Sparkle and posthog-ios, WeatherKit opens its own connection, so it cannot
be held to the in-code allowlist. Instead its address is written in
`NetworkPledge` beside the others, and the test that compares this page against
that list fails if the two drift. Pomeroy never calls a third-party weather
service: a build Apple will not answer (one not signed by the paid team) gets no
weather at all, and says so, rather than a fallback that leaks your questions
elsewhere.

### The four counts

They exist to answer one question: of the people who install Pomeroy, how
many go on to buy it. There are four, there have only ever been four, and a
test fails if the code and this page disagree.

| Event        | Sent when                                               | How often                                             |
| ------------ | ------------------------------------------------------- | ----------------------------------------------------- |
| `install`    | You close the setup wizard for the first time           | Once per install                                      |
| `activation` | Your assistant answers from your Mac for the first time | Once per install                                      |
| `cap_hit`    | The free weekly allowance runs out                      | Once per week at most, however many calls are refused |
| `upgrade`    | A licence key is activated on this Mac                  | Once per activation                                   |

Each one carries the event name, the moment it happened, the identifier
described below, a random id for that one message, and exactly these four
properties. That is the whole event, checked by pointing the library at a local
server and reading what it sent:

| Property                  | Value                                                                      |
| ------------------------- | -------------------------------------------------------------------------- |
| `app_version`             | This build's version, e.g. `0.1.0`, shared by everyone on that build       |
| `$process_person_profile` | `false`, an instruction to PostHog not to build a profile                  |
| `$geoip_disable`          | `true`, an instruction not to look your address up in a location database  |
| `$ip`                     | `127.0.0.1`, an instruction not to store the address the request came from |

### The identifier, stated plainly

The four counts share **a random identifier generated on your Mac the first
time Pomeroy needs one**. It is a UUID from the system random number
generator. It is not derived from your hardware: not your serial number, not
`IOPlatformUUID`, not a MAC address, not your hostname, not your licence key.
It is not connected to your name, your email, or your purchase either.

It exists for one reason: without it, the four counts are four unrelated
numbers, and "how many people who install go on to buy" cannot be answered.
With it, they form one install's timeline.

Being exact about what that means: this makes the counts **pseudonymous, not
anonymous**. Four events from this Mac can be told apart from four events
from another one. Nobody receiving them can work out whose Mac it is, and the
identifier is not readable by any other app or website. But it is an
identifier, and calling it anything else would be untrue.

You can throw it away. Deleting Pomeroy's settings (`defaults delete
com.joesaunderson.pomeroy`) discards it, and the next identifier is unrelated to
the last.

**What is deliberately not there.** No licence key. No hardware identifier.
No macOS version, no Mac model, no Mac name, no screen size, no language, no
time zone, no CPU. No tool names. No counts of your events, messages or mail.
Nothing you typed and nothing your assistant said.

### About the counting library

The counts are sent by [posthog-ios](https://github.com/PostHog/posthog-ios).
Out of the box that library does a great deal more than count: it captures
taps, screen views, application lifecycle events, feature-flag evaluations
and person profiles, and it attaches roughly twenty-five properties to every
event: the Mac's model and friendly name, its screen size, its language, its
time zone, whether the app was sideloaded, and more.

Pointed at a local server with the collectors off but no filtering, it sends
twenty-one properties Pomeroy never asked for, including this Mac's exact
macOS version, its model, its name, its language, its time zone and a session
identifier.

Pomeroy switches off every collector the library allows to be switched off, and
then, because none of those twenty-one can be switched off, filters every event
through an allowlist before it is queued: anything not in the four-row table
above is dropped. The same local-server check with the filter in place sends the
four properties above and nothing else. That filter keeps what is named rather
than removing what is known, so a property added by a future version of the
library is dropped by default instead of shipped by accident. The code is
`PostHogTelemetrySink`, it is the only file in Pomeroy allowed to see the
library, and a test fails if any switch goes unapplied (ADR-0008).

One thing cannot be switched off: when the library starts, it fetches its own
settings from `us-assets.i.posthog.com`. That request carries Pomeroy's
PostHog project token in the address and nothing else. No identifier, no
event, nothing about you. It is on the table above because it happens and you
should know it happens.

So Pomeroy does not start the library when it launches. It starts it the
first time a count is actually going to be sent, which is after the wizard
has been closed once. Until then the library never starts, and that request
never happens either.

The library also writes three things under `~/Library/Application
Support/com.joesaunderson.pomeroy/`: two identifiers of its own (which never
leave your Mac, because the only request that would carry them is the
feature-flag call, and that is switched off), and a queue folder holding counts
waiting to be sent. Those queued files contain the count as it will be sent,
after the allowlist has already been applied, so the filtering above happens
before anything touches your disk rather than only before it reaches the
network.

## What can reach Pomeroy

Everything above is about what goes out. This section is the other direction,
and it is here because a buyer reading a page called "What leaves your Mac"
deserves to find it rather than discover it.

There are two ways an assistant reaches Pomeroy.

**Direct**, which is the default and what almost everything uses: the
extension inside Claude Desktop, or the small pipe inside Pomeroy's own app
bundle. Neither is a port. Both meet Pomeroy at a file in your own home
folder, mode `0600` inside a `0700` directory, so the only things that can
reach it are programs already running on this Mac as you. macOS decided that,
not Pomeroy, which is why nothing here asks you to approve a connection.

**The local address**, for an assistant that cannot start a program on this
Mac: one running in a container, or one that takes a URL and nothing else.
That one is a listening port, and four things are true of it.

* **It is off until you switch it on.** There is no launch default, and no
  environment variable can force it open.
* **It listens only on this Mac.** The listener binds `127.0.0.1` and `::1`
  and refuses every other interface. There is no bind setting and no interface
  picker. A test pins it and names ADR-0014 in its failure message, so the next
  person tempted to widen it reads the reasoning first.
* **How it is guarded is yours to choose**, from three modes: **Token**, the
  default, where one secret opens the address and Pomeroy writes it into the
  settings of every assistant it can reach; **Approval**, where there is no
  shared secret and each assistant asks for its own, which you grant in a
  Pomeroy window; and **Open**, where nothing is checked at all. Open is
  offered because a container or a script can have a real reason to need it,
  and switching to it asks you first, in a sheet that names what becomes
  reachable. On this Mac the credential is the whole boundary: a local
  connection carries no identity macOS will vouch for, so there is nothing
  else standing behind it.
* **It sends nothing anywhere.** An inbound listener is not an outbound
  request. The hosts table above is unchanged by this feature, and
  `networkDiscipline.test.ts` still asserts it against the allowlist in code.

macOS asks for nothing when this port opens: no entitlement to add and no prompt
to expect. That is a fact about macOS rather than a permission Pomeroy declined,
and it is why the credential you pick is the whole boundary. The longer version,
including what macOS will and will not tell Pomeroy about a caller, is in
[docs/permissions.md](permissions.md#the-local-address-and-why-macos-asks-nothing-for-it).

## What the other end can see anyway

Being straight about the limits: any server you connect to sees that a
connection arrived, and from roughly where, the way every server does. The
`$ip` and `$geoip_disable` instructions above stop PostHog *storing* your
address on the event or turning it into a location; they cannot stop its
servers seeing the connection. Deleting Pomeroy's settings throws the
install identifier away; it does not un-send a count that already left.

Pomeroy's own requests do not make it worse: they carry a fixed `User-Agent`
of `Pomeroy` and `Accept-Language: en`, replacing the ones macOS would attach,
which name your exact macOS build and your language. They follow no
redirects, keep no cookies and write nothing to disk.

The counting library sets its own `User-Agent` of `posthog-ios/<version>` on
its two requests, which names the library and its version and nothing about
you or your Mac.

## Switching the update check off

Click the Pomeroy icon in the menu bar, choose **Settings**, then **General**.
**Keep Pomeroy up to date** starts on and can be switched off for good. The four
counts always run after the wizard has been closed once, and there is no switch
for them. With updates off and no licence, the four counts, plus a weather
question when you ask one, are the only requests Pomeroy makes. Weather has its
own toggle, off until you switch it on, and off means no request.
