Build1 distinct publisher3 min readPublished
Belay's receiver asked macOS for any free port and the installer wrote that number into Claude Code's config, so when Sparkle shipped 1.6.2 mid-session the port advanced by one and the agent kept posting into a closed socket.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
Call `NWListener(using: parameters)` with no port and macOS hands back whatever is free above 49152, fresh on every launch [9]. The socket is healthy for the life of the process, which is exactly as long as the number stays true. Belay's installer wrote that number into the agent's `settings.json` as a literal [10]. The 61716 in the user's config sat inside the ephemeral range itself, so it was an OS handout rather than a chosen value [21]. Ordinary restarts hid the consequence, because Belay re-pointed the config files at launch and the mismatch window lasted seconds [11].
An auto-update removes that cushion. Long unattended runs are what the app exists for, so the session is mid-flight by definition, and the human is elsewhere while the port moves [12]. The developer reproduced the move on his own machine at the first attempt: restart, and 49680 became 49683 [13].
The two dead hypotheses are the useful part of the account on dev.to. The first was a crash during the update, which the log refuted, since the bridge was up and healthy on 61717 while the POSTs bounced [7]. The second was per-session caching of the hook URL, which died on a live test: editing `settings.json` mid-session moved the running session within seconds [8]. The client was reading current config; the server had changed address.
`requiredLocalEndpoint` on `NWParameters` reads like the fix, and the unit test agreed [14]. Connections honor it. Listeners ignore it without raising an error, the documentation says nothing about that, and the API accepts the value anyway [16]. The test passed for a reason unrelated to the code: release an ephemeral port, immediately ask for any port, and the allocator usually returns the same one from the front of the free list [17]. The soak log is where the luck ran out. Three restarts reported 49731, then 49734, then 49738 [15], steps of 3 and then 4, an allocator walking forward past a request nobody enforced [20].
The initializer that holds is `NWListener(using: parameters, on: wanted)` [18]. The part worth copying on any platform is the test that came with it, which plants a port around 7,000 away from the one the OS just offered and insists on that [19]. As the developer puts it, a restart-and-compare test for port stability is a test of the kernel's allocator mood [17].
A loopback endpoint you write into somebody else's config file is an API, and the port number is part of its signature. In my context I would persist the endpoint record, port and token together, and bind it again on launch, which is what the shipped fix stores [19]. Where the port genuinely cannot be pinned, the cost moves to the caller: re-read the endpoint before each POST, and a relaunch costs one refused request instead of three hours of them [3].
Ranked by verification strength, evidence, and original report placement.
Belay's receiver was an NWListener created without a port, so macOS hands it an ephemeral port from the 49152+ range, producing a new port on every launch.
The installer wrote the receiver's port into the agent's settings.json once, as a literal number.
The first fix set requiredLocalEndpoint on NWParameters to the loopback host and the wanted port; a test that started a receiver, stopped it, started another and asserted the port came back passed.
After the requiredLocalEndpoint change was soaked on the developer's own machine, three restarts logged 'bridge up port=49731', then 49734, then 49738.
Belay is a macOS menu bar utility, written by the author of the post, that keeps a Mac awake while local AI coding agents are working.
One of Belay's detection tiers is a loopback HTTP receiver: the agent's hooks POST lifecycle events such as 'a tool call started' and 'the turn finished' to 127.0.0.1:<port>, and Belay uses those signals to decide whether the machine may sleep.
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 30, 2026
Follow any of these and your For You feed starts watching them — no settings page required.
build
Waku 0.1.0 bets the product is the control plane, not another coding agent1 distinct publisher
build
The 46GB Leak Your RSS Alert Cannot See: macOS Compressed Memory Breaks Threshold Monitoring1 distinct publisher
build
Exit 0 is not a health check: three weeks of macOS backups that copied nothing1 distinct publisher
build
A quota error looks like a retry, so 15 jobs idled six hours unnoticed1 distinct publisher
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Traceable mechanism, one uncorroborated platform claim
For a single-author bug story this is unusually checkable: log lines from both sides of the update, a one-try reproduction that turned 49680 into 49683, and a soak whose three climbing ports contradicted the author's own fix. The weak spot is the finding with the widest reach — that NWListener accepts requiredLocalEndpoint and then ignores it — which rests on three log entries and an assertion that the documentation is silent, with no Apple reference or outside reproduction alongside it.
One shipping app, one outside user
Everything observable amounts to a menu bar utility that ships updates through Sparkle and exactly one person outside the developer's machine running the integration. No install count, no second report of the same three-hour silence, no indication of how many configs carry a stale port right now. The auto-updater firing in the wild is genuine deployment evidence; it is also the whole of it.
Modest framing, one claim stretched past its data
The headline promises exactly what the post delivers — an ephemeral port, an update, three hours of refused POSTs — and the author spends most of the piece being wrong in public, which is the opposite of overselling. The small overreach is the leap from three soak ports on one Mac to a flat statement about how Apple's listener treats a documented parameter; that is presented as settled platform behaviour when it is one machine's observation.
Author owns the app that broke
The person telling the story wrote the software, the installer, and the auto-updater that combined to break a user's session, and he says so in the third paragraph. That cuts both ways: a postmortem casting your own updater as the culprit is not promotion, but Belay is still his product and this is still many readers' introduction to it — which may explain why the piece dwells on the elegant Network.framework trap and never says how many other users were affected or when the fix reached them.
First-hand and falsifiable, but singly sourced
Specific enough that anyone with Xcode can settle the central question in an afternoon, and internally consistent from the error excerpt through the reproduction to the rewritten test. What holds the number down is structural rather than suspicious: one incident, one machine, one narrator who is also the defendant, and a second-hand user report reconstructed from two screenshots and a log the developer asked for after the fact.