Claude Code v2.1.78+ Root Restriction — Non-Root User Workaround

Trigger

Claude Code desktop auto-updated to v2.1.78, introducing a permanent security policy: --dangerously-skip-permissions is blocked when running as root/sudo. This flag is automatically passed by Claude Code desktop when connecting to a remote server via SSH. Since the VPS was configured as root@72.61.173.164, the remote ccd-cli process crashed on every connection attempt with exit code 1.

This is a permanent Anthropic security policy, not a bug.

Three Issues Resolved

Issue 1 — Stale SSH Host Key

The VPS had been rebuilt previously, leaving a stale host key in ~/.ssh/known_hosts on the desktop machine. Fixed with ssh-keygen -R 72.61.173.164 and re-accepting the new key.

Issue 2 — Root + Skip-Permissions Block (Primary)

Fix: Created non-root user claude (uid=1002) with:

  • Passwordless sudo: ALL=(ALL) NOPASSWD:ALL
  • Group memberships: claude, root, sudo
  • SSH alias aj-vps-claude (User: claude) added to desktop ~/.ssh/config
  • Desktop SSH Host changed from aj-vps to aj-vps-claude
  • Original aj-vps alias (User: root) preserved for direct terminal SSH

Issue 3 — Malformed Settings Hook

/root/.claude/settings.json had a malformed Stop hook (missing matcher field and hooks array wrapper). Fixed with proper {"matcher": "", "hooks": [...]} structure.

Post-Migration Fix — OpenClaw Config Continuity

After the user change, Claude Code’s runtime (running as claude with HOME=/home/claude) could not see the OpenClaw setup at /root/.claude/ — settings, hooks, skills, plugins, agent-instructions, CLAUDE.md, todos, sessions were all invisible.

Fix applied:

  1. Replaced /home/claude/.claude/ (empty runtime directories) with symlink: /home/claude/.claude/root/.claude
  2. Set group read/write permissions: chmod -R g+rwX /root/.claude/
  3. Set setgid on all directories: find /root/.claude -type d -exec chmod g+s {} \;
  4. Works because claude user is in the root group

Final Verified State

ComponentStatus
Claude Code CLI as user claude (uid=1002)Operational
SSH: aj-vps-claude (claude) for Claude Code, aj-vps (root) for terminalBoth working
/home/claude/.claude/root/.claude symlinkFull R/W verified
settings.json — hooks, plugins, alwaysThinkingEnabled, effortLevelAll wired
31 skills at ~/.claude/skills/All discoverable
3 Python hooks at ~/.claude/hooks/All firing
Agent instructions (SOUL.md + 12 agents)Accessible
MCP registrations (/root/.claude.json)Readable
Project memories (17 files)Full R/W
OpenClaw — separate openclaw user (uid=1001), systemd, port 18789Completely unaffected
Docker — claude user uses sudo dockerWorking
Workspaces — /root/aj-workspace, /root/aj-eaBoth accessible

Architecture Invariants

  • Single source of truth: All Claude Code config lives at /root/.claude/. Symlink ensures both root and claude users see the same state.
  • OpenClaw isolation: Runs as its own openclaw user — zero coupling with Claude Code user change.
  • New files inherit group: setgid ensures files created by either user remain group-accessible.
  • No functional change: Every capability (hooks, skills, plugins, MCP servers, agent instructions, memory) works identically.

Key Takeaway

Anthropic’s root restriction is permanent. The claude user with passwordless sudo provides identical authority without triggering the binary-level block. The symlink from /home/claude/.claude/root/.claude ensures zero config divergence. This setup survives future Claude Code updates as long as non-root + sudo remains permitted.