dcdbae211c
Servizio self-hosted su VPS per interazione programmatica con modelli Anthropic tramite Claude Code SDK e abbonamento Pro/Max. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
669 lines
20 KiB
Markdown
669 lines
20 KiB
Markdown
# OpusAgent — Design Specification
|
|
|
|
> Servizio self-hosted che consente l'interazione programmatica con i modelli
|
|
> Anthropic attraverso Claude Code SDK, sfruttando un abbonamento Claude
|
|
> Pro/Max esistente. Il servizio espone un'API REST asincrona con gestione
|
|
> degli argomenti, coda di richieste sequenziale, rate limiting e generazione
|
|
> automatica di riassunti.
|
|
|
|
---
|
|
|
|
## 1. Panoramica
|
|
|
|
OpusAgent è un servizio a due componenti, deployato via Docker su una VPS
|
|
Hostinger, che funge da intermediario tra software client e i modelli
|
|
Anthropic. Invece di richiedere API key a consumo, il servizio sfrutta
|
|
un'istanza autenticata di Claude Code che opera con l'abbonamento Pro/Max
|
|
dell'utente.
|
|
|
|
### Obiettivi
|
|
|
|
- Consentire ai propri software di comunicare con Claude in modo programmatico
|
|
- Utilizzare l'abbonamento Claude Pro/Max esistente, evitando costi API a consumo
|
|
- Organizzare le interazioni per argomento con system prompt dedicati
|
|
- Supportare sia richieste one-shot che conversazioni multi-turn
|
|
- Accumulare conoscenza tramite riassunti incrementali e completi
|
|
- Garantire sicurezza con autenticazione API key e rate limiting
|
|
|
|
### Utenti
|
|
|
|
Uso esclusivamente personale: l'operatore e i suoi software.
|
|
|
|
---
|
|
|
|
## 2. Architettura
|
|
|
|
Il sistema è composto da due container Docker che comunicano via HTTP sulla
|
|
rete interna Docker, con persistenza su SQLite in un volume condiviso.
|
|
|
|
```
|
|
┌─────────────┐ ┌──────────────────┐ ┌──────────────────┐
|
|
│ Client │ REST │ FastAPI │ HTTP │ Node.js Worker │
|
|
│ Software │───────▶│ (Python) │───────▶│ (Claude Code │
|
|
│ │◀───────│ Queue + Auth │◀───────│ SDK) │
|
|
└─────────────┘ │ Rate Limit │ └────────┬─────────┘
|
|
└────────┬──────────┘ │
|
|
│ ┌─────▼─────────┐
|
|
┌────▼────┐ │ ~/.claude/ │
|
|
│ SQLite │ │ (auth volume) │
|
|
│ (coda) │ └───────────────┘
|
|
└─────────┘
|
|
```
|
|
|
|
### Componenti
|
|
|
|
| Componente | Tecnologia | Ruolo |
|
|
|------------|------------|-------|
|
|
| **fastapi-service** | Python 3.11+, FastAPI, SQLite | API REST pubblica, autenticazione, rate limiting, gestione coda |
|
|
| **claude-worker** | Node.js, @anthropic-ai/claude-code | Processamento richieste via Claude Code SDK, gestione sessioni |
|
|
| **SQLite** | Volume Docker condiviso | Persistenza coda richieste e argomenti |
|
|
| **Claude Auth** | Volume Docker dedicato | Credenziali Claude Code (solo worker) |
|
|
|
|
### Principi architetturali
|
|
|
|
- Il worker non è esposto all'esterno: comunica solo via rete Docker interna
|
|
- Processamento sequenziale: una richiesta alla volta (FIFO)
|
|
- Il FastAPI service è l'unico punto di ingresso
|
|
- Nessuna dipendenza da NATS: HTTP interno sufficiente per due servizi
|
|
- Integrazione Traefik per reverse proxy (ultima fase del deploy)
|
|
|
|
---
|
|
|
|
## 3. Data Model
|
|
|
|
### Tabella `topics`
|
|
|
|
Contiene gli argomenti con i rispettivi system prompt. Ogni argomento
|
|
rappresenta un contesto di conversazione distinto.
|
|
|
|
| Campo | Tipo | Vincoli | Descrizione |
|
|
|-------|------|---------|-------------|
|
|
| `id` | TEXT (UUID) | PK | Identificativo unico |
|
|
| `name` | TEXT | NOT NULL, UNIQUE | Nome breve (es. "coding", "analisi") |
|
|
| `system_prompt` | TEXT | NOT NULL | System prompt inviato a Claude per questo argomento |
|
|
| `summary` | TEXT | DEFAULT "" | Riassunto accumulato delle interazioni |
|
|
| `created_at` | TEXT (ISO 8601) | NOT NULL | Timestamp di creazione |
|
|
| `model` | TEXT | NULLABLE | Modello Claude per questo topic (override del default globale) |
|
|
| `updated_at` | TEXT (ISO 8601) | NOT NULL | Timestamp ultima modifica |
|
|
|
|
### Tabella `requests`
|
|
|
|
Contiene le richieste in coda, in elaborazione e completate.
|
|
|
|
| Campo | Tipo | Vincoli | Descrizione |
|
|
|-------|------|---------|-------------|
|
|
| `id` | TEXT (UUID) | PK | Identificativo unico |
|
|
| `session_id` | TEXT | NULLABLE | Raggruppa richieste multi-turn. Null = one-shot |
|
|
| `topic_id` | TEXT (UUID) | FK → topics.id, NOT NULL | Argomento di riferimento |
|
|
| `prompt` | TEXT | NOT NULL | Il prompt da inviare a Claude |
|
|
| `model` | TEXT | NULLABLE | Override modello per questa richiesta (prevale su topic e default) |
|
|
| `summarize` | INTEGER | DEFAULT 0 | 1 = genera riassunto e lo appende al topic |
|
|
| `status` | TEXT | NOT NULL, DEFAULT "pending" | `pending`, `processing`, `completed`, `failed` |
|
|
| `result` | TEXT | NULLABLE | Risposta di Claude |
|
|
| `error` | TEXT | NULLABLE | Messaggio di errore (se status = failed) |
|
|
| `created_at` | TEXT (ISO 8601) | NOT NULL | Timestamp di creazione |
|
|
| `completed_at` | TEXT (ISO 8601) | NULLABLE | Timestamp di completamento |
|
|
|
|
### Relazioni
|
|
|
|
- `requests.topic_id` → `topics.id` (molti a uno)
|
|
- `requests.session_id` raggruppa logicamente richieste della stessa conversazione
|
|
- Un topic può avere zero o più richieste
|
|
- Una sessione è definita implicitamente dal `session_id` condiviso tra richieste
|
|
|
|
---
|
|
|
|
## 4. API REST
|
|
|
|
Tutti gli endpoint richiedono l'header `X-Api-Key` con la chiave configurata
|
|
nel `.env`. Risposte nel formato envelope standard:
|
|
`{success: bool, data: any, error: {code, message} | null}`.
|
|
|
|
### 4.1 Topics
|
|
|
|
#### `POST /api/topics`
|
|
|
|
Crea un nuovo argomento.
|
|
|
|
```json
|
|
// Request
|
|
{
|
|
"name": "coding",
|
|
"system_prompt": "Sei un esperto sviluppatore Python e TypeScript...",
|
|
"summary": "Argomento per domande di programmazione",
|
|
"model": "claude-sonnet-4-6"
|
|
}
|
|
|
|
// Response 201
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
"name": "coding",
|
|
"system_prompt": "Sei un esperto sviluppatore Python e TypeScript...",
|
|
"summary": "Argomento per domande di programmazione",
|
|
"created_at": "2026-05-25T10:00:00Z",
|
|
"updated_at": "2026-05-25T10:00:00Z"
|
|
},
|
|
"error": null
|
|
}
|
|
```
|
|
|
|
#### `GET /api/topics`
|
|
|
|
Lista tutti gli argomenti.
|
|
|
|
#### `GET /api/topics/{id}`
|
|
|
|
Dettaglio di un argomento.
|
|
|
|
#### `PUT /api/topics/{id}`
|
|
|
|
Aggiorna un argomento (name, system_prompt, summary).
|
|
|
|
#### `DELETE /api/topics/{id}`
|
|
|
|
Elimina un argomento. Fallisce se ci sono richieste pending/processing.
|
|
|
|
#### `POST /api/topics/{id}/summarize`
|
|
|
|
Rigenera il summary completo del topic analizzando tutte le richieste
|
|
completate. Invia l'elenco degli scambi (prompt + risultato) a Claude Code
|
|
e sostituisce il campo `summary` con il nuovo riassunto complessivo.
|
|
|
|
### 4.2 Requests
|
|
|
|
#### `POST /api/requests`
|
|
|
|
Invia una nuova richiesta alla coda.
|
|
|
|
```json
|
|
// Request
|
|
{
|
|
"prompt": "Come implemento un middleware di autenticazione JWT in FastAPI?",
|
|
"topic_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
"session_id": null,
|
|
"model": null,
|
|
"summarize": true
|
|
}
|
|
|
|
// Response 202
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
|
|
"status": "pending",
|
|
"created_at": "2026-05-25T10:05:00Z"
|
|
},
|
|
"error": null
|
|
}
|
|
```
|
|
|
|
#### `GET /api/requests/{id}`
|
|
|
|
Restituisce stato e risultato (quando disponibile).
|
|
|
|
```json
|
|
// Response (completata)
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
|
|
"session_id": null,
|
|
"topic_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
"prompt": "Come implemento un middleware di autenticazione JWT in FastAPI?",
|
|
"summarize": true,
|
|
"status": "completed",
|
|
"result": "Per implementare un middleware JWT in FastAPI...",
|
|
"error": null,
|
|
"created_at": "2026-05-25T10:05:00Z",
|
|
"completed_at": "2026-05-25T10:05:45Z"
|
|
},
|
|
"error": null
|
|
}
|
|
```
|
|
|
|
#### `GET /api/requests`
|
|
|
|
Lista richieste con filtri opzionali: `?status=pending&topic_id=xxx&session_id=yyy`.
|
|
|
|
#### `DELETE /api/requests/{id}`
|
|
|
|
Cancella una richiesta con status `pending`. Non è possibile cancellare
|
|
richieste in `processing`, `completed` o `failed`.
|
|
|
|
### 4.3 Sessions
|
|
|
|
#### `GET /api/sessions`
|
|
|
|
Lista sessioni attive con conteggio richieste per ciascuna.
|
|
|
|
#### `DELETE /api/sessions/{id}`
|
|
|
|
Chiude una sessione. Le richieste existing restano, ma non si possono
|
|
aggiungere nuove richieste a questa sessione.
|
|
|
|
### 4.4 System
|
|
|
|
#### `GET /api/health`
|
|
|
|
Health check del servizio. Verifica:
|
|
- Stato FastAPI
|
|
- Connettività al worker (HTTP ping)
|
|
- Accesso al database SQLite
|
|
|
|
---
|
|
|
|
## 5. Flusso di Processamento
|
|
|
|
### 5.1 Flusso richiesta standard
|
|
|
|
1. Il client invia `POST /api/requests` con prompt e topic_id
|
|
2. FastAPI valida la richiesta, verifica API key, controlla rate limit
|
|
3. Crea record in SQLite con `status: "pending"`, restituisce `202 Accepted` con ID
|
|
4. Il client riceve l'ID e può fare polling su `GET /api/requests/{id}`
|
|
5. Il worker loop (nel FastAPI service) prende la richiesta pending più vecchia
|
|
6. Aggiorna status a `processing`
|
|
7. Carica il `system_prompt` dal topic associato
|
|
8. Chiama il worker Node.js via HTTP: `POST http://claude-worker:3001/process`
|
|
9. Il worker Node.js esegue la richiesta tramite Claude Code SDK
|
|
10. Il worker restituisce il risultato
|
|
11. FastAPI aggiorna il record: `status: "completed"`, `result: "..."`
|
|
12. Se `summarize: true`: il worker genera un riassunto dello scambio
|
|
e lo appende al `summary` del topic
|
|
13. Il client ottiene il risultato al prossimo polling
|
|
|
|
### 5.2 Flusso multi-turn
|
|
|
|
1. Prima richiesta: `POST /api/requests {prompt, topic_id}` (senza session_id)
|
|
2. Il sistema genera un `session_id` e lo restituisce nella risposta
|
|
3. Richieste successive: `POST /api/requests {prompt, topic_id, session_id: "..."}`
|
|
4. Il worker Node.js usa il session_id per mantenere il contesto con Claude Code
|
|
(flag `--resume` o equivalente SDK)
|
|
5. Ogni richiesta nella sessione condivide la storia della conversazione
|
|
|
|
### 5.3 Flusso summary completo
|
|
|
|
1. Il client chiama `POST /api/topics/{id}/summarize`
|
|
2. FastAPI raccoglie tutte le richieste `completed` del topic
|
|
3. Compone un payload con tutti gli scambi (prompt + risultato)
|
|
4. Chiama il worker per generare un riassunto complessivo
|
|
5. Sostituisce il campo `summary` del topic con il nuovo riassunto
|
|
6. Restituisce il summary aggiornato
|
|
|
|
### 5.4 Flusso summary incrementale
|
|
|
|
1. Richiesta con `summarize: true` viene completata
|
|
2. Dopo aver salvato il risultato, il worker genera un riassunto
|
|
in 1-2 frasi dello scambio
|
|
3. Il riassunto viene appeso al `summary` del topic con timestamp:
|
|
`[2026-05-25] Descrizione dello scambio.`
|
|
|
|
---
|
|
|
|
## 6. Node.js Worker
|
|
|
|
### Responsabilità
|
|
|
|
Il worker è un server HTTP interno minimale con un'unica responsabilità:
|
|
eseguire richieste tramite Claude Code SDK e restituire il risultato.
|
|
|
|
### Endpoint interni
|
|
|
|
| Metodo | Path | Descrizione |
|
|
|--------|------|-------------|
|
|
| `POST` | `/process` | Processa una richiesta Claude Code |
|
|
| `POST` | `/summarize` | Genera riassunto di uno o più scambi |
|
|
| `GET` | `/health` | Health check del worker |
|
|
|
|
### Payload `/process`
|
|
|
|
```json
|
|
// Request
|
|
{
|
|
"prompt": "Come implemento JWT?",
|
|
"system_prompt": "Sei un esperto sviluppatore...",
|
|
"model": "claude-sonnet-4-6",
|
|
"session_id": null
|
|
}
|
|
|
|
// Response
|
|
{
|
|
"success": true,
|
|
"result": "Per implementare JWT in FastAPI...",
|
|
"session_id": "generated-or-existing-id"
|
|
}
|
|
```
|
|
|
|
### Payload `/summarize`
|
|
|
|
```json
|
|
// Request
|
|
{
|
|
"exchanges": [
|
|
{"prompt": "Come faccio X?", "result": "Si fa così..."},
|
|
{"prompt": "E se devo Y?", "result": "In quel caso..."}
|
|
],
|
|
"mode": "incremental"
|
|
}
|
|
|
|
// Response
|
|
{
|
|
"success": true,
|
|
"summary": "[2026-05-25] Discusso come implementare X e gestire il caso Y."
|
|
}
|
|
```
|
|
|
|
### Claude Code SDK Usage
|
|
|
|
```javascript
|
|
import { claude } from '@anthropic-ai/claude-code';
|
|
|
|
const result = await claude({
|
|
prompt: request.prompt,
|
|
systemPrompt: request.system_prompt,
|
|
model: request.model,
|
|
// Per multi-turn: resume dalla sessione
|
|
...(request.session_id && { resume: request.session_id }),
|
|
// Output in formato testo, non interattivo
|
|
print: true,
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Selezione Modello
|
|
|
|
Il modello Claude da utilizzare si risolve con priorità a cascata:
|
|
|
|
1. **Request `model`** — se la richiesta specifica un modello, usa quello
|
|
2. **Topic `model`** — se il topic ha un modello configurato, usa quello
|
|
3. **Default globale** — `CLAUDE_MODEL` dal `.env`
|
|
|
|
Questa gerarchia consente di avere un default ragionevole (es. `claude-sonnet-4-6`)
|
|
con la flessibilità di usare modelli diversi per argomenti specifici (es. Opus
|
|
per analisi complesse) o per singole richieste (es. Haiku per domande semplici).
|
|
|
|
### Modelli supportati
|
|
|
|
I valori accettati corrispondono agli identificativi dei modelli Claude:
|
|
- `claude-opus-4-7`
|
|
- `claude-sonnet-4-6`
|
|
- `claude-haiku-4-5-20251001`
|
|
|
|
La validazione accetta qualsiasi stringa che inizi con `claude-` per
|
|
compatibilità con modelli futuri.
|
|
|
|
---
|
|
|
|
## 8. Rate Limiting
|
|
|
|
Implementato con `slowapi` (wrapper di `limits` per FastAPI).
|
|
|
|
### Configurazione
|
|
|
|
```
|
|
# .env
|
|
RATE_LIMIT_PER_MINUTE=10
|
|
RATE_LIMIT_PER_HOUR=100
|
|
```
|
|
|
|
### Comportamento
|
|
|
|
- Limiti applicati per API key
|
|
- Quando superati: risposta `429 Too Many Requests` con header
|
|
`Retry-After` e `X-RateLimit-Remaining`
|
|
- I limiti si applicano solo a `POST /api/requests` (invio richieste)
|
|
- Gli endpoint di lettura (GET) e gestione topics non sono limitati
|
|
|
|
---
|
|
|
|
## 9. Sicurezza
|
|
|
|
### Autenticazione API
|
|
|
|
- Header `X-Api-Key` obbligatorio su tutti gli endpoint
|
|
- Chiave configurata in `.env`
|
|
- Risposta `403 Forbidden` se mancante o non valida
|
|
|
|
### Isolamento Worker
|
|
|
|
- Il worker Node.js non è esposto all'esterno (`expose`, non `ports`)
|
|
- Raggiungibile solo dalla rete Docker interna
|
|
- Nessuna autenticazione sul worker (rete fidata interna)
|
|
|
|
### Credenziali Claude Code
|
|
|
|
- Conservate in volume Docker dedicato (`claude-auth`)
|
|
- Non accessibili dal container FastAPI
|
|
- Autenticazione manuale una tantum alla prima configurazione
|
|
|
|
### Integrazione Traefik
|
|
|
|
- Sarà implementata come ultima fase del deploy
|
|
- Il servizio FastAPI sarà raggiungibile tramite reverse proxy Traefik
|
|
- HTTPS via Let's Encrypt tramite Traefik
|
|
- Labels Docker per il routing automatico
|
|
|
|
---
|
|
|
|
## 10. Configurazione
|
|
|
|
### .env
|
|
|
|
```
|
|
# Server
|
|
API_HOST=0.0.0.0
|
|
API_PORT=8000
|
|
|
|
# Sicurezza
|
|
API_KEY=
|
|
|
|
# Rate Limiting
|
|
RATE_LIMIT_PER_MINUTE=10
|
|
RATE_LIMIT_PER_HOUR=100
|
|
|
|
# Worker
|
|
WORKER_URL=http://claude-worker:3001
|
|
|
|
# Database
|
|
DB_PATH=/data/opus-agent.db
|
|
|
|
# Claude Code (worker)
|
|
CLAUDE_MODEL=claude-sonnet-4-6
|
|
```
|
|
|
|
### Variabili condivise
|
|
|
|
Entrambi i container ricevono lo stesso `.env` via `env_file`.
|
|
Il FastAPI service usa le variabili di server, sicurezza, rate limit e DB.
|
|
Il worker usa `CLAUDE_MODEL` e il path DB per eventuali accessi diretti.
|
|
|
|
---
|
|
|
|
## 11. Struttura Progetto
|
|
|
|
```
|
|
opus-agent/
|
|
├── src/
|
|
│ └── backend/
|
|
│ ├── __init__.py
|
|
│ ├── main.py # Entry point FastAPI
|
|
│ ├── config.py # Pydantic Settings
|
|
│ ├── api/
|
|
│ │ ├── __init__.py
|
|
│ │ ├── dependencies.py # API Key auth + rate limiting
|
|
│ │ └── routes/
|
|
│ │ ├── __init__.py
|
|
│ │ ├── topics.py # CRUD topics + summarize
|
|
│ │ ├── requests.py # CRUD requests
|
|
│ │ ├── sessions.py # Lista/chiudi sessioni
|
|
│ │ └── health.py # Health check
|
|
│ ├── models/
|
|
│ │ ├── __init__.py
|
|
│ │ └── api.py # Pydantic models request/response
|
|
│ ├── db/
|
|
│ │ ├── __init__.py
|
|
│ │ ├── database.py # SQLite connection + init schema
|
|
│ │ └── models.py # Schema tabelle
|
|
│ └── services/
|
|
│ ├── __init__.py
|
|
│ ├── queue.py # Logica coda (pick pending, update status)
|
|
│ └── worker_client.py # Client HTTP per chiamare il worker
|
|
│
|
|
├── worker/
|
|
│ ├── index.js # Server HTTP + Claude Code SDK
|
|
│ ├── package.json
|
|
│ └── Dockerfile
|
|
│
|
|
├── tests/
|
|
│ ├── __init__.py
|
|
│ ├── conftest.py
|
|
│ ├── test_api_topics.py
|
|
│ ├── test_api_requests.py
|
|
│ └── test_services.py
|
|
│
|
|
├── Dockerfile # Backend Python
|
|
├── docker-compose.yml
|
|
├── pyproject.toml
|
|
├── .env.example
|
|
├── .gitignore
|
|
└── README.md
|
|
```
|
|
|
|
---
|
|
|
|
## 12. Docker
|
|
|
|
### Dockerfile Backend (Python)
|
|
|
|
```dockerfile
|
|
FROM python:3.11-slim AS base
|
|
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
|
WORKDIR /app
|
|
COPY pyproject.toml uv.lock ./
|
|
RUN uv sync --frozen --no-dev
|
|
COPY src/ src/
|
|
EXPOSE 8000
|
|
CMD ["uv", "run", "start"]
|
|
```
|
|
|
|
### Dockerfile Worker (Node.js)
|
|
|
|
```dockerfile
|
|
FROM node:20-slim
|
|
RUN npm install -g @anthropic-ai/claude-code
|
|
WORKDIR /app
|
|
COPY package.json ./
|
|
RUN npm ci --production
|
|
COPY index.js ./
|
|
EXPOSE 3001
|
|
CMD ["node", "index.js"]
|
|
```
|
|
|
|
### docker-compose.yml
|
|
|
|
```yaml
|
|
services:
|
|
fastapi-service:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
ports:
|
|
- "${API_PORT:-8000}:8000"
|
|
env_file: .env
|
|
volumes:
|
|
- opus-data:/data
|
|
depends_on:
|
|
claude-worker:
|
|
condition: service_healthy
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c",
|
|
"import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health')"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 3
|
|
|
|
claude-worker:
|
|
build:
|
|
context: ./worker
|
|
dockerfile: Dockerfile
|
|
expose:
|
|
- "3001"
|
|
env_file: .env
|
|
volumes:
|
|
- opus-data:/data
|
|
- claude-auth:/home/node/.claude
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3001/health"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 3
|
|
|
|
volumes:
|
|
opus-data:
|
|
claude-auth:
|
|
```
|
|
|
|
### Integrazione Traefik (ultima fase)
|
|
|
|
Nella configurazione finale, le porte dirette verranno sostituite da
|
|
labels Traefik per il routing automatico:
|
|
|
|
```yaml
|
|
# Da aggiungere a fastapi-service
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.opus-agent.rule=Host(`opus.tuodominio.com`)"
|
|
- "traefik.http.routers.opus-agent.tls.certresolver=letsencrypt"
|
|
- "traefik.http.services.opus-agent.loadbalancer.server.port=8000"
|
|
```
|
|
|
|
---
|
|
|
|
## 13. Setup Iniziale
|
|
|
|
### Prima installazione sulla VPS
|
|
|
|
1. Clona il repository e copia `.env.example` in `.env`, compila i valori
|
|
2. Avvia solo il worker per autenticare Claude Code:
|
|
```bash
|
|
docker compose run --rm claude-worker npx claude login
|
|
```
|
|
3. Segui il flusso di autenticazione nel browser
|
|
4. Le credenziali vengono salvate nel volume `claude-auth`
|
|
5. Avvia il sistema completo:
|
|
```bash
|
|
docker compose up -d
|
|
```
|
|
6. Verifica con `GET /api/health`
|
|
|
|
### Rinnovo credenziali
|
|
|
|
Se le credenziali Claude Code scadono:
|
|
```bash
|
|
docker compose run --rm claude-worker npx claude login
|
|
docker compose restart claude-worker
|
|
```
|
|
|
|
---
|
|
|
|
## 14. Limiti e Vincoli Noti
|
|
|
|
- **Throughput**: Una richiesta alla volta. Il tempo di risposta dipende dalla
|
|
complessità del prompt e dal carico sull'abbonamento Claude.
|
|
- **Rate limit abbonamento**: Claude Pro/Max ha limiti d'uso propri.
|
|
Se l'abbonamento raggiunge il suo limite, le richieste falliranno con
|
|
un errore specifico. Il servizio marca queste come `failed` con il
|
|
messaggio d'errore di Claude.
|
|
- **Sessioni multi-turn**: La persistenza delle sessioni dipende dal
|
|
comportamento del Claude Code SDK. Se il SDK non supporta nativamente
|
|
il resume di sessioni, si implementa passando lo storico come contesto.
|
|
- **Volume credenziali**: Le credenziali Claude Code nel volume Docker
|
|
possono scadere. Serve rinnovo manuale periodico.
|
|
- **SQLite concorrenza**: Con un solo writer (il queue processor), non ci
|
|
sono problemi di locking. Se in futuro si volessero più worker paralleli,
|
|
servirebbe migrare a PostgreSQL o usare WAL mode.
|