From 323acb3f1d227cac4cfc8a4d3668d2e7f452e33c Mon Sep 17 00:00:00 2001 From: andyb Date: Wed, 1 Jul 2026 14:45:10 -0500 Subject: [PATCH] maintenance(shell): guard against unwritable inherited TMPDIR in headless contexts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A headless / launchd-launched agent (the 24/7 Mac mini) inherits the generic macOS fallback temp dir (TMPDIR=/var/folders/zz/zyxvpxvq6csfxvn_n0000000000000/T, owned root:wheel mode 0700) instead of the per-user temp, because launchd never set up the DARWIN_USER_TEMP_DIR bootstrap. Any tool that writes to $TMPDIR then fails with EACCES — e.g. `vitest run` (its coverage provider mkdir's under $TMPDIR), npm, and esbuild. Add a guard to .zprofile that points TMPDIR/TMP/TEMP at ~/.claude/tmp ONLY when the inherited value is unset or not writable, so healthy interactive machines keep the system temp dir untouched. Co-Authored-By: Claude Opus 4.8 (1M context) --- shell/.zprofile | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/shell/.zprofile b/shell/.zprofile index 96ebef1..60ed9e6 100644 --- a/shell/.zprofile +++ b/shell/.zprofile @@ -4,6 +4,18 @@ if [ -r "/opt/homebrew/bin/brew" ]; then eval $(/opt/homebrew/bin/brew shellenv) fi + +# Ensure a writable temp dir. Headless / launchd-launched contexts inherit the +# root-owned macOS fallback (TMPDIR=/var/folders/zz/.../T, mode 0700), which is +# unwritable by the user and breaks vitest/npm/esbuild with EACCES. Only override +# when TMPDIR is unset or not writable, so interactive machines keep system temp. +if [ -z "$TMPDIR" ] || [ ! -w "${TMPDIR%/}" ]; then + export TMPDIR="$HOME/.claude/tmp" + export TMP="$TMPDIR" + export TEMP="$TMPDIR" + mkdir -p "$TMPDIR" +fi + if [[ $- == *i* ]] && [ -t 0 ]; then echo "This is an interactive shell" else