claude.md
This commit is contained in:
228
CLAUDE.md
Normal file
228
CLAUDE.md
Normal file
@@ -0,0 +1,228 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
**Container-per-session architecture** for Norwegian legal research chat interface:
|
||||
|
||||
- **session-manager**: FastAPI service managing OpenCode container lifecycles (one per user session)
|
||||
- **OpenCode containers**: Isolated chat environments with MCP integration
|
||||
- **Lovdata MCP server**: External Norwegian legal research server (15+ tools for law search, provisions, cross-references)
|
||||
- **Caddy**: Reverse proxy with dynamic session-based routing
|
||||
|
||||
### Session Manager Components
|
||||
|
||||
The session-manager is built with a layered architecture:
|
||||
|
||||
```
|
||||
main.py → FastAPI endpoints, session lifecycle orchestration
|
||||
docker_service.py → Docker abstraction layer (testable, mockable)
|
||||
async_docker_client.py → Async Docker operations
|
||||
database.py → PostgreSQL session persistence with asyncpg
|
||||
session_auth.py → Token-based session authentication
|
||||
container_health.py → Health monitoring and auto-recovery
|
||||
resource_manager.py → CPU/memory limits, throttling
|
||||
http_pool.py → Connection pooling for container HTTP requests
|
||||
host_ip_detector.py → Docker host IP detection (host.docker.internal fallback)
|
||||
logging_config.py → Structured JSON logging with context
|
||||
```
|
||||
|
||||
**Key design patterns:**
|
||||
- **Dependency injection**: SessionManager receives DockerService via constructor (enables testing with MockDockerService)
|
||||
- **Service abstraction**: Clean separation between business logic (main.py) and infrastructure (docker_service.py)
|
||||
- **Async-first**: All I/O operations use asyncio (Docker, HTTP, database)
|
||||
- **Database persistence**: Sessions survive manager restarts via PostgreSQL
|
||||
|
||||
### MCP Integration
|
||||
|
||||
OpenCode containers connect to two MCP servers:
|
||||
1. **lovdata MCP server**: Norwegian legal tools (configured via `MCP_SERVER` env var)
|
||||
2. **sequential-thinking**: Local MCP for reasoning (optional)
|
||||
|
||||
Configuration: `config_opencode/opencode.jsonc`
|
||||
|
||||
Skills: `config_opencode/skills/norwegian-legal-queries/`
|
||||
|
||||
## Development Commands
|
||||
|
||||
### Running the stack
|
||||
|
||||
```bash
|
||||
# Start all services (session-manager, docker-daemon, caddy)
|
||||
docker-compose up --build
|
||||
|
||||
# Start in background
|
||||
docker-compose up -d --build
|
||||
|
||||
# View logs
|
||||
docker-compose logs -f session-manager
|
||||
|
||||
# Stop services
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
### Session management (API)
|
||||
|
||||
```bash
|
||||
# Create session
|
||||
curl http://localhost/api/sessions -X POST
|
||||
|
||||
# List sessions
|
||||
curl http://localhost/api/sessions
|
||||
|
||||
# Get session info
|
||||
curl http://localhost/api/sessions/{session_id}
|
||||
|
||||
# Delete session
|
||||
curl http://localhost/api/sessions/{session_id} -X DELETE
|
||||
|
||||
# Manual cleanup
|
||||
curl http://localhost/api/cleanup -X POST
|
||||
|
||||
# Health check
|
||||
curl http://localhost/api/health
|
||||
```
|
||||
|
||||
### Running session-manager locally (without Docker)
|
||||
|
||||
```bash
|
||||
cd session-manager
|
||||
|
||||
# Install dependencies
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Run directly (requires Docker socket or TLS connection)
|
||||
uvicorn main:app --reload --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
Test scripts in `docker/scripts/`:
|
||||
|
||||
```bash
|
||||
# Test Docker service abstraction
|
||||
python docker/scripts/test-docker-service.py
|
||||
|
||||
# Test async Docker operations
|
||||
python docker/scripts/test-async-docker.py
|
||||
|
||||
# Test resource limits
|
||||
python docker/scripts/test-resource-limits.py
|
||||
|
||||
# Test session authentication
|
||||
python docker/scripts/test-session-auth.py
|
||||
|
||||
# Test database persistence
|
||||
python docker/scripts/test-database-persistence.py
|
||||
|
||||
# Test container health monitoring
|
||||
python docker/scripts/test-container-health.py
|
||||
|
||||
# Test HTTP connection pooling
|
||||
python docker/scripts/test-http-connection-pool.py
|
||||
|
||||
# Test host IP detection
|
||||
python docker/scripts/test-host-ip-detection.py
|
||||
|
||||
# Test structured logging
|
||||
python docker/scripts/test-structured-logging.py
|
||||
```
|
||||
|
||||
All test scripts are self-contained and can run independently.
|
||||
|
||||
### Building the OpenCode image
|
||||
|
||||
```bash
|
||||
# Build with custom MCP server
|
||||
make build MCP_SERVER=http://your-lovdata-server:8001
|
||||
|
||||
# Run container interactively
|
||||
make run
|
||||
|
||||
# Clean up image
|
||||
make clean
|
||||
```
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
Required environment variables (see `.env.example`):
|
||||
|
||||
```bash
|
||||
MCP_SERVER=http://localhost:8001 # External Lovdata MCP server URL
|
||||
|
||||
# Docker TLS (if using TLS instead of socket)
|
||||
DOCKER_TLS_VERIFY=1
|
||||
DOCKER_CERT_PATH=/etc/docker/certs
|
||||
DOCKER_HOST=tcp://host.docker.internal:2376
|
||||
|
||||
# Optional LLM keys (at least one required for chat functionality)
|
||||
OPENAI_API_KEY=...
|
||||
ANTHROPIC_API_KEY=...
|
||||
GOOGLE_API_KEY=...
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
**Current setup uses Docker socket mounting** (`/var/run/docker.sock`) which grants root access. TLS-based Docker API access is implemented but not enabled by default.
|
||||
|
||||
To enable TLS (recommended for production):
|
||||
|
||||
```bash
|
||||
# Generate certificates
|
||||
cd docker
|
||||
DOCKER_ENV=production ./scripts/generate-certs.sh
|
||||
|
||||
# Configure Docker daemon
|
||||
./scripts/setup-docker-tls.sh
|
||||
|
||||
# Update docker-compose.yml to use TLS instead of socket
|
||||
```
|
||||
|
||||
**Session isolation:**
|
||||
- Each session gets dedicated container
|
||||
- Resource limits: 4GB RAM, 1 CPU core per container
|
||||
- Max 3 concurrent sessions (configurable in resource_manager.py)
|
||||
- Auto-cleanup after 60 minutes inactivity
|
||||
|
||||
## Session Data Persistence
|
||||
|
||||
Sessions are stored in PostgreSQL with the following schema:
|
||||
- Session ID, container ID, status, timestamps
|
||||
- Survives session-manager restarts
|
||||
- Health monitoring tracks container state
|
||||
|
||||
Session working directories: `./sessions/` (bind-mounted into containers)
|
||||
|
||||
## Container Health Monitoring
|
||||
|
||||
Automatic health checks run every 30 seconds:
|
||||
- Restart unhealthy containers (max 3 attempts)
|
||||
- Mark failed sessions for cleanup
|
||||
- Track health history for debugging
|
||||
|
||||
## Implementation Documentation
|
||||
|
||||
Detailed implementation guides in `docker/`:
|
||||
- `ASYNC_DOCKER_IMPLEMENTATION.md` - Async Docker client
|
||||
- `CONTAINER_HEALTH_MONITORING_IMPLEMENTATION.md` - Health checks
|
||||
- `DATABASE_PERSISTENCE_IMPLEMENTATION.md` - Session database
|
||||
- `HOST_IP_IMPLEMENTATION.md` - Host IP detection
|
||||
- `HTTP_CONNECTION_POOLING_IMPLEMENTATION.md` - HTTP pooling
|
||||
- `RESOURCE_LIMITS_IMPLEMENTATION.md` - Resource management
|
||||
- `SESSION_AUTHENTICATION_IMPLEMENTATION.md` - Auth tokens
|
||||
- `STRUCTURED_LOGGING_IMPLEMENTATION.md` - JSON logging
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
1. **MCP_SERVER must point to external server**: The lovdata-ai MCP server is NOT part of this stack, configure URL in `.env`
|
||||
|
||||
2. **Docker socket permissions**: Session-manager needs access to Docker socket or TLS certificates
|
||||
|
||||
3. **Port conflicts**: Session-manager uses ports 8000, Caddy uses 80/443, docker-daemon uses 2376
|
||||
|
||||
4. **Container cleanup**: Failed containers may linger, use `/api/cleanup` to force cleanup
|
||||
|
||||
5. **Resource exhaustion**: Default limit is 3 concurrent sessions, increase in resource_manager.py if needed
|
||||
|
||||
6. **Database connection**: PostgreSQL connection configured in database.py, defaults to localhost:5432
|
||||
Reference in New Issue
Block a user