The v0.1.1 cask installs correctly — signed, notarized, stapled, spctl accepts it — but the binary never executes a single line of its own code when run from /Applications. It blocks in the dynamic loader.
Reproduced on macOS 25.5.0 (Darwin), Apple Silicon, 2026-08-05.
Symptom
$ timeout 8 /Applications/Tacet.app/Contents/MacOS/tacet
$ echo $?
124 # timed out; expected 2, after printing "usage: tacet <serve|agent>"
main.swift cannot hang there — with no arguments it writes usage to stderr and exit(2) before touching AppKit. A sample of the hung process confirms it never gets that far:
Call graph:
1597 Thread_163286913: Main Thread DispatchQueue_<multiple>
1597 _dyld_start (in dyld) + 0 [0x10273c9c0]
The whole stack is _dyld_start. Same result for tacet serve under launchd: state = running, never binds its port, nothing in the log.
The bundle is fine — it is the path
The identical bundle, ditto'd elsewhere, runs instantly:
| location |
result |
/Applications/Tacet.app |
hangs, rc=124 |
/tmp/tt/Tacet.app (ditto of the above) |
usage: tacet <serve|agent>, rc=2 |
~/Applications/Tacet.app (same copy) |
usage: tacet <serve|agent>, rc=2 |
Same bytes, same xattrs (com.apple.macl, com.apple.provenance on both), same signature.
Ruled out, each by test
- Signature / notarization.
spctl -a -vvv → accepted / source=Notarized Developer ID. stapler validate passes. And the same bytes run elsewhere.
- Quarantine. Homebrew applies
com.apple.quarantine to casks by default. Removing it with xattr -dr did not change the hang.
- Online Gatekeeper check. A copy runs fine, and the ticket is stapled, so no network is needed.
- Contention from
KeepAlive respawns. Hung instances pile up because launchd restarts them. Booting the service out entirely and killing every process still reproduced it.
Why this matters
tacet is never double-clicked — launchd starts it. A first-launch consent dialog, if that is what this is, has nobody to click it, so the app deadlocks instead of failing. Whatever the cause, an app that hangs in dyld gives an operator nothing: no log line, no exit code, no error.
It also makes the installers' verification step hang forever. install-server.sh runs the installed binary to prove it works:
usage_out="$("$APP_DST/Contents/MacOS/tacet" 2>&1 || true)"
With no timeout, that blocked for 10+ minutes before being killed by hand. That check needs a timeout regardless of what causes the hang — it is the difference between a diagnosable failure and a wedged install.
Not yet tried
- Replacing
/Applications/Tacet.app with a freshly written copy (new inode) to see whether the path or the specific file is at fault.
- Whether this reproduces on a machine other than the author's. CI installs and uninstalls the cask but never executes it, so it provides no evidence either way.
Impact
The cask (drycodeworks/tap) should not be recommended until this is understood. Installing from source to ~/Applications is unaffected and works.
The v0.1.1 cask installs correctly — signed, notarized, stapled,
spctlaccepts it — but the binary never executes a single line of its own code when run from/Applications. It blocks in the dynamic loader.Reproduced on macOS 25.5.0 (Darwin), Apple Silicon, 2026-08-05.
Symptom
main.swiftcannot hang there — with no arguments it writes usage to stderr andexit(2)before touching AppKit. Asampleof the hung process confirms it never gets that far:The whole stack is
_dyld_start. Same result fortacet serveunder launchd:state = running, never binds its port, nothing in the log.The bundle is fine — it is the path
The identical bundle,
ditto'd elsewhere, runs instantly:/Applications/Tacet.apprc=124/tmp/tt/Tacet.app(ditto of the above)usage: tacet <serve|agent>,rc=2~/Applications/Tacet.app(same copy)usage: tacet <serve|agent>,rc=2Same bytes, same xattrs (
com.apple.macl,com.apple.provenanceon both), same signature.Ruled out, each by test
spctl -a -vvv→accepted / source=Notarized Developer ID.stapler validatepasses. And the same bytes run elsewhere.com.apple.quarantineto casks by default. Removing it withxattr -drdid not change the hang.KeepAliverespawns. Hung instances pile up because launchd restarts them. Booting the service out entirely and killing every process still reproduced it.Why this matters
tacet is never double-clicked — launchd starts it. A first-launch consent dialog, if that is what this is, has nobody to click it, so the app deadlocks instead of failing. Whatever the cause, an app that hangs in dyld gives an operator nothing: no log line, no exit code, no error.
It also makes the installers' verification step hang forever.
install-server.shruns the installed binary to prove it works:usage_out="$("$APP_DST/Contents/MacOS/tacet" 2>&1 || true)"With no timeout, that blocked for 10+ minutes before being killed by hand. That check needs a timeout regardless of what causes the hang — it is the difference between a diagnosable failure and a wedged install.
Not yet tried
/Applications/Tacet.appwith a freshly written copy (new inode) to see whether the path or the specific file is at fault.Impact
The cask (drycodeworks/tap) should not be recommended until this is understood. Installing from source to
~/Applicationsis unaffected and works.