Upload files to "/"
This commit is contained in:
parent
03547a476d
commit
5881d0f0df
5 changed files with 1249 additions and 0 deletions
449
CHECKLIST.md
Normal file
449
CHECKLIST.md
Normal file
|
|
@ -0,0 +1,449 @@
|
||||||
|
# Claude Code Stack - Pre & Post Deployment Checklist
|
||||||
|
|
||||||
|
## ✅ Pre-Deployment Checklist
|
||||||
|
|
||||||
|
### Environment Preparation
|
||||||
|
- [ ] Anthropic API key obtained from https://console.anthropic.com/
|
||||||
|
- [ ] TrueNAS system is up and running
|
||||||
|
- [ ] Docker and Docker Compose installed on TrueNAS
|
||||||
|
- Verify: `ssh root@truenas-ip "docker --version"`
|
||||||
|
- Verify: `ssh root@truenas-ip "docker-compose --version"`
|
||||||
|
- [ ] SSH access to TrueNAS is working
|
||||||
|
- Test: `ssh root@your-truenas-ip "echo 'Connected'"`
|
||||||
|
- [ ] Sufficient disk space available (minimum 20GB)
|
||||||
|
- Check: `ssh root@truenas-ip "df -h"`
|
||||||
|
- [ ] Sufficient RAM (minimum 4GB allocated to Docker)
|
||||||
|
|
||||||
|
### Network Preparation
|
||||||
|
- [ ] TrueNAS IP address noted: _______________
|
||||||
|
- [ ] Firewall allows ports 3000, 5000, 5432, 6379, 80, 443
|
||||||
|
- [ ] No port conflicts on TrueNAS
|
||||||
|
- Check: `ssh root@truenas-ip "netstat -tuln | grep LISTEN"`
|
||||||
|
- [ ] DNS is correctly configured (if accessing via hostname)
|
||||||
|
|
||||||
|
### File Preparation
|
||||||
|
- [ ] All deployment files downloaded
|
||||||
|
- [ ] docker-compose.yml
|
||||||
|
- [ ] deploy-ssh.sh or deploy-mcp.py
|
||||||
|
- [ ] claude-code-stack.env
|
||||||
|
- [ ] nginx.conf
|
||||||
|
- [ ] Dockerfile (optional)
|
||||||
|
- [ ] deployment scripts have execute permissions
|
||||||
|
- Run: `chmod +x deploy-ssh.sh`
|
||||||
|
- Run: `chmod +x deploy-mcp.py`
|
||||||
|
|
||||||
|
### System Information (for reference)
|
||||||
|
- [ ] TrueNAS IP: _______________
|
||||||
|
- [ ] SSH Username: _______________
|
||||||
|
- [ ] Pool Name: _______________
|
||||||
|
- [ ] Anthropic API Key (first 10 chars): _______________
|
||||||
|
- [ ] PostgreSQL Password (secure): _______________
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Deployment Execution Checklist
|
||||||
|
|
||||||
|
### Method 1: SSH Deployment (Recommended)
|
||||||
|
|
||||||
|
- [ ] Set API key environment variable
|
||||||
|
```bash
|
||||||
|
export ANTHROPIC_API_KEY="sk-ant-your-key-here"
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Run deployment script
|
||||||
|
```bash
|
||||||
|
chmod +x deploy-ssh.sh
|
||||||
|
./deploy-ssh.sh 192.168.1.100 root tank
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Monitor deployment progress
|
||||||
|
- [ ] Directory creation: `✓ created`
|
||||||
|
- [ ] Files uploaded: `✓ uploaded`
|
||||||
|
- [ ] Docker images pulled: `✓ pulled`
|
||||||
|
- [ ] Services started: `✓ started`
|
||||||
|
|
||||||
|
- [ ] Record deployment output
|
||||||
|
- [ ] Project directory: _______________
|
||||||
|
- [ ] Access URL: http://_______________:3000
|
||||||
|
- [ ] Start time: _______________
|
||||||
|
- [ ] End time: _______________
|
||||||
|
|
||||||
|
### Method 2: MCP Deployment
|
||||||
|
|
||||||
|
- [ ] Dependencies installed
|
||||||
|
```bash
|
||||||
|
pip install httpx
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] MCP server accessible
|
||||||
|
- Test: `curl https://mcp.wilddragon.net/mcp`
|
||||||
|
|
||||||
|
- [ ] Run deployment script
|
||||||
|
```bash
|
||||||
|
python deploy-mcp.py --mcp-url https://mcp.wilddragon.net/mcp --pool tank
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Monitor deployment status
|
||||||
|
- [ ] Directory created
|
||||||
|
- [ ] Files written
|
||||||
|
- [ ] Images pulled
|
||||||
|
- [ ] Services started
|
||||||
|
|
||||||
|
### Method 3: Manual Deployment
|
||||||
|
|
||||||
|
- [ ] SSH into TrueNAS
|
||||||
|
```bash
|
||||||
|
ssh root@your-truenas-ip
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Create directory
|
||||||
|
```bash
|
||||||
|
mkdir -p /mnt/tank/docker/claude-code-stack
|
||||||
|
cd /mnt/tank/docker/claude-code-stack
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Copy docker-compose.yml
|
||||||
|
- [ ] Copy .env file and update with API key
|
||||||
|
- [ ] Verify .env file
|
||||||
|
```bash
|
||||||
|
cat .env | grep ANTHROPIC_API_KEY
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Start services
|
||||||
|
```bash
|
||||||
|
docker-compose pull
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Verify services
|
||||||
|
```bash
|
||||||
|
docker-compose ps
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Post-Deployment Verification
|
||||||
|
|
||||||
|
### Immediate Verification (0-2 minutes)
|
||||||
|
|
||||||
|
- [ ] Docker services are running
|
||||||
|
```bash
|
||||||
|
docker-compose ps
|
||||||
|
```
|
||||||
|
Expected output:
|
||||||
|
```
|
||||||
|
NAME STATUS PORTS
|
||||||
|
claude-agents-ui Up (healthy) 0.0.0.0:3000->3000/tcp
|
||||||
|
claude-code-runtime Up (healthy) 0.0.0.0:5000->5000/tcp
|
||||||
|
claude-postgres Up (healthy) 0.0.0.0:5432->5432/tcp
|
||||||
|
claude-redis Up (healthy) 0.0.0.0:6379->6379/tcp
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] All services showing "healthy" status
|
||||||
|
- [ ] No error messages in deployment output
|
||||||
|
|
||||||
|
### Web Interface Verification (2-5 minutes)
|
||||||
|
|
||||||
|
- [ ] Access Agents UI
|
||||||
|
- URL: http://your-truenas-ip:3000
|
||||||
|
- [ ] Page loads successfully
|
||||||
|
- [ ] No console errors
|
||||||
|
|
||||||
|
- [ ] Check UI is responsive
|
||||||
|
- [ ] Can click menu items
|
||||||
|
- [ ] Can see available agents
|
||||||
|
- [ ] Can see command structure
|
||||||
|
|
||||||
|
### Service Health Check (5-10 minutes)
|
||||||
|
|
||||||
|
- [ ] Agents UI health check
|
||||||
|
```bash
|
||||||
|
curl http://localhost:3000/health
|
||||||
|
```
|
||||||
|
Expected: `healthy` response
|
||||||
|
|
||||||
|
- [ ] Claude Code backend responding
|
||||||
|
```bash
|
||||||
|
docker-compose logs claude-code-backend | tail -20
|
||||||
|
```
|
||||||
|
Look for: No error messages
|
||||||
|
|
||||||
|
- [ ] PostgreSQL is initialized
|
||||||
|
```bash
|
||||||
|
docker-compose exec postgres pg_isready -U claude
|
||||||
|
```
|
||||||
|
Expected: `accepting connections`
|
||||||
|
|
||||||
|
- [ ] Redis is running
|
||||||
|
```bash
|
||||||
|
docker-compose exec redis redis-cli ping
|
||||||
|
```
|
||||||
|
Expected: `PONG`
|
||||||
|
|
||||||
|
### Configuration Verification
|
||||||
|
|
||||||
|
- [ ] .env file is properly configured
|
||||||
|
- [ ] ANTHROPIC_API_KEY is set
|
||||||
|
- [ ] POSTGRES_PASSWORD is changed from default
|
||||||
|
- [ ] SESSION_SECRET is set
|
||||||
|
|
||||||
|
- [ ] Volumes are mounted correctly
|
||||||
|
```bash
|
||||||
|
docker-compose exec agents-ui ls -la /root/.claude
|
||||||
|
docker-compose exec agents-ui ls -la /workspace
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Network connectivity between services
|
||||||
|
```bash
|
||||||
|
docker-compose exec agents-ui ping -c 1 claude-code-backend
|
||||||
|
```
|
||||||
|
Expected: successful ping
|
||||||
|
|
||||||
|
### Data Persistence Verification
|
||||||
|
|
||||||
|
- [ ] PostgreSQL database is accessible
|
||||||
|
```bash
|
||||||
|
docker-compose exec postgres psql -U claude -d claude_agents -c "\dt"
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Redis data can be stored and retrieved
|
||||||
|
```bash
|
||||||
|
docker-compose exec redis redis-cli SET test_key "test_value"
|
||||||
|
docker-compose exec redis redis-cli GET test_key
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Initial Configuration Tasks
|
||||||
|
|
||||||
|
### First-Time Setup
|
||||||
|
|
||||||
|
- [ ] Access Agents UI at http://your-truenas-ip:3000
|
||||||
|
- [ ] Create initial agent
|
||||||
|
- [ ] Test agent with simple prompt
|
||||||
|
- [ ] Configure workspace directory
|
||||||
|
- [ ] Set up SSH keys for git operations (optional)
|
||||||
|
|
||||||
|
### Authentication Setup
|
||||||
|
|
||||||
|
- [ ] Verify Claude Code authentication
|
||||||
|
```bash
|
||||||
|
docker-compose exec claude-code-backend claude auth status
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] If needed, re-authenticate
|
||||||
|
```bash
|
||||||
|
docker-compose exec claude-code-backend claude auth login
|
||||||
|
```
|
||||||
|
|
||||||
|
### Workspace Configuration
|
||||||
|
|
||||||
|
- [ ] Create workspace structure
|
||||||
|
```bash
|
||||||
|
docker-compose exec agents-ui mkdir -p /workspace/{projects,agents,tools}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Mount external projects (if applicable)
|
||||||
|
```bash
|
||||||
|
# Update docker-compose.yml volumes section
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 Security Post-Deployment Tasks
|
||||||
|
|
||||||
|
### Immediate Security
|
||||||
|
|
||||||
|
- [ ] Change PostgreSQL password
|
||||||
|
```bash
|
||||||
|
docker-compose exec postgres psql -U claude -c "ALTER USER claude WITH PASSWORD 'new-password';"
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Update SESSION_SECRET in .env
|
||||||
|
```bash
|
||||||
|
SESSION_SECRET=$(openssl rand -base64 32)
|
||||||
|
# Update .env and restart
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Restrict SSH access to TrueNAS (if possible)
|
||||||
|
|
||||||
|
### Recommended Security
|
||||||
|
|
||||||
|
- [ ] Enable SSL/TLS for web interface
|
||||||
|
- [ ] Configure firewall rules on TrueNAS
|
||||||
|
- [ ] Set up regular backups
|
||||||
|
- [ ] Configure log rotation
|
||||||
|
- [ ] Review and harden Nginx configuration
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Monitoring & Logging Setup
|
||||||
|
|
||||||
|
### Log Aggregation
|
||||||
|
|
||||||
|
- [ ] Set up log monitoring
|
||||||
|
```bash
|
||||||
|
docker-compose logs -f
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Configure log rotation (optional)
|
||||||
|
|
||||||
|
### Monitoring Tools
|
||||||
|
|
||||||
|
- [ ] Set up resource monitoring
|
||||||
|
```bash
|
||||||
|
docker stats
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Configure alerts (optional)
|
||||||
|
|
||||||
|
### Backup Strategy
|
||||||
|
|
||||||
|
- [ ] Create backup script
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
docker-compose exec claude-code-backend tar czf - -C /root .claude | gzip > backup.tar.gz
|
||||||
|
docker-compose exec postgres pg_dump -U claude claude_agents > backup.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Schedule daily backups
|
||||||
|
- [ ] Test backup restoration
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚨 Troubleshooting Post-Deployment
|
||||||
|
|
||||||
|
### If Services Won't Start
|
||||||
|
|
||||||
|
- [ ] Check Docker daemon is running
|
||||||
|
```bash
|
||||||
|
docker ps
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Check logs for errors
|
||||||
|
```bash
|
||||||
|
docker-compose logs agents-ui
|
||||||
|
docker-compose logs claude-code-backend
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Verify API key format
|
||||||
|
```bash
|
||||||
|
grep ANTHROPIC_API_KEY .env
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Check port availability
|
||||||
|
```bash
|
||||||
|
netstat -tuln | grep 3000
|
||||||
|
```
|
||||||
|
|
||||||
|
### If UI Won't Load
|
||||||
|
|
||||||
|
- [ ] Verify service is running
|
||||||
|
```bash
|
||||||
|
docker-compose ps agents-ui
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Check network connectivity
|
||||||
|
```bash
|
||||||
|
curl -v http://localhost:3000
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Review browser console for errors
|
||||||
|
- [ ] Check DNS resolution
|
||||||
|
```bash
|
||||||
|
nslookup your-truenas-ip
|
||||||
|
```
|
||||||
|
|
||||||
|
### If Claude Code Won't Execute
|
||||||
|
|
||||||
|
- [ ] Verify API key is correct
|
||||||
|
```bash
|
||||||
|
docker-compose exec claude-code-backend echo $ANTHROPIC_API_KEY
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Check authentication status
|
||||||
|
```bash
|
||||||
|
docker-compose exec claude-code-backend claude auth status
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Test with simple prompt
|
||||||
|
```bash
|
||||||
|
docker-compose exec claude-code-backend claude "hello"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Documentation & Handoff
|
||||||
|
|
||||||
|
### Documentation Created
|
||||||
|
|
||||||
|
- [ ] Deployment notes saved
|
||||||
|
- [ ] Custom configuration documented
|
||||||
|
- [ ] Access credentials stored securely
|
||||||
|
- [ ] Network diagram created (if complex setup)
|
||||||
|
|
||||||
|
### Team Handoff (if applicable)
|
||||||
|
|
||||||
|
- [ ] Access credentials shared securely
|
||||||
|
- [ ] Deployment process documented
|
||||||
|
- [ ] Troubleshooting guide provided
|
||||||
|
- [ ] Emergency contact information shared
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎉 Final Checklist
|
||||||
|
|
||||||
|
### Deployment Success Criteria
|
||||||
|
|
||||||
|
- [ ] All services running and healthy
|
||||||
|
- [ ] Web UI accessible and responsive
|
||||||
|
- [ ] Claude Code can execute prompts
|
||||||
|
- [ ] Database is initialized
|
||||||
|
- [ ] Redis cache is working
|
||||||
|
- [ ] Logs show no critical errors
|
||||||
|
- [ ] All required ports are open
|
||||||
|
- [ ] API key is properly configured
|
||||||
|
|
||||||
|
### Deployment Complete When
|
||||||
|
|
||||||
|
- [x] Docker Compose stack deployed
|
||||||
|
- [x] All services are healthy
|
||||||
|
- [x] Web interface is accessible
|
||||||
|
- [x] Claude Code is responding
|
||||||
|
- [x] Database is initialized
|
||||||
|
- [x] Backups are configured
|
||||||
|
- [x] Security measures in place
|
||||||
|
- [x] Documentation complete
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Sign-Off
|
||||||
|
|
||||||
|
**Deployment Date**: _______________
|
||||||
|
**Deployed By**: _______________
|
||||||
|
**System**: TrueNAS SCALE
|
||||||
|
**Pool**: _______________
|
||||||
|
**Project Directory**: _______________
|
||||||
|
**Access URL**: http://_______________:3000
|
||||||
|
|
||||||
|
**Notes**:
|
||||||
|
```
|
||||||
|
_____________________________________________________________________________
|
||||||
|
_____________________________________________________________________________
|
||||||
|
_____________________________________________________________________________
|
||||||
|
```
|
||||||
|
|
||||||
|
**Verification Complete**: ☐ Yes ☐ No
|
||||||
|
|
||||||
|
**Ready for Production**: ☐ Yes ☐ No (if No, list remaining items below)
|
||||||
|
|
||||||
|
```
|
||||||
|
_____________________________________________________________________________
|
||||||
|
_____________________________________________________________________________
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Deployment Package Version**: 1.0.0
|
||||||
|
**Last Updated**: 2026-04-04
|
||||||
|
**Checklist Version**: 1.0
|
||||||
92
claude-agents-ui-Dockerfile
Normal file
92
claude-agents-ui-Dockerfile
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install build dependencies
|
||||||
|
RUN apk add --no-cache git bun
|
||||||
|
|
||||||
|
# Clone the Claude Code Agents UI repository
|
||||||
|
RUN git clone --depth 1 https://github.com/Ngxba/claude-code-agents-ui.git . || true
|
||||||
|
|
||||||
|
# Install dependencies using bun or npm
|
||||||
|
RUN if [ -f bun.lockb ]; then \
|
||||||
|
bun install --frozen-lockfile; \
|
||||||
|
else \
|
||||||
|
npm install; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build the Nuxt application
|
||||||
|
RUN npm run build || bun run build
|
||||||
|
|
||||||
|
# Production stage
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install runtime dependencies including Claude Code and utilities
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
python3 py3-pip \
|
||||||
|
git git-lfs \
|
||||||
|
curl wget \
|
||||||
|
bash zsh \
|
||||||
|
vim nano \
|
||||||
|
build-base \
|
||||||
|
openssh-client \
|
||||||
|
ca-certificates \
|
||||||
|
tini
|
||||||
|
|
||||||
|
# Install Claude Code CLI
|
||||||
|
RUN npm install -g @anthropic-ai/claude-code
|
||||||
|
|
||||||
|
# Install Python tools for agent execution
|
||||||
|
RUN pip3 install --no-cache-dir \
|
||||||
|
requests \
|
||||||
|
python-dotenv \
|
||||||
|
pydantic \
|
||||||
|
fastapi \
|
||||||
|
uvicorn
|
||||||
|
|
||||||
|
# Copy built application from builder
|
||||||
|
COPY --from=builder /app/.output /app/.output
|
||||||
|
COPY --from=builder /app/package.json /app/package.json
|
||||||
|
COPY --from=builder /app/node_modules /app/node_modules
|
||||||
|
|
||||||
|
# Create non-root user for security
|
||||||
|
RUN addgroup -g 1000 claude && \
|
||||||
|
adduser -D -u 1000 -G claude claude
|
||||||
|
|
||||||
|
# Create necessary directories
|
||||||
|
RUN mkdir -p /workspace /root/.claude && \
|
||||||
|
chown -R claude:claude /workspace /root/.claude
|
||||||
|
|
||||||
|
# Set permissions
|
||||||
|
RUN chown -R claude:claude /app
|
||||||
|
|
||||||
|
# Create entrypoint script that starts both services
|
||||||
|
RUN cat > /entrypoint.sh << 'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Start Claude Code in the background if specified
|
||||||
|
if [ "$RUN_CLAUDE_CODE" = "true" ]; then
|
||||||
|
echo "Starting Claude Code daemon..."
|
||||||
|
claude serve &
|
||||||
|
CLAUDE_PID=$!
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start the Nuxt application
|
||||||
|
echo "Starting Claude Code Agents UI..."
|
||||||
|
exec node /app/.output/server/index.mjs
|
||||||
|
EOF
|
||||||
|
|
||||||
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
||||||
|
CMD curl -f http://localhost:3000/api/health || exit 1
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
# Use tini to handle signals properly
|
||||||
|
ENTRYPOINT ["/sbin/tini", "--"]
|
||||||
|
CMD ["/entrypoint.sh"]
|
||||||
142
claude-code-stack-docker-compose.yml
Normal file
142
claude-code-stack-docker-compose.yml
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# Claude Code Agents UI - Frontend interface for agent management
|
||||||
|
agents-ui:
|
||||||
|
build:
|
||||||
|
context: ./claude-code-agents-ui
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: claude-agents-ui
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
environment:
|
||||||
|
# Point agents-ui to the Claude Code backend
|
||||||
|
CLAUDE_DIR: /root/.claude
|
||||||
|
NODE_ENV: production
|
||||||
|
volumes:
|
||||||
|
# Mount Claude configuration directory
|
||||||
|
- claude-config:/root/.claude
|
||||||
|
# Mount workspace directory for agent projects
|
||||||
|
- workspace:/workspace
|
||||||
|
depends_on:
|
||||||
|
- claude-code-backend
|
||||||
|
networks:
|
||||||
|
- claude-stack
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:3000"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
# Claude Code Runtime - Backend service for code execution
|
||||||
|
claude-code-backend:
|
||||||
|
image: ghcr.io/anthropics/claude-code:latest
|
||||||
|
container_name: claude-code-runtime
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "5000:5000" # Internal API port if needed
|
||||||
|
environment:
|
||||||
|
# Required: Your Anthropic API key
|
||||||
|
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
||||||
|
# Optional: Use a custom API endpoint
|
||||||
|
# ANTHROPIC_BASE_URL: https://api.anthropic.com
|
||||||
|
# Claude model selection
|
||||||
|
CLAUDE_MODEL: claude-opus-4-1
|
||||||
|
# Workspace configuration
|
||||||
|
WORKSPACE_DIR: /workspace
|
||||||
|
volumes:
|
||||||
|
# Mount Claude configuration
|
||||||
|
- claude-config:/root/.claude
|
||||||
|
# Mount workspace for projects
|
||||||
|
- workspace:/workspace
|
||||||
|
# Mount SSH keys for git operations (read-only)
|
||||||
|
- ${HOME}/.ssh:/root/.ssh:ro
|
||||||
|
# Optional: Mount system package managers for agent access
|
||||||
|
# - /usr/local/bin:/usr/local/bin:ro
|
||||||
|
networks:
|
||||||
|
- claude-stack
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "test", "-d", "/workspace"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
# Security: Run as non-root user
|
||||||
|
user: "0:0" # Can be configured for non-root if needed
|
||||||
|
|
||||||
|
# Optional: PostgreSQL for agent data persistence
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: claude-postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: claude
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-changeMe123!}
|
||||||
|
POSTGRES_DB: claude_agents
|
||||||
|
volumes:
|
||||||
|
- postgres-data:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- claude-stack
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U claude"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
# Optional: Redis for caching and session management
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: claude-redis
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
volumes:
|
||||||
|
- redis-data:/data
|
||||||
|
networks:
|
||||||
|
- claude-stack
|
||||||
|
command: redis-server --appendonly yes
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
# Optional: Nginx reverse proxy for production setup
|
||||||
|
nginx:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: claude-nginx
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
# Uncomment for SSL:
|
||||||
|
# - ./certs:/etc/nginx/certs:ro
|
||||||
|
depends_on:
|
||||||
|
- agents-ui
|
||||||
|
- claude-code-backend
|
||||||
|
networks:
|
||||||
|
- claude-stack
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
claude-config:
|
||||||
|
driver: local
|
||||||
|
workspace:
|
||||||
|
driver: local
|
||||||
|
postgres-data:
|
||||||
|
driver: local
|
||||||
|
redis-data:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
networks:
|
||||||
|
claude-stack:
|
||||||
|
driver: bridge
|
||||||
147
claude-code-stack.env
Normal file
147
claude-code-stack.env
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
# ============================================================================
|
||||||
|
# Claude Code Stack Environment Configuration
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# ANTHROPIC API CONFIGURATION (REQUIRED)
|
||||||
|
# Get your API key from: https://console.anthropic.com/
|
||||||
|
ANTHROPIC_API_KEY=your_api_key_here
|
||||||
|
|
||||||
|
# Optional: Use a custom API endpoint (leave blank for default)
|
||||||
|
# ANTHROPIC_BASE_URL=https://api.anthropic.com
|
||||||
|
|
||||||
|
# CLAUDE CODE CONFIGURATION
|
||||||
|
# Model to use (options: claude-opus-4-1, claude-sonnet-4-20250514, claude-haiku-4)
|
||||||
|
CLAUDE_MODEL=claude-opus-4-1
|
||||||
|
|
||||||
|
# Enable Claude Code daemon in background
|
||||||
|
RUN_CLAUDE_CODE=true
|
||||||
|
|
||||||
|
# WORKSPACE CONFIGURATION
|
||||||
|
WORKSPACE_DIR=/workspace
|
||||||
|
|
||||||
|
# CLAUDE CONFIGURATION DIRECTORY
|
||||||
|
CLAUDE_CONFIG_DIR=/root/.claude
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# DATABASE CONFIGURATION (Optional - for persistence)
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# PostgreSQL
|
||||||
|
POSTGRES_USER=claude
|
||||||
|
POSTGRES_PASSWORD=changeMe123!
|
||||||
|
POSTGRES_DB=claude_agents
|
||||||
|
POSTGRES_HOST=postgres
|
||||||
|
POSTGRES_PORT=5432
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
REDIS_HOST=redis
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# APPLICATION CONFIGURATION
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# Node environment
|
||||||
|
NODE_ENV=production
|
||||||
|
|
||||||
|
# Frontend configuration
|
||||||
|
NUXT_PUBLIC_API_URL=http://localhost:3000/api
|
||||||
|
NUXT_PUBLIC_WS_URL=ws://localhost:3000/ws
|
||||||
|
|
||||||
|
# Backend API configuration
|
||||||
|
API_PORT=5000
|
||||||
|
API_HOST=0.0.0.0
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# LOGGING CONFIGURATION
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
LOG_LEVEL=info
|
||||||
|
DEBUG=false
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# NGINX CONFIGURATION (if using Nginx reverse proxy)
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
NGINX_ENABLE=true
|
||||||
|
NGINX_PROXY_PASS_UI=http://agents-ui:3000
|
||||||
|
NGINX_PROXY_PASS_API=http://claude-code-backend:5000
|
||||||
|
|
||||||
|
# SSL/TLS Configuration (optional)
|
||||||
|
# NGINX_SSL_ENABLE=false
|
||||||
|
# NGINX_SSL_CERT_PATH=/etc/nginx/certs/cert.pem
|
||||||
|
# NGINX_SSL_KEY_PATH=/etc/nginx/certs/key.pem
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# SECURITY CONFIGURATION
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# Enable CORS for specific origins
|
||||||
|
CORS_ORIGIN=*
|
||||||
|
|
||||||
|
# API rate limiting
|
||||||
|
RATE_LIMIT_ENABLED=true
|
||||||
|
RATE_LIMIT_MAX_REQUESTS=100
|
||||||
|
RATE_LIMIT_WINDOW_MS=60000
|
||||||
|
|
||||||
|
# Session configuration
|
||||||
|
SESSION_SECRET=your_random_session_secret_here_change_this
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# STORAGE CONFIGURATION
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# Local storage paths (inside containers)
|
||||||
|
STORAGE_PATH=/workspace
|
||||||
|
CACHE_PATH=/tmp/claude-cache
|
||||||
|
|
||||||
|
# Optional: S3/MinIO configuration for distributed storage
|
||||||
|
# S3_ENABLED=false
|
||||||
|
# S3_ENDPOINT=https://s3.amazonaws.com
|
||||||
|
# S3_BUCKET=claude-agents
|
||||||
|
# S3_ACCESS_KEY=
|
||||||
|
# S3_SECRET_KEY=
|
||||||
|
# S3_REGION=us-east-1
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# AGENT CONFIGURATION
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# Maximum concurrent agents
|
||||||
|
MAX_CONCURRENT_AGENTS=5
|
||||||
|
|
||||||
|
# Agent timeout (seconds)
|
||||||
|
AGENT_TIMEOUT=3600
|
||||||
|
|
||||||
|
# Allow agents to execute shell commands
|
||||||
|
ALLOW_SHELL_EXECUTION=true
|
||||||
|
|
||||||
|
# Allowed directories for agent access (comma-separated)
|
||||||
|
ALLOWED_DIRECTORIES=/workspace,/tmp
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# MONITORING & OBSERVABILITY
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# Enable health checks
|
||||||
|
HEALTH_CHECK_ENABLED=true
|
||||||
|
|
||||||
|
# Optional: Sentry error tracking
|
||||||
|
# SENTRY_DSN=
|
||||||
|
|
||||||
|
# Optional: Prometheus metrics
|
||||||
|
# PROMETHEUS_ENABLED=false
|
||||||
|
# PROMETHEUS_PORT=9090
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# DEVELOPMENT CONFIGURATION (not recommended for production)
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# Enable hot reload
|
||||||
|
HOT_RELOAD=false
|
||||||
|
|
||||||
|
# Enable debug mode
|
||||||
|
DEBUG_MODE=false
|
||||||
|
|
||||||
|
# Verbose logging
|
||||||
|
VERBOSE=false
|
||||||
419
deploy-mcp.py
Normal file
419
deploy-mcp.py
Normal file
|
|
@ -0,0 +1,419 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""
|
||||||
|
Claude Code Stack - TrueNAS MCP Deployment Script
|
||||||
|
|
||||||
|
Deploys the Claude Code + Agents UI stack to TrueNAS SCALE using the MCP protocol.
|
||||||
|
Requires mcp-server to be running on TrueNAS and accessible via MCP.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python deploy-mcp.py --mcp-url https://mcp.wilddragon.net/mcp --pool tank
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
import httpx
|
||||||
|
except ImportError:
|
||||||
|
print("Error: httpx is required. Install with: pip install httpx")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# ANSI Color codes
|
||||||
|
class Colors:
|
||||||
|
GREEN = '\033[0;32m'
|
||||||
|
YELLOW = '\033[1;33m'
|
||||||
|
RED = '\033[0;31m'
|
||||||
|
BLUE = '\033[0;34m'
|
||||||
|
RESET = '\033[0m'
|
||||||
|
|
||||||
|
def colored(text: str, color: str) -> str:
|
||||||
|
"""Return colored text for terminal output"""
|
||||||
|
return f"{color}{text}{Colors.RESET}"
|
||||||
|
|
||||||
|
def log_info(msg: str):
|
||||||
|
print(colored(f"[INFO] {msg}", Colors.GREEN))
|
||||||
|
|
||||||
|
def log_warn(msg: str):
|
||||||
|
print(colored(f"[WARN] {msg}", Colors.YELLOW))
|
||||||
|
|
||||||
|
def log_error(msg: str):
|
||||||
|
print(colored(f"[ERROR] {msg}", Colors.RED))
|
||||||
|
|
||||||
|
def log_step(msg: str):
|
||||||
|
print(colored(f"\n>>> {msg}", Colors.BLUE))
|
||||||
|
|
||||||
|
# Docker Compose YAML template
|
||||||
|
DOCKER_COMPOSE_TEMPLATE = """version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
agents-ui:
|
||||||
|
image: node:20-alpine
|
||||||
|
container_name: claude-agents-ui
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
environment:
|
||||||
|
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
||||||
|
NODE_ENV: production
|
||||||
|
CLAUDE_DIR: /root/.claude
|
||||||
|
volumes:
|
||||||
|
- claude-config:/root/.claude
|
||||||
|
- workspace:/workspace
|
||||||
|
depends_on:
|
||||||
|
- claude-code-backend
|
||||||
|
networks:
|
||||||
|
- claude-stack
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
claude-code-backend:
|
||||||
|
image: ghcr.io/anthropics/claude-code:latest
|
||||||
|
container_name: claude-code-runtime
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "5000:5000"
|
||||||
|
environment:
|
||||||
|
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
||||||
|
CLAUDE_MODEL: claude-opus-4-1
|
||||||
|
WORKSPACE_DIR: /workspace
|
||||||
|
volumes:
|
||||||
|
- claude-config:/root/.claude
|
||||||
|
- workspace:/workspace
|
||||||
|
- ${HOME}/.ssh:/root/.ssh:ro
|
||||||
|
networks:
|
||||||
|
- claude-stack
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "test", "-d", "/workspace"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: claude-postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: claude
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
POSTGRES_DB: claude_agents
|
||||||
|
volumes:
|
||||||
|
- postgres-data:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- claude-stack
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U claude"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: claude-redis
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
volumes:
|
||||||
|
- redis-data:/data
|
||||||
|
networks:
|
||||||
|
- claude-stack
|
||||||
|
command: redis-server --appendonly yes
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
claude-config:
|
||||||
|
driver: local
|
||||||
|
workspace:
|
||||||
|
driver: local
|
||||||
|
postgres-data:
|
||||||
|
driver: local
|
||||||
|
redis-data:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
networks:
|
||||||
|
claude-stack:
|
||||||
|
driver: bridge
|
||||||
|
"""
|
||||||
|
|
||||||
|
ENV_TEMPLATE = """# Claude Code Stack Environment Configuration
|
||||||
|
ANTHROPIC_API_KEY={api_key}
|
||||||
|
POSTGRES_PASSWORD={postgres_password}
|
||||||
|
SESSION_SECRET={session_secret}
|
||||||
|
NODE_ENV=production
|
||||||
|
CLAUDE_MODEL=claude-opus-4-1
|
||||||
|
RUN_CLAUDE_CODE=true
|
||||||
|
LOG_LEVEL=info
|
||||||
|
"""
|
||||||
|
|
||||||
|
class TrueNASMCPDeployer:
|
||||||
|
def __init__(self, mcp_url: str, pool_name: str, api_key: str):
|
||||||
|
self.mcp_url = mcp_url
|
||||||
|
self.pool_name = pool_name
|
||||||
|
self.api_key = api_key
|
||||||
|
self.project_dir = f"/mnt/{pool_name}/docker/claude-code-stack"
|
||||||
|
self.client = httpx.AsyncClient(timeout=30.0)
|
||||||
|
|
||||||
|
async def call_mcp(self, method: str, params: dict) -> dict:
|
||||||
|
"""Call MCP method via HTTP"""
|
||||||
|
payload = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": method,
|
||||||
|
"params": params,
|
||||||
|
"id": 1
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = await self.client.post(
|
||||||
|
self.mcp_url,
|
||||||
|
json=payload,
|
||||||
|
headers={"Content-Type": "application/json"}
|
||||||
|
)
|
||||||
|
|
||||||
|
if response.status_code != 200:
|
||||||
|
log_error(f"MCP call failed: {response.status_code}")
|
||||||
|
log_error(f"Response: {response.text}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
result = response.json()
|
||||||
|
|
||||||
|
if "error" in result:
|
||||||
|
log_error(f"MCP error: {result['error']}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
return result.get("result")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"MCP connection error: {str(e)}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def create_directory(self) -> bool:
|
||||||
|
"""Create project directory on TrueNAS"""
|
||||||
|
log_step(f"Creating project directory: {self.project_dir}")
|
||||||
|
|
||||||
|
result = await self.call_mcp(
|
||||||
|
"truenas:start_process",
|
||||||
|
{
|
||||||
|
"command": f"mkdir -p {self.project_dir} && chmod 755 {self.project_dir}",
|
||||||
|
"shell": True
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
log_info(f"Directory created: {self.project_dir}")
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def write_file(self, filename: str, content: str) -> bool:
|
||||||
|
"""Write file to TrueNAS via MCP"""
|
||||||
|
filepath = f"{self.project_dir}/{filename}"
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Write file using exec command
|
||||||
|
escaped_content = content.replace('"', '\\"').replace('\n', '\\n')
|
||||||
|
|
||||||
|
result = await self.call_mcp(
|
||||||
|
"truenas:start_process",
|
||||||
|
{
|
||||||
|
"command": f'cat > {filepath} << \'EOF\'\n{content}\nEOF',
|
||||||
|
"shell": True
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
log_info(f"Created: {filename}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"Failed to write {filename}: {str(e)}")
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def generate_env(self) -> str:
|
||||||
|
"""Generate .env file with random secrets"""
|
||||||
|
import secrets
|
||||||
|
import string
|
||||||
|
|
||||||
|
postgres_password = secrets.token_urlsafe(16)
|
||||||
|
session_secret = secrets.token_urlsafe(32)
|
||||||
|
|
||||||
|
return ENV_TEMPLATE.format(
|
||||||
|
api_key=self.api_key,
|
||||||
|
postgres_password=postgres_password,
|
||||||
|
session_secret=session_secret
|
||||||
|
)
|
||||||
|
|
||||||
|
async def deploy_docker_compose(self) -> bool:
|
||||||
|
"""Deploy docker-compose.yml"""
|
||||||
|
log_step("Deploying docker-compose.yml")
|
||||||
|
return await self.write_file("docker-compose.yml", DOCKER_COMPOSE_TEMPLATE)
|
||||||
|
|
||||||
|
async def deploy_env_file(self) -> bool:
|
||||||
|
"""Deploy .env file"""
|
||||||
|
log_step("Generating and deploying .env file")
|
||||||
|
env_content = await self.generate_env()
|
||||||
|
return await self.write_file(".env", env_content)
|
||||||
|
|
||||||
|
async def pull_images(self) -> bool:
|
||||||
|
"""Pull Docker images"""
|
||||||
|
log_step("Pulling Docker images")
|
||||||
|
|
||||||
|
result = await self.call_mcp(
|
||||||
|
"truenas:start_process",
|
||||||
|
{
|
||||||
|
"command": f"cd {self.project_dir} && docker-compose pull",
|
||||||
|
"shell": True
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result is not None
|
||||||
|
|
||||||
|
async def start_services(self) -> bool:
|
||||||
|
"""Start Docker services"""
|
||||||
|
log_step("Starting Docker services")
|
||||||
|
|
||||||
|
result = await self.call_mcp(
|
||||||
|
"truenas:start_process",
|
||||||
|
{
|
||||||
|
"command": f"cd {self.project_dir} && docker-compose up -d",
|
||||||
|
"shell": True
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result is not None
|
||||||
|
|
||||||
|
async def get_service_status(self) -> Optional[str]:
|
||||||
|
"""Get service status"""
|
||||||
|
result = await self.call_mcp(
|
||||||
|
"truenas:start_process",
|
||||||
|
{
|
||||||
|
"command": f"cd {self.project_dir} && docker-compose ps",
|
||||||
|
"shell": True
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
async def deploy(self) -> bool:
|
||||||
|
"""Execute full deployment"""
|
||||||
|
try:
|
||||||
|
print(colored("="*50, Colors.BLUE))
|
||||||
|
print(colored("Claude Code Stack - TrueNAS MCP Deployment", Colors.BLUE))
|
||||||
|
print(colored("="*50, Colors.BLUE))
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Check API key
|
||||||
|
if not self.api_key:
|
||||||
|
log_error("ANTHROPIC_API_KEY is required")
|
||||||
|
return False
|
||||||
|
|
||||||
|
log_info(f"MCP Server: {self.mcp_url}")
|
||||||
|
log_info(f"Pool: {self.pool_name}")
|
||||||
|
log_info(f"Project Directory: {self.project_dir}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Execute deployment steps
|
||||||
|
if not await self.create_directory():
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not await self.deploy_docker_compose():
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not await self.deploy_env_file():
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not await self.pull_images():
|
||||||
|
log_warn("Failed to pull images, continuing...")
|
||||||
|
|
||||||
|
if not await self.start_services():
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Wait for services
|
||||||
|
log_step("Waiting for services to stabilize...")
|
||||||
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
|
# Get status
|
||||||
|
log_step("Checking service status")
|
||||||
|
status = await self.get_service_status()
|
||||||
|
if status:
|
||||||
|
print(status)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
finally:
|
||||||
|
await self.client.aclose()
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Deploy Claude Code Stack to TrueNAS via MCP"
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--mcp-url",
|
||||||
|
required=True,
|
||||||
|
help="MCP server URL (e.g., https://mcp.wilddragon.net/mcp)"
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--pool",
|
||||||
|
default="tank",
|
||||||
|
help="TrueNAS pool name (default: tank)"
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--api-key",
|
||||||
|
help="Anthropic API Key (or set ANTHROPIC_API_KEY env var)"
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Get API key
|
||||||
|
api_key = args.api_key or os.environ.get("ANTHROPIC_API_KEY")
|
||||||
|
|
||||||
|
if not api_key:
|
||||||
|
log_error("ANTHROPIC_API_KEY not provided")
|
||||||
|
log_info("Set it via: export ANTHROPIC_API_KEY=your_key")
|
||||||
|
log_info("Or pass: --api-key your_key")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Create deployer
|
||||||
|
deployer = TrueNASMCPDeployer(
|
||||||
|
mcp_url=args.mcp_url,
|
||||||
|
pool_name=args.pool,
|
||||||
|
api_key=api_key
|
||||||
|
)
|
||||||
|
|
||||||
|
# Execute deployment
|
||||||
|
success = await deployer.deploy()
|
||||||
|
|
||||||
|
if success:
|
||||||
|
print()
|
||||||
|
print(colored("="*50, Colors.GREEN))
|
||||||
|
print(colored("Deployment Successful!", Colors.GREEN))
|
||||||
|
print(colored("="*50, Colors.GREEN))
|
||||||
|
print()
|
||||||
|
print("Access Agents UI at: http://your-truenas-ip:3000")
|
||||||
|
print(f"Project directory: {deployer.project_dir}")
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print()
|
||||||
|
print(colored("="*50, Colors.RED))
|
||||||
|
print(colored("Deployment Failed!", Colors.RED))
|
||||||
|
print(colored("="*50, Colors.RED))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
Loading…
Reference in a new issue