Skip to content

claude-sudo

claude-sudo is a small wrapper that launches Claude Code with passwordless sudo for the lifetime of that one Claude process, and takes the privilege away again the moment Claude exits.

Plain claude has no passwordless sudo. That is deliberate: an agent that can run sudo silently, forever, in every session is a much larger blast radius than one that can only do so while you knowingly started it that way.

The trade-off in one line

While claude-sudo is running, Claude can run any command as root without prompting. Start it only for sessions that genuinely need server administration.

How it works

Step What happens
1 Clears any stale rule left behind by a previously killed session
2 Writes <user> ALL=(ALL) NOPASSWD:ALL to /etc/sudoers.d/49-claude-session (prompts for your password once, via sudo tee)
3 chmod 440 on the rule, then validates it with visudo -cf
4 Runs claude as your normal user, so files stay owned by you rather than root
5 On exit — including INT, TERM, HUP — a trap removes the rule

The username is resolved at runtime with id -un, so the same script works unchanged on any machine and for any user.

The rule survives a hard kill

The EXIT/INT/TERM/HUP trap covers normal exits and Ctrl-C, but not SIGKILL, a power cut, or a crashed terminal. The next claude-sudo start clears the stale rule, but until then the NOPASSWD grant is still live. To clean up by hand:

sudo rm -f /etc/sudoers.d/49-claude-session

Check whether one is currently active:

ls -l /etc/sudoers.d/49-claude-session

The script

/usr/local/bin/claude-sudo
#!/usr/bin/env bash
#
# claude-sudo — launch Claude Code with passwordless sudo for THIS session only.
#
# On start it installs a NOPASSWD sudoers rule (prompting for your password once),
# runs Claude as your normal user, and removes the rule again the moment Claude
# exits. Plain `claude` has no passwordless sudo.
#
set -uo pipefail

RULE="/etc/sudoers.d/49-claude-session"
USER_NAME="$(id -un)"

revoke() { [ -e "$RULE" ] && sudo -n rm -f "$RULE" 2>/dev/null; }
trap revoke EXIT INT TERM HUP

# Clear any stale rule left by a previously killed session, then grant for this one.
sudo rm -f "$RULE"
printf '%s ALL=(ALL) NOPASSWD:ALL\n' "$USER_NAME" | sudo tee "$RULE" >/dev/null
sudo chmod 440 "$RULE"

# Validate the rule; a broken sudoers file would break sudo entirely.
if ! sudo visudo -cf "$RULE" >/dev/null; then
    echo "claude-sudo: refusing to start, invalid sudoers rule" >&2
    revoke
    exit 1
fi

# Run Claude as the normal (non-root) user so files stay owned by you.
command claude "$@"

Two details worth keeping if you edit it:

command claude "$@"

The command builtin bypasses shell aliases and functions, so an alias claude=... in your rc file cannot hijack the launch. "$@" forwards every flag you pass through to Claude Code.

visudo -cf "$RULE"

A syntactically broken file in /etc/sudoers.d/ breaks sudo entirely — including the sudo you would need to fix it. The check is cheap insurance; do not remove it.


Installation on a new machine

Requires: a working claude on your PATH, and your user already in sudo (or wheel).

1. Write the script

cat > ~/claude-sudo <<'EOF'
#!/usr/bin/env bash
#
# claude-sudo — launch Claude Code with passwordless sudo for THIS session only.
#
set -uo pipefail

RULE="/etc/sudoers.d/49-claude-session"
USER_NAME="$(id -un)"

revoke() { [ -e "$RULE" ] && sudo -n rm -f "$RULE" 2>/dev/null; }
trap revoke EXIT INT TERM HUP

sudo rm -f "$RULE"
printf '%s ALL=(ALL) NOPASSWD:ALL\n' "$USER_NAME" | sudo tee "$RULE" >/dev/null
sudo chmod 440 "$RULE"

if ! sudo visudo -cf "$RULE" >/dev/null; then
    echo "claude-sudo: refusing to start, invalid sudoers rule" >&2
    revoke
    exit 1
fi

command claude "$@"
EOF

2. Install it

sudo install -m 755 -o root -g root ~/claude-sudo /usr/local/bin/claude-sudo
rm ~/claude-sudo

install runs in the directory you are standing in

sudo install ... claude-sudo ... with a bare filename only works from the directory holding the file. Use ~/claude-sudo — or an absolute path — and it works from anywhere.

3. Verify

ls -l /usr/local/bin/claude-sudo      # -rwxr-xr-x 1 root root
bash -n /usr/local/bin/claude-sudo    # syntax check, runs nothing

4. Add the convenience alias

The server uses a single long-lived tmux session named cc, so a dropped SSH connection does not kill the running Claude:

~/.bashrc
alias rc='tmux attach -t cc 2>/dev/null || tmux new -s cc claude-sudo'

Then rc either reattaches to the existing session or starts a fresh claude-sudo inside a new one. For Zsh, put the same line in ~/.zshrc.


Copying it between machines

The script is self-contained — it needs no config file, and it creates and removes its own sudoers rule at runtime. To move it to another host, such as a Raspberry Pi:

scp franz@franzvoid.is:/usr/local/bin/claude-sudo ~/claude-sudo
sudo install -m 755 -o root -g root ~/claude-sudo /usr/local/bin/claude-sudo

If you cannot read /usr/local/bin/claude-sudo over SFTP because of its ownership, copy it into your home directory on the source machine first:

cp /usr/local/bin/claude-sudo ~/claude-sudo     # run on the source host

Or skip the transfer entirely and paste the heredoc from Installation on a new machine.


Using it

claude-sudo              # same flags as `claude`
claude-sudo --resume
rc                       # via tmux, the normal way on this server

Inside the session, confirm the grant is live:

sudo -n true && echo "passwordless sudo active"

If sudo -n true fails inside a Claude session

Claude should not work around it. The correct responses are to relaunch with claude-sudo, or to run the single command yourself from the Claude prompt with the ! prefix:

! sudo systemctl restart apache2

Don't background a long privileged task and then quit

claude-sudo removes the sudoers rule on exit. Anything still running that needs sudo — a /new-wp provision and its rollback, for example — loses the grant mid-flight. See Creating a new site from the template.


Common problems

install: cannot stat 'claude-sudo': No such file or directory

You are not in the directory holding the file. Use the full path:

sudo install -m 755 -o root -g root ~/claude-sudo /usr/local/bin/claude-sudo

It asks for a password every time

Expected — sudo tee on the first line of the script needs one password entry per session, because the rule it is about to write does not exist yet. Everything after that is passwordless.

If it asks again during the session, the rule was removed or never validated. Check:

sudo cat /etc/sudoers.d/49-claude-session

claude-sudo: refusing to start, invalid sudoers rule

visudo rejected the generated file. Almost always means id -un returned something unexpected, such as a username with characters sudoers will not accept. The script removes the bad file before exiting, so sudo is left intact.

sudo: command not found on a minimal Debian image

Fresh Debian installs do not always ship sudo, and the first user is not in the sudo group. As root:

apt install sudo
usermod -aG sudo <user>

Log out and back in for the group change to take effect.

Claude is editing files as root

It should not — the script deliberately runs command claude as your normal user. If you find root-owned files in your tree, something inside the session ran sudo on a write it did not need to. Fix ownership with:

sudo chown -R "$(id -un):$(id -gn)" <path>

Final checklist

  • /usr/local/bin/claude-sudo exists, mode 755, owned by root:root
  • bash -n /usr/local/bin/claude-sudo passes
  • claude resolves on the PATH
  • Your user is in the sudo group
  • The rc alias is in ~/.bashrc (or ~/.zshrc)
  • sudo -n true succeeds inside a claude-sudo session
  • sudo -n true fails inside a plain claude session
  • /etc/sudoers.d/49-claude-session is gone after the session exits