This guide explains how to run Claude Code as a separate macOS user account, giving you fine-grained control over which directories Claude can access — and allowing Claude to run in yolo mode safely.
TLDR
Run Claude Code as a user. Use ACL to give claude access to specific folders, and to make sure you can read/write files created by claude.
Motivation
I want to let Claude run in yolo mode (--dangerously-skip-permissions), but I also want to make sure it’ll never delete my home directory by accident.
Alternatives
- Buy Claude a computer. I could let it run in a separate Mac mini[1][2] or a cloud instance. This makes sense for tasks where Claude needs privileged access, but for most coding tasks it’s unnecessary overhead.
- Docker. Docker provides great isolation and probably matches the environment Claude is trained in, but it also adds friction to the workflow.
- Claude Code/Codex builtin sandbox. These things evolve with each version. It has some limitations and it’s hard to keep track of how it works. (Claude Code is not open source). I just want to run
--dangerously-skip-permissions!
Setup (tested on macOS)
1. Create the claude user
Use macOS System Settings → Users & Groups to create a new standard user named “claude”. You might need to login to the GUI as claude at least once for some things to work correctly (e.g. keychain).
2. Install Claude Code for the claude user
# Switch to claude user
su claude
# Install Claude Code
curl -fsSL https://claude.ai/install.sh | bash3. (Optional) Allow passwordless sudo to claude
This lets you switch to the claude user without typing a password each time:
echo "$(whoami) ALL=(claude) NOPASSWD: ALL" | sudo EDITOR='tee -a' visudo -f /etc/sudoers.d/claude4. Grant Claude access to a directory
# Set the directory you want to grant access to
DIR=/path/to/dir
# ACL permissions for full read/write/delete with inheritance
ACL_PERMS="allow list,add_file,search,add_subdirectory,delete_child,readattr,writeattr,readextattr,writeextattr,readsecurity,file_inherit,directory_inherit,delete"
# Grant claude access
chmod -R +a "user:claude $ACL_PERMS" "$DIR"
# Grant yourself access to files claude creates
chmod -R +a "user:$(whoami) $ACL_PERMS" "$DIR"To revoke access:
chmod -R -a "user:claude $ACL_PERMS" "$DIR"
chmod -R -a "user:$(whoami) $ACL_PERMS" "$DIR"This uses macOS ACLs (Access Control Lists) to grant the claude user access to specific folder, and to allow you to have r/w access to files created by claude.
Key ACL flags:
file_inherit,directory_inherit— new files/subdirectories inherit this ACLlist,add_file,search,add_subdirectory,delete_child,delete— full read/write/delete accessreadattr,writeattr,readextattr,writeextattr,readsecurity— metadata access
5. Run Claude Code as claude
sudo -u claude -i bash -lc "cd '$(pwd)' && claude --dangerously-skip-permissions"Automating it (Recommended)
The manual workflow above works, but you can automate it with a helper script.
Save this to ~/.local/bin/claude-access:
claude-access (click to expand)
#!/bin/bash
# Manage Claude's directory access
CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/claude-access"
CONFIG_FILE="$CONFIG_DIR/directories"
CLAUDE_USER="claude"
mkdir -p "$CONFIG_DIR"
touch "$CONFIG_FILE"
usage() {
echo "Usage: claude-access <command> [args]"
echo ""
echo "Commands:"
echo " list List all shared directories"
echo " add <dir> Add a directory (use . for current)"
echo " remove <dir> Remove a directory (use . for current)"
echo " sync Apply permissions to all directories"
}
resolve_dir() {
local dir="$1"
if [[ "$dir" == "." ]]; then
pwd
else
realpath "$dir"
fi
}
list_dirs() {
if [[ ! -s "$CONFIG_FILE" ]]; then
echo "No directories configured."
else
cat "$CONFIG_FILE"
fi
}
apply_permissions() {
local dir="$1"
echo "Applying permissions: $dir"
# Grant claude access
chmod -R +a "user:$CLAUDE_USER allow list,add_file,search,add_subdirectory,delete_child,readattr,writeattr,readextattr,writeextattr,readsecurity,file_inherit,directory_inherit,delete" "$dir"
# Grant current user access to files claude creates
chmod -R +a "user:$(whoami) allow list,add_file,search,add_subdirectory,delete_child,readattr,writeattr,readextattr,writeextattr,readsecurity,file_inherit,directory_inherit,delete" "$dir"
}
remove_permissions() {
local dir="$1"
echo "Removing permissions: $dir"
chmod -R -a "user:$CLAUDE_USER allow list,add_file,search,add_subdirectory,delete_child,readattr,writeattr,readextattr,writeextattr,readsecurity,file_inherit,directory_inherit,delete" "$dir"
}
add_dir() {
local dir
dir=$(resolve_dir "$1")
if [[ ! -d "$dir" ]]; then
echo "Error: $dir is not a directory"
exit 1
fi
if grep -qxF "$dir" "$CONFIG_FILE" 2>/dev/null; then
echo "Already in list: $dir"
else
echo "$dir" >> "$CONFIG_FILE"
echo "Added: $dir"
apply_permissions "$dir"
fi
}
remove_dir() {
local dir
dir=$(resolve_dir "$1")
if grep -qxF "$dir" "$CONFIG_FILE" 2>/dev/null; then
grep -vxF "$dir" "$CONFIG_FILE" > "$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
echo "Removed: $dir"
remove_permissions "$dir"
else
echo "Not in list: $dir"
fi
}
sync_dirs() {
if [[ ! -s "$CONFIG_FILE" ]]; then
echo "No directories configured. Use 'add' first."
exit 1
fi
while IFS= read -r dir; do
if [[ -d "$dir" ]]; then
apply_permissions "$dir"
else
echo "Skipping (not a directory): $dir"
fi
done < "$CONFIG_FILE"
echo "Done."
}
case "${1:-}" in
list)
list_dirs
;;
add)
[[ -z "${2:-}" ]] && { echo "Error: specify a directory"; exit 1; }
add_dir "$2"
;;
remove)
[[ -z "${2:-}" ]] && { echo "Error: specify a directory"; exit 1; }
remove_dir "$2"
;;
sync)
sync_dirs
;;
*)
usage
;;
esacMake it executable and ensure ~/.local/bin is in your PATH:
chmod +x ~/.local/bin/claude-access
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
source ~/.zshrcScript usage
claude-access add . # Grant access to current directory
claude-access remove . # Revoke access
claude-access list # List shared directories
claude-access sync # Re-apply permissions to all directories
# note: The directory list is stored at `~/.config/claude-access/directories`You can alias the run command in your shell config (e.g. .zshrc):
cc() {
local dir="$(pwd)"
claude-access add .
sudo -u claude -i bash -lc "cd '$dir' && claude --dangerously-skip-permissions $*"
}Usage
Once setup is complete (including the cc alias):
cd ~/path/to/your/project
ccAppendix
Dedicated group (optional)
If you’re on a machine with multiple users and want to prevent other users from reading files created by claude, you can create a group and make it the primary group of claude, so files created by claude are in group claude, and is only readable by claude (user) and you (via ACL).
Group creation commands (click to expand)
# Create a group just for claude
NEXT_GID=$(($(dscl . list /Groups PrimaryGroupID | awk '{print $2}' | sort -n | tail -1) + 1))
sudo dscl . create /Groups/claude
sudo dscl . create /Groups/claude PrimaryGroupID $NEXT_GID
sudo dscl . append /Groups/claude GroupMembership claude
sudo dscl . create /Users/claude PrimaryGroupID $NEXT_GIDGit Setup
The claude user needs git configuration (name, email) to make commits. Copy your .gitconfig or set it up manually.
GitHub Setup
By default, claude can’t use your gh token, unless you make the token available to claude. This is desirable for security. You can review the code before pushing manually, or go one step further to setup a separate GitHub account/token for Claude.
Alternative: Group permissions and umask
I also tried using group permission (g+rw) and umask to manage file access, but it’s not as robust as ACL.
Issues with umask (click to expand)
Setting umask for the claude user:
echo 'umask 002' | sudo tee -a /Users/claude/.bash_profileThis sets a default so files created by claude are group-writable.
Issues with this approach:
- Umask can be unreliable across different tools and contexts
- Claude Code’s
Writetool (as of v2.0.69) does not respect umask, meaning files created with theWritetool may not be accessible without manual permission fixes (sudo chown/chmod) - The ACL inheritance approach (shown above) is more reliable for ensuring you can access files claude creates
Troubleshooting
Troubleshooting commands (click to expand)
Check current ACLs on a directory
ls -le /path/to/dirVerify claude can access a directory
sudo -u claude ls /path/to/dirClear all ACLs from a directory
chmod -RN /path/to/dir