Two Doors, Two Audiences
One Delta process runs on each family Mac, and it listens on exactly two sockets. They are not two copies of one server. They face two different audiences, and almost every rule in Delta follows from keeping them apart.
| engine | gateway | |
|---|---|---|
| Bound to | 127.0.0.1:5200 | 0.0.0.0:5201 |
| Who calls it | The apps on this Mac | The Deltas on the other Macs |
| Proof of who is asking | The local token, X-Delta-Local-Token | Depends on the route the connection arrived on |
| What it does | Reads other Macs' shares through the cache, starts transfer jobs, reports health | Serves this Mac's shares, mints tickets, receives pushed files |
An app that wants a file from the workbench does not talk to the workbench. It talks to its own Mac's engine, on loopback, naming itself in X-Delta-App. The engine checks its cache, picks a route, and asks the workbench's gateway. That is how the last lesson's rule holds: the app's own Python never dials the LAN, and the engine's address is one no other machine can even reach.
The Engine: Loopback and a Token
The engine refuses any connection that does not come from a loopback address, before reading a byte of it. Then every route except health and version needs the local token: 32 bytes of randomness in a file called local.token in Delta's state folder, mode 0600, so only the account Delta runs as can read it. Loopback alone is not identity. Any account logged in to the Mac can open a socket to 127.0.0.1; only the owning account can read the file. The comparison uses hmac.compare_digest, which takes the same time whether the first byte or the last one differs.
The Gateway: Classified by Where It Arrived
The gateway binds every interface, so it has to decide who is calling from facts it can verify at the socket. It looks at two addresses, the caller's and the local one the connection arrived on, and sorts each connection into exactly one kind:
- loopback: a process on this Mac. It is this Mac only if it shows the local token too. (Before that rule, any account on the Mac read the home share as "this Mac".)
- tailnet: both addresses inside the tailnet's range. The caller is whichever node Tailscale's roster names for that address. Plain HTTP, because WireGuard already encrypts and authenticates the tunnel.
- thunderbolt: the local address belongs to a Thunderbolt bridge, a cable between two Macs. Plain HTTP plus a ticket.
- lan: the local address belongs to another physical interface (Ethernet, Wi-Fi) and the caller's address is private. TLS with a pinned certificate, plus a ticket.
- anything else: closed unanswered. No error page, no banner, nothing to fingerprint.
Which physical interface is which comes from the Mac itself: networksetup -listallhardwareports names each device's hardware port (Thunderbolt Bridge, Wi-Fi, Ethernet) and ifconfig gives its addresses. Track 3 follows that information outward into route choice, and track 4 takes the proofs apart.
No Address, Port or Machine Name in Code
You have just read two port numbers. You will not find either in Delta's source as a literal a request uses. Ports come from Firelink's port ledger, where Delta holds two @each claims (one engine and one gateway port, the same on every Mac). Delta's config asks the vendored registry module for them, and if that snapshot predates the claim, it reads the live ledger file rather than guessing a number. If neither knows, it refuses to start with a named error. This Mac's identity comes from its fleet label file, its peers from the registry, and LAN addresses from each peer's own Delta at run time. That is invariant 8, and it is why moving a service between Macs never means editing Delta.
Kept Alive by launchd
The process is a LaunchAgent, com.cwk.delta, with RunAtLoad and KeepAlive: it starts at login and launchd restarts it whenever it exits, waiting at least 10 seconds between starts (ThrottleInterval). Its state lives in one folder, ~/cwk-dbs/delta-db/: the SQLite file, the cache, partial transfers, TLS material, the local token and logs. Connections are HTTP/1.1 keep-alive and idle out after 75 seconds. The serve loop wakes once a second for its signal check and, every six hours, sweeps abandoned partial transfers. Nothing else runs on a timer. Delta has no scheduler: it moves data only when a person or an app asks.