Summary
agent-relay node up under launchd writes no runtime log at all. Its declared stdout/stderr sinks receive the startup banner and then nothing, for the entire life of the process.
This is not a logging nicety. It is the difference between a diagnosable fleet and one that can only be power-cycled.
Evidence
On finn-mini (macOS, launchd com.agentrelay.fleet-node, relay-broker/11.4.0), with the node process running continuously for 25 hours:
fleet-node.stdout.log 3,882 B mtime Aug 6 12:41:10 <- process start
fleet-node.stderr.log 434 KB mtime Aug 6 12:41:02 <- process start
Both frozen at startup. Not truncated, not rotated — the node has never written a runtime line.
Corroborating, all read-only:
find across ~/.agentworkforce/relay, ~/.agent-relay and ~/Library/Application Support/agent-relay for anything modified that day returned exactly one file, belonging to an unrelated broken service.
log show --last 3h --predicate 'eventMessage CONTAINS "agent-relay" OR ... "fleet-node"' → completely empty.
~/Library/Logs/agent-relay does not exist. /usr/local/var/log does not exist. No /tmp/agent-relay*.
What it cost
The node silently stopped heartbeating at 2026-08-07T11:52:35Z while the process stayed alive and healthy: no crash report, no jetsam/OOM, no sleep/wake transition, no OS-level signal, and its TCP session to the control plane still ESTABLISHED with Recv-Q 0 / Send-Q 0. An application-level heartbeat stall on an open socket.
There is no host-side record of the heartbeat loop existing at all, so there was no way to distinguish a wedged timer from a rejected request. The only place that evidence existed was the process's own memory. That process has since been restarted and the state is permanently unrecoverable.
If this recurs, the investigation starts from zero again and reaches the same dead end.
Suggested fixes
- Log the heartbeat loop — at minimum each send and its outcome, at a level that survives to disk.
- Log connection state transitions — reconnect, backoff, auth failure, rate-limit rejection. Any of these would have answered the question in one line.
- Log unexpectedly quiet periods. A node that has not successfully heartbeated in N intervals should say so locally, even if it cannot reach the control plane — especially then.
- Make the declared launchd sinks actually receive runtime output, or document that they do not and point operators somewhere real.
Note on interpretation
Absence of a log here is not evidence of absence of activity — the process was demonstrably running the whole time. Anyone diagnosing a node by reading these files will conclude the process died at startup. It did not.
Summary
agent-relay node upunder launchd writes no runtime log at all. Its declared stdout/stderr sinks receive the startup banner and then nothing, for the entire life of the process.This is not a logging nicety. It is the difference between a diagnosable fleet and one that can only be power-cycled.
Evidence
On
finn-mini(macOS, launchdcom.agentrelay.fleet-node,relay-broker/11.4.0), with the node process running continuously for 25 hours:Both frozen at startup. Not truncated, not rotated — the node has never written a runtime line.
Corroborating, all read-only:
findacross~/.agentworkforce/relay,~/.agent-relayand~/Library/Application Support/agent-relayfor anything modified that day returned exactly one file, belonging to an unrelated broken service.log show --last 3h --predicate 'eventMessage CONTAINS "agent-relay" OR ... "fleet-node"'→ completely empty.~/Library/Logs/agent-relaydoes not exist./usr/local/var/logdoes not exist. No/tmp/agent-relay*.What it cost
The node silently stopped heartbeating at
2026-08-07T11:52:35Zwhile the process stayed alive and healthy: no crash report, no jetsam/OOM, no sleep/wake transition, no OS-level signal, and its TCP session to the control plane stillESTABLISHEDwithRecv-Q 0 / Send-Q 0. An application-level heartbeat stall on an open socket.There is no host-side record of the heartbeat loop existing at all, so there was no way to distinguish a wedged timer from a rejected request. The only place that evidence existed was the process's own memory. That process has since been restarted and the state is permanently unrecoverable.
If this recurs, the investigation starts from zero again and reaches the same dead end.
Suggested fixes
Note on interpretation
Absence of a log here is not evidence of absence of activity — the process was demonstrably running the whole time. Anyone diagnosing a node by reading these files will conclude the process died at startup. It did not.