Claude CLI Docker Integration Issues Analysis
Generated: 2025-01-10 UTC
Purpose: Comprehensive analysis of Claude CLI integration issues in Docker environments
Impact: Critical for Sliplane and containerized deployments
Executive Summary
The Claude CLI integration in Docker environments faces multiple architectural challenges that prevent proper functionality in production deployments, particularly on Sliplane. These issues stem from fundamental mismatches between local development assumptions and containerized runtime realities.
Core Problems
- Workspace Path Mismatch: Files created in one location, Claude CLI expects them elsewhere
- Installation Failures: Complex symlink logic fails in Alpine Linux containers
- Environment Detection: Inconsistent Docker environment detection across codebase
- Permission Conflicts: File system permissions differ between local and container environments
- Architecture Issues: Forced AMD64 builds may not match deployment platforms
Impact
- Claude CLI fails to start or find projects in Sliplane deployments
- Workspace initialization creates directories in wrong locations
- API key configuration doesn't persist correctly
- Sessions cannot be resumed after container restarts
Architecture Mismatch Issues
Current Architecture Assumptions
Key Differences
| Component | Local Docker | Sliplane Docker | Issue |
|---|---|---|---|
| Workspace Path | $HOME/.claude/projects/ |
/app/workspaces/ |
Mismatch in creation vs usage |
| Claude CLI Install | Global npm install | Manual symlink creation | Symlink may fail or point wrong |
| Environment Detection | RUNNING_IN_DOCKER |
Multiple checks | Inconsistent detection |
| File Permissions | User-based | Volume-based | Permission denied errors |
| Architecture | Native | Forced AMD64 | Platform mismatch |
Detailed Issue Analysis
Issue #1: Workspace Path Mismatch
Problem: The workspace manager creates projects in one location while Claude CLI looks for them in another.
Code Evidence:
// workspace-manager.js (lines 24-26)
workspacePath = path.join(process.env.HOME, '.claude/projects', `${sanitizedName}-${projectId}`);
// Creates at: /home/nodejs/.claude/projects/default-workspace
// claude-cli.js (line 45)
if (process.env.RUNNING_IN_DOCKER === 'true') {
workingDir = `/app/workspaces/${workingDir}`;
}
// Expects at: /app/workspaces/workspace
Impact:
- Claude CLI cannot find project files
- Sessions cannot be resumed
- CLAUDE.md instructions not accessible
Root Cause:
- Inconsistent path resolution between services
- docker-init.js attempts to bridge but creates confusion
Issue #2: Claude CLI Installation & Symlink Problems
Problem: The Dockerfile.sliplane contains extensive debugging and manual symlink creation that may fail.
Code Evidence (Dockerfile.sliplane lines 95-141):
# Debug: Comprehensive Claude CLI installation verification
RUN echo "π Claude CLI Installation Debug:" && \
# ... 40+ lines of debugging and symlink attempts ...
ln -sf /usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js /usr/local/bin/claude
Issues:
- Manual symlink creation is fragile
- Assumes specific file locations that may change with package updates
- Complex debugging suggests underlying installation problems
- Alpine Linux may handle symlinks differently
Impact:
- Claude CLI command not found
- Symlink points to non-existent file
- Different behavior across Claude CLI versions
Issue #3: Environment Variable Conflicts
Problem: Multiple environment variables control similar behaviors with unclear precedence.
Conflicting Variables:
# Docker detection
RUNNING_IN_DOCKER=true
USE_DOCKER_WORKSPACE=true
# Path configuration
WORKSPACES_PATH=/app/workspaces
CLAUDE_PROJECTS_PATH=/app/workspaces
CLAUDE_HOME=/home/nodejs/.claude
# Actual usage varies
process.env.HOME = /home/nodejs # But code uses this for paths
Code Confusion (claude-cli.js lines 289-292):
const isDockerEnv = process.env.RUNNING_IN_DOCKER === 'true' ||
process.env.USE_DOCKER_WORKSPACE === 'true' ||
process.cwd().startsWith('/app') ||
process.env.HOME === '/home/nodejs' ||
require('fs').existsSync('/.dockerenv');
Impact:
- Inconsistent behavior across different code paths
- Difficult to debug which condition triggered
- May work locally but fail in production
Issue #4: Docker Detection Logic
Problem: Complex Docker detection with multiple fallbacks creates unpredictable behavior.
Detection Methods:
- Environment variable checks
- Working directory inspection
- Home directory pattern matching
- Docker indicator file (/.dockerenv)
- Different execution methods (execFile vs spawn)
Code Issues (claude-cli.js lines 298-387):
if (isDockerEnv) {
// Uses execFile with node explicitly
claudeCommand = '/usr/local/bin/node';
finalArgs = [claudeScriptPath, ...args];
claudeProcess = execFile(claudeCommand, finalArgs, spawnOptions);
} else {
// Uses spawn with 'claude' command
claudeProcess = spawnFunction('claude', args, spawnOptions);
}
Impact:
- Different execution paths may have different bugs
- Hard to reproduce issues consistently
- Alpine-specific issues with execFile
Issue #5: Platform Architecture Issues
Problem: Build scripts force AMD64 architecture which may not match Sliplane's actual platform.
Code Evidence (push-to-sliplane.sh line 191):
docker buildx build \
--platform linux/amd64 \ # Forced platform
-f "$DOCKERFILE" \
...
Issues:
- Sliplane may run on ARM64 or other architectures
- Forced platform can cause performance issues
- Native modules compiled for wrong architecture
Impact:
- Slow performance due to emulation
- Potential crashes with native modules
- Increased container size
Root Cause Analysis
Design Assumptions vs Reality
| Assumption | Reality | Consequence |
|---|---|---|
| Single workspace path strategy | Multiple path resolution strategies | Files created in wrong location |
| npm global install "just works" | Alpine Linux requires special handling | Claude CLI not accessible |
| Docker environment is uniform | Multiple Docker variants exist | Inconsistent behavior |
| Simple environment detection | Complex multi-layered detection needed | Unpredictable code paths |
| AMD64 is universal | Cloud platforms use various architectures | Performance and compatibility issues |
Architectural Debt
- Incremental Fixes: Each issue was patched individually rather than redesigning
- Multiple Truth Sources: Environment variables, file paths, and detection logic conflict
- Debugging Code in Production: Extensive debugging left in production Dockerfile
- Assumption Cascade: Each fix assumes previous fixes work correctly
Proposed Solutions
Short-term Fixes (Immediate)
1. Standardize Workspace Paths
// Add to workspace-manager.js
function getWorkspacePath(projectName) {
if (process.env.WORKSPACES_PATH) {
return path.join(process.env.WORKSPACES_PATH, projectName);
}
return path.join(process.env.HOME, '.claude/projects', projectName);
}
2. Simplify Claude CLI Installation
# Remove complex symlink logic, use npm bin directly
RUN npm install -g @anthropic-ai/claude-code@latest && \
npm bin -g && \
ln -sf $(npm bin -g)/claude /usr/local/bin/claude
3. Single Docker Detection Method
// Standardize on one detection method
function isDockerEnvironment() {
return process.env.RUNNING_IN_DOCKER === 'true';
}
Long-term Solutions (Architectural)
1. Unified Path Resolution Service
Create a single service responsible for all path resolution:
class PathResolver {
getWorkspacePath(project) { /* ... */ }
getClaudePath() { /* ... */ }
getDocumentPath() { /* ... */ }
}
2. Container-First Design
- Design for containers first, adapt for local development
- Use volume mounts consistently
- Avoid home directory assumptions
3. Platform-Agnostic Builds
# docker-compose.yml
services:
sasha:
build:
platforms:
- linux/amd64
- linux/arm64
4. Configuration Over Detection
Replace complex detection with explicit configuration:
// config.js
export default {
environment: process.env.DEPLOYMENT_ENV || 'local',
paths: {
workspace: process.env.WORKSPACE_PATH || '/app/workspaces',
claude: process.env.CLAUDE_PATH || '/home/nodejs/.claude'
}
}
Testing & Validation
Health Check Recommendations
1. Claude CLI Availability Check
// Add to health endpoint
async function checkClaudeCLI() {
try {
const { execSync } = require('child_process');
const result = execSync('which claude', { encoding: 'utf8' });
return { available: true, path: result.trim() };
} catch (error) {
return { available: false, error: error.message };
}
}
2. Workspace Path Validation
async function validateWorkspacePaths() {
const paths = {
configured: process.env.WORKSPACES_PATH,
expected: '/app/workspaces',
actual: await getActualWorkspacePath()
};
return {
valid: paths.configured === paths.actual,
paths
};
}
3. Environment Consistency Check
function checkEnvironmentConsistency() {
const checks = {
dockerEnv: process.env.RUNNING_IN_DOCKER === 'true',
dockerWorkspace: process.env.USE_DOCKER_WORKSPACE === 'true',
pathsAlign: process.env.WORKSPACES_PATH === process.env.CLAUDE_PROJECTS_PATH,
dockerFile: fs.existsSync('/.dockerenv')
};
return {
consistent: Object.values(checks).every(v => v === checks.dockerEnv),
checks
};
}
Deployment Verification Script
#!/bin/bash
# verify-claude-deployment.sh
echo "π Verifying Claude CLI Deployment"
# Check Claude CLI installation
if command -v claude &> /dev/null; then
echo "β
Claude CLI found at: $(which claude)"
claude --version
else
echo "β Claude CLI not found"
exit 1
fi
# Check workspace paths
echo "π Checking workspace paths:"
echo " WORKSPACES_PATH: $WORKSPACES_PATH"
echo " CLAUDE_PROJECTS_PATH: $CLAUDE_PROJECTS_PATH"
[ -d "$WORKSPACES_PATH" ] && echo " β
Workspace directory exists" || echo " β Workspace directory missing"
# Test Claude CLI execution
echo "π§ͺ Testing Claude CLI execution:"
echo "test" | claude --print "echo hello" --output-format stream-json &> /tmp/claude-test.log
[ $? -eq 0 ] && echo " β
Claude CLI executes" || echo " β Claude CLI execution failed"
Impact Assessment
Current State Impact
- Severity: Critical
- Affected Deployments: All containerized environments
- User Impact: Claude CLI features completely unavailable
- Business Impact: Core product functionality broken in production
Post-Fix Benefits
- Consistent behavior across all environments
- Simplified debugging and maintenance
- Faster deployment cycles
- Improved reliability
Migration Path
Phase 1: Immediate Patches (1-2 days)
- Fix workspace path resolution
- Simplify Claude CLI installation
- Add health checks
Phase 2: Refactoring (1 week)
- Implement PathResolver service
- Standardize environment detection
- Update all path references
Phase 3: Architecture Update (2 weeks)
- Container-first redesign
- Multi-platform builds
- Comprehensive testing suite
References
- Alpine Linux Node.js Best Practices
- Docker Multi-Platform Builds
- npm Global Installs in Docker
- Sliplane Documentation
Resolution Implemented
Fixes Applied (2025-08-10)
Workspace Path Resolution
- Created symlink from
/home/nodejs/.claude/projectsto/app/workspaces - All Claude CLI operations now use unified workspace directory
- Prevents duplicate workspace creation
- Created symlink from
Claude CLI Installation
- Simplified installation using
npm install -g @anthropic-ai/claude-code@latest - Proper symlink creation in Dockerfile
- Version 1.0.72 successfully deployed
- Simplified installation using
Docker Environment Detection
- Simplified to single
RUNNING_IN_DOCKER=truecheck - Added
USE_DOCKER_WORKSPACE=truefor redundancy - Removed complex multi-layered detection
- Simplified to single
Environment Variables
- All critical variables properly set in Dockerfile
- docker-entrypoint.sh ensures runtime configuration
- Consistent path resolution across services
Health Checks
- Created verification scripts for deployment validation
- Health endpoint configured in Dockerfile
- Monitoring scripts available
Final Solution Architecture
Verification Results
- Claude CLI installed and accessible at
/usr/local/bin/claude - Environment variables correctly set
- Workspace symlink functioning properly
- No duplicate workspace directories
- All operations use
/app/workspaces/as base
Checklist for Resolution
- Standardize workspace path resolution
- Fix Claude CLI installation in Alpine
- Simplify Docker environment detection
- Remove platform-specific build constraints
- Add comprehensive health checks
- Test in actual Sliplane environment
- Update documentation with findings
- Create verification scripts
- Monitor production deployments
- Document lessons learned
Last Updated: 2025-08-10
Status: Resolved
Owner: DevOps Team
Resolution: Successfully deployed to Sliplane with all issues fixed