Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/claude-code/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,23 @@ Installs the Claude Code CLI globally
}
```

### Installing as a user (recommended for non-root containers)

If you run your devcontainer as a non-root user (e.g., `vscode` user), use the `installAsUser` option to prevent permission issues with auto-updates:

```json
"features": {
"ghcr.io/anthropics/devcontainer-features/claude-code:1": {
"installAsUser": true
}
}
```

## Options

| Options Id | Description | Type | Default Value |
|-----|-----|-----|-----|
| installAsUser | Install Claude Code locally for the current user instead of globally. This prevents permission issues with auto-updates when running as a non-root user. | boolean | false |


## Customizations
Expand Down Expand Up @@ -60,6 +73,19 @@ If your container already has Node.js installed (for example, a container based

When using with containers that have nvm pre-installed, you can use the Claude Code feature directly, and it will use the existing Node.js installation.

## User Installation vs Global Installation

### Global Installation (default)
- Installs Claude Code system-wide
- Requires root permissions for updates
- May cause permission issues when running as non-root user

### User Installation (`installAsUser: true`)
- Installs Claude Code to `~/.local/bin`
- Allows updates without root permissions
- Recommended when running devcontainers as non-root users
- Automatically configures PATH in shell profiles



---
Expand Down
12 changes: 9 additions & 3 deletions src/claude-code/devcontainer-feature.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
{
"name": "Claude Code CLI",
"id": "claude-code",
"version": "1.0.5",
"description": "Installs the Claude Code CLI globally",
"options": {},
"version": "1.1.0",
"description": "Installs the Claude Code CLI globally or locally for the current user",
"options": {
"installAsUser": {
"type": "boolean",
"default": false,
"description": "Install Claude Code locally for the current user instead of globally. This prevents permission issues with auto-updates when running as a non-root user."
}
},
"documentationURL": "https://github.com/anthropics/devcontainer-features/tree/main/src/claude-code",
"licenseURL": "https://github.com/anthropics/devcontainer-features/blob/main/LICENSE",
"customizations": {
Expand Down
47 changes: 44 additions & 3 deletions src/claude-code/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,46 @@ install_nodejs() {

# Function to install Claude Code CLI
install_claude_code() {
echo "Installing Claude Code CLI..."
npm install -g @anthropic-ai/claude-code
local install_as_user="$1"

if [ "$install_as_user" = "true" ]; then
echo "Installing Claude Code CLI for current user..."

# Set npm to install to user directory
export NPM_CONFIG_PREFIX="$HOME/.local"
mkdir -p "$HOME/.local/bin"

# Install globally but to user directory
npm install -g @anthropic-ai/claude-code

# Add user bin directory to PATH
if [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then
export PATH="$HOME/.local/bin:$PATH"
echo "Added $HOME/.local/bin to PATH"
fi

# Create a script to ensure PATH is set for the user
cat > "$HOME/.bashrc_claude" << 'EOF'
# Add user-local npm packages to PATH
if [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then
export PATH="$HOME/.local/bin:$PATH"
fi
EOF

# Source the script in common shell configs
for config_file in "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.profile"; do
if [ -f "$config_file" ] && ! grep -q "source.*\.bashrc_claude" "$config_file"; then
echo "source ~/.bashrc_claude" >> "$config_file"
echo "Added Claude Code PATH setup to $config_file"
fi
done

else
echo "Installing Claude Code CLI globally..."
npm install -g @anthropic-ai/claude-code
fi

# Check if claude command is available
if command -v claude >/dev/null; then
echo "Claude Code CLI installed successfully!"
claude --version
Expand Down Expand Up @@ -121,6 +158,10 @@ EOF
# Main script starts here
main() {
echo "Activating feature 'claude-code'"

# Read the installAsUser option (default: false)
local install_as_user="${INSTALLASUSER:-false}"
echo "Install as user: $install_as_user"

# Detect package manager
PKG_MANAGER=$(detect_package_manager)
Expand All @@ -133,7 +174,7 @@ main() {
fi

# Install Claude Code CLI
install_claude_code || exit 1
install_claude_code "$install_as_user" || exit 1
}

# Execute main function
Expand Down
9 changes: 9 additions & 0 deletions test/claude-code/scenarios.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,14 @@
"ghcr.io/devcontainers/features/node:1": {},
"claude-code": {}
}
},
"user_install": {
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/node:1": {},
"claude-code": {
"installAsUser": true
}
}
}
}