Build1 publisher3 min readPublished
Eleven breaks in one sitting: where a non-developer's agent gateway install actually dies
Every failure was documented somewhere. The order was not, and that is what ends the install for anyone who does not write code.
The Engineer · Build desk
Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction
What happened
- An operator who does not write code installed a self-hosted agent gateway on a Mac, from nothing, in one sitting last week; the author logged every place it broke, eleven items, all of which actually happened.
- Every individual item on the list is documented somewhere; what the author could not find documented anywhere is the order, and the fact that fixing item 3 creates item 4, which creates item 5. A non-developer fails not because a step is hard but because step 3's official doc ends before step 4 exists.
- Cause of the first break: no Node on the machine, so the install path fell through to Homebrew, which wants admin.
- Fix: do not grant admin; install Node from the official .pkg in the admin account, then work in the unprivileged one. The author calls 'move the part, not the privilege' the single most useful rule of the whole install, because every time the answer was 'just give this account admin' it was the wrong answer.
- npm's default prefix is /usr/local, which the unprivileged account cannot write; fix was npm config set prefix ~/.npm-global.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
An operator who does not write code installed a self-hosted agent gateway on a Mac, from nothing, in one sitting last week, and the person guiding the install logged all eleven places it broke [1]. None of the eleven was a hard problem, which is the useful part: according to the write-up, each item is documented somewhere, but the order is not documented anywhere the author could find, and fixing item 3 creates item 4, which creates item 5 [2].
Read that chain in sequence. There was no Node on the machine, so the install path fell through to Homebrew, which wants admin [3]. Refusing the admin grant and installing Node from the official .pkg in the admin account, then working in the unprivileged one, produced the author's one durable rule: move the part, not the privilege [4]. But npm's default prefix is /usr/local, which the unprivileged account cannot write, so the prefix moves to ~/.npm-global [5]. That new prefix's bin is not on PATH, so nothing runs until one line goes into ~/.zshrc [6]. Then --allow-scripts turns out to apply only to the invocation it is passed on, so it looks like the setting did not take when in fact it was never persisted [7].
The author checked the official EACCES document, the official scripts document, and a well-ranked 2026 community article: all three cover part of that chain and all three stop before its last link, with script approval living in a separate document that none of them links to [8]. A developer crosses that gap without noticing. A non-developer reads "installation complete" and then stares at command not found [9].
The rest of the log has the same shape. The macOS clipboard is per-session, so a token copied in one account pastes as yesterday's clipboard in another; everything moved as a file through /Users/Shared instead [10]. Guidance was being sent as images and retyped by hand, producing "is" for "ls" and "protobyfjs" for "protobufjs"; putting an executable file in the shared folder to be double-clicked took typos to zero [11]. A blinking cursor waiting on a preference is indistinguishable from a frozen app, and the fix is to press Enter, which the author could not find mentioned in a single write-up [12]. TextEdit's default format silently wrote formatting bytes into a file a program had to read [13]. The sticky bit on the shared folder meant only the creating account could delete its own files, which is the folder working as designed [14]. And one command refused to run with stdin closed, because it requires a real terminal [15].
One item is not a papercut. Searching for the bot inside the messenger surfaced impersonators near the top of results, and the fix is to enter through the canonical t.me link and verify the username rather than the display name [16]. By the author's account this is the only item on the list where getting it wrong hands your token to a stranger [17].
The gateway came up and the round trip worked, correct to the minute [18]. Then the log shows anthropic:claude-cli: expiring (7h), because the subscription-based credential expires in seven hours and renewal wants an interactive terminal [19]. That put the measured ceiling on unattended operation at seven hours and the daily human cost at three logins, on a system whose stated purpose was not needing a human [20], which is roughly what a seven-hour credential implies across a day [21].
Worth watching: whether subscription-tier credentials ever get a non-interactive renewal path, and whether install docs start linking to the script-approval step instead of ending one page short of it. Note also that four of the eleven items trace back to the decision to stay in an unprivileged account [22]; that rule bought security and paid for it in steps.