> ## 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.

# How Pomeroy works

> Three doors, one contract. How an assistant's request reaches your Mac, what holds the permissions, and why the bridges do not understand MCP.

Understanding the shape helps when something goes wrong, and it is the reason
several of Pomeroy's promises can be kept at all.

## Three doors, one contract

Whichever door an assistant comes through, it reaches the same app.

```
Claude Desktop ── stdio ──> the extension (Node, .mcpb)   [dumb byte pipe]
                               │
any assistant on this Mac ─┐   │  Unix domain socket, 0600
(Claude Code, Cursor, …)   │   │  ~/Library/Application Support/Pomeroy/mcp.sock
                           ▼   ▼
a container, a VM,      ┌──────────────────────────────┐
a runner  ── HTTP ─────>│  Pomeroy.app (Swift, menu bar)│  [permission holder,
   127.0.0.1:13579/mcp  │                               │   MCP server]
                        └───────────────┬───────────────┘
                                        │
                        EventKit, Contacts, Apple events (Mail, Notes),
                        MapKit, Core Location, /usr/bin/shortcuts,
                        chat.db via SQLite (Messages)
```

[What each door is for](/docs/configuration/overview)

## The bridges do not understand MCP

Two of the three doors are byte pipes: the `.mcpb` extension inside Claude
Desktop, and `pomeroy-mcp` inside the app bundle. Both do the same three
things: connect to the socket, launch the app if it is not running, copy
bytes. Neither parses JSON-RPC. Neither knows what a tool is.

That is why the Claude Desktop extension never has to be updated. Pomeroy can
add tools, change what they return, and rewrite every answer, and the
extension carries on copying bytes. Both speak **bridge protocol version 1**,
and the app cannot tell them apart.

The HTTP endpoint is different. It terminates HTTP and speaks MCP, which is
exactly why it is confined to a small number of files and gated by a
credential.

## The app holds everything that matters

Every permission, every toggle and every tool lives in the app. That is the
decision the rest follows from:

* **One place to check a toggle.** A tool call is gated once, in the app,
  whichever door it came through. There is no second path to your data that
  could miss the gate.
* **One process holds the grants.** macOS grants permission to an application,
  and Pomeroy.app is the application. A bridge holds nothing.
* **The pipe carries no weight.** A stdio session loads no AppKit, no Sparkle
  and no analytics library.

## Why the local door is a socket, and the remote one is not

The default path is a **Unix domain socket** in your home folder, mode `0600`:
readable and writable only by processes running as you, on this Mac. The
filesystem decides who reaches it, so there is no key to manage and nothing to
leak.

A TCP port has no such gate, because any process on the Mac can open one. When
the HTTP endpoint was added for the cases stdio cannot serve (a container, a VM,
a runner), it did not inherit the socket's guarantee and had to bring its own: a
credential, in one of three exclusive modes, and a binding to loopback only.

Two doors, two threat models, stated separately rather than averaged into one
reassuring sentence.

## A connection is not a grant

When an assistant connects, Pomeroy labels the connection from what the
assistant says about itself in its opening request. That label is
**descriptive, not a security boundary**. The socket's file permissions, or the
endpoint's credential, are the boundary.

Nothing about an assistant survives the connection. There is no stored consent
and nothing to revoke, because the only gate on a tool call is the app's
toggle. Setting an assistant up *is* the consent: it was you choosing that
assistant.

## What this buys you

<Columns cols={2}>
  <div>
    **Checkable**

    Every request that can leave your Mac goes through one client with one
    allowlist, so a test can drive every flow through a recorder and read what
    went out, byte by byte.
  </div>

  <div>
    **Narrow**

    Pomeroy reaches an app only through the interface that app publishes for
    automation. It holds no grant over your screen, and none over any file
    except the one Messages database you hand it.
  </div>
</Columns>

<CardGroup cols={2}>
  <Card title="What leaves your Mac" icon="shield-check" href="/docs/privacy/what-leaves-your-mac">
    Every request, what is in it, and what can reach Pomeroy.
  </Card>

  <Card title="What Pomeroy asks macOS for" icon="lock" href="/docs/privacy/what-pomeroy-asks-macos-for">
    The grants it requests, and the two it never asks for.
  </Card>
</CardGroup>
