From 515306cd4af41ecbe2d35cc1653b7ae6875e9651 Mon Sep 17 00:00:00 2001 From: claude Date: Wed, 27 May 2026 16:02:47 -0400 Subject: [PATCH] fix(smolmachines): restore /tmp + /var/tmp perms after smolvm pack remap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit smolvm's pack process remaps OCI-layer ownership to the host invoker's uid for *every* directory, not just /home/node — so /tmp lands as `0755 501:dialout` instead of the standard `1777 root:root`. Non-root processes can't create per-uid scratch dirs in there. Claude-code's first Bash tool call fails with `EACCES: permission denied, mkdir '/tmp/claude-1000'`. Same workaround folded into the existing perms-repair sh -c: `chown root:root /tmp /var/tmp && chmod 1777 /tmp /var/tmp` next to the /home/node chown. One machine_exec round trip total. Co-Authored-By: Claude Opus 4.7 --- claude_bottle/backend/smolmachines/launch.py | 36 ++++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/claude_bottle/backend/smolmachines/launch.py b/claude_bottle/backend/smolmachines/launch.py index cf9d61b..1932e99 100644 --- a/claude_bottle/backend/smolmachines/launch.py +++ b/claude_bottle/backend/smolmachines/launch.py @@ -193,17 +193,31 @@ def launch( _smolvm.machine_start(plan.machine_name) stack.callback(_smolvm.machine_stop, plan.machine_name) - # 6. Reclaim /home/node for the node user. smolvm's pack - # process remaps OCI-layer ownership to the host invoker's - # uid (501 on macOS) rather than preserving the image's - # uid 1000 — so without this chown, node can't write its - # own dotfiles (claude appendFileSync on - # ~/.claude.json bails with ENOENT/EPERM and the TUI hangs - # without surfacing the error). - _smolvm.machine_exec( - plan.machine_name, - ["chown", "-R", "node:node", "/home/node"], - ) + # 6. Repair filesystem ownership + perms that smolvm's + # pack process remapped to the host invoker's uid (501 + # on macOS) rather than preserving the image's expected + # ownership. + # + # - /home/node → node:node so the node user can write + # its own dotfiles (claude appendFileSync on + # ~/.claude.json otherwise bails with ENOENT/EPERM + # and the TUI hangs without surfacing the error). + # - /tmp + /var/tmp → root:root mode 1777 so non-root + # processes can create their per-uid scratch dirs + # (claude-code creates /tmp/claude-/ as soon as + # it spawns a Bash tool call). + # + # All folded into one sh -c so we only pay one + # machine_exec round trip — back-to-back exec calls + # right after machine_start hit a SIGKILL race in + # libkrun's exec channel (see provision_ca for the + # other half of this same workaround). + _smolvm.machine_exec(plan.machine_name, [ + "sh", "-c", + "chown -R node:node /home/node && " + "chown root:root /tmp /var/tmp && " + "chmod 1777 /tmp /var/tmp", + ]) # Wait briefly for the VM to settle. Back-to-back smolvm # machine_exec calls immediately after machine_start